From 16f373e36cb2ef0512ac8a281cc18132b2b14b98 Mon Sep 17 00:00:00 2001 From: "arg@localhost.localdomain" Date: Sun, 11 May 2008 16:36:13 +0000 Subject: [PATCH 0001/1146] added new TODO --- TODO | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 0000000..f43eade --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ +- add the new st source code here +- add the new std source code here +- add new Makefile and config.mk +- add LICENSE From 1987ae4bacf58c588bbc967434be4e39125c37f9 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Tue, 20 May 2008 10:03:59 +0100 Subject: [PATCH 0002/1146] added some new files for the initial rewrite of st from scratch --- LICENSE | 22 ++++++++++++++++++++ Makefile | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ config.mk | 33 ++++++++++++++++++++++++++++++ st.c | 11 ++++++++++ std.c | 4 ++++ 5 files changed, 130 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 config.mk create mode 100644 st.c create mode 100644 std.c diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5b1d694 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT/X Consortium License + +© 2007-2008 Anselm R Garbe +© 2007-2008 Matthias Christian Ott + +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/Makefile b/Makefile new file mode 100644 index 0000000..c4d0b1a --- /dev/null +++ b/Makefile @@ -0,0 +1,60 @@ +# st - simple terminal +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = st +OBJ = ${SRC:.c=.o} + +all: options st + +options: + @echo st build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + @echo CC $< + @${CC} -c ${CFLAGS} $< + +${OBJ}: config.h config.mk + +config.h: + @echo creating $@ from config.def.h + @cp config.def.h $@ + +st: ${OBJ} + @echo CC -o $@ + @${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + @echo cleaning + @rm -f st ${OBJ} st-${VERSION}.tar.gz + +dist: clean + @echo creating dist tarball + @mkdir -p st-${VERSION} + @cp -R LICENSE Makefile README config.def.h config.mk \ + st.1 ${SRC} st-${VERSION} + @tar -cf st-${VERSION}.tar st-${VERSION} + @gzip st-${VERSION}.tar + @rm -rf st-${VERSION} + +install: all + @echo installing executable file to ${DESTDIR}${PREFIX}/bin + @mkdir -p ${DESTDIR}${PREFIX}/bin + @cp -f st ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/st + @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 + @mkdir -p ${DESTDIR}${MANPREFIX}/man1 + @sed "s/VERSION/${VERSION}/g" < st.1 > ${DESTDIR}${MANPREFIX}/man1/st.1 + @chmod 644 ${DESTDIR}${MANPREFIX}/man1/st.1 + +uninstall: + @echo removing executable file from ${DESTDIR}${PREFIX}/bin + @rm -f ${DESTDIR}${PREFIX}/bin/st + @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 + @rm -f ${DESTDIR}${MANPREFIX}/man1/st.1 + +.PHONY: all options clean dist install uninstall diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..5983bcb --- /dev/null +++ b/config.mk @@ -0,0 +1,33 @@ +# st version +VERSION = 0.0 + +# Customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = ${PREFIX}/share/man + +X11INC = /usr/X11R6/include +X11LIB = /usr/X11R6/lib + +# Xinerama, comment if you don't want it +XINERAMALIBS = -L${X11LIB} -lXinerama +XINERAMAFLAGS = -DXINERAMA + +# includes and libs +INCS = -I. -I/usr/include -I${X11INC} +LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} + +# flags +CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +CFLAGS = -Os ${INCS} ${CPPFLAGS} +LDFLAGS = -s ${LIBS} +#CFLAGS = -g -std=c99 -pedantic -Wall -O2 ${INCS} ${CPPFLAGS} +#LDFLAGS = -g ${LIBS} + +# Solaris +#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" +#LDFLAGS = ${LIBS} + +# compiler and linker +CC = cc diff --git a/st.c b/st.c new file mode 100644 index 0000000..33f165c --- /dev/null +++ b/st.c @@ -0,0 +1,11 @@ +/* See LICENSE file for copyright and license details. */ +#include + +int +main(int argc, char *argv[]) { + if(argc == 2 && !strcmp("-v", argv[1])) + eprint("st-"VERSION", © 2007-2008 st engineers, see LICENSE for details\n"); + else if(argc != 1) + eprint("usage: st [-v]\n"); + return 0; +} diff --git a/std.c b/std.c new file mode 100644 index 0000000..af1f2bc --- /dev/null +++ b/std.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ + +/* TODO: add the necessary code into here, which is going to be fork()ed from + * st if this isn't an attach process */ From 771ece25e89882a39700d0a24febbda42363d2ef Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Sun, 1 Jun 2008 18:02:48 +0100 Subject: [PATCH 0003/1146] applied Matthias-Christians changes to std.c --- std.c | 342 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 339 insertions(+), 3 deletions(-) diff --git a/std.c b/std.c index af1f2bc..a0d9a54 100644 --- a/std.c +++ b/std.c @@ -1,4 +1,340 @@ -/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -/* TODO: add the necessary code into here, which is going to be fork()ed from - * st if this isn't an attach process */ +#define LENGTH(x) (sizeof (x) / sizeof (x)[0]) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +void buffer(char c); +void cmd(const char *cmdstr, ...); +void *emallocz(unsigned int size); +void eprint(const char *errstr, ...); +void eprintn(const char *errstr, ...); +void getpty(void); +void movea(int x, int y); +void mover(int x, int y); +void parse(void); +void scroll(int l); +void shell(void); +void sigchld(int n); +char unbuffer(void); + +enum { QuestionMark = 1, Digit = 2 }; + +typedef struct { + unsigned char data[BUFSIZ]; + int s, e; + int n; +} RingBuffer; + +int cols = 80, lines = 25; +int cx = 0, cy = 0; +int c, s; +FILE *fptm = NULL; +int ptm, pts; +_Bool bold; +pid_t pid; +RingBuffer buf; + +void +buffer(char c) { + if(buf.n < LENGTH(buf.data)) + buf.n++; + else + buf.s = (buf.s + 1) % LENGTH(buf.data); + buf.data[buf.e++] = c; + buf.e %= LENGTH(buf.data); +} + +void +cmd(const char *cmdstr, ...) { + va_list ap; + + putchar('\n'); + putchar(':'); + va_start(ap, cmdstr); + vfprintf(stdout, cmdstr, ap); + va_end(ap); +} + +void * +emallocz(unsigned int size) { + void *res = calloc(1, size); + + if(!res) + eprint("fatal: could not malloc() %u bytes\n", size); + return res; +} + +void +eprint(const char *errstr, ...) { + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +void +eprintn(const char *errstr, ...) { + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + fprintf(stderr, ": %s\n", strerror(errno)); + exit(EXIT_FAILURE); +} + +void +getpty(void) { + char *ptsdev; + +#if defined(_GNU_SOURCE) + ptm = getpt(); +#elif _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 + ptm = posix_openpt(O_RDWR); +#elif defined(__sgi) + ttydev = _getpty(&ptm, O_RDWR, 0622, 0); +#elif defined(_AIX) + ptm = open("/dev/ptc", O_RDWR); +#else + ptm = open("/dev/ptmx", O_RDWR); +#if defined(__hpux) + if(ptm == -1) + ptm = open("/dev/ptym/clone", O_RDWR); +#endif + if(ptm == -1) { + if(openpty(&ptm, &pts, NULL, NULL, NULL) == -1) + eprintn("error, cannot open pty"); + return; + } +#endif + if(ptm != -1) { +#if defined(_XOPEN_SOURCE) || !defined(__sgi) || !defined(_AIX) + if(grantpt(ptm) == -1) + eprintn("error, cannot grant access to pty"); + if(unlockpt(ptm) == -1) + eprintn("error, cannot unlock pty"); + ptsdev = ptsname(ptm); +#elif defined(_AIX) + ptsdev = ttyname(ptm); +#endif + if(!ptsdev) + eprintn("error, slave pty name undefined"); + pts = open(ptsdev, O_RDWR); + if(pts == -1) + eprintn("error, cannot open slave pty"); + puts(ptsdev); +#if defined(__hpux) || defined(sun) || defined(__sun) + ioctl(pts, I_PUSH, "ptem"); + ioctl(pts, I_PUSH, "ldterm"); +#endif + } + else + eprintn("error, cannot open pty"); +} + +void +movea(int x, int y) { + x = MAX(x, cols); + y = MAX(y, lines); + cx = x; + cy = y; + cmd("s %d,%d", x, y); +} + +void +mover(int x, int y) { + movea(cx + x, cy + y); +} + +void +parseesc(void) { + int i, j; + int arg[16]; + + memset(arg, 0, LENGTH(arg)); + s = 0; + c = getc(fptm); + switch(c) { + case '[': + c = getc(fptm); + for(j = 0; j < LENGTH(arg);) { + if(isdigit(c)) { + s |= Digit; + arg[j] *= 10; + arg[j] += c - '0'; + } + else if(c == '?') + s |= QuestionMark; + else if(c == ';') { + if(!(s & Digit)) + eprint("syntax error"); + s &= ~Digit; + j++; + } + else { + if(s & Digit) { + s &= ~Digit; + j++; + } + break; + } + c = getc(fptm); + } + switch(c) { + case '@': + break; + case 'A': + mover(0, j ? arg[0] : 1); + break; + case 'B': + mover(0, j ? -arg[0] : -1); + break; + case 'C': + mover(j ? arg[0] : 1, 0); + break; + case 'D': + mover(j ? -arg[0] : -1, 0); + break; + case 'E': + /* movel(j ? arg[0] : 1); */ + break; + case 'F': + /* movel(j ? -arg[0] : -1); */ + break; + case '`': + case 'G': + movea(j ? arg[0] : 1, cy); + break; + case 'f': + case 'H': + movea(arg[1] ? arg[1] : 1, arg[0] ? arg[0] : 1); + case 'L': + /* insline(j ? arg[0] : 1); */ + break; + case 'M': + /* delline(j ? arg[0] : 1); */ + break; + case 'P': + break; + case 'S': + scroll(j ? arg[0] : 1); + break; + case 'T': + scroll(j ? -arg[0] : -1); + break; + case 'd': + movea(cx, j ? arg[0] : 1); + break; + case 'm': + for(i = 0; i < j; i++) { + if(arg[i] >= 30 && arg[i] <= 37) + cmd("#%d", arg[i] - 30); + if(arg[i] >= 40 && arg[i] <= 47) + cmd("|%d", arg[i] - 40); + /* xterm bright colors */ + if(arg[i] >= 90 && arg[i] <= 97) + cmd("#%d", arg[i] - 90); + if(arg[i] >= 100 && arg[i] <= 107) + cmd("|%d", arg[i] - 100); + switch(arg[i]) { + case 0: + case 22: + if(bold) + cmd("b"); + case 1: + if(!bold) + cmd("b"); + break; + } + } + break; + } + break; + default: + putchar('\033'); + ungetc(c, fptm); + } +} + +void +scroll(int l) { + cmd("s %d, %d", cx, cy + l); +} + +void +shell(void) { + static char *shell = NULL; + + if(!shell && !(shell = getenv("SHELL"))) + shell = "/bin/sh"; + pid = fork(); + switch(pid) { + case -1: + eprint("error, cannot fork\n"); + case 0: + setsid(); + dup2(pts, STDIN_FILENO); + dup2(pts, STDOUT_FILENO); + dup2(pts, STDERR_FILENO); + close(ptm); + putenv("TERM=vt102"); + execvp(shell, NULL); + break; + default: + close(pts); + signal(SIGCHLD, sigchld); + } +} + +void +sigchld(int n) { + int ret; + + if(waitpid(pid, &ret, 0) == -1) + eprintn("error, waiting for child failed"); + if(WIFEXITED(ret)) + exit(WEXITSTATUS(ret)); + else + exit(EXIT_SUCCESS); +} + +char +unbuffer(void) { + char c; + + c = buf.data[buf.s++]; + buf.s %= LENGTH(buf.data); + buf.n--; + return c; +} + +int +main(int argc, char *argv[]) { + fd_set rd; + if(argc == 2 && !strcmp("-v", argv[1])) + eprint("std-"VERSION", © 2008 Matthias-Christian Ott\n"); + else if(argc == 1) + eprint("usage: st [-v]\n"); + getpty(); + shell(); + fdopen(fptm, "r+"); + if(!fptm) + eprintn("cannot open slave pty"); + return 0; +} From 375efb8891a2d131d46f1582fd770d34464094e0 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Sun, 1 Jun 2008 18:04:49 +0100 Subject: [PATCH 0004/1146] slight changes --- Makefile | 10 +++------- st.c | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index c4d0b1a..cf1766c 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = st +SRC = st.c std.c OBJ = ${SRC:.c=.o} all: options st @@ -18,11 +18,7 @@ options: @echo CC $< @${CC} -c ${CFLAGS} $< -${OBJ}: config.h config.mk - -config.h: - @echo creating $@ from config.def.h - @cp config.def.h $@ +${OBJ}: config.mk st: ${OBJ} @echo CC -o $@ @@ -35,7 +31,7 @@ clean: dist: clean @echo creating dist tarball @mkdir -p st-${VERSION} - @cp -R LICENSE Makefile README config.def.h config.mk \ + @cp -R LICENSE Makefile README config.mk \ st.1 ${SRC} st-${VERSION} @tar -cf st-${VERSION}.tar st-${VERSION} @gzip st-${VERSION}.tar diff --git a/st.c b/st.c index 33f165c..a3421ff 100644 --- a/st.c +++ b/st.c @@ -2,7 +2,7 @@ #include int -main(int argc, char *argv[]) { +Xmain(int argc, char *argv[]) { if(argc == 2 && !strcmp("-v", argv[1])) eprint("st-"VERSION", © 2007-2008 st engineers, see LICENSE for details\n"); else if(argc != 1) From e2ac1676b10e71dcc2c11614637ea8f00d3ba9a1 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 2 Jun 2008 18:40:22 +0200 Subject: [PATCH 0005/1146] drop support for proprietary UNIX variants Proprietary UNIX variants like AIX, HP-UX or SCO UNIX are nowadays rarely used and maintaining compatibility to non-standard operating systems interfaces is wasteful and practically useless. Projects like xterm suffer from backward compatibility to decades-old UNIX variants and terminal standards. This does not conform to st's design goals. --- std.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/std.c b/std.c index a0d9a54..ef946dd 100644 --- a/std.c +++ b/std.c @@ -107,45 +107,31 @@ getpty(void) { ptm = getpt(); #elif _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 ptm = posix_openpt(O_RDWR); -#elif defined(__sgi) - ttydev = _getpty(&ptm, O_RDWR, 0622, 0); -#elif defined(_AIX) - ptm = open("/dev/ptc", O_RDWR); #else ptm = open("/dev/ptmx", O_RDWR); -#if defined(__hpux) - if(ptm == -1) - ptm = open("/dev/ptym/clone", O_RDWR); -#endif if(ptm == -1) { if(openpty(&ptm, &pts, NULL, NULL, NULL) == -1) eprintn("error, cannot open pty"); return; } #endif +#if defined(_XOPEN_SOURCE) if(ptm != -1) { -#if defined(_XOPEN_SOURCE) || !defined(__sgi) || !defined(_AIX) if(grantpt(ptm) == -1) eprintn("error, cannot grant access to pty"); if(unlockpt(ptm) == -1) eprintn("error, cannot unlock pty"); ptsdev = ptsname(ptm); -#elif defined(_AIX) - ptsdev = ttyname(ptm); -#endif if(!ptsdev) eprintn("error, slave pty name undefined"); pts = open(ptsdev, O_RDWR); if(pts == -1) eprintn("error, cannot open slave pty"); puts(ptsdev); -#if defined(__hpux) || defined(sun) || defined(__sun) - ioctl(pts, I_PUSH, "ptem"); - ioctl(pts, I_PUSH, "ldterm"); -#endif } else eprintn("error, cannot open pty"); +#endif } void From 40c0ecfe821036a3eefc210e6f5dc09e846ae5bf Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 2 Jun 2008 18:41:23 +0200 Subject: [PATCH 0006/1146] remove stdio slave pty opening --- std.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/std.c b/std.c index ef946dd..080c490 100644 --- a/std.c +++ b/std.c @@ -319,8 +319,5 @@ main(int argc, char *argv[]) { eprint("usage: st [-v]\n"); getpty(); shell(); - fdopen(fptm, "r+"); - if(!fptm) - eprintn("cannot open slave pty"); return 0; } From 0b3510df45057bf63f0e3b5ce225ff4491912bb8 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 2 Jun 2008 18:42:23 +0200 Subject: [PATCH 0007/1146] remove debug code --- std.c | 1 - 1 file changed, 1 deletion(-) diff --git a/std.c b/std.c index 080c490..53cbd2d 100644 --- a/std.c +++ b/std.c @@ -127,7 +127,6 @@ getpty(void) { pts = open(ptsdev, O_RDWR); if(pts == -1) eprintn("error, cannot open slave pty"); - puts(ptsdev); } else eprintn("error, cannot open pty"); From 693e2413c8c114c6a95327a609c28be643b9d582 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 2 Jun 2008 20:01:35 +0200 Subject: [PATCH 0008/1146] simplify control flow --- std.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/std.c b/std.c index 53cbd2d..5368f67 100644 --- a/std.c +++ b/std.c @@ -109,11 +109,9 @@ getpty(void) { ptm = posix_openpt(O_RDWR); #else ptm = open("/dev/ptmx", O_RDWR); - if(ptm == -1) { + if(ptm == -1) if(openpty(&ptm, &pts, NULL, NULL, NULL) == -1) eprintn("error, cannot open pty"); - return; - } #endif #if defined(_XOPEN_SOURCE) if(ptm != -1) { From c61b34e8e1883faba38f94b0c6775a47b1267e6f Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 2 Jun 2008 20:15:52 +0200 Subject: [PATCH 0009/1146] correct LENGTH() --- std.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std.c b/std.c index 5368f67..78e9237 100644 --- a/std.c +++ b/std.c @@ -13,7 +13,7 @@ #include #include -#define LENGTH(x) (sizeof (x) / sizeof (x)[0]) +#define LENGTH(x) (sizeof(x) / sizeof((x)[0])) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) From 50b4785f2650a741f827f4be17ecc18844a1b175 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Wed, 4 Jun 2008 19:52:59 +0200 Subject: [PATCH 0010/1146] terminate error message with newline --- std.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std.c b/std.c index 78e9237..4afdc3c 100644 --- a/std.c +++ b/std.c @@ -166,7 +166,7 @@ parseesc(void) { s |= QuestionMark; else if(c == ';') { if(!(s & Digit)) - eprint("syntax error"); + eprint("syntax error\n"); s &= ~Digit; j++; } From a6efc851b6b0fa9befe1f81627c5c5955d48e6f6 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Sun, 8 Jun 2008 20:47:08 +0200 Subject: [PATCH 0011/1146] replace state with separate variables --- std.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/std.c b/std.c index 4afdc3c..4808db4 100644 --- a/std.c +++ b/std.c @@ -31,8 +31,6 @@ void shell(void); void sigchld(int n); char unbuffer(void); -enum { QuestionMark = 1, Digit = 2 }; - typedef struct { unsigned char data[BUFSIZ]; int s, e; @@ -41,10 +39,10 @@ typedef struct { int cols = 80, lines = 25; int cx = 0, cy = 0; -int c, s; +int c; FILE *fptm = NULL; int ptm, pts; -_Bool bold; +_Bool bold, digit, qmark; pid_t pid; RingBuffer buf; @@ -151,28 +149,27 @@ parseesc(void) { int arg[16]; memset(arg, 0, LENGTH(arg)); - s = 0; c = getc(fptm); switch(c) { case '[': c = getc(fptm); for(j = 0; j < LENGTH(arg);) { if(isdigit(c)) { - s |= Digit; + digit = 1; arg[j] *= 10; arg[j] += c - '0'; } else if(c == '?') - s |= QuestionMark; + qmark = 1; else if(c == ';') { - if(!(s & Digit)) + if(!digit) eprint("syntax error\n"); - s &= ~Digit; + digit = 0; j++; } else { - if(s & Digit) { - s &= ~Digit; + if(digit) { + digit = 0; j++; } break; From 5d055fdc7cb441162f4ff5b67d0cbf6c58439d10 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Sun, 8 Jun 2008 20:55:42 +0200 Subject: [PATCH 0012/1146] remove useless variable --- std.c | 1 - 1 file changed, 1 deletion(-) diff --git a/std.c b/std.c index 4808db4..0dae5c2 100644 --- a/std.c +++ b/std.c @@ -306,7 +306,6 @@ unbuffer(void) { int main(int argc, char *argv[]) { - fd_set rd; if(argc == 2 && !strcmp("-v", argv[1])) eprint("std-"VERSION", © 2008 Matthias-Christian Ott\n"); else if(argc == 1) From dc01596e6d7b81d52b805a3e8c16e47228325540 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Sun, 8 Jun 2008 21:17:02 +0200 Subject: [PATCH 0013/1146] add parser loop --- std.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/std.c b/std.c index 0dae5c2..be3f41a 100644 --- a/std.c +++ b/std.c @@ -312,5 +312,18 @@ main(int argc, char *argv[]) { eprint("usage: st [-v]\n"); getpty(); shell(); + fptm = fdopen(ptm, "r+"); + if(!fptm) + eprintn("cannot open slave pty"); + for(;;) { + c = getc(fptm); + switch(c) { + case '\033': + parseesc(); + break; + default: + putchar(c); + } + } return 0; } From 5e680d7102ec540ca5859a87a82a2c8d93532518 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Sun, 8 Jun 2008 21:18:49 +0200 Subject: [PATCH 0014/1146] add missing header file --- std.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/std.c b/std.c index be3f41a..4c28ae4 100644 --- a/std.c +++ b/std.c @@ -6,6 +6,9 @@ #include #include #include +#if !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) +#include +#endif #include #include #include From b8f79f0ed0db553745798cd4fb43329ba5c61cef Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Sun, 8 Jun 2008 21:36:58 +0200 Subject: [PATCH 0015/1146] remove xinerama flags The xinerama related variables in config.mk are a relict of dwm and therefore should be removed. --- config.mk | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/config.mk b/config.mk index 5983bcb..224bbbf 100644 --- a/config.mk +++ b/config.mk @@ -10,16 +10,12 @@ MANPREFIX = ${PREFIX}/share/man X11INC = /usr/X11R6/include X11LIB = /usr/X11R6/lib -# Xinerama, comment if you don't want it -XINERAMALIBS = -L${X11LIB} -lXinerama -XINERAMAFLAGS = -DXINERAMA - # includes and libs INCS = -I. -I/usr/include -I${X11INC} -LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} +LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 # flags -CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +CPPFLAGS = -DVERSION=\"${VERSION}\" CFLAGS = -Os ${INCS} ${CPPFLAGS} LDFLAGS = -s ${LIBS} #CFLAGS = -g -std=c99 -pedantic -Wall -O2 ${INCS} ${CPPFLAGS} From 0dce422d31d1178f93ecaf1dcf4e2c0bccb3c076 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 9 Jun 2008 22:21:37 +0200 Subject: [PATCH 0016/1146] correct function name --- std.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std.c b/std.c index 4c28ae4..fcfead9 100644 --- a/std.c +++ b/std.c @@ -28,7 +28,7 @@ void eprintn(const char *errstr, ...); void getpty(void); void movea(int x, int y); void mover(int x, int y); -void parse(void); +void parseesc(void); void scroll(int l); void shell(void); void sigchld(int n); From 0dedee5de8e35f4bab3d707d63be31943715264e Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 9 Jun 2008 22:24:44 +0200 Subject: [PATCH 0017/1146] update TODO --- TODO | 3 --- 1 file changed, 3 deletions(-) diff --git a/TODO b/TODO index f43eade..c1952be 100644 --- a/TODO +++ b/TODO @@ -1,4 +1 @@ - add the new st source code here -- add the new std source code here -- add new Makefile and config.mk -- add LICENSE From 47d8633f157156ef4701ce71ed7eff766206c107 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Tue, 10 Jun 2008 17:30:15 +0200 Subject: [PATCH 0018/1146] source getpty() out to pty.c --- pty.c | 41 +++++++++++++++++++++++++++++++++++++++++ std.c | 35 ----------------------------------- 2 files changed, 41 insertions(+), 35 deletions(-) create mode 100644 pty.c diff --git a/pty.c b/pty.c new file mode 100644 index 0000000..a3e43b0 --- /dev/null +++ b/pty.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#if !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) +#include +#endif + +extern int ptm, pts; + +void +getpty(void) { + char *ptsdev; + +#if defined(_GNU_SOURCE) + ptm = getpt(); +#elif _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 + ptm = posix_openpt(O_RDWR); +#else + ptm = open("/dev/ptmx", O_RDWR); + if(ptm == -1) + if(openpty(&ptm, &pts, NULL, NULL, NULL) == -1) + eprintn("error, cannot open pty"); +#endif +#if defined(_XOPEN_SOURCE) + if(ptm != -1) { + if(grantpt(ptm) == -1) + eprintn("error, cannot grant access to pty"); + if(unlockpt(ptm) == -1) + eprintn("error, cannot unlock pty"); + ptsdev = ptsname(ptm); + if(!ptsdev) + eprintn("error, slave pty name undefined"); + pts = open(ptsdev, O_RDWR); + if(pts == -1) + eprintn("error, cannot open slave pty"); + } + else + eprintn("error, cannot open pty"); +#endif +} diff --git a/std.c b/std.c index fcfead9..1b918f5 100644 --- a/std.c +++ b/std.c @@ -6,9 +6,6 @@ #include #include #include -#if !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) -#include -#endif #include #include #include @@ -100,38 +97,6 @@ eprintn(const char *errstr, ...) { exit(EXIT_FAILURE); } -void -getpty(void) { - char *ptsdev; - -#if defined(_GNU_SOURCE) - ptm = getpt(); -#elif _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 - ptm = posix_openpt(O_RDWR); -#else - ptm = open("/dev/ptmx", O_RDWR); - if(ptm == -1) - if(openpty(&ptm, &pts, NULL, NULL, NULL) == -1) - eprintn("error, cannot open pty"); -#endif -#if defined(_XOPEN_SOURCE) - if(ptm != -1) { - if(grantpt(ptm) == -1) - eprintn("error, cannot grant access to pty"); - if(unlockpt(ptm) == -1) - eprintn("error, cannot unlock pty"); - ptsdev = ptsname(ptm); - if(!ptsdev) - eprintn("error, slave pty name undefined"); - pts = open(ptsdev, O_RDWR); - if(pts == -1) - eprintn("error, cannot open slave pty"); - } - else - eprintn("error, cannot open pty"); -#endif -} - void movea(int x, int y) { x = MAX(x, cols); From 05ebee60843f24201f3e7c5c76ff94b6b5e868b2 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Tue, 10 Jun 2008 17:32:15 +0200 Subject: [PATCH 0019/1146] add copyright comment --- pty.c | 1 + std.c | 1 + 2 files changed, 2 insertions(+) diff --git a/pty.c b/pty.c index a3e43b0..bf0b0f7 100644 --- a/pty.c +++ b/pty.c @@ -1,3 +1,4 @@ +/* See LICENSE file for copyright and license details. */ #include #include #include diff --git a/std.c b/std.c index 1b918f5..3fd07a4 100644 --- a/std.c +++ b/std.c @@ -1,3 +1,4 @@ +/* See LICENSE file for copyright and license details. */ #include #include #include From 5f287254715dd91f2c508a2a6b9853f0ef4ed785 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Tue, 10 Jun 2008 17:56:57 +0200 Subject: [PATCH 0020/1146] source utility functions out to util.c --- Makefile | 2 +- pty.c | 1 + st.c | 1 + std.c | 39 +-------------------------------------- util.c | 37 +++++++++++++++++++++++++++++++++++++ util.h | 5 +++++ 6 files changed, 46 insertions(+), 39 deletions(-) create mode 100644 util.c create mode 100644 util.h diff --git a/Makefile b/Makefile index cf1766c..dcbbbcf 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = st.c std.c +SRC = st.c std.c util.c pty.c OBJ = ${SRC:.c=.o} all: options st diff --git a/pty.c b/pty.c index bf0b0f7..4c38d86 100644 --- a/pty.c +++ b/pty.c @@ -1,4 +1,5 @@ /* See LICENSE file for copyright and license details. */ +#include "util.h" #include #include #include diff --git a/st.c b/st.c index a3421ff..8dd7793 100644 --- a/st.c +++ b/st.c @@ -1,4 +1,5 @@ /* See LICENSE file for copyright and license details. */ +#include "util.h" #include int diff --git a/std.c b/std.c index 3fd07a4..a7b2f4a 100644 --- a/std.c +++ b/std.c @@ -1,12 +1,8 @@ /* See LICENSE file for copyright and license details. */ -#include -#include -#include +#include "util.h" #include #include #include -#include -#include #include #include #include @@ -20,9 +16,6 @@ void buffer(char c); void cmd(const char *cmdstr, ...); -void *emallocz(unsigned int size); -void eprint(const char *errstr, ...); -void eprintn(const char *errstr, ...); void getpty(void); void movea(int x, int y); void mover(int x, int y); @@ -68,36 +61,6 @@ cmd(const char *cmdstr, ...) { va_end(ap); } -void * -emallocz(unsigned int size) { - void *res = calloc(1, size); - - if(!res) - eprint("fatal: could not malloc() %u bytes\n", size); - return res; -} - -void -eprint(const char *errstr, ...) { - va_list ap; - - va_start(ap, errstr); - vfprintf(stderr, errstr, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - -void -eprintn(const char *errstr, ...) { - va_list ap; - - va_start(ap, errstr); - vfprintf(stderr, errstr, ap); - va_end(ap); - fprintf(stderr, ": %s\n", strerror(errno)); - exit(EXIT_FAILURE); -} - void movea(int x, int y) { x = MAX(x, cols); diff --git a/util.c b/util.c new file mode 100644 index 0000000..f8b9eee --- /dev/null +++ b/util.c @@ -0,0 +1,37 @@ +/* See LICENSE file for copyright and license details. */ +#include "util.h" +#include +#include +#include +#include +#include + +void * +emallocz(unsigned int size) { + void *res = calloc(1, size); + + if(!res) + eprint("fatal: could not malloc() %u bytes\n", size); + return res; +} + +void +eprint(const char *errstr, ...) { + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +void +eprintn(const char *errstr, ...) { + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + fprintf(stderr, ": %s\n", strerror(errno)); + exit(EXIT_FAILURE); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..34db193 --- /dev/null +++ b/util.h @@ -0,0 +1,5 @@ +/* See LICENSE file for copyright and license details. */ + +void *emallocz(unsigned int size); +void eprint(const char *errstr, ...); +void eprintn(const char *errstr, ...); From 09fe1e22ce65b2478b47fc2cf1bbe9a9eb966212 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Tue, 10 Jun 2008 18:00:15 +0200 Subject: [PATCH 0021/1146] assume glibc by default --- config.mk | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 224bbbf..eca6028 100644 --- a/config.mk +++ b/config.mk @@ -14,8 +14,11 @@ X11LIB = /usr/X11R6/lib INCS = -I. -I/usr/include -I${X11INC} LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 +# glibc +CPPFLAGS = -DVERSION=\"${VERSION}\" -D_GNU_SOURCE + # flags -CPPFLAGS = -DVERSION=\"${VERSION}\" +#CPPFLAGS = -DVERSION=\"${VERSION}\" CFLAGS = -Os ${INCS} ${CPPFLAGS} LDFLAGS = -s ${LIBS} #CFLAGS = -g -std=c99 -pedantic -Wall -O2 ${INCS} ${CPPFLAGS} From 339e7f35713ae0c35be2537e6639cd5eee592acb Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Tue, 10 Jun 2008 18:01:15 +0200 Subject: [PATCH 0022/1146] add missing header file --- st.c | 1 + 1 file changed, 1 insertion(+) diff --git a/st.c b/st.c index 8dd7793..9b1d131 100644 --- a/st.c +++ b/st.c @@ -1,6 +1,7 @@ /* See LICENSE file for copyright and license details. */ #include "util.h" #include +#include int Xmain(int argc, char *argv[]) { From 0c0ada8a7f6e916eb2b05ae5571e375e522d0a2e Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Sat, 14 Jun 2008 11:03:29 +0200 Subject: [PATCH 0023/1146] make st and std separate programmes --- Makefile | 22 +++++++++++++++------- config.mk | 4 +++- st.c | 2 +- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index dcbbbcf..ddf1952 100644 --- a/Makefile +++ b/Makefile @@ -6,13 +6,14 @@ include config.mk SRC = st.c std.c util.c pty.c OBJ = ${SRC:.c=.o} -all: options st +all: options st std options: @echo st build options: - @echo "CFLAGS = ${CFLAGS}" - @echo "LDFLAGS = ${LDFLAGS}" - @echo "CC = ${CC}" + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "X11LDFLAGS = ${X11LDFLAGS}" + @echo "CC = ${CC}" .c.o: @echo CC $< @@ -20,13 +21,17 @@ options: ${OBJ}: config.mk -st: ${OBJ} +st: st.o util.o @echo CC -o $@ - @${CC} -o $@ ${OBJ} ${LDFLAGS} + @${CC} -o $@ $^ ${LDFLAGS} ${X11LDFLAGS} + +std: std.o pty.o util.o + @echo CC -o $@ + @${CC} -o $@ $^ ${LDFLAGS} clean: @echo cleaning - @rm -f st ${OBJ} st-${VERSION}.tar.gz + @rm -f st std ${OBJ} st-${VERSION}.tar.gz dist: clean @echo creating dist tarball @@ -41,11 +46,14 @@ install: all @echo installing executable file to ${DESTDIR}${PREFIX}/bin @mkdir -p ${DESTDIR}${PREFIX}/bin @cp -f st ${DESTDIR}${PREFIX}/bin + @cp -f std ${DESTDIR}${PREFIX}/bin @chmod 755 ${DESTDIR}${PREFIX}/bin/st @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 @mkdir -p ${DESTDIR}${MANPREFIX}/man1 @sed "s/VERSION/${VERSION}/g" < st.1 > ${DESTDIR}${MANPREFIX}/man1/st.1 @chmod 644 ${DESTDIR}${MANPREFIX}/man1/st.1 + @sed "s/VERSION/${VERSION}/g" < std.1 > ${DESTDIR}${MANPREFIX}/man1/std.1 + @chmod 644 ${DESTDIR}${MANPREFIX}/man1/std.1 uninstall: @echo removing executable file from ${DESTDIR}${PREFIX}/bin diff --git a/config.mk b/config.mk index eca6028..4d76c67 100644 --- a/config.mk +++ b/config.mk @@ -12,7 +12,8 @@ X11LIB = /usr/X11R6/lib # includes and libs INCS = -I. -I/usr/include -I${X11INC} -LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 +LIBS = -L/usr/lib -lc +X11LIBS = -L${X11LIB} -lX11 # glibc CPPFLAGS = -DVERSION=\"${VERSION}\" -D_GNU_SOURCE @@ -21,6 +22,7 @@ CPPFLAGS = -DVERSION=\"${VERSION}\" -D_GNU_SOURCE #CPPFLAGS = -DVERSION=\"${VERSION}\" CFLAGS = -Os ${INCS} ${CPPFLAGS} LDFLAGS = -s ${LIBS} +X11LDFLAGS = ${X11LIBS} #CFLAGS = -g -std=c99 -pedantic -Wall -O2 ${INCS} ${CPPFLAGS} #LDFLAGS = -g ${LIBS} diff --git a/st.c b/st.c index 9b1d131..e82faaa 100644 --- a/st.c +++ b/st.c @@ -4,7 +4,7 @@ #include int -Xmain(int argc, char *argv[]) { +main(int argc, char *argv[]) { if(argc == 2 && !strcmp("-v", argv[1])) eprint("st-"VERSION", © 2007-2008 st engineers, see LICENSE for details\n"); else if(argc != 1) From a49919a10c11c141f1bfb8414d5c8d2ca9d4a90e Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Sat, 14 Jun 2008 23:12:07 +0200 Subject: [PATCH 0024/1146] drop stdio usage Std requires I/O multiplexing which is very complicated with stdio, because it provides no transparent buffering. --- std.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/std.c b/std.c index a7b2f4a..961ca55 100644 --- a/std.c +++ b/std.c @@ -16,6 +16,7 @@ void buffer(char c); void cmd(const char *cmdstr, ...); +int getch(); void getpty(void); void movea(int x, int y); void mover(int x, int y); @@ -24,6 +25,7 @@ void scroll(int l); void shell(void); void sigchld(int n); char unbuffer(void); +void ungetch(int c); typedef struct { unsigned char data[BUFSIZ]; @@ -31,14 +33,19 @@ typedef struct { int n; } RingBuffer; +typedef struct { + unsigned char data[BUFSIZ]; + int i, n; +} ReadBuffer; + int cols = 80, lines = 25; int cx = 0, cy = 0; int c; -FILE *fptm = NULL; int ptm, pts; _Bool bold, digit, qmark; pid_t pid; RingBuffer buf; +ReadBuffer rbuf; void buffer(char c) { @@ -61,6 +68,17 @@ cmd(const char *cmdstr, ...) { va_end(ap); } +int +getch() { + if(rbuf.i++ >= rbuf.n) { + rbuf.n = read(ptm, rbuf.data, LENGTH(rbuf.data)); + if(rbuf.n == -1) + eprintn("error, cannot read from slave pty"); + rbuf.i = 0; + } + return rbuf.data[rbuf.i]; +} + void movea(int x, int y) { x = MAX(x, cols); @@ -81,10 +99,10 @@ parseesc(void) { int arg[16]; memset(arg, 0, LENGTH(arg)); - c = getc(fptm); + c = getch(); switch(c) { case '[': - c = getc(fptm); + c = getch(); for(j = 0; j < LENGTH(arg);) { if(isdigit(c)) { digit = 1; @@ -106,7 +124,7 @@ parseesc(void) { } break; } - c = getc(fptm); + c = getch(); } switch(c) { case '@': @@ -180,7 +198,7 @@ parseesc(void) { break; default: putchar('\033'); - ungetc(c, fptm); + ungetch(c); } } @@ -236,6 +254,13 @@ unbuffer(void) { return c; } +void +ungetch(int c) { + if(rbuf.i + 1 >= rbuf.n) + eprint("error, read buffer full\n"); + rbuf.data[rbuf.i++] = c; +} + int main(int argc, char *argv[]) { if(argc == 2 && !strcmp("-v", argv[1])) @@ -244,11 +269,8 @@ main(int argc, char *argv[]) { eprint("usage: st [-v]\n"); getpty(); shell(); - fptm = fdopen(ptm, "r+"); - if(!fptm) - eprintn("cannot open slave pty"); for(;;) { - c = getc(fptm); + c = getch(); switch(c) { case '\033': parseesc(); From f9a0524f9430147a3e4a0d200cb3bbd54d1448a4 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Sat, 14 Jun 2008 23:24:12 +0200 Subject: [PATCH 0025/1146] add select(2)-based i/o multiplexing --- std.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/std.c b/std.c index 961ca55..fbabaa4 100644 --- a/std.c +++ b/std.c @@ -263,20 +263,32 @@ ungetch(int c) { int main(int argc, char *argv[]) { + fd_set rfds; + int r; + if(argc == 2 && !strcmp("-v", argv[1])) eprint("std-"VERSION", © 2008 Matthias-Christian Ott\n"); else if(argc == 1) eprint("usage: st [-v]\n"); getpty(); shell(); + FD_ZERO(&rfds); + FD_SET(STDIN_FILENO, &rfds); + FD_SET(ptm, &rfds); for(;;) { - c = getch(); - switch(c) { - case '\033': - parseesc(); - break; - default: - putchar(c); + r = select(ptm + 1, &rfds, NULL, NULL, NULL); + if(r == -1) + eprintn("error, cannot select"); + if(FD_ISSET(ptm, &rfds)) { + c = getch(); + switch(c) { + case '\033': + parseesc(); + break; + default: + putchar(c); + } + fflush(stdout); } } return 0; From cf147ae9da0221123596b749d4742d06f0ea643b Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Sat, 14 Jun 2008 23:29:11 +0200 Subject: [PATCH 0026/1146] make local functions and variables static --- std.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/std.c b/std.c index fbabaa4..5e19245 100644 --- a/std.c +++ b/std.c @@ -14,18 +14,18 @@ #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) -void buffer(char c); -void cmd(const char *cmdstr, ...); -int getch(); +static void buffer(char c); +static void cmd(const char *cmdstr, ...); +static int getch(); void getpty(void); -void movea(int x, int y); -void mover(int x, int y); -void parseesc(void); -void scroll(int l); -void shell(void); -void sigchld(int n); -char unbuffer(void); -void ungetch(int c); +static void movea(int x, int y); +static void mover(int x, int y); +static void parseesc(void); +static void scroll(int l); +static void shell(void); +static void sigchld(int n); +static char unbuffer(void); +static void ungetch(int c); typedef struct { unsigned char data[BUFSIZ]; @@ -38,14 +38,14 @@ typedef struct { int i, n; } ReadBuffer; -int cols = 80, lines = 25; -int cx = 0, cy = 0; -int c; +static int cols = 80, lines = 25; +static int cx = 0, cy = 0; +static int c; int ptm, pts; -_Bool bold, digit, qmark; -pid_t pid; -RingBuffer buf; -ReadBuffer rbuf; +static _Bool bold, digit, qmark; +static pid_t pid; +static RingBuffer buf; +static ReadBuffer rbuf; void buffer(char c) { From 3cb67937811b34fcc600b4eb96bd8fdd392ecab4 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Sun, 15 Jun 2008 09:19:22 +0200 Subject: [PATCH 0027/1146] correct buffering --- std.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/std.c b/std.c index 5e19245..b0142fe 100644 --- a/std.c +++ b/std.c @@ -85,7 +85,7 @@ movea(int x, int y) { y = MAX(y, lines); cx = x; cy = y; - cmd("s %d,%d", x, y); + cmd("seek(%d,%d)", x, y); } void @@ -186,10 +186,10 @@ parseesc(void) { case 0: case 22: if(bold) - cmd("b"); + cmd("bold"); case 1: if(!bold) - cmd("b"); + cmd("bold"); break; } } @@ -204,7 +204,7 @@ parseesc(void) { void scroll(int l) { - cmd("s %d, %d", cx, cy + l); + cmd("seek(%d,%d)", cx, cy + l); } void @@ -279,17 +279,18 @@ main(int argc, char *argv[]) { r = select(ptm + 1, &rfds, NULL, NULL, NULL); if(r == -1) eprintn("error, cannot select"); - if(FD_ISSET(ptm, &rfds)) { - c = getch(); - switch(c) { - case '\033': - parseesc(); - break; - default: - putchar(c); - } - fflush(stdout); - } + if(FD_ISSET(ptm, &rfds)) + do { + c = getch(); + switch(c) { + case '\033': + parseesc(); + break; + default: + putchar(c); + } + fflush(stdout); + } while(rbuf.i < rbuf.n); } return 0; } From d83cbc27b99427d00846832a73810f285d8f0d05 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Sun, 15 Jun 2008 17:31:24 +0200 Subject: [PATCH 0028/1146] simplify flushing --- std.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/std.c b/std.c index b0142fe..84048e4 100644 --- a/std.c +++ b/std.c @@ -279,7 +279,7 @@ main(int argc, char *argv[]) { r = select(ptm + 1, &rfds, NULL, NULL, NULL); if(r == -1) eprintn("error, cannot select"); - if(FD_ISSET(ptm, &rfds)) + if(FD_ISSET(ptm, &rfds)) { do { c = getch(); switch(c) { @@ -289,8 +289,9 @@ main(int argc, char *argv[]) { default: putchar(c); } - fflush(stdout); } while(rbuf.i < rbuf.n); + fflush(stdout); + } } return 0; } From f982c1c37ccc4adc38260a132aa64ee29d1a1a8c Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Fri, 4 Jul 2008 18:05:08 +0200 Subject: [PATCH 0029/1146] replace eprint() functions with BSD error functions --- pty.c | 12 ++++++------ st.c | 14 +++++++++----- std.c | 25 +++++++++++++++---------- util.c | 23 +---------------------- util.h | 2 -- 5 files changed, 31 insertions(+), 45 deletions(-) diff --git a/pty.c b/pty.c index 4c38d86..a173dab 100644 --- a/pty.c +++ b/pty.c @@ -22,22 +22,22 @@ getpty(void) { ptm = open("/dev/ptmx", O_RDWR); if(ptm == -1) if(openpty(&ptm, &pts, NULL, NULL, NULL) == -1) - eprintn("error, cannot open pty"); + err(EXIT_FAILURE, "cannot open pty"); #endif #if defined(_XOPEN_SOURCE) if(ptm != -1) { if(grantpt(ptm) == -1) - eprintn("error, cannot grant access to pty"); + err(EXIT_FAILURE, "cannot grant access to pty"); if(unlockpt(ptm) == -1) - eprintn("error, cannot unlock pty"); + err(EXIT_FAILURE, "cannot unlock pty"); ptsdev = ptsname(ptm); if(!ptsdev) - eprintn("error, slave pty name undefined"); + err(EXIT_FAILURE, "slave pty name undefined"); pts = open(ptsdev, O_RDWR); if(pts == -1) - eprintn("error, cannot open slave pty"); + err(EXIT_FAILURE, "cannot open slave pty"); } else - eprintn("error, cannot open pty"); + err(EXIT_FAILURE, "cannot open pty"); #endif } diff --git a/st.c b/st.c index e82faaa..8a8804f 100644 --- a/st.c +++ b/st.c @@ -1,13 +1,17 @@ /* See LICENSE file for copyright and license details. */ -#include "util.h" #include +#include #include int main(int argc, char *argv[]) { - if(argc == 2 && !strcmp("-v", argv[1])) - eprint("st-"VERSION", © 2007-2008 st engineers, see LICENSE for details\n"); - else if(argc != 1) - eprint("usage: st [-v]\n"); + if(argc == 2 && !strcmp("-v", argv[1])) { + fprintf(stderr, "st-"VERSION", © 2007-2008 st engineers, see LICENSE for details\n"); + exit(EXIT_SUCCESS); + } + else if(argc != 1) { + fprintf(stderr, "usage: st [-v]\n"); + exit(EXIT_FAILURE); + } return 0; } diff --git a/std.c b/std.c index 84048e4..daf759e 100644 --- a/std.c +++ b/std.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +74,7 @@ getch() { if(rbuf.i++ >= rbuf.n) { rbuf.n = read(ptm, rbuf.data, LENGTH(rbuf.data)); if(rbuf.n == -1) - eprintn("error, cannot read from slave pty"); + err(EXIT_FAILURE, "cannot read from slave pty"); rbuf.i = 0; } return rbuf.data[rbuf.i]; @@ -113,7 +114,7 @@ parseesc(void) { qmark = 1; else if(c == ';') { if(!digit) - eprint("syntax error\n"); + errx(EXIT_FAILURE, "syntax error"); digit = 0; j++; } @@ -216,7 +217,7 @@ shell(void) { pid = fork(); switch(pid) { case -1: - eprint("error, cannot fork\n"); + err(EXIT_FAILURE, "cannot fork"); case 0: setsid(); dup2(pts, STDIN_FILENO); @@ -237,7 +238,7 @@ sigchld(int n) { int ret; if(waitpid(pid, &ret, 0) == -1) - eprintn("error, waiting for child failed"); + err(EXIT_FAILURE, "waiting for child failed"); if(WIFEXITED(ret)) exit(WEXITSTATUS(ret)); else @@ -257,7 +258,7 @@ unbuffer(void) { void ungetch(int c) { if(rbuf.i + 1 >= rbuf.n) - eprint("error, read buffer full\n"); + errx(EXIT_FAILURE, "read buffer full"); rbuf.data[rbuf.i++] = c; } @@ -266,10 +267,14 @@ main(int argc, char *argv[]) { fd_set rfds; int r; - if(argc == 2 && !strcmp("-v", argv[1])) - eprint("std-"VERSION", © 2008 Matthias-Christian Ott\n"); - else if(argc == 1) - eprint("usage: st [-v]\n"); + if(argc == 2 && !strcmp("-v", argv[1])) { + fprintf(stderr, "std-"VERSION", © 2008 Matthias-Christian Ott\n"); + exit(EXIT_SUCCESS); + } + else if(argc == 1) { + fprintf(stderr, "usage: st [-v]\n"); + exit(EXIT_FAILURE); + } getpty(); shell(); FD_ZERO(&rfds); @@ -278,7 +283,7 @@ main(int argc, char *argv[]) { for(;;) { r = select(ptm + 1, &rfds, NULL, NULL, NULL); if(r == -1) - eprintn("error, cannot select"); + err(EXIT_FAILURE, "cannot select"); if(FD_ISSET(ptm, &rfds)) { do { c = getch(); diff --git a/util.c b/util.c index f8b9eee..2e33fbd 100644 --- a/util.c +++ b/util.c @@ -11,27 +11,6 @@ emallocz(unsigned int size) { void *res = calloc(1, size); if(!res) - eprint("fatal: could not malloc() %u bytes\n", size); + err(EXIT_FAILURE, "could not malloc() %u bytes\n", size); return res; } - -void -eprint(const char *errstr, ...) { - va_list ap; - - va_start(ap, errstr); - vfprintf(stderr, errstr, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - -void -eprintn(const char *errstr, ...) { - va_list ap; - - va_start(ap, errstr); - vfprintf(stderr, errstr, ap); - va_end(ap); - fprintf(stderr, ": %s\n", strerror(errno)); - exit(EXIT_FAILURE); -} diff --git a/util.h b/util.h index 34db193..9d87a95 100644 --- a/util.h +++ b/util.h @@ -1,5 +1,3 @@ /* See LICENSE file for copyright and license details. */ void *emallocz(unsigned int size); -void eprint(const char *errstr, ...); -void eprintn(const char *errstr, ...); From b3902ca1782515ee8b9cd38af10e51bc3ba2fc98 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Fri, 4 Jul 2008 18:18:51 +0200 Subject: [PATCH 0030/1146] remove emallocz() --- Makefile | 6 +++--- pty.c | 1 - std.c | 1 - util.c | 16 ---------------- util.h | 3 --- 5 files changed, 3 insertions(+), 24 deletions(-) delete mode 100644 util.c delete mode 100644 util.h diff --git a/Makefile b/Makefile index ddf1952..72154e9 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = st.c std.c util.c pty.c +SRC = st.c std.c pty.c OBJ = ${SRC:.c=.o} all: options st std @@ -21,11 +21,11 @@ options: ${OBJ}: config.mk -st: st.o util.o +st: st.o @echo CC -o $@ @${CC} -o $@ $^ ${LDFLAGS} ${X11LDFLAGS} -std: std.o pty.o util.o +std: std.o pty.o @echo CC -o $@ @${CC} -o $@ $^ ${LDFLAGS} diff --git a/pty.c b/pty.c index a173dab..3efaa7f 100644 --- a/pty.c +++ b/pty.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "util.h" #include #include #include diff --git a/std.c b/std.c index daf759e..5b430b8 100644 --- a/std.c +++ b/std.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "util.h" #include #include #include diff --git a/util.c b/util.c deleted file mode 100644 index 2e33fbd..0000000 --- a/util.c +++ /dev/null @@ -1,16 +0,0 @@ -/* See LICENSE file for copyright and license details. */ -#include "util.h" -#include -#include -#include -#include -#include - -void * -emallocz(unsigned int size) { - void *res = calloc(1, size); - - if(!res) - err(EXIT_FAILURE, "could not malloc() %u bytes\n", size); - return res; -} diff --git a/util.h b/util.h deleted file mode 100644 index 9d87a95..0000000 --- a/util.h +++ /dev/null @@ -1,3 +0,0 @@ -/* See LICENSE file for copyright and license details. */ - -void *emallocz(unsigned int size); From afc73c920df958dabaf1e8e544be47cbe9c919ce Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Sat, 5 Jul 2008 13:29:21 +0200 Subject: [PATCH 0031/1146] remove useless variable --- std.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/std.c b/std.c index 5b430b8..3e155e6 100644 --- a/std.c +++ b/std.c @@ -264,7 +264,6 @@ ungetch(int c) { int main(int argc, char *argv[]) { fd_set rfds; - int r; if(argc == 2 && !strcmp("-v", argv[1])) { fprintf(stderr, "std-"VERSION", © 2008 Matthias-Christian Ott\n"); @@ -280,8 +279,7 @@ main(int argc, char *argv[]) { FD_SET(STDIN_FILENO, &rfds); FD_SET(ptm, &rfds); for(;;) { - r = select(ptm + 1, &rfds, NULL, NULL, NULL); - if(r == -1) + if(select(ptm + 1, &rfds, NULL, NULL, NULL) == -1) err(EXIT_FAILURE, "cannot select"); if(FD_ISSET(ptm, &rfds)) { do { From 0cbcedb89ffe6e29b3c0640f371bed578c6e0c07 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Wed, 9 Jul 2008 10:50:44 +0200 Subject: [PATCH 0032/1146] make ptm and pts static --- std.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std.c b/std.c index 3e155e6..5bc27b8 100644 --- a/std.c +++ b/std.c @@ -41,7 +41,7 @@ typedef struct { static int cols = 80, lines = 25; static int cx = 0, cy = 0; static int c; -int ptm, pts; +static int ptm, pts; static _Bool bold, digit, qmark; static pid_t pid; static RingBuffer buf; From fb4508b0b7ca638decb03482535c2087383a523d Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Wed, 9 Jul 2008 11:10:38 +0200 Subject: [PATCH 0033/1146] remove TODO --- TODO | 1 - 1 file changed, 1 deletion(-) delete mode 100644 TODO diff --git a/TODO b/TODO deleted file mode 100644 index c1952be..0000000 --- a/TODO +++ /dev/null @@ -1 +0,0 @@ -- add the new st source code here From 7a132bd6ac40bfa32b6ac1da412c8c7d35e2d5ca Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Thu, 10 Jul 2008 22:42:10 +0200 Subject: [PATCH 0034/1146] Backed out changeset d2bb4220fdf3 Ptm and pts are used by pty.c, thus they have to be non-static. --- std.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std.c b/std.c index 5bc27b8..3e155e6 100644 --- a/std.c +++ b/std.c @@ -41,7 +41,7 @@ typedef struct { static int cols = 80, lines = 25; static int cx = 0, cy = 0; static int c; -static int ptm, pts; +int ptm, pts; static _Bool bold, digit, qmark; static pid_t pid; static RingBuffer buf; From 746931a3d4114f9bd35a43307fd48bfa64ff0d8b Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 21 Jul 2008 09:25:25 +0200 Subject: [PATCH 0035/1146] use errx() for help and version messages --- std.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/std.c b/std.c index 3e155e6..5c12fbd 100644 --- a/std.c +++ b/std.c @@ -265,14 +265,10 @@ int main(int argc, char *argv[]) { fd_set rfds; - if(argc == 2 && !strcmp("-v", argv[1])) { - fprintf(stderr, "std-"VERSION", © 2008 Matthias-Christian Ott\n"); - exit(EXIT_SUCCESS); - } - else if(argc == 1) { - fprintf(stderr, "usage: st [-v]\n"); - exit(EXIT_FAILURE); - } + if(argc == 2 && !strcmp("-v", argv[1])) + errx(EXIT_SUCCESS, "std-"VERSION", © 2008 Matthias-Christian Ott"); + else if(argc == 1) + errx(EXIT_FAILURE, "usage: st [-v]"); getpty(); shell(); FD_ZERO(&rfds); From 6c6b65ea6ec775cc02c25b8cf69cce32971f9fe8 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 21 Jul 2008 09:25:47 +0200 Subject: [PATCH 0036/1146] correct programme name --- std.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std.c b/std.c index 5c12fbd..2ce1722 100644 --- a/std.c +++ b/std.c @@ -268,7 +268,7 @@ main(int argc, char *argv[]) { if(argc == 2 && !strcmp("-v", argv[1])) errx(EXIT_SUCCESS, "std-"VERSION", © 2008 Matthias-Christian Ott"); else if(argc == 1) - errx(EXIT_FAILURE, "usage: st [-v]"); + errx(EXIT_FAILURE, "usage: std [-v]"); getpty(); shell(); FD_ZERO(&rfds); From 082d8bb82bc478bdd0b1470232ba52976a0c035d Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 21 Jul 2008 10:34:02 +0200 Subject: [PATCH 0037/1146] reunite pty.c with std.c --- pty.c | 42 ------------------------------------------ std.c | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 44 deletions(-) delete mode 100644 pty.c diff --git a/pty.c b/pty.c deleted file mode 100644 index 3efaa7f..0000000 --- a/pty.c +++ /dev/null @@ -1,42 +0,0 @@ -/* See LICENSE file for copyright and license details. */ -#include -#include -#include -#include -#if !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) -#include -#endif - -extern int ptm, pts; - -void -getpty(void) { - char *ptsdev; - -#if defined(_GNU_SOURCE) - ptm = getpt(); -#elif _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 - ptm = posix_openpt(O_RDWR); -#else - ptm = open("/dev/ptmx", O_RDWR); - if(ptm == -1) - if(openpty(&ptm, &pts, NULL, NULL, NULL) == -1) - err(EXIT_FAILURE, "cannot open pty"); -#endif -#if defined(_XOPEN_SOURCE) - if(ptm != -1) { - if(grantpt(ptm) == -1) - err(EXIT_FAILURE, "cannot grant access to pty"); - if(unlockpt(ptm) == -1) - err(EXIT_FAILURE, "cannot unlock pty"); - ptsdev = ptsname(ptm); - if(!ptsdev) - err(EXIT_FAILURE, "slave pty name undefined"); - pts = open(ptsdev, O_RDWR); - if(pts == -1) - err(EXIT_FAILURE, "cannot open slave pty"); - } - else - err(EXIT_FAILURE, "cannot open pty"); -#endif -} diff --git a/std.c b/std.c index 2ce1722..ef9e57a 100644 --- a/std.c +++ b/std.c @@ -3,6 +3,10 @@ #include #include #include +#include +#if !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) +#include +#endif #include #include #include @@ -17,7 +21,7 @@ static void buffer(char c); static void cmd(const char *cmdstr, ...); static int getch(); -void getpty(void); +static void getpty(void); static void movea(int x, int y); static void mover(int x, int y); static void parseesc(void); @@ -41,7 +45,7 @@ typedef struct { static int cols = 80, lines = 25; static int cx = 0, cy = 0; static int c; -int ptm, pts; +static int ptm, pts; static _Bool bold, digit, qmark; static pid_t pid; static RingBuffer buf; @@ -207,6 +211,38 @@ scroll(int l) { cmd("seek(%d,%d)", cx, cy + l); } +void +getpty(void) { + char *ptsdev; + +#if defined(_GNU_SOURCE) + ptm = getpt(); +#elif _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 + ptm = posix_openpt(O_RDWR); +#else + ptm = open("/dev/ptmx", O_RDWR); + if(ptm == -1) + if(openpty(&ptm, &pts, NULL, NULL, NULL) == -1) + err(EXIT_FAILURE, "cannot open pty"); +#endif +#if defined(_XOPEN_SOURCE) + if(ptm != -1) { + if(grantpt(ptm) == -1) + err(EXIT_FAILURE, "cannot grant access to pty"); + if(unlockpt(ptm) == -1) + err(EXIT_FAILURE, "cannot unlock pty"); + ptsdev = ptsname(ptm); + if(!ptsdev) + err(EXIT_FAILURE, "slave pty name undefined"); + pts = open(ptsdev, O_RDWR); + if(pts == -1) + err(EXIT_FAILURE, "cannot open slave pty"); + } + else + err(EXIT_FAILURE, "cannot open pty"); +#endif +} + void shell(void) { static char *shell = NULL; From e0d0a2b96e84bba95f6f3e274131e3bbfb3a4f56 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 21 Jul 2008 17:06:59 +0200 Subject: [PATCH 0038/1146] simplify Makefile Due to consideration of POSIX compliance issues config.mk had to be removed. Configuration variables can be overridden by environment variables or specified via command line. Additionally all pretty-printed messages were removed and built-in rules are used. This also simplifies and purges the Makefile. --- Makefile | 81 +++++++++++++++++++++---------------------------------- config.mk | 34 ----------------------- 2 files changed, 31 insertions(+), 84 deletions(-) delete mode 100644 config.mk diff --git a/Makefile b/Makefile index 72154e9..0f74456 100644 --- a/Makefile +++ b/Makefile @@ -1,64 +1,45 @@ # st - simple terminal # See LICENSE file for copyright and license details. -include config.mk +VERSION = 0.0 -SRC = st.c std.c pty.c -OBJ = ${SRC:.c=.o} +PREFIX = /usr/local +MANDIR = $(PREFIX)/share/man -all: options st std +CFLAGS = -DVERSION=\"0.0\" -D_GNU_SOURCE -options: - @echo st build options: - @echo "CFLAGS = ${CFLAGS}" - @echo "LDFLAGS = ${LDFLAGS}" - @echo "X11LDFLAGS = ${X11LDFLAGS}" - @echo "CC = ${CC}" - -.c.o: - @echo CC $< - @${CC} -c ${CFLAGS} $< - -${OBJ}: config.mk - -st: st.o - @echo CC -o $@ - @${CC} -o $@ $^ ${LDFLAGS} ${X11LDFLAGS} - -std: std.o pty.o - @echo CC -o $@ - @${CC} -o $@ $^ ${LDFLAGS} +all: st std clean: - @echo cleaning - @rm -f st std ${OBJ} st-${VERSION}.tar.gz + rm -f st std + rm -f st.o std.o + rm -f st-$(VERSION).tar.gz dist: clean - @echo creating dist tarball - @mkdir -p st-${VERSION} - @cp -R LICENSE Makefile README config.mk \ - st.1 ${SRC} st-${VERSION} - @tar -cf st-${VERSION}.tar st-${VERSION} - @gzip st-${VERSION}.tar - @rm -rf st-${VERSION} + mkdir st-$(VERSION) + cp -f LICENSE README st-$(VERSION) + cp -f Makefile config.mk st-$(VERSION) + cp -f st.1 std.1 st-$(VERSION) + cp -f st.c std.c st-$(VERSION) + tar -czf st-$(VERSION).tar st-$(VERSION) + rm -rf st-$(VERSION) -install: all - @echo installing executable file to ${DESTDIR}${PREFIX}/bin - @mkdir -p ${DESTDIR}${PREFIX}/bin - @cp -f st ${DESTDIR}${PREFIX}/bin - @cp -f std ${DESTDIR}${PREFIX}/bin - @chmod 755 ${DESTDIR}${PREFIX}/bin/st - @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 - @mkdir -p ${DESTDIR}${MANPREFIX}/man1 - @sed "s/VERSION/${VERSION}/g" < st.1 > ${DESTDIR}${MANPREFIX}/man1/st.1 - @chmod 644 ${DESTDIR}${MANPREFIX}/man1/st.1 - @sed "s/VERSION/${VERSION}/g" < std.1 > ${DESTDIR}${MANPREFIX}/man1/std.1 - @chmod 644 ${DESTDIR}${MANPREFIX}/man1/std.1 +install: + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f st $(DESTDIR)$(PREFIX)/bin + cp -f std $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/st + chmod 755 $(DESTDIR)$(PREFIX)/bin/std + mkdir -p $(DESTDIR)$(MANDIR)/man1 + sed 's/VERSION/$(VERSION)/g' < st.1 > $(DESTDIR)$(MANDIR)/man1/st.1 + chmod 644 $(DESTDIR)$(MANDIR)/man1/st.1 + sed 's/VERSION/$(VERSION)/g' < std.1 > $(DESTDIR)$(MANDIR)/man1/std.1 + chmod 644 $(DESTDIR)$(MANDIR)/man1/std.1 uninstall: - @echo removing executable file from ${DESTDIR}${PREFIX}/bin - @rm -f ${DESTDIR}${PREFIX}/bin/st - @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 - @rm -f ${DESTDIR}${MANPREFIX}/man1/st.1 + rm -f $(DESTDIR)$(PREFIX)/bin/st + rm -f $(DESTDIR)$(PREFIX)/bin/std + rm -f $(DESTDIR)$(MANDIR)/man1/st.1 + rm -f $(DESTDIR)$(MANDIR)/man1/std.1 -.PHONY: all options clean dist install uninstall +.PHONY: all clean dist install uninstall diff --git a/config.mk b/config.mk deleted file mode 100644 index 4d76c67..0000000 --- a/config.mk +++ /dev/null @@ -1,34 +0,0 @@ -# st version -VERSION = 0.0 - -# Customize below to fit your system - -# paths -PREFIX = /usr/local -MANPREFIX = ${PREFIX}/share/man - -X11INC = /usr/X11R6/include -X11LIB = /usr/X11R6/lib - -# includes and libs -INCS = -I. -I/usr/include -I${X11INC} -LIBS = -L/usr/lib -lc -X11LIBS = -L${X11LIB} -lX11 - -# glibc -CPPFLAGS = -DVERSION=\"${VERSION}\" -D_GNU_SOURCE - -# flags -#CPPFLAGS = -DVERSION=\"${VERSION}\" -CFLAGS = -Os ${INCS} ${CPPFLAGS} -LDFLAGS = -s ${LIBS} -X11LDFLAGS = ${X11LIBS} -#CFLAGS = -g -std=c99 -pedantic -Wall -O2 ${INCS} ${CPPFLAGS} -#LDFLAGS = -g ${LIBS} - -# Solaris -#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" -#LDFLAGS = ${LIBS} - -# compiler and linker -CC = cc From 240411e7d08006f181afbf70930f748d7585ce85 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 21 Jul 2008 17:10:33 +0200 Subject: [PATCH 0039/1146] correct year of copyright notice --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 5b1d694..ce8ec88 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ MIT/X Consortium License © 2007-2008 Anselm R Garbe -© 2007-2008 Matthias Christian Ott +© 2008 Matthias Christian Ott Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), From d61a2a8fce2638594644feb664ce04398825b0f3 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Thu, 7 Aug 2008 10:38:54 +0200 Subject: [PATCH 0040/1146] add prototype for command parsing --- std.c | 81 ++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/std.c b/std.c index ef9e57a..a9a4f8c 100644 --- a/std.c +++ b/std.c @@ -18,19 +18,6 @@ #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) -static void buffer(char c); -static void cmd(const char *cmdstr, ...); -static int getch(); -static void getpty(void); -static void movea(int x, int y); -static void mover(int x, int y); -static void parseesc(void); -static void scroll(int l); -static void shell(void); -static void sigchld(int n); -static char unbuffer(void); -static void ungetch(int c); - typedef struct { unsigned char data[BUFSIZ]; int s, e; @@ -40,8 +27,23 @@ typedef struct { typedef struct { unsigned char data[BUFSIZ]; int i, n; + int fd; } ReadBuffer; +static void buffer(char c); +static void cmd(const char *cmdstr, ...); +static int getch(ReadBuffer *buf); +static void getpty(void); +static void movea(int x, int y); +static void mover(int x, int y); +static void parsecmd(void); +static void parseesc(void); +static void scroll(int l); +static void shell(void); +static void sigchld(int n); +static char unbuffer(void); +static void ungetch(ReadBuffer *buf, int c); + static int cols = 80, lines = 25; static int cx = 0, cy = 0; static int c; @@ -49,7 +51,7 @@ static int ptm, pts; static _Bool bold, digit, qmark; static pid_t pid; static RingBuffer buf; -static ReadBuffer rbuf; +static ReadBuffer cmdbuf, ptmbuf; void buffer(char c) { @@ -73,14 +75,14 @@ cmd(const char *cmdstr, ...) { } int -getch() { - if(rbuf.i++ >= rbuf.n) { - rbuf.n = read(ptm, rbuf.data, LENGTH(rbuf.data)); - if(rbuf.n == -1) - err(EXIT_FAILURE, "cannot read from slave pty"); - rbuf.i = 0; +getch(ReadBuffer *buf) { + if(buf->i++ >= buf->n) { + buf->n = read(buf->fd, buf->data, BUFSIZ); + if(buf->n == -1) + err(EXIT_FAILURE, "cannot read"); + buf->i = 0; } - return rbuf.data[rbuf.i]; + return buf->data[buf->i]; } void @@ -97,16 +99,20 @@ mover(int x, int y) { movea(cx + x, cy + y); } +void +parsecmd(void) { +} + void parseesc(void) { int i, j; int arg[16]; memset(arg, 0, LENGTH(arg)); - c = getch(); + c = getch(&ptmbuf); switch(c) { case '[': - c = getch(); + c = getch(&ptmbuf); for(j = 0; j < LENGTH(arg);) { if(isdigit(c)) { digit = 1; @@ -128,7 +134,7 @@ parseesc(void) { } break; } - c = getch(); + c = getch(&ptmbuf); } switch(c) { case '@': @@ -202,7 +208,7 @@ parseesc(void) { break; default: putchar('\033'); - ungetch(c); + ungetch(&ptmbuf, c); } } @@ -291,10 +297,10 @@ unbuffer(void) { } void -ungetch(int c) { - if(rbuf.i + 1 >= rbuf.n) - errx(EXIT_FAILURE, "read buffer full"); - rbuf.data[rbuf.i++] = c; +ungetch(ReadBuffer *buf, int c) { + if(buf->i + 1 >= buf->n) + errx(EXIT_FAILURE, "buffer full"); + buf->data[buf->i++] = c; } int @@ -307,15 +313,28 @@ main(int argc, char *argv[]) { errx(EXIT_FAILURE, "usage: std [-v]"); getpty(); shell(); + cmdbuf.fd = STDIN_FILENO; + ptmbuf.fd = ptm; FD_ZERO(&rfds); FD_SET(STDIN_FILENO, &rfds); FD_SET(ptm, &rfds); for(;;) { if(select(ptm + 1, &rfds, NULL, NULL, NULL) == -1) err(EXIT_FAILURE, "cannot select"); + if(FD_ISSET(STDIN_FILENO, &rfds)) + do { + c = getch(&cmdbuf); + switch(c) { + case ':': + parsecmd(); + break; + default: + break; + } + } while(cmdbuf.i < cmdbuf.n); if(FD_ISSET(ptm, &rfds)) { do { - c = getch(); + c = getch(&ptmbuf); switch(c) { case '\033': parseesc(); @@ -323,7 +342,7 @@ main(int argc, char *argv[]) { default: putchar(c); } - } while(rbuf.i < rbuf.n); + } while(ptmbuf.i < ptmbuf.n); fflush(stdout); } } From 07d1edcd76cf8ec3f6e72e79bbc1481da77e30f7 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 25 Aug 2008 16:29:37 +0200 Subject: [PATCH 0041/1146] add description of std --- std.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/std.c b/std.c index a9a4f8c..84a4b49 100644 --- a/std.c +++ b/std.c @@ -1,4 +1,16 @@ -/* See LICENSE file for copyright and license details. */ +/* See LICENSE file for copyright and license details. + * + * Simple terminal daemon is a terminal emulator. It can be used in + * combination with simple terminal to emulate a mostly VT100-compatible + * terminal. + * + * In this process std works like a filter. It reads data from a + * pseudo-terminal and parses the escape sequences and transforms + * them into an ed(1)-like. The resulting data is buffered and written + * to stdout. + * Parallely it reads data from stdin and parses and executes the + * commands. The resulting data is written to the pseudo-terminal. + */ #include #include #include From a7f50ebb64892900e5b56e30c6edd83807a4040b Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Mon, 25 Aug 2008 17:56:00 +0200 Subject: [PATCH 0042/1146] use stdio(3) --- std.c | 95 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/std.c b/std.c index 84a4b49..c2f4c3e 100644 --- a/std.c +++ b/std.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #if !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) #include @@ -36,15 +37,8 @@ typedef struct { int n; } RingBuffer; -typedef struct { - unsigned char data[BUFSIZ]; - int i, n; - int fd; -} ReadBuffer; - static void buffer(char c); static void cmd(const char *cmdstr, ...); -static int getch(ReadBuffer *buf); static void getpty(void); static void movea(int x, int y); static void mover(int x, int y); @@ -54,7 +48,6 @@ static void scroll(int l); static void shell(void); static void sigchld(int n); static char unbuffer(void); -static void ungetch(ReadBuffer *buf, int c); static int cols = 80, lines = 25; static int cx = 0, cy = 0; @@ -63,7 +56,7 @@ static int ptm, pts; static _Bool bold, digit, qmark; static pid_t pid; static RingBuffer buf; -static ReadBuffer cmdbuf, ptmbuf; +static FILE *fptm; void buffer(char c) { @@ -86,17 +79,6 @@ cmd(const char *cmdstr, ...) { va_end(ap); } -int -getch(ReadBuffer *buf) { - if(buf->i++ >= buf->n) { - buf->n = read(buf->fd, buf->data, BUFSIZ); - if(buf->n == -1) - err(EXIT_FAILURE, "cannot read"); - buf->i = 0; - } - return buf->data[buf->i]; -} - void movea(int x, int y) { x = MAX(x, cols); @@ -121,10 +103,10 @@ parseesc(void) { int arg[16]; memset(arg, 0, LENGTH(arg)); - c = getch(&ptmbuf); + c = getc(fptm); switch(c) { case '[': - c = getch(&ptmbuf); + c = getc(fptm); for(j = 0; j < LENGTH(arg);) { if(isdigit(c)) { digit = 1; @@ -146,7 +128,7 @@ parseesc(void) { } break; } - c = getch(&ptmbuf); + c = getc(fptm); } switch(c) { case '@': @@ -220,7 +202,7 @@ parseesc(void) { break; default: putchar('\033'); - ungetch(&ptmbuf, c); + ungetc(c, fptm); } } @@ -308,13 +290,6 @@ unbuffer(void) { return c; } -void -ungetch(ReadBuffer *buf, int c) { - if(buf->i + 1 >= buf->n) - errx(EXIT_FAILURE, "buffer full"); - buf->data[buf->i++] = c; -} - int main(int argc, char *argv[]) { fd_set rfds; @@ -325,28 +300,31 @@ main(int argc, char *argv[]) { errx(EXIT_FAILURE, "usage: std [-v]"); getpty(); shell(); - cmdbuf.fd = STDIN_FILENO; - ptmbuf.fd = ptm; FD_ZERO(&rfds); FD_SET(STDIN_FILENO, &rfds); FD_SET(ptm, &rfds); + if(!(fptm = fdopen(ptm, "r+"))) + err(EXIT_FAILURE, "cannot open pty"); + if(fcntl(ptm, F_SETFL, O_NONBLOCK) == -1) + err(EXIT_FAILURE, "cannot set pty to non-blocking mode"); + if(fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1) + err(EXIT_FAILURE, "cannot set stdin to non-blocking mode"); for(;;) { - if(select(ptm + 1, &rfds, NULL, NULL, NULL) == -1) + if(select(MAX(ptm, STDIN_FILENO) + 1, &rfds, NULL, NULL, NULL) == -1) err(EXIT_FAILURE, "cannot select"); - if(FD_ISSET(STDIN_FILENO, &rfds)) - do { - c = getch(&cmdbuf); - switch(c) { - case ':': - parsecmd(); - break; - default: + if(FD_ISSET(ptm, &rfds)) { + for(;;) { + if((c = getc(fptm)) == EOF) { + if(feof(fptm)) { + FD_CLR(ptm, &rfds); + fflush(fptm); + break; + } + if(errno != EAGAIN) + err(EXIT_FAILURE, "cannot read from pty"); + fflush(stdout); break; } - } while(cmdbuf.i < cmdbuf.n); - if(FD_ISSET(ptm, &rfds)) { - do { - c = getch(&ptmbuf); switch(c) { case '\033': parseesc(); @@ -354,9 +332,32 @@ main(int argc, char *argv[]) { default: putchar(c); } - } while(ptmbuf.i < ptmbuf.n); + } fflush(stdout); } + if(FD_ISSET(STDIN_FILENO, &rfds)) { + for(;;) { + if((c = getchar()) == EOF) { + if(feof(stdin)) { + FD_CLR(STDIN_FILENO, &rfds); + fflush(fptm); + break; + } + if(errno != EAGAIN) + err(EXIT_FAILURE, "cannot read from stdin"); + fflush(fptm); + break; + } + switch(c) { + case ':': + parsecmd(); + break; + default: + putc(c, fptm); + } + } + fflush(fptm); + } } return 0; } From 802f1922f93aef1e4876719e107828a1fa15b1a6 Mon Sep 17 00:00:00 2001 From: Matthias-Christian Ott Date: Fri, 5 Sep 2008 20:25:34 +0200 Subject: [PATCH 0043/1146] add accidentally omitted word --- std.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std.c b/std.c index c2f4c3e..55da9d6 100644 --- a/std.c +++ b/std.c @@ -5,9 +5,9 @@ * terminal. * * In this process std works like a filter. It reads data from a - * pseudo-terminal and parses the escape sequences and transforms - * them into an ed(1)-like. The resulting data is buffered and written - * to stdout. + * pseudo-terminal and parses the escape sequences and transforms them + * into an ed(1)-like language. The resulting data is buffered and + * written to stdout. * Parallely it reads data from stdin and parses and executes the * commands. The resulting data is written to the pseudo-terminal. */ From d58dd3b8bc42ed31232e4145696d7dacb117a31c Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Sun, 10 May 2009 13:17:09 +0100 Subject: [PATCH 0044/1146] backport of local changes --- LICENSE | 43 +-- Makefile | 67 ++-- README | 28 ++ TODO | 9 + config.mk | 31 ++ st.c | 928 +++++++++++++++++++++++++++++++++++++++++++++++++++++- st.h | 181 +++++++++++ st.info | 54 ++++ std.c | 363 --------------------- 9 files changed, 1278 insertions(+), 426 deletions(-) create mode 100644 README create mode 100644 TODO create mode 100644 config.mk create mode 100644 st.h create mode 100644 st.info delete mode 100644 std.c diff --git a/LICENSE b/LICENSE index ce8ec88..ee32d28 100644 --- a/LICENSE +++ b/LICENSE @@ -1,22 +1,25 @@ -MIT/X Consortium License +Copyright (c) 2009, Aurélien APTEL +Copyright (c) 2009, Anselm R Garbe -© 2007-2008 Anselm R Garbe -© 2008 Matthias Christian Ott +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. -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. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile index 0f74456..b0bd42d 100644 --- a/Makefile +++ b/Makefile @@ -1,45 +1,50 @@ # st - simple terminal # See LICENSE file for copyright and license details. -VERSION = 0.0 +include config.mk -PREFIX = /usr/local -MANDIR = $(PREFIX)/share/man +SRC = st.c +OBJ = ${SRC:.c=.o} -CFLAGS = -DVERSION=\"0.0\" -D_GNU_SOURCE +all: options st -all: st std +options: + @echo st build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + @echo CC $< + @${CC} -c ${CFLAGS} $< + +${OBJ}: config.mk + +st: ${OBJ} + @echo CC -o $@ + @${CC} -o $@ ${OBJ} ${LDFLAGS} clean: - rm -f st std - rm -f st.o std.o - rm -f st-$(VERSION).tar.gz + @echo cleaning + @rm -f st ${OBJ} st-${VERSION}.tar.gz dist: clean - mkdir st-$(VERSION) - cp -f LICENSE README st-$(VERSION) - cp -f Makefile config.mk st-$(VERSION) - cp -f st.1 std.1 st-$(VERSION) - cp -f st.c std.c st-$(VERSION) - tar -czf st-$(VERSION).tar st-$(VERSION) - rm -rf st-$(VERSION) + @echo creating dist tarball + @mkdir -p st-${VERSION} + @cp -R LICENSE Makefile README config.mk st.h ${SRC} st-${VERSION} + @tar -cf st-${VERSION}.tar st-${VERSION} + @gzip st-${VERSION}.tar + @rm -rf st-${VERSION} -install: - mkdir -p $(DESTDIR)$(PREFIX)/bin - cp -f st $(DESTDIR)$(PREFIX)/bin - cp -f std $(DESTDIR)$(PREFIX)/bin - chmod 755 $(DESTDIR)$(PREFIX)/bin/st - chmod 755 $(DESTDIR)$(PREFIX)/bin/std - mkdir -p $(DESTDIR)$(MANDIR)/man1 - sed 's/VERSION/$(VERSION)/g' < st.1 > $(DESTDIR)$(MANDIR)/man1/st.1 - chmod 644 $(DESTDIR)$(MANDIR)/man1/st.1 - sed 's/VERSION/$(VERSION)/g' < std.1 > $(DESTDIR)$(MANDIR)/man1/std.1 - chmod 644 $(DESTDIR)$(MANDIR)/man1/std.1 +install: all + @echo installing executable file to ${DESTDIR}${PREFIX}/bin + @mkdir -p ${DESTDIR}${PREFIX}/bin + @cp -f st ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/st + @tic st.info uninstall: - rm -f $(DESTDIR)$(PREFIX)/bin/st - rm -f $(DESTDIR)$(PREFIX)/bin/std - rm -f $(DESTDIR)$(MANDIR)/man1/st.1 - rm -f $(DESTDIR)$(MANDIR)/man1/std.1 + @echo removing executable file from ${DESTDIR}${PREFIX}/bin + @rm -f ${DESTDIR}${PREFIX}/bin/st -.PHONY: all clean dist install uninstall +.PHONY: all options clean dist install uninstall diff --git a/README b/README new file mode 100644 index 0000000..09a7fff --- /dev/null +++ b/README @@ -0,0 +1,28 @@ +st - simple terminal +-------------------- +st is a simple virtual 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 +---------- +See the man page for details. + +Credits +------- +Based on Aurélien APTEL bt source code. diff --git a/TODO b/TODO new file mode 100644 index 0000000..70fa785 --- /dev/null +++ b/TODO @@ -0,0 +1,9 @@ + - write a clean terminfo entry + - write global "setup" func + - try to split more logic/gfx + - optimize drawing + - handle copy/paste + - fix fork/child exit problem + - fix resize (shrinking should move last line up) + - handle utf8 + - refactor/clean code diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..62eb48f --- /dev/null +++ b/config.mk @@ -0,0 +1,31 @@ +# st version +VERSION = 0.0 + +# Customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = ${PREFIX}/share/man + +X11INC = /usr/X11R6/include +X11LIB = /usr/X11R6/lib + +# Xinerama, comment if you don't want it +#XINERAMALIBS = -L${X11LIB} -lXinerama +#XINERAMAFLAGS = -DXINERAMA + +# includes and libs +INCS = -I. -I/usr/include -I${X11INC} +LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} + +# flags +CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} +LDFLAGS = -s ${LIBS} + +# Solaris +#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" +#LDFLAGS = ${LIBS} + +# compiler and linker +CC = cc diff --git a/st.c b/st.c index 8a8804f..d5f004b 100644 --- a/st.c +++ b/st.c @@ -1,17 +1,921 @@ -/* See LICENSE file for copyright and license details. */ -#include -#include -#include +/* See LICENSE for licence details. */ +#include "st.h" + +/* Globals */ +DC dc; +XWindow xw; +Term term; +Escseq escseq; +int cmdfd; +int running; + +void +die(const char *errstr, ...) { + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +void +execsh(void) { + char *args[3] = {SHELL, "-i", NULL}; + putenv("TERM=" TNAME); + execvp(SHELL, args); +} + +void +xbell(void) { /* visual bell */ + XRectangle r = { 0, 0, xw.w, xw.h }; + XSetForeground(xw.dis, dc.gc, dc.col[BellCol]); + XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1); + XFlush(xw.dis); + usleep(30000); + draw(SCredraw); +} + +void +ttynew(void) { + int m, s; + pid_t pid; + char *pts; + + if((m = posix_openpt(O_RDWR | O_NOCTTY)) < 0) + die("openpt"); + if(grantpt(m) == -1) + die("grandpt"); + if(unlockpt(m) == -1) + die("unlockpt"); + if((pts = ptsname(m)) == NULL) + die("ptsname"); + if((s = open(pts, O_RDWR | O_NOCTTY)) < 0) + die("slave open"); + fcntl(s, F_SETFL, O_NDELAY); + switch(pid = fork()) { + case -1: + die("fork"); + break; + case 0: + setsid(); /* create a new process group */ + dup2(s, STDIN_FILENO); + dup2(s, STDOUT_FILENO); + dup2(s, STDERR_FILENO); + if(ioctl(s, TIOCSCTTY, NULL) < 0) + die("slave TTIOCSTTY"); + execsh(); + break; + default: + close(s); + cmdfd = m; + } +} + +void +dump(char c) { + static int col; + fprintf(stderr, " %02x %c ", c, isprint(c)?c:'.'); + if(++col % 10 == 0) + fprintf(stderr, "\n"); +} + +void +ttyread(void) { + char buf[BUFSIZ] = {0}; + int ret; + + switch(ret = read(cmdfd, buf, BUFSIZ)) { + case -1: /* error or exit */ + /* XXX: be more precise */ + running = 0; + break; + default: + tputs(buf, ret); + } +} + +void +ttywrite(char *s, size_t n) { + if(write(cmdfd, s, n) == -1) + die("write error on tty."); +} + +void +ttyresize(int x, int y) { + struct winsize w; + + w.ws_row = term.row; + w.ws_col = term.col; + w.ws_xpixel = w.ws_ypixel = 0; + if(ioctl(cmdfd, TIOCSWINSZ, &w) < 0) + fprintf(stderr, "Couldn't set window size: %m\n"); +} + +int +escfinal(char c) { + if(escseq.len == 1) + switch(c) { + case '[': + case ']': + case '(': + return 0; + case '=': + case '>': + default: + return 1; + } + else if(BETWEEN(c, 0x40, 0x7E)) + return 1; + return 0; +} + +void +tcpos(int mode) { + static int x = 0; + static int y = 0; + + if(mode == CSsave) + x = term.c.x, y = term.c.y; + else if(mode == CSload) + tmoveto(x, y); +} + +void +tnew(int col, int row) { /* screen size */ + term.row = row, term.col = col; + term.top = 0, term.bot = term.row - 1; + /* mode */ + term.mode = TMwrap; + /* cursor */ + term.c.attr.mode = ATnone; + term.c.attr.fg = DefaultFG; + term.c.attr.bg = DefaultBG; + term.c.x = term.c.y = 0; + term.c.hidden = 0; + /* allocate screen */ + term.line = calloc(term.row, sizeof(Line)); + for(row = 0 ; row < term.row; row++) + term.line[row] = calloc(term.col, sizeof(Glyph)); +} + +void +tscroll(void) { + Line temp = term.line[term.top]; + int i; + + for(i = term.top; i < term.bot; i++) + term.line[i] = term.line[i+1]; + memset(temp, 0, sizeof(Glyph) * term.col); + term.line[term.bot] = temp; + xscroll(); +} + +void +tnewline(void) { + int y = term.c.y + 1; + + if(y > term.bot) { + tscroll(), y = term.bot; + } + tmoveto(0, y); +} + +int +escaddc(char c) { + escseq.buf[escseq.len++] = c; + if(escfinal(c) || escseq.len >= ESCSIZ) { + escparse(), eschandle(); + return 0; + } + return 1; +} + +void +escparse(void) { + /* int noarg = 1; */ + char *p = escseq.buf; + + escseq.narg = 0; + switch(escseq.pre = *p++) { + case '[': /* CSI */ + if(*p == '?') + escseq.priv = 1, p++; + + while(p < escseq.buf+escseq.len) { + while(isdigit(*p)) { + escseq.arg[escseq.narg] *= 10; + escseq.arg[escseq.narg] += *(p++) - '0'/*, noarg = 0 */; + } + if(*p == ';') + escseq.narg++, p++; + else { + escseq.mode = *p; + escseq.narg++; + return; + } + } + break; + case '(': + /* humf charset stuff */ + break; + } +} + +void +tmoveto(int x, int y) { + term.c.x = x < 0 ? 0 : x >= term.col ? term.col-1 : x; + term.c.y = y < 0 ? 0 : y >= term.row ? term.row-1 : y; +} + +void +tcursor(int dir) { + int xi = term.c.x, yi = term.c.y; + int xf = xi, yf = yi; + + switch(dir) { + case CSup: + yf--; + break; + case CSdown: + yf++; + break; + case CSleft: + xf--; + if(xf < 0) { + xf = term.col-1, yf--; + if(yf < term.top) + yf = term.top, xf = 0; + } + break; + case CSright: + xf++; + if(xf >= term.col) { + xf = 0, yf++; + if(yf > term.bot) + yf = term.bot, tscroll(); + } + break; + } + tmoveto(xf, yf); +} + +void +tsetchar(char c) { + term.line[term.c.y][term.c.x] = term.c.attr; + term.line[term.c.y][term.c.x].c = c; + term.line[term.c.y][term.c.x].state |= CRset | CRupdate; +} + +void +tclearregion(int x1, int y1, int x2, int y2) { + int x, y; + + LIMIT(x1, 0, term.col-1); + LIMIT(x2, 0, term.col-1); + LIMIT(y1, 0, term.row-1); + LIMIT(y2, 0, term.row-1); + + /* XXX: could be optimized */ + for(x = x1; x <= x2; x++) + for(y = y1; y <= y2; y++) + memset(&term.line[y][x], 0, sizeof(Glyph)); + + xclear(x1, y1, x2, y2); +} + +void +tdeletechar(int n) { + int src = term.c.x + n; + int dst = term.c.x; + int size = term.col - src; + + if(src >= term.col) { + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); + return; + } + memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph)); + tclearregion(term.col-size, term.c.y, term.col-1, term.c.y); +} + +void +tinsertblank(int n) { + int src = term.c.x; + int dst = src + n; + int size = term.col - n - src; + + if(dst >= term.col) { + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); + return; + } + memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph)); + tclearregion(src, term.c.y, dst, term.c.y); +} + +void +tinsertblankline (int n) { + int i; + Line blank; + int bot = term.bot; + + if(term.c.y > term.bot) + bot = term.row - 1; + else if(term.c.y < term.top) + bot = term.top - 1; + if(term.c.y + n >= bot) { + tclearregion(0, term.c.y, term.col-1, bot); + return; + } + for(i = bot; i >= term.c.y+n; i--) { + /* swap deleted line <-> blanked line */ + blank = term.line[i]; + term.line[i] = term.line[i-n]; + term.line[i-n] = blank; + /* blank it */ + memset(blank, 0, term.col * sizeof(Glyph)); + } +} + + +void +tdeleteline(int n) { + int i; + Line blank; + int bot = term.bot; + + if(term.c.y > term.bot) + bot = term.row - 1; + else if(term.c.y < term.top) + bot = term.top - 1; + if(term.c.y + n >= bot) { + tclearregion(0, term.c.y, term.col-1, bot); + return; + } + for(i = term.c.y; i <= bot-n; i++) { + /* swap deleted line <-> blanked line */ + blank = term.line[i]; + term.line[i] = term.line[i+n]; + term.line[i+n] = blank; + /* blank it */ + memset(blank, 0, term.col * sizeof(Glyph)); + } +} + +void +tsetattr(int *attr, int l) { + int i; + +#ifdef TRUECOLOR /* ESC [ ? ; ; ; m */ + Color col; + if(escseq.priv && escseq.len == 4) { /* True color extension :) */ + col = (escseq.arg[1]<<16) + (escseq.arg[2]<<8) + escseq.arg[3]; + switch(escseq.arg[0]) { + case 3: /* foreground */ + term.c.attr.fg = col; + break; + case 4: /* background */ + term.c.attr.bg = col; + break; + } + } + else +#endif + for(i = 0; i < l; i++) { + switch(attr[i]) { + case 0: + memset(&term.c.attr, 0, sizeof(term.c.attr)); + term.c.attr.fg = DefaultFG; + term.c.attr.bg = DefaultBG; + break; + case 1: + term.c.attr.mode |= ATbold; + break; + case 4: + term.c.attr.mode |= ATunderline; + break; + case 7: + term.c.attr.mode |= ATreverse; + break; + case 8: + term.c.hidden = CShide; + break; + case 22: + term.c.attr.mode &= ~ATbold; + break; + case 24: + term.c.attr.mode &= ~ATunderline; + break; + case 27: + term.c.attr.mode &= ~ATreverse; + break; + case 39: + term.c.attr.fg = DefaultFG; + break; + case 49: + term.c.attr.fg = 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; + 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 +eschandle(void) { + /* escdump(); */ + switch(escseq.pre) { + case '[': + switch(escseq.mode) { + case '@': /* Insert blank char */ + DEFAULT(escseq.arg[0], 1); + tinsertblank(escseq.arg[0]); + break; + case 'A': /* Cursor Up */ + case 'e': + DEFAULT(escseq.arg[0], 1); + tmoveto(term.c.x, term.c.y-escseq.arg[0]); + break; + case 'B': /* Cursor Down */ + DEFAULT(escseq.arg[0], 1); + tmoveto(term.c.x, term.c.y+escseq.arg[0]); + break; + case 'C': /* Cursor Forward */ + case 'a': + DEFAULT(escseq.arg[0], 1); + tmoveto(term.c.x+escseq.arg[0], term.c.y); + break; + case 'D': /* Cursor Backward */ + DEFAULT(escseq.arg[0], 1); + tmoveto(term.c.x-escseq.arg[0], term.c.y); + break; + case 'E': /* Cursor Down and first col */ + DEFAULT(escseq.arg[0], 1); + tmoveto(0, term.c.y+escseq.arg[0]); + break; + case 'F': /* Cursor Up and first col */ + DEFAULT(escseq.arg[0], 1); + tmoveto(0, term.c.y-escseq.arg[0]); + break; + case 'G': /* Move to */ + case '`': + DEFAULT(escseq.arg[0], 1); + tmoveto(escseq.arg[0]-1, term.c.y); + break; + case 'H': /* Move to */ + case 'f': + DEFAULT(escseq.arg[0], 1); + DEFAULT(escseq.arg[1], 1); + tmoveto(escseq.arg[1]-1, escseq.arg[0]-1); + break; + case 'J': /* Clear screen */ + switch(escseq.arg[0]) { + case 0: /* below */ + tclearregion(term.c.x, term.c.y, term.col-1, term.row-1); + break; + case 1: /* above */ + tclearregion(0, 0, term.c.x, term.c.y); + break; + case 2: /* all */ + tclearregion(0, 0, term.col-1, term.row-1); + break; + } + break; + case 'K': /* Clear line */ + switch(escseq.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 'L': /* Insert blank lines */ + DEFAULT(escseq.arg[0], 1); + tinsertblankline(escseq.arg[0]); + break; + case 'M': /* Delete lines */ + DEFAULT(escseq.arg[0], 1); + tdeleteline(escseq.arg[0]); + break; + case 'P': /* Delete char */ + DEFAULT(escseq.arg[0], 1); + tdeletechar(escseq.arg[0]); + break; + case 'd': /* Move to */ + DEFAULT(escseq.arg[0], 1); + tmoveto(term.c.x, escseq.arg[0]-1); + break; + case 'h': /* Set terminal mode */ + break; + case 'm': /* Terminal attribute (color) */ + tsetattr(escseq.arg, escseq.narg); + break; + case 'r': + if(escseq.priv) + ; + else { + DEFAULT(escseq.arg[0], 1); + DEFAULT(escseq.arg[1], term.row); + tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1); + } + break; + case 's': /* Save cursor position */ + tcpos(CSsave); + break; + case 'u': /* Load cursor position */ + tcpos(CSload); + break; + } + break; + } +} + +void +escdump(void) { + int i; + puts("------"); + printf("rawbuf : %s\n", escseq.buf); + printf("prechar : %c\n", escseq.pre); + printf("private : %c\n", escseq.priv ? '?' : ' '); + printf("narg : %d\n", escseq.narg); + if(escseq.narg) { + for(i = 0; i < escseq.narg; i++) + printf("\targ %d = %d\n", i, escseq.arg[i]); + } + printf("mode : %c\n", escseq.mode); +} + +void +escreset(void) { + memset(&escseq, 0, sizeof(escseq)); +} + +void +tputc(char c) { + static int inesc = 0; + + dump(c); + /* start of escseq */ + if(c == '\033') + escreset(), inesc = 1; + else if(inesc) { + inesc = escaddc(c); + } /* normal char */ + else switch(c) { + default: + tsetchar(c); + tcursor(CSright); + break; + case '\b': + tcursor(CSleft); + break; + case '\r': + tmoveto(0, term.c.y); + break; + case '\n': + tnewline(); + break; + case '\a': + xbell(); + break; + } +} + +void +tputs(char *s, int len) { + for(; len > 0; len--) + tputc(*s++); +} + +void +tdump(void) { + int row, col; + Glyph c; + + for(row = 0; row < term.row; row++) { + for(col = 0; col < term.col; col++) { + if(col == term.c.x && row == term.c.y) + putchar('#'); + else { + c = term.line[row][col]; + putchar(c.state & CRset ? c.c : '.'); + } + } + putchar('\n'); + } +} + +void +tresize(int col, int row) { + int i; + Line *line; + int minrow = MIN(row, term.row); + int mincol = MIN(col, term.col); + + if(col < 1 || row < 1) + return; + line = calloc(row, sizeof(Line)); + for(i = 0 ; i < row; i++) + line[i] = calloc(col, sizeof(Glyph)); + for(i = 0 ; i < minrow; i++) { + memcpy(line[i], term.line[i], mincol * sizeof(Glyph)); + free(term.line[i]); + } + free(term.line); + LIMIT(term.c.x, 0, col-1); + LIMIT(term.c.y, 0, row-1); + LIMIT(term.top, 0, row-1); + LIMIT(term.bot, 0, row-1); + // if(term.bot == term.row-1) + term.bot = row-1; + term.line = line; + term.col = col, term.row = row; +} + +unsigned long +xgetcol(const char *s) { + XColor color; + Colormap cmap = DefaultColormap(xw.dis, xw.scr); + + if(!XAllocNamedColor(xw.dis, cmap, s, &color, &color)) { + color.pixel = WhitePixel(xw.dis, xw.scr); + fprintf(stderr, "Could not allocate color '%s'\n", s); + } + return color.pixel; +} + + +void +xclear(int x1, int y1, int x2, int y2) { + XClearArea(xw.dis, xw.win, + x1 * xw.cw, y1 * xw.ch, + (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch, + False); +} + + +void +xscroll(void) { + int srcy = (term.top+1) * xw.ch; + int dsty = term.top * xw.ch; + int height = (term.bot-term.top) * xw.ch; + + xcursor(CShide); + XCopyArea(xw.dis, xw.win, xw.win, dc.gc, 0, srcy, xw.w, height, 0, dsty); + xclear(0, term.bot, term.col-1, term.bot); +} + + + + +void +xinit(void) { + XGCValues values; + unsigned long valuemask; + XClassHint chint; + XWMHints wmhint; + XSizeHints shint; + char *args[] = {NULL}; + int i; + + xw.dis = XOpenDisplay(NULL); + xw.scr = XDefaultScreen(xw.dis); + /* font */ + dc.font = XLoadQueryFont(xw.dis, FONT); + xw.cw = dc.font->max_bounds.rbearing - dc.font->min_bounds.lbearing; + xw.ch = dc.font->ascent + dc.font->descent + LINESPACE; + /* colors */ + for(i = 0; i < LEN(colorname); i++) + dc.col[i] = xgetcol(colorname[i]); + term.c.attr.fg = DefaultFG; + term.c.attr.bg = DefaultBG; + term.c.attr.mode = ATnone; + /* windows */ + xw.h = term.row * xw.ch; + xw.w = term.col * xw.cw; + /* XXX: this BORDER is useless after the first resize, handle it in xdraws() */ + xw.win = XCreateSimpleWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0, + xw.w, xw.h, BORDER, + dc.col[DefaultBG], + dc.col[DefaultBG]); + /* gc */ + values.foreground = XWhitePixel(xw.dis, xw.scr); + values.font = dc.font->fid; + valuemask = GCForeground | GCFont; + dc.gc = XCreateGC(xw.dis, xw.win, valuemask, &values); + XMapWindow(xw.dis, xw.win); + /* wm stuff */ + chint.res_name = TNAME, chint.res_class = TNAME; + wmhint.input = 1, wmhint.flags = InputHint; + shint.height_inc = xw.ch, shint.width_inc = xw.cw; + shint.height = xw.h, shint.width = xw.w; + shint.flags = PSize | PResizeInc; + XSetWMProperties(xw.dis, xw.win, NULL, NULL, &args[0], 0, &shint, &wmhint, &chint); + XStoreName(xw.dis, xw.win, TNAME); + XSync(xw.dis, 0); +} + +void +xdrawc(int x, int y, Glyph g) { + XRectangle r = { x * xw.cw, y * xw.ch, xw.cw, xw.ch }; + unsigned long xfg, xbg; + + /* reverse video */ + if(g.mode & ATreverse) + xfg = dc.col[g.bg], xbg = dc.col[g.fg]; + else + xfg = dc.col[g.fg], xbg = dc.col[g.bg]; + /* background */ + XSetForeground(xw.dis, dc.gc, xbg); + XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1); + /* string */ + XSetForeground(xw.dis, dc.gc, xfg); + XDrawString(xw.dis, xw.win, dc.gc, r.x, r.y+dc.font->ascent, &(g.c), 1); + if(g.mode & ATbold) /* XXX: bold hack (draw again at x+1) */ + XDrawString(xw.dis, xw.win, dc.gc, r.x+1, r.y+dc.font->ascent, &(g.c), 1); + /* underline */ + if(g.mode & ATunderline) { + r.y += dc.font->ascent + 1; + XDrawLine(xw.dis, xw.win, dc.gc, r.x, r.y, r.x+r.width-1, r.y); + } +} + +void +xcursor(int mode) { + static int oldx = 0; + static int oldy = 0; + Glyph g = {' ', ATnone, DefaultBG, DefaultCS, 0}; + + if(term.line[term.c.y][term.c.x].state & CRset) + g.c = term.line[term.c.y][term.c.x].c; + /* remove the old cursor */ + if(term.line[oldy][oldx].state & CRset) + xdrawc(oldx, oldy, term.line[oldy][oldx]); + else xclear(oldx, oldy, oldx, oldy); /* XXX: maybe a bug */ + if(mode == CSdraw && !term.c.hidden) { + xdrawc(term.c.x, term.c.y, g); + oldx = term.c.x, oldy = term.c.y; + } +} + + +void +draw(int redraw_all) { + int x, y; + int changed, set; + + if(redraw_all) + XClearWindow(xw.dis, xw.win); + /* XXX: drawing could be optimised */ + for(y = 0; y < term.row; y++) { + for(x = 0; x < term.col; x++) { + changed = term.line[y][x].state & CRupdate; + set = term.line[y][x].state & CRset; + if((changed && set) || (redraw_all && set)) { + term.line[y][x].state &= ~CRupdate; + xdrawc(x, y, term.line[y][x]); + } + } + } + xcursor(CSdraw); +} + +void +kpress(XKeyEvent *e) { + KeySym ksym; + char buf[32]; + int len; + int meta; + int shift; + + meta = e->state & Mod4Mask; + shift = e->state & ShiftMask; + len = XLookupString(e, buf, sizeof(buf), &ksym, NULL); + if(len > 0) { + buf[sizeof(buf)-1] = '\0'; + if(meta && len == 1) + ttywrite("\033", 1); + ttywrite(buf, len); + return; + } + switch(ksym) { +#ifdef DEBUG1 + default: + printf("errkey: %d\n", (int)ksym); + break; +#endif + case XK_Up: + case XK_Down: + case XK_Left: + case XK_Right: + sprintf(buf, "\033[%c", "DACB"[ksym - XK_Left]); + ttywrite(buf, 3); + break; + case XK_Delete: ttywrite(KEYDELETE, sizeof(KEYDELETE)-1); break; + case XK_Home: ttywrite( KEYHOME, sizeof( KEYHOME)-1); break; + case XK_End: ttywrite( KEYEND, sizeof( KEYEND)-1); break; + case XK_Prior: ttywrite( KEYPREV, sizeof( KEYPREV)-1); break; + case XK_Next: ttywrite( KEYNEXT, sizeof( KEYNEXT)-1); break; + case XK_Insert: + /* XXX: paste X clipboard */ + if(shift); + break; + } +} + +void +resize(XEvent *e) { + int col, row; + col = e->xconfigure.width / xw.cw; + row = e->xconfigure.height / xw.ch; + + if(term.col != col && term.row != row) { + tresize(col, row); + ttyresize(col, row); + xw.w = e->xconfigure.width; + xw.h = e->xconfigure.height; + draw(SCredraw); + } +} + + +void +run(void) { + int ret; + XEvent ev; + fd_set rfd; + struct timeval tv = {0, 10000}; + + running = 1; + XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNotifyMask); + XResizeWindow(xw.dis, xw.win, xw.w , xw.h); /* seems to fix the resize bug in wmii */ + while(running) { + while(XPending(xw.dis)) { + XNextEvent(xw.dis, &ev); + switch (ev.type) { + default: + break; + case KeyPress: + kpress(&ev.xkey); + break; + case Expose: + draw(SCredraw); + break; + case ConfigureNotify: + resize(&ev); + break; + } + } + FD_ZERO(&rfd); + FD_SET(cmdfd, &rfd); + ret = select(cmdfd+1, &rfd, NULL, NULL, &tv); + if(ret < 0) { + fprintf(stderr, "select: %m\n"); + running = 0; + } + if(!ret) + continue; + if(FD_ISSET(cmdfd, &rfd)) { + ttyread(); + draw(SCupdate); + } + } +} int main(int argc, char *argv[]) { - if(argc == 2 && !strcmp("-v", argv[1])) { - fprintf(stderr, "st-"VERSION", © 2007-2008 st engineers, see LICENSE for details\n"); - exit(EXIT_SUCCESS); - } - else if(argc != 1) { - fprintf(stderr, "usage: st [-v]\n"); - exit(EXIT_FAILURE); - } + if(argc == 2 && !strncmp("-v", argv[1], 3)) + die("st-"VERSION", © 2009 st engineers\n"); + else if(argc != 1) + die("usage: st [-v]\n"); + setlocale(LC_CTYPE, ""); + tnew(80, 24); + ttynew(); + xinit(); + run(); return 0; } diff --git a/st.h b/st.h new file mode 100644 index 0000000..be39ef4 --- /dev/null +++ b/st.h @@ -0,0 +1,181 @@ +/* See LICENSE for licence details. */ + +#define _XOPEN_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* special keys */ +#define KEYDELETE "\033[3~" +#define KEYHOME "\033[1~" +#define KEYEND "\033[4~" +#define KEYPREV "\033[5~" +#define KEYNEXT "\033[6~" + +#define TNAME "st" +#define SHELL "/bin/bash" +#define TAB 8 + +#define FONT "-*-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*" +#define BORDER 3 +#define LINESPACE 1 /* additional pixel between each line */ + +/* Default colors */ +#define DefaultFG 7 +#define DefaultBG 0 +#define DefaultCS 1 +#define BellCol DefaultFG /* visual bell color */ + +static char* colorname[] = { + "black", + "red", + "green", + "yellow", + "blue", + "magenta", + "cyan", + "white", +}; + + +/* Arbitrary sizes */ +#define ESCSIZ 256 +#define ESCARG 16 + +#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 DEFAULT(a, b) (a) = (a) ? (a) : (b) +#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) +#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) + + +enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 }; /* Attribute */ +enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload }; /* Cursor */ +enum { CRset=1 , CRupdate=2 }; /* Character state */ +enum { TMwrap=1 , TMinsert=2 }; /* Terminal mode */ +enum { SCupdate, SCredraw }; /* screen draw mode */ + +#ifdef TRUECOLOR +#error Truecolor not implemented yet +typedef int Color; +#else +typedef char Color; +#endif + + +typedef struct { + char c; /* character code */ + char mode; /* attribute flags */ + Color fg; /* foreground */ + Color bg; /* background */ + char state; /* state flag */ +} Glyph; + +typedef Glyph* Line; + +typedef struct { + Glyph attr; /* current char attributes */ + char hidden; + int x; + int y; +} TCursor; + +/* Escape sequence structs */ +typedef struct { + char buf[ESCSIZ+1]; /* raw string */ + int len; /* raw string length */ + /* ESC
 [[ []  [;]] ] */
+	char pre;           
+	char priv;
+	int arg[ESCARG+1];
+	int narg;           /* nb of args */
+	char mode;
+} Escseq;
+
+/* Internal representation of the screen */
+typedef struct {
+	int row;    /* nb row */  
+	int col;    /* nb col */
+	Line* line; /* screen */
+	TCursor c;  /* cursor */
+	int top;    /* top    scroll limit */
+	int bot;    /* bottom scroll limit */
+	int mode;   /* terminal mode */
+} Term;
+
+/* Purely graphic info */
+typedef struct {
+	Display* dis;
+	Window win;
+	int scr;
+	int w;  /* window width  */
+	int h;  /* window height */
+	int ch; /* char height */
+	int cw; /* char width  */
+} XWindow; 
+
+/* Drawing Context */
+typedef struct {
+	unsigned long col[LEN(colorname)];
+	XFontStruct* font;
+	GC gc;
+} DC;
+
+
+void die(const char *errstr, ...);
+void draw(int);
+void execsh(void);
+void kpress(XKeyEvent *);
+void resize(XEvent *);
+void run(void);
+
+int escaddc(char);
+int escfinal(char);
+void escdump(void);
+void eschandle(void);
+void escparse(void);
+void escreset(void);
+
+void tclearregion(int, int, int, int);
+void tcpos(int);
+void tcursor(int);
+void tdeletechar(int);
+void tdeleteline(int);
+void tdump(void);
+void tinsertblank(int);
+void tinsertblankline(int);
+void tmoveto(int, int);
+void tnew(int, int);
+void tnewline(void);
+void tputc(char);
+void tputs(char*, int);
+void tresize(int, int);
+void tscroll(void);
+void tsetattr(int*, int);
+void tsetchar(char);
+void tsetscroll(int, int);
+
+void ttynew(void);
+void ttyread(void);
+void ttyresize(int, int);
+void ttywrite(char *, size_t);
+
+unsigned long xgetcol(const char *);
+void xclear(int, int, int, int);
+void xcursor(int);
+void xdrawc(int, int, Glyph);
+void xinit(void);
+void xscroll(void);
diff --git a/st.info b/st.info
new file mode 100644
index 0000000..1ded6b5
--- /dev/null
+++ b/st.info
@@ -0,0 +1,54 @@
+#	Reconstructed via infocmp from file: /lib/terminfo/p/pcansi
+st| simpleterm,
+	am,
+    ul,
+	mir,
+	msgr,
+	colors#8,
+	cols#80,
+	it#8,
+	lines#24,
+	ncv#3,
+	pairs#64,
+    acsc=*`#aof+g+j+k+l+m+n-o-p-q-r-s+t+u+v+w|xz{{||}}-~,
+	bel=^G,
+	bold=\E[1m,
+	cbt=\E[Z,
+	clear=\E[H\E[2J,
+	cr=^M,
+	cub1=\E[D,
+	cud1=\E[B,
+	cuf1=\E[C,
+	cup=\E[%i%p1%d;%p2%dH,
+	cuu1=\E[A,
+	dch1=\E[P,
+	dl1=\E[M,
+	ed=\E[J,
+	el=\E[K,
+	home=\E[H,
+	ht=^I,
+	hts=\EH,
+	il1=\E[L,
+	ind=^J,
+	invis=\E[8m,
+	kbs=^H,
+	kcub1=\E[D,
+	kcud1=\E[B,
+	kcuf1=\E[C,
+	kcuu1=\E[A,
+	khome=\E[1~,
+    knp=\E[6~,
+    kpp=\E[5~,
+	op=\E[37;40m,
+	rev=\E[7m,
+	rmacs=\E[10m,
+	rmso=\E[m,
+	rmul=\E[m,
+	setab=\E[4%p1%dm,
+	setaf=\E[3%p1%dm,
+#	sgr=\E[0;10%?%p1%t;7%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p6%t;1%;%?%p7%t;8%;%?%p9%t;12%;m,
+	sgr0=\E[0m,
+	smacs=\E[12m,
+	smso=\E[7m,
+	smul=\E[4m,
+	tbc=\E[2g,
diff --git a/std.c b/std.c
deleted file mode 100644
index 55da9d6..0000000
--- a/std.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/* See LICENSE file for copyright and license details.
- *
- * Simple terminal daemon is a terminal emulator. It can be used in
- * combination with simple terminal to emulate a mostly VT100-compatible
- * terminal.
- * 
- * In this process std works like a filter. It reads data from a
- * pseudo-terminal and parses the escape sequences and transforms them
- * into an ed(1)-like language. The resulting data is buffered and
- * written to stdout.
- * Parallely it reads data from stdin and parses and executes the
- * commands. The resulting data is written to the pseudo-terminal.
- */
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#if !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
-#include 
-#endif
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#define LENGTH(x)	(sizeof(x) / sizeof((x)[0]))
-#define MAX(a,b)	(((a) > (b)) ? (a) : (b))
-#define MIN(a,b)	(((a) < (b)) ? (a) : (b))
-
-typedef struct {
-	unsigned char data[BUFSIZ];
-	int s, e;
-	int n;
-} RingBuffer;
-
-static void buffer(char c);
-static void cmd(const char *cmdstr, ...);
-static void getpty(void);
-static void movea(int x, int y);
-static void mover(int x, int y);
-static void parsecmd(void);
-static void parseesc(void);
-static void scroll(int l);
-static void shell(void);
-static void sigchld(int n);
-static char unbuffer(void);
-
-static int cols = 80, lines = 25;
-static int cx = 0, cy = 0;
-static int c;
-static int ptm, pts;
-static _Bool bold, digit, qmark;
-static pid_t pid;
-static RingBuffer buf;
-static FILE *fptm;
-
-void
-buffer(char c) {
-	if(buf.n < LENGTH(buf.data))
-		buf.n++;
-	else
-		buf.s = (buf.s + 1) % LENGTH(buf.data);
-	buf.data[buf.e++] = c;
-	buf.e %= LENGTH(buf.data);
-}
-
-void
-cmd(const char *cmdstr, ...) {
-	va_list ap;
-
-	putchar('\n');
-	putchar(':');
-	va_start(ap, cmdstr);
-	vfprintf(stdout, cmdstr, ap);
-	va_end(ap);
-}
-
-void
-movea(int x, int y) {
-	x = MAX(x, cols);
-	y = MAX(y, lines);
-	cx = x;
-	cy = y;
-	cmd("seek(%d,%d)", x, y);
-}
-
-void
-mover(int x, int y) {
-	movea(cx + x, cy + y);
-}
-
-void
-parsecmd(void) {
-}
-
-void
-parseesc(void) {
-	int i, j;
-	int arg[16];
-
-	memset(arg, 0, LENGTH(arg));
-	c = getc(fptm);
-	switch(c) {
-	case '[':
-		c = getc(fptm);
-		for(j = 0; j < LENGTH(arg);) {
-			if(isdigit(c)) {
-				digit = 1;
-				arg[j] *= 10;
-				arg[j] += c - '0';
-			}
-			else if(c == '?')
-				qmark = 1;
-			else if(c == ';') {
-				if(!digit)
-					errx(EXIT_FAILURE, "syntax error");
-				digit = 0;
-				j++;
-			}
-			else {
-				if(digit) {
-					digit = 0;
-					j++;
-				}
-				break;
-			}
-			c = getc(fptm);
-		}
-		switch(c) {
-		case '@':
-			break;
-		case 'A':
-			mover(0, j ? arg[0] : 1);
-			break;
-		case 'B':
-			mover(0, j ? -arg[0] : -1);
-			break;
-		case 'C':
-			mover(j ? arg[0] : 1, 0);
-			break;
-		case 'D':
-			mover(j ? -arg[0] : -1, 0);
-			break;
-		case 'E':
-			/* movel(j ? arg[0] : 1); */
-			break;
-		case 'F':
-			/* movel(j ? -arg[0] : -1); */
-			break;
-		case '`':
-		case 'G':
-			movea(j ? arg[0] : 1, cy);
-			break;
-		case 'f':
-		case 'H':
-			movea(arg[1] ? arg[1] : 1, arg[0] ? arg[0] : 1);
-		case 'L':
-			/* insline(j ? arg[0] : 1); */
-			break;
-		case 'M':
-			/* delline(j ? arg[0] : 1); */
-			break;
-		case 'P':
-			break;
-		case 'S':
-			scroll(j ? arg[0] : 1);
-			break;
-		case 'T':
-			scroll(j ? -arg[0] : -1);
-			break;
-		case 'd':
-			movea(cx, j ? arg[0] : 1);
-			break;
-		case 'm':
-			for(i = 0; i < j; i++) {
-				if(arg[i] >= 30 && arg[i] <= 37)
-					cmd("#%d", arg[i] - 30);
-				if(arg[i] >= 40 && arg[i] <= 47)
-					cmd("|%d", arg[i] - 40);
-				/* xterm bright colors */
-				if(arg[i] >= 90 && arg[i] <= 97)
-					cmd("#%d", arg[i] - 90);
-				if(arg[i] >= 100 && arg[i] <= 107)
-					cmd("|%d", arg[i] - 100);
-				switch(arg[i]) {
-				case 0:
-				case 22:
-					if(bold)
-						cmd("bold");
-				case 1:
-					if(!bold)
-						cmd("bold");
-					break;
-				}
-			}
-			break;
-		}
-		break;
-	default:
-		putchar('\033');
-		ungetc(c, fptm);
-	}
-}
-
-void
-scroll(int l) {
-	cmd("seek(%d,%d)", cx, cy + l);
-}
-
-void
-getpty(void) {
-	char *ptsdev;
-
-#if defined(_GNU_SOURCE)
-	ptm = getpt();
-#elif _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600
-	ptm = posix_openpt(O_RDWR);
-#else
-	ptm = open("/dev/ptmx", O_RDWR);
-	if(ptm == -1)
-		if(openpty(&ptm, &pts, NULL, NULL, NULL) == -1)
-			err(EXIT_FAILURE, "cannot open pty");
-#endif
-#if defined(_XOPEN_SOURCE)
-	if(ptm != -1) {
-		if(grantpt(ptm) == -1)
-			err(EXIT_FAILURE, "cannot grant access to pty");
-		if(unlockpt(ptm) == -1)
-			err(EXIT_FAILURE, "cannot unlock pty");
-		ptsdev = ptsname(ptm);
-		if(!ptsdev)
-			err(EXIT_FAILURE, "slave pty name undefined");
-		pts = open(ptsdev, O_RDWR);
-		if(pts == -1)
-			err(EXIT_FAILURE, "cannot open slave pty");
-	}
-	else
-		err(EXIT_FAILURE, "cannot open pty");
-#endif
-}
-
-void
-shell(void) {
-	static char *shell = NULL;
-
-	if(!shell && !(shell = getenv("SHELL")))
-		shell = "/bin/sh";
-	pid = fork();
-	switch(pid) {
-	case -1:
-		err(EXIT_FAILURE, "cannot fork");
-	case 0:
-		setsid();
-		dup2(pts, STDIN_FILENO);
-		dup2(pts, STDOUT_FILENO);
-		dup2(pts, STDERR_FILENO);
-		close(ptm);
-		putenv("TERM=vt102");
-		execvp(shell, NULL);
-		break;
-	default:
-		close(pts);
-		signal(SIGCHLD, sigchld);
-	}
-}
-
-void
-sigchld(int n) {
-	int ret;
-
-	if(waitpid(pid, &ret, 0) == -1)
-		err(EXIT_FAILURE, "waiting for child failed");
-	if(WIFEXITED(ret))
-		exit(WEXITSTATUS(ret));
-	else
-		exit(EXIT_SUCCESS);
-}
-
-char
-unbuffer(void) {
-	char c;
-
-	c = buf.data[buf.s++];
-	buf.s %= LENGTH(buf.data);
-	buf.n--;
-	return c;
-}
-
-int
-main(int argc, char *argv[]) {
-	fd_set rfds;
-
-	if(argc == 2 && !strcmp("-v", argv[1]))
-		errx(EXIT_SUCCESS, "std-"VERSION", © 2008 Matthias-Christian Ott");
-	else if(argc == 1)
-		errx(EXIT_FAILURE, "usage: std [-v]");
-	getpty();
-	shell();
-	FD_ZERO(&rfds);
-	FD_SET(STDIN_FILENO, &rfds);
-	FD_SET(ptm, &rfds);
-	if(!(fptm = fdopen(ptm, "r+")))
-		err(EXIT_FAILURE, "cannot open pty");
-	if(fcntl(ptm, F_SETFL, O_NONBLOCK) == -1)
-		err(EXIT_FAILURE, "cannot set pty to non-blocking mode");
-	if(fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
-		err(EXIT_FAILURE, "cannot set stdin to non-blocking mode");
-	for(;;) {
-		if(select(MAX(ptm, STDIN_FILENO) + 1, &rfds, NULL, NULL, NULL) == -1)
-			err(EXIT_FAILURE, "cannot select");
-		if(FD_ISSET(ptm, &rfds)) {
-			for(;;) {
-				if((c = getc(fptm)) == EOF) {
-					if(feof(fptm)) {
-						FD_CLR(ptm, &rfds);
-						fflush(fptm);
-						break;
-					}
-					if(errno != EAGAIN)
-						err(EXIT_FAILURE, "cannot read from pty");
-					fflush(stdout);
-					break;
-				}
-				switch(c) {
-				case '\033':
-					parseesc();
-					break;
-				default:
-					putchar(c);
-				}
-			}
-			fflush(stdout);
-		}
-		if(FD_ISSET(STDIN_FILENO, &rfds)) {
-			for(;;) {
-				if((c = getchar()) == EOF) {
-					if(feof(stdin)) {
-						FD_CLR(STDIN_FILENO, &rfds);
-						fflush(fptm);
-						break;
-					}
-					if(errno != EAGAIN)
-						err(EXIT_FAILURE, "cannot read from stdin");
-					fflush(fptm);
-					break;
-				}
-				switch(c) {
-				case ':':
-					parsecmd();
-					break;
-				default:
-					putc(c, fptm);
-				}
-			}
-			fflush(fptm);
-		}
-	}
-	return 0;
-}

From fd281ad336166de21c9d8652f465ab40a0f12468 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sun, 10 May 2009 23:32:21 +0200
Subject: [PATCH 0045/1146] Removed unused variable and cleaned some comment.

---
 st.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index d5f004b..f295955 100644
--- a/st.c
+++ b/st.c
@@ -217,7 +217,7 @@ escparse(void) {
 		}
 		break;
 	case '(':
-		/* humf charset stuff */
+		/* XXX: graphic character set */
 		break;
 	}
 }
@@ -230,8 +230,7 @@ tmoveto(int x, int y) {
 
 void
 tcursor(int dir) {
-	int xi = term.c.x, yi = term.c.y;
-	int xf = xi, yf = yi;
+	int xf = term.c.x, yf = term.c.y;
 
 	switch(dir) {
 	case CSup:

From ccafacb3ff22c85516ff46a88275097936dfe442 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 14 May 2009 00:04:34 +0200
Subject: [PATCH 0046/1146] added some error checking in xinit (fixed the
 segfault caused by a missing font)

---
 st.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index f295955..1f58569 100644
--- a/st.c
+++ b/st.c
@@ -703,18 +703,25 @@ xinit(void) {
 
 	xw.dis = XOpenDisplay(NULL);
 	xw.scr = XDefaultScreen(xw.dis);
+    if(!(xw.dis && xw.scr))
+        die("can not open display");
+    
 	/* font */
-	dc.font = XLoadQueryFont(xw.dis, FONT);
+	if(!(dc.font = XLoadQueryFont(xw.dis, FONT)))
+        die("can not find font " FONT);
+
 	xw.cw = dc.font->max_bounds.rbearing - dc.font->min_bounds.lbearing;
 	xw.ch = dc.font->ascent + dc.font->descent + LINESPACE;
+
 	/* colors */
 	for(i = 0; i < LEN(colorname); i++)
 		dc.col[i] = xgetcol(colorname[i]);
+
 	term.c.attr.fg = DefaultFG;
 	term.c.attr.bg = DefaultBG;
 	term.c.attr.mode = ATnone;
 	/* windows */
-	xw.h = term.row * xw.ch;
+    xw.h = term.row * xw.ch;
 	xw.w = term.col * xw.cw;
 	/* XXX: this BORDER is useless after the first resize, handle it in xdraws() */
 	xw.win = XCreateSimpleWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0,
@@ -736,6 +743,7 @@ xinit(void) {
 	XSetWMProperties(xw.dis, xw.win, NULL, NULL, &args[0], 0, &shint, &wmhint, &chint);
 	XStoreName(xw.dis, xw.win, TNAME);
 	XSync(xw.dis, 0);
+    
 }
 
 void
@@ -908,13 +916,13 @@ run(void) {
 int
 main(int argc, char *argv[]) {
 	if(argc == 2 && !strncmp("-v", argv[1], 3))
-		die("st-"VERSION", © 2009 st engineers\n");
+		die("st-"", © 2009 st engineers\n");
 	else if(argc != 1)
 		die("usage: st [-v]\n");
 	setlocale(LC_CTYPE, "");
-	tnew(80, 24);
-	ttynew();
-	xinit();
-	run();
+    tnew(80, 24);
+    ttynew();
+    xinit();
+    run();
 	return 0;
 }

From 86fa756033e9072a4b114a50896baff36b804ce4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 14 May 2009 00:18:05 +0200
Subject: [PATCH 0047/1146] same thing, really fixed this time.

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 1f58569..2318435 100644
--- a/st.c
+++ b/st.c
@@ -703,7 +703,7 @@ xinit(void) {
 
 	xw.dis = XOpenDisplay(NULL);
 	xw.scr = XDefaultScreen(xw.dis);
-    if(!(xw.dis && xw.scr))
+    if(!xw.dis)
         die("can not open display");
     
 	/* font */
@@ -916,7 +916,7 @@ run(void) {
 int
 main(int argc, char *argv[]) {
 	if(argc == 2 && !strncmp("-v", argv[1], 3))
-		die("st-"", © 2009 st engineers\n");
+		die("st-" VERSION ", © 2009 st engineers\n");
 	else if(argc != 1)
 		die("usage: st [-v]\n");
 	setlocale(LC_CTYPE, "");

From abe6f3b0e4a76ff80315cf6e958549e8295737d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 14 May 2009 00:27:37 +0200
Subject: [PATCH 0048/1146] removed the truecolor stuff

---
 st.h | 20 +++++---------------
 1 file changed, 5 insertions(+), 15 deletions(-)

diff --git a/st.h b/st.h
index be39ef4..87db5c2 100644
--- a/st.h
+++ b/st.h
@@ -1,5 +1,4 @@
 /* See LICENSE for licence details. */
-
 #define _XOPEN_SOURCE
 #include 
 #include 
@@ -8,11 +7,11 @@
 #include 
 #include 
 #include 
-#include 
-#include 
-#include 
-#include 
 #include 
+#include 
+#include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -28,7 +27,7 @@
 #define SHELL "/bin/bash"
 #define TAB    8
 
-#define FONT "-*-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*"
+#define FONT "fixed"
 #define BORDER 3
 #define LINESPACE 1 /* additional pixel between each line */
 
@@ -49,7 +48,6 @@ static char* colorname[] = {
 	"white",
 };
 
-
 /* Arbitrary sizes */
 #define ESCSIZ 256
 #define ESCARG 16
@@ -68,14 +66,6 @@ enum { CRset=1 , CRupdate=2 }; /* Character state */
 enum { TMwrap=1 , TMinsert=2 }; /* Terminal mode */
 enum { SCupdate, SCredraw }; /* screen draw mode */
 
-#ifdef TRUECOLOR
-#error Truecolor not implemented yet
-typedef int Color;
-#else
-typedef char Color;
-#endif
-
-
 typedef struct {
 	char c;     /* character code  */
 	char mode;  /* attribute flags */

From 0ecfcc39b07bb7cca6a688a743299e6ef990e122 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 14 May 2009 00:28:10 +0200
Subject: [PATCH 0049/1146] removed truecolor stuff

---
 st.c | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/st.c b/st.c
index 2318435..ef0fd17 100644
--- a/st.c
+++ b/st.c
@@ -364,21 +364,6 @@ void
 tsetattr(int *attr, int l) {
 	int i;
 
-#ifdef TRUECOLOR /* ESC [ ?  ;  ;  ;  m */
-	Color col;
-	if(escseq.priv && escseq.len == 4) { /* True color extension :) */
-		col = (escseq.arg[1]<<16) + (escseq.arg[2]<<8) + escseq.arg[3];
-		switch(escseq.arg[0]) {
-		case 3: /* foreground */
-			term.c.attr.fg = col;
-			break;
-		case 4: /* background */
-			term.c.attr.bg = col;
-			break;
-		}
-	}
-	else
-#endif
 		for(i = 0; i < l; i++) {
 			switch(attr[i]) {
 			case 0:

From 1cf8b77d2798a43c979b71e16fd45d63b808f569 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 14 May 2009 01:03:17 +0200
Subject: [PATCH 0050/1146] handle tabulation (still not perfect)

---
 st.c | 14 ++++++++++++++
 st.h |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/st.c b/st.c
index ef0fd17..79fb161 100644
--- a/st.c
+++ b/st.c
@@ -558,6 +558,17 @@ escreset(void) {
 	memset(&escseq, 0, sizeof(escseq));
 }
 
+void
+tputtab(void) {
+    int space = TAB - term.c.x % TAB;
+    
+    if(term.c.x + space >= term.col)
+        space--;
+    
+    for(; space > 0; space--)
+        tputc(' ');
+}
+
 void
 tputc(char c) {
 	static int inesc = 0;
@@ -574,6 +585,9 @@ tputc(char c) {
 			tsetchar(c);
 			tcursor(CSright);
 			break;
+        case '\t':
+            tputtab();
+            break;
 		case '\b':
 			tcursor(CSleft);
 			break;
diff --git a/st.h b/st.h
index 87db5c2..4652a33 100644
--- a/st.h
+++ b/st.h
@@ -66,6 +66,8 @@ enum { CRset=1 , CRupdate=2 }; /* Character state */
 enum { TMwrap=1 , TMinsert=2 }; /* Terminal mode */
 enum { SCupdate, SCredraw }; /* screen draw mode */
 
+typedef int Color;
+
 typedef struct {
 	char c;     /* character code  */
 	char mode;  /* attribute flags */

From a866108af2c6c008e37a32c61cee931efa5e4f9a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Fri, 15 May 2009 00:39:51 +0200
Subject: [PATCH 0051/1146] tab moves the cursor instead of inserting spaces.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 79fb161..c24bb1d 100644
--- a/st.c
+++ b/st.c
@@ -566,7 +566,7 @@ tputtab(void) {
         space--;
     
     for(; space > 0; space--)
-        tputc(' ');
+        tcursor(CSright);
 }
 
 void

From 059d2ba264f8ee2f6fbdb4d7199b611433ad8a72 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Fri, 15 May 2009 00:40:47 +0200
Subject: [PATCH 0052/1146] updated TODO.

---
 TODO | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/TODO b/TODO
index 70fa785..0dfff9a 100644
--- a/TODO
+++ b/TODO
@@ -1,9 +1,5 @@
-  - write a clean terminfo entry
-  - write global "setup" func
-  - try to split more logic/gfx
-  - optimize drawing
-  - handle copy/paste
-  - fix fork/child exit problem
   - fix resize (shrinking should move last line up)
+  - total rewrite of X code (pixmap, mouse, copy-paste, ...)
+  - write a clean terminfo entry
+  - fix fork/child exit problem
   - handle utf8 
-  - refactor/clean code

From 129bcd7586968ed882e41c0df76c5c0c0c414e6d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Tue, 26 May 2009 02:21:02 +0200
Subject: [PATCH 0053/1146] fixed a memory leak & segfault in tresize.

---
 st.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index c24bb1d..8ddfa8b 100644
--- a/st.c
+++ b/st.c
@@ -573,7 +573,7 @@ void
 tputc(char c) {
 	static int inesc = 0;
 
-	dump(c);
+	//dump(c);
 	/* start of escseq */
 	if(c == '\033')
 		escreset(), inesc = 1;
@@ -636,20 +636,24 @@ tresize(int col, int row) {
 
 	if(col < 1 || row < 1)
 		return;
+    /* alloc */
 	line = calloc(row, sizeof(Line));
 	for(i = 0 ; i < row; i++)
 		line[i] = calloc(col, sizeof(Glyph));
-	for(i = 0 ; i < minrow; i++) {
-		memcpy(line[i], term.line[i], mincol * sizeof(Glyph));
-		free(term.line[i]);
-	}
+    /* copy */
+    for(i = 0 ; i < minrow; i++)
+        memcpy(line[i], term.line[i], mincol * sizeof(Glyph));
+    /* free */
+    for(i = 0; i < term.row; i++)
+        free(term.line[i]);
 	free(term.line);
+
 	LIMIT(term.c.x, 0, col-1);
 	LIMIT(term.c.y, 0, row-1);
 	LIMIT(term.top, 0, row-1);
 	LIMIT(term.bot, 0, row-1);
-	//    if(term.bot == term.row-1)
-	term.bot = row-1;
+
+    term.bot = row-1;
 	term.line = line;
 	term.col = col, term.row = row;
 }
@@ -775,7 +779,10 @@ xcursor(int mode) {
 	static int oldx = 0;
 	static int oldy = 0;
 	Glyph g = {' ', ATnone, DefaultBG, DefaultCS, 0};
-
+    
+    LIMIT(oldx, 0, term.col-1);
+	LIMIT(oldy, 0, term.row-1);
+    
 	if(term.line[term.c.y][term.c.x].state & CRset)
 		g.c = term.line[term.c.y][term.c.x].c;
 	/* remove the old cursor */
@@ -859,7 +866,7 @@ resize(XEvent *e) {
 	col = e->xconfigure.width / xw.cw;
 	row = e->xconfigure.height / xw.ch;
     
-	if(term.col != col && term.row != row) {
+	if(term.col != col || term.row != row) {
 		tresize(col, row);
 		ttyresize(col, row);
 		xw.w = e->xconfigure.width;

From 2f35cef54b5a32b5498aded0a25f78d0d973a152 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 28 May 2009 01:33:01 +0200
Subject: [PATCH 0054/1146] cleaned up (removed space indentation).
 select/event bug fixed.

---
 st.c | 167 +++++++++++++++++++++++++++++++----------------------------
 1 file changed, 88 insertions(+), 79 deletions(-)

diff --git a/st.c b/st.c
index 8ddfa8b..9a8fa35 100644
--- a/st.c
+++ b/st.c
@@ -1,4 +1,4 @@
-/* See LICENSE for licence details.  */
+/* See LICENSE for licence details.	 */
 #include "st.h"
 
 /* Globals */
@@ -27,11 +27,10 @@ execsh(void) {
 }
 
 void
-xbell(void) {   /* visual bell */
+xbell(void) {	/* visual bell */
 	XRectangle r = { 0, 0, xw.w, xw.h };
 	XSetForeground(xw.dis, dc.gc, dc.col[BellCol]);
 	XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1);
-	XFlush(xw.dis);
 	usleep(30000);
 	draw(SCredraw);
 }
@@ -127,7 +126,7 @@ escfinal(char c) {
 		}
 	else if(BETWEEN(c, 0x40, 0x7E))
 		return 1;
-	return 0;     
+	return 0;	  
 }
 
 void
@@ -168,7 +167,7 @@ tscroll(void) {
 		term.line[i] = term.line[i+1];
 	memset(temp, 0, sizeof(Glyph) * term.col);
 	term.line[term.bot] = temp;
-	xscroll();    
+	xscroll();	  
 }
 
 void
@@ -372,13 +371,13 @@ tsetattr(int *attr, int l) {
 				term.c.attr.bg = DefaultBG;
 				break;
 			case 1:
-				term.c.attr.mode |= ATbold;  
+				term.c.attr.mode |= ATbold;	 
 				break;
 			case 4: 
 				term.c.attr.mode |= ATunderline;
 				break;
 			case 7: 
-				term.c.attr.mode |= ATreverse;  
+				term.c.attr.mode |= ATreverse;	
 				break;
 			case 8:
 				term.c.hidden = CShide;
@@ -390,7 +389,7 @@ tsetattr(int *attr, int l) {
 				term.c.attr.mode &= ~ATunderline;
 				break;
 			case 27: 
-				term.c.attr.mode &= ~ATreverse;  
+				term.c.attr.mode &= ~ATreverse;	 
 				break;
 			case 39:
 				term.c.attr.fg = DefaultFG;
@@ -420,7 +419,7 @@ tsetscroll(int t, int b) {
 		b = temp;
 	}
 	term.top = t;
-	term.bot = b;    
+	term.bot = b;	 
 }
 
 
@@ -481,7 +480,7 @@ eschandle(void) {
 				break;
 			case 2: /* all */
 				tclearregion(0, 0, term.col-1, term.row-1);
-				break;                
+				break;				  
 			}
 			break;
 		case 'K': /* Clear line */
@@ -501,6 +500,10 @@ eschandle(void) {
 			DEFAULT(escseq.arg[0], 1);
 			tinsertblankline(escseq.arg[0]);
 			break;
+		case 'l':
+			if(escseq.priv && escseq.arg[0] == 25)
+				term.c.hidden = 1;
+			break;
 		case 'M': /* Delete  lines */
 			DEFAULT(escseq.arg[0], 1);
 			tdeleteline(escseq.arg[0]);
@@ -514,6 +517,8 @@ eschandle(void) {
 			tmoveto(term.c.x, escseq.arg[0]-1);
 			break;
 		case 'h': /* Set terminal mode */
+			if(escseq.priv && escseq.arg[0] == 25)
+				term.c.hidden = 0;
 			break;
 		case 'm': /* Terminal attribute (color) */
 			tsetattr(escseq.arg, escseq.narg);
@@ -542,15 +547,15 @@ void
 escdump(void) { 
 	int i;
 	puts("------");
-	printf("rawbuf  : %s\n", escseq.buf);
+	printf("rawbuf	: %s\n", escseq.buf);
 	printf("prechar : %c\n", escseq.pre);
 	printf("private : %c\n", escseq.priv ? '?' : ' ');
-	printf("narg    : %d\n", escseq.narg);
+	printf("narg	: %d\n", escseq.narg);
 	if(escseq.narg) {
 		for(i = 0; i < escseq.narg; i++)
 			printf("\targ %d = %d\n", i, escseq.arg[i]);
 	}
-	printf("mode    : %c\n", escseq.mode);
+	printf("mode	: %c\n", escseq.mode);
 }
 
 void
@@ -560,20 +565,21 @@ escreset(void) {
 
 void
 tputtab(void) {
-    int space = TAB - term.c.x % TAB;
-    
-    if(term.c.x + space >= term.col)
-        space--;
-    
-    for(; space > 0; space--)
-        tcursor(CSright);
+	int space = TAB - term.c.x % TAB;
+	
+	if(term.c.x + space >= term.col)
+		space--;
+	
+	for(; space > 0; space--)
+		tcursor(CSright);
 }
 
 void
 tputc(char c) {
 	static int inesc = 0;
-
-	//dump(c);
+#if 0
+	dump(c);
+#endif	
 	/* start of escseq */
 	if(c == '\033')
 		escreset(), inesc = 1;
@@ -585,9 +591,9 @@ tputc(char c) {
 			tsetchar(c);
 			tcursor(CSright);
 			break;
-        case '\t':
-            tputtab();
-            break;
+		case '\t':
+			tputtab();
+			break;
 		case '\b':
 			tcursor(CSleft);
 			break;
@@ -636,24 +642,24 @@ tresize(int col, int row) {
 
 	if(col < 1 || row < 1)
 		return;
-    /* alloc */
+	/* alloc */
 	line = calloc(row, sizeof(Line));
 	for(i = 0 ; i < row; i++)
 		line[i] = calloc(col, sizeof(Glyph));
-    /* copy */
-    for(i = 0 ; i < minrow; i++)
-        memcpy(line[i], term.line[i], mincol * sizeof(Glyph));
-    /* free */
-    for(i = 0; i < term.row; i++)
-        free(term.line[i]);
+	/* copy */
+	for(i = 0 ; i < minrow; i++)
+		memcpy(line[i], term.line[i], mincol * sizeof(Glyph));
+	/* free */
+	for(i = 0; i < term.row; i++)
+		free(term.line[i]);
 	free(term.line);
-
+	
 	LIMIT(term.c.x, 0, col-1);
 	LIMIT(term.c.y, 0, row-1);
 	LIMIT(term.top, 0, row-1);
 	LIMIT(term.bot, 0, row-1);
-
-    term.bot = row-1;
+	
+	term.bot = row-1;
 	term.line = line;
 	term.col = col, term.row = row;
 }
@@ -706,12 +712,12 @@ xinit(void) {
 
 	xw.dis = XOpenDisplay(NULL);
 	xw.scr = XDefaultScreen(xw.dis);
-    if(!xw.dis)
-        die("can not open display");
-    
+	if(!xw.dis)
+		die("can not open display");
+	
 	/* font */
 	if(!(dc.font = XLoadQueryFont(xw.dis, FONT)))
-        die("can not find font " FONT);
+		die("can not find font " FONT);
 
 	xw.cw = dc.font->max_bounds.rbearing - dc.font->min_bounds.lbearing;
 	xw.ch = dc.font->ascent + dc.font->descent + LINESPACE;
@@ -724,7 +730,7 @@ xinit(void) {
 	term.c.attr.bg = DefaultBG;
 	term.c.attr.mode = ATnone;
 	/* windows */
-    xw.h = term.row * xw.ch;
+	xw.h = term.row * xw.ch;
 	xw.w = term.col * xw.cw;
 	/* XXX: this BORDER is useless after the first resize, handle it in xdraws() */
 	xw.win = XCreateSimpleWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0,
@@ -746,7 +752,6 @@ xinit(void) {
 	XSetWMProperties(xw.dis, xw.win, NULL, NULL, &args[0], 0, &shint, &wmhint, &chint);
 	XStoreName(xw.dis, xw.win, TNAME);
 	XSync(xw.dis, 0);
-    
 }
 
 void
@@ -765,7 +770,7 @@ xdrawc(int x, int y, Glyph g) {
 	/* string */
 	XSetForeground(xw.dis, dc.gc, xfg);
 	XDrawString(xw.dis, xw.win, dc.gc, r.x, r.y+dc.font->ascent, &(g.c), 1);
-	if(g.mode & ATbold)  /* XXX: bold hack (draw again at x+1) */
+	if(g.mode & ATbold)	 /* XXX: bold hack (draw again at x+1) */
 		XDrawString(xw.dis, xw.win, dc.gc, r.x+1, r.y+dc.font->ascent, &(g.c), 1);
 	/* underline */
 	if(g.mode & ATunderline) {
@@ -779,10 +784,10 @@ xcursor(int mode) {
 	static int oldx = 0;
 	static int oldy = 0;
 	Glyph g = {' ', ATnone, DefaultBG, DefaultCS, 0};
-    
-    LIMIT(oldx, 0, term.col-1);
+	
+	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
-    
+	
 	if(term.line[term.c.y][term.c.x].state & CRset)
 		g.c = term.line[term.c.y][term.c.x].c;
 	/* remove the old cursor */
@@ -825,7 +830,7 @@ kpress(XKeyEvent *e) {
 	int meta;
 	int shift;
 
-	meta  = e->state & Mod4Mask;
+	meta  = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
 	len = XLookupString(e, buf, sizeof(buf), &ksym, NULL);
 	if(len > 0) {
@@ -836,11 +841,9 @@ kpress(XKeyEvent *e) {
 		return;
 	}
 	switch(ksym) {
-#ifdef DEBUG1
 	default:
-		printf("errkey: %d\n", (int)ksym);
+		fprintf(stderr, "errkey: %d\n", (int)ksym);
 		break;
-#endif
 	case XK_Up:
 	case XK_Down:
 	case XK_Left:
@@ -849,13 +852,14 @@ kpress(XKeyEvent *e) {
 		ttywrite(buf, 3);
 		break;
 	case XK_Delete: ttywrite(KEYDELETE, sizeof(KEYDELETE)-1); break;
-	case XK_Home:   ttywrite(  KEYHOME, sizeof(  KEYHOME)-1); break;
-	case XK_End:    ttywrite(   KEYEND, sizeof(   KEYEND)-1); break;
-	case XK_Prior:	ttywrite(  KEYPREV, sizeof(  KEYPREV)-1); break;
-	case XK_Next:	ttywrite(  KEYNEXT, sizeof(  KEYNEXT)-1); break;
+	case XK_Home:  ttywrite(KEYHOME, sizeof(KEYHOME)-1); break;
+	case XK_End:   ttywrite(KEYEND,  sizeof(KEYEND) -1); break;
+	case XK_Prior: ttywrite(KEYPREV, sizeof(KEYPREV)-1); break;
+	case XK_Next:  ttywrite(KEYNEXT, sizeof(KEYNEXT)-1); break;
 	case XK_Insert:
 		/* XXX: paste X clipboard */
-		if(shift);
+		if(shift)
+			;
 		break;
 	}
 }
@@ -865,7 +869,7 @@ resize(XEvent *e) {
 	int col, row;
 	col = e->xconfigure.width / xw.cw;
 	row = e->xconfigure.height / xw.ch;
-    
+	
 	if(term.col != col || term.row != row) {
 		tresize(col, row);
 		ttyresize(col, row);
@@ -881,37 +885,42 @@ run(void) {
 	int ret;
 	XEvent ev;
 	fd_set rfd;
-	struct timeval tv = {0, 10000};
+	int xfd = XConnectionNumber(xw.dis);
 
 	running = 1;
 	XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNotifyMask);
 	XResizeWindow(xw.dis, xw.win, xw.w , xw.h); /* seems to fix the resize bug in wmii */
+	
 	while(running) {
-		while(XPending(xw.dis)) {
-			XNextEvent(xw.dis, &ev);
-			switch (ev.type) {
-			default:
-				break;
-			case KeyPress:
-				kpress(&ev.xkey);
-				break;
-			case Expose:
-				draw(SCredraw);
-				break;
-			case ConfigureNotify:
-				resize(&ev);
-				break;
-			}
-		}
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
-		ret = select(cmdfd+1, &rfd, NULL, NULL, &tv);
+		FD_SET(xfd, &rfd);
+		XFlush(xw.dis);
+		ret = select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL);
+
 		if(ret < 0) {
 			fprintf(stderr, "select: %m\n");
 			running = 0;
 		}
-		if(!ret)
-			continue;
+		
+		if(FD_ISSET(xfd, &rfd)) {
+			while(XPending(xw.dis)) {
+				XNextEvent(xw.dis, &ev);
+				switch (ev.type) {
+				default:
+					break;
+				case KeyPress:
+					kpress(&ev.xkey);
+					break;
+				case Expose:
+					draw(SCredraw);
+					break;
+				case ConfigureNotify:
+					resize(&ev);
+					break;
+				}
+			}
+		}
 		if(FD_ISSET(cmdfd, &rfd)) {
 			ttyread();
 			draw(SCupdate);
@@ -926,9 +935,9 @@ main(int argc, char *argv[]) {
 	else if(argc != 1)
 		die("usage: st [-v]\n");
 	setlocale(LC_CTYPE, "");
-    tnew(80, 24);
-    ttynew();
-    xinit();
-    run();
+	tnew(80, 24);
+	ttynew();
+	xinit();
+	run();
 	return 0;
 }

From ad39f000be87ec16e74c05bdc3fa81ef307b5477 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 11 Jun 2009 16:41:14 +0200
Subject: [PATCH 0055/1146] added sigchld handler, cleaned error checking.

---
 st.c | 60 +++++++++++++++++++++++++++++++++++-------------------------
 st.h |  7 ++++++-
 2 files changed, 41 insertions(+), 26 deletions(-)

diff --git a/st.c b/st.c
index 9a8fa35..64a37e1 100644
--- a/st.c
+++ b/st.c
@@ -1,4 +1,4 @@
-/* See LICENSE for licence details.	 */
+/* See LICENSE for licence details. */
 #include "st.h"
 
 /* Globals */
@@ -7,6 +7,7 @@ XWindow xw;
 Term term;
 Escseq escseq;
 int cmdfd;
+pid_t pid;
 int running;
 
 void
@@ -27,34 +28,45 @@ execsh(void) {
 }
 
 void
-xbell(void) {	/* visual bell */
+xbell(void) { /* visual bell */
 	XRectangle r = { 0, 0, xw.w, xw.h };
 	XSetForeground(xw.dis, dc.gc, dc.col[BellCol]);
 	XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1);
-	usleep(30000);
+	/* usleep(30000); */
 	draw(SCredraw);
 }
 
+void 
+sigchld(int a) {
+	int stat = 0;
+	if(waitpid(pid, &stat, 0) < 0)
+		die("Waiting for pid %hd failed: %s\n",	pid, SERRNO);
+	if(WIFEXITED(stat))
+		exit(WEXITSTATUS(stat));
+	else
+		exit(EXIT_FAILURE);
+}
+
+
 void
 ttynew(void) {
 	int m, s;
-	pid_t pid;
 	char *pts;
 
 	if((m = posix_openpt(O_RDWR | O_NOCTTY)) < 0)
-		die("openpt");
-	if(grantpt(m) == -1)
-		die("grandpt");
-	if(unlockpt(m) == -1)
-		die("unlockpt");
-	if((pts = ptsname(m)) == NULL)
-		die("ptsname");
+		die("openpt failed: %s\n", SERRNO);
+	if(grantpt(m) < 0)
+		die("grandpt failed: %s\n", SERRNO);
+	if(unlockpt(m) < 0)
+		die("unlockpt failed: %s\n", SERRNO);
+	if(!(pts = ptsname(m)))
+		die("ptsname failed: %s\n", SERRNO);
 	if((s = open(pts, O_RDWR | O_NOCTTY)) < 0)
-		die("slave open");
+		die("Couldn't open slave: %s\n", SERRNO);
 	fcntl(s, F_SETFL, O_NDELAY);
 	switch(pid = fork()) {
 	case -1:
-		die("fork");
+		die("fork failed\n");
 		break;
 	case 0:
 		setsid(); /* create a new process group */
@@ -62,12 +74,13 @@ ttynew(void) {
 		dup2(s, STDOUT_FILENO);
 		dup2(s, STDERR_FILENO);
 		if(ioctl(s, TIOCSCTTY, NULL) < 0)
-			die("slave TTIOCSTTY");
+			die("ioctl TTIOCSTTY failed: %s\n", SERRNO);
 		execsh();
 		break;
 	default:
 		close(s);
 		cmdfd = m;
+		signal(SIGCHLD, sigchld);
 	}
 }
 
@@ -85,9 +98,8 @@ ttyread(void) {
 	int ret;
 
 	switch(ret = read(cmdfd, buf, BUFSIZ)) {
-	case -1: /* error or exit */
-		/* XXX: be more precise */
-		running = 0;
+	case -1: 
+		die("Couldn't read from shell: %s\n", SERRNO);
 		break;
 	default:
 		tputs(buf, ret);
@@ -97,7 +109,7 @@ ttyread(void) {
 void
 ttywrite(char *s, size_t n) {
 	if(write(cmdfd, s, n) == -1)
-		die("write error on tty.");
+		die("write error on tty: %s\n", SERRNO);
 }
 
 void
@@ -108,7 +120,7 @@ ttyresize(int x, int y) {
 	w.ws_col = term.col;
 	w.ws_xpixel = w.ws_ypixel = 0;
 	if(ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
-		fprintf(stderr, "Couldn't set window size: %m\n");
+		fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
 }
 
 int
@@ -889,7 +901,7 @@ run(void) {
 
 	running = 1;
 	XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNotifyMask);
-	XResizeWindow(xw.dis, xw.win, xw.w , xw.h); /* seems to fix the resize bug in wmii */
+	XResizeWindow(xw.dis, xw.win, xw.w , xw.h); /* fix resize bug in wmii (?) */
 	
 	while(running) {
 		FD_ZERO(&rfd);
@@ -898,11 +910,9 @@ run(void) {
 		XFlush(xw.dis);
 		ret = select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL);
 
-		if(ret < 0) {
-			fprintf(stderr, "select: %m\n");
-			running = 0;
-		}
-		
+		if(ret < 0)
+			die("select failed: %s\n", SERRNO);
+				
 		if(FD_ISSET(xfd, &rfd)) {
 			while(XPending(xw.dis)) {
 				XNextEvent(xw.dis, &ev);
diff --git a/st.h b/st.h
index 4652a33..0bd2c4e 100644
--- a/st.h
+++ b/st.h
@@ -1,16 +1,19 @@
 /* See LICENSE for licence details. */
 #define _XOPEN_SOURCE
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -52,6 +55,7 @@ static char* colorname[] = {
 #define ESCSIZ 256
 #define ESCARG 16
 
+#define SERRNO strerror(errno)
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
 #define MAX(a, b)  ((a) < (b) ? (b) : (a))
 #define LEN(a)     (sizeof(a) / sizeof(a[0]))
@@ -63,7 +67,7 @@ static char* colorname[] = {
 enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 }; /* Attribute */
 enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload }; /* Cursor */
 enum { CRset=1 , CRupdate=2 }; /* Character state */
-enum { TMwrap=1 , TMinsert=2 }; /* Terminal mode */
+enum { TMwrap=1 , TMinsert=2, TMaltcharset }; /* Terminal mode */
 enum { SCupdate, SCredraw }; /* screen draw mode */
 
 typedef int Color;
@@ -130,6 +134,7 @@ typedef struct {
 void die(const char *errstr, ...);
 void draw(int);
 void execsh(void);
+void sigchld(int);
 void kpress(XKeyEvent *);
 void resize(XEvent *);
 void run(void);

From 5d8aa08ba5a13b20166f21540370b01e239819b1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 11 Jun 2009 17:03:25 +0200
Subject: [PATCH 0056/1146] updated TODO.

---
 TODO | 2 --
 1 file changed, 2 deletions(-)

diff --git a/TODO b/TODO
index 0dfff9a..de7743f 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,3 @@
-  - fix resize (shrinking should move last line up)
   - total rewrite of X code (pixmap, mouse, copy-paste, ...)
   - write a clean terminfo entry
-  - fix fork/child exit problem
   - handle utf8 

From 8b4bfe31ec1075316dbb2e7d21753771ae3e5590 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Tue, 16 Jun 2009 02:23:46 +0200
Subject: [PATCH 0057/1146] made kpress() more flexible, removed st.h, added
 config.h.

---
 st.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 181 insertions(+), 29 deletions(-)

diff --git a/st.c b/st.c
index 64a37e1..a203c72 100644
--- a/st.c
+++ b/st.c
@@ -1,5 +1,160 @@
 /* See LICENSE for licence details. */
-#include "st.h"
+/* See LICENSE for licence details. */
+#define _XOPEN_SOURCE
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define TNAME "st"
+
+/* Arbitrary sizes */
+#define ESCSIZ 256
+#define ESCARG 16
+
+#define SERRNO strerror(errno)
+#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 DEFAULT(a, b)     (a) = (a) ? (a) : (b)    
+#define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (b))
+#define LIMIT(x, a, b)    (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
+
+/* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
+enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 };
+enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload };
+enum { CRset=1 , CRupdate=2 };
+enum { TMwrap=1 , TMinsert=2, TMaltcharset };
+enum { SCupdate, SCredraw };
+
+typedef int Color;
+
+typedef struct {
+	KeySym k;
+	char s[ESCSIZ];
+} Key;
+
+typedef struct {
+	char c;     /* character code  */
+	char mode;  /* attribute flags */
+	Color fg;   /* foreground      */
+	Color bg;   /* background      */
+	char state; /* state flag      */
+} Glyph;
+
+typedef Glyph* Line;
+
+typedef struct {
+	Glyph attr;  /* current char attributes */
+	char hidden;
+	int x;
+	int y;
+} TCursor;
+
+/* Escape sequence structs */
+/* ESC 
 [[ []  [;]] ] */
+typedef struct {
+	char buf[ESCSIZ+1]; /* raw string */
+	int len;            /* raw string length */
+	char pre;           
+	char priv;
+	int arg[ESCARG+1];
+	int narg;           /* nb of args */
+	char mode;
+} Escseq;
+
+/* Internal representation of the screen */
+typedef struct {
+	int row;    /* nb row */  
+	int col;    /* nb col */
+	Line* line; /* screen */
+	TCursor c;  /* cursor */
+	int top;    /* top    scroll limit */
+	int bot;    /* bottom scroll limit */
+	int mode;   /* terminal mode */
+} Term;
+
+/* Purely graphic info */
+typedef struct {
+	Display* dis;
+	Window win;
+	int scr;
+	int w;  /* window width  */
+	int h;  /* window height */
+	int ch; /* char height */
+	int cw; /* char width  */
+} XWindow; 
+
+#include "config.h"
+
+/* Drawing Context */
+typedef struct {
+	unsigned long col[LEN(colorname)];
+	XFontStruct* font;
+	GC gc;
+} DC;
+
+void die(const char *errstr, ...);
+void draw(int);
+void execsh(void);
+void sigchld(int);
+char* kmap(KeySym);
+void kpress(XKeyEvent *);
+void resize(XEvent *);
+void run(void);
+
+int escaddc(char);
+int escfinal(char);
+void escdump(void);
+void eschandle(void);
+void escparse(void);
+void escreset(void);
+
+void tclearregion(int, int, int, int);
+void tcpos(int);
+void tcursor(int);
+void tdeletechar(int);
+void tdeleteline(int);
+void tdump(void);
+void tinsertblank(int);
+void tinsertblankline(int);
+void tmoveto(int, int);
+void tnew(int, int);
+void tnewline(void);
+void tputc(char);
+void tputs(char*, int);
+void tresize(int, int);
+void tscroll(void);
+void tsetattr(int*, int);
+void tsetchar(char);
+void tsetscroll(int, int);
+
+void ttynew(void);
+void ttyread(void);
+void ttyresize(int, int);
+void ttywrite(char *, size_t);
+
+unsigned long xgetcol(const char *);
+void xclear(int, int, int, int);
+void xcursor(int);
+void xdrawc(int, int, Glyph);
+void xinit(void);
+void xscroll(void);
+
 
 /* Globals */
 DC dc;
@@ -725,11 +880,11 @@ xinit(void) {
 	xw.dis = XOpenDisplay(NULL);
 	xw.scr = XDefaultScreen(xw.dis);
 	if(!xw.dis)
-		die("can not open display");
+		die("Can't open display\n");
 	
 	/* font */
 	if(!(dc.font = XLoadQueryFont(xw.dis, FONT)))
-		die("can not find font " FONT);
+		die("Can't load font %s\n", FONT);
 
 	xw.cw = dc.font->max_bounds.rbearing - dc.font->min_bounds.lbearing;
 	xw.ch = dc.font->ascent + dc.font->descent + LINESPACE;
@@ -834,6 +989,15 @@ draw(int redraw_all) {
 	xcursor(CSdraw);
 }
 
+char*
+kmap(KeySym k) {
+	int i;
+	for(i = 0; i < LEN(key); i++)
+		if(key[i].k == k)
+			return (char*)key[i].s;
+	return NULL;
+}
+
 void
 kpress(XKeyEvent *e) {
 	KeySym ksym;
@@ -841,39 +1005,28 @@ kpress(XKeyEvent *e) {
 	int len;
 	int meta;
 	int shift;
+	char* skmap;
 
 	meta  = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
 	len = XLookupString(e, buf, sizeof(buf), &ksym, NULL);
-	if(len > 0) {
+	if(skmap = kmap(ksym))
+		ttywrite(skmap, strlen(skmap));
+	else if(len > 0) {
 		buf[sizeof(buf)-1] = '\0';
 		if(meta && len == 1)
 			ttywrite("\033", 1);
 		ttywrite(buf, len);
-		return;
-	}
-	switch(ksym) {
-	default:
-		fprintf(stderr, "errkey: %d\n", (int)ksym);
-		break;
-	case XK_Up:
-	case XK_Down:
-	case XK_Left:
-	case XK_Right:
-		sprintf(buf, "\033[%c", "DACB"[ksym - XK_Left]);
-		ttywrite(buf, 3);
-		break;
-	case XK_Delete: ttywrite(KEYDELETE, sizeof(KEYDELETE)-1); break;
-	case XK_Home:  ttywrite(KEYHOME, sizeof(KEYHOME)-1); break;
-	case XK_End:   ttywrite(KEYEND,  sizeof(KEYEND) -1); break;
-	case XK_Prior: ttywrite(KEYPREV, sizeof(KEYPREV)-1); break;
-	case XK_Next:  ttywrite(KEYNEXT, sizeof(KEYNEXT)-1); break;
-	case XK_Insert:
-		/* XXX: paste X clipboard */
-		if(shift)
-			;
-		break;
-	}
+	} else
+		switch(ksym) {
+		case XK_Insert:
+			if(shift)
+				/* XXX: paste X clipboard */;
+			break;
+		default:
+			fprintf(stderr, "errkey: %d\n", (int)ksym);
+			break;
+		}
 }
 
 void
@@ -891,7 +1044,6 @@ resize(XEvent *e) {
 	}
 }
 
-
 void
 run(void) {
 	int ret;

From 2e37752961f439c33614a9d8469d7c297f0465cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Tue, 16 Jun 2009 02:33:38 +0200
Subject: [PATCH 0058/1146] added/removed files, updated Makefile.

---
 Makefile |   2 +-
 config.h |  39 ++++++++++++
 st.h     | 178 -------------------------------------------------------
 3 files changed, 40 insertions(+), 179 deletions(-)
 create mode 100644 config.h
 delete mode 100644 st.h

diff --git a/Makefile b/Makefile
index b0bd42d..9ec8d21 100644
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@ options:
 	@echo CC $<
 	@${CC} -c ${CFLAGS} $<
 
-${OBJ}: config.mk
+${OBJ}: config.h config.mk
 
 st: ${OBJ}
 	@echo CC -o $@
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..c01354d
--- /dev/null
+++ b/config.h
@@ -0,0 +1,39 @@
+#define SHELL "/bin/bash"
+#define TAB    8
+
+#define FONT "fixed"
+#define BORDER 3
+#define LINESPACE 1 /* additional pixel between each line */
+
+/* Terminal colors */
+static char* colorname[] = {
+	"black",
+	"red",
+	"green",
+	"yellow",
+	"blue",
+	"magenta",
+	"cyan",
+	"white",
+};
+
+/* Default colors (colorname index) */
+/* foreground, background, cursor, visual bell */
+#define DefaultFG 7
+#define DefaultBG 0
+#define DefaultCS 1
+#define BellCol   DefaultFG
+
+
+/* special keys */
+static Key key[] = {
+	{ XK_Delete, "\033[3~" },
+	{ XK_Home,   "\033[1~" },
+	{ XK_End,    "\033[4~" },
+	{ XK_Prior,  "\033[5~" },
+	{ XK_Next,   "\033[6~" },
+	{ XK_Left,   "\033[D" },
+	{ XK_Right,  "\033[C" },
+	{ XK_Up,     "\033[A" },
+	{ XK_Down,   "\033[B" },
+};
diff --git a/st.h b/st.h
deleted file mode 100644
index 0bd2c4e..0000000
--- a/st.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/* See LICENSE for licence details. */
-#define _XOPEN_SOURCE
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-/* special keys */
-#define KEYDELETE "\033[3~"
-#define KEYHOME   "\033[1~"
-#define KEYEND    "\033[4~"
-#define KEYPREV   "\033[5~"
-#define KEYNEXT   "\033[6~"
-
-#define TNAME "st"
-#define SHELL "/bin/bash"
-#define TAB    8
-
-#define FONT "fixed"
-#define BORDER 3
-#define LINESPACE 1 /* additional pixel between each line */
-
-/* Default colors */
-#define DefaultFG 7
-#define DefaultBG 0
-#define DefaultCS 1
-#define BellCol   DefaultFG /* visual bell color */
-
-static char* colorname[] = {
-	"black",
-	"red",
-	"green",
-	"yellow",
-	"blue",
-	"magenta",
-	"cyan",
-	"white",
-};
-
-/* Arbitrary sizes */
-#define ESCSIZ 256
-#define ESCARG 16
-
-#define SERRNO strerror(errno)
-#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 DEFAULT(a, b)     (a) = (a) ? (a) : (b)    
-#define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (b))
-#define LIMIT(x, a, b)    (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
-
-
-enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 }; /* Attribute */
-enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload }; /* Cursor */
-enum { CRset=1 , CRupdate=2 }; /* Character state */
-enum { TMwrap=1 , TMinsert=2, TMaltcharset }; /* Terminal mode */
-enum { SCupdate, SCredraw }; /* screen draw mode */
-
-typedef int Color;
-
-typedef struct {
-	char c;     /* character code  */
-	char mode;  /* attribute flags */
-	Color fg;   /* foreground      */
-	Color bg;   /* background      */
-	char state; /* state flag      */
-} Glyph;
-
-typedef Glyph* Line;
-
-typedef struct {
-	Glyph attr;  /* current char attributes */
-	char hidden;
-	int x;
-	int y;
-} TCursor;
-
-/* Escape sequence structs */
-typedef struct {
-	char buf[ESCSIZ+1]; /* raw string */
-	int len;            /* raw string length */
-	/* ESC 
 [[ []  [;]] ] */
-	char pre;           
-	char priv;
-	int arg[ESCARG+1];
-	int narg;           /* nb of args */
-	char mode;
-} Escseq;
-
-/* Internal representation of the screen */
-typedef struct {
-	int row;    /* nb row */  
-	int col;    /* nb col */
-	Line* line; /* screen */
-	TCursor c;  /* cursor */
-	int top;    /* top    scroll limit */
-	int bot;    /* bottom scroll limit */
-	int mode;   /* terminal mode */
-} Term;
-
-/* Purely graphic info */
-typedef struct {
-	Display* dis;
-	Window win;
-	int scr;
-	int w;  /* window width  */
-	int h;  /* window height */
-	int ch; /* char height */
-	int cw; /* char width  */
-} XWindow; 
-
-/* Drawing Context */
-typedef struct {
-	unsigned long col[LEN(colorname)];
-	XFontStruct* font;
-	GC gc;
-} DC;
-
-
-void die(const char *errstr, ...);
-void draw(int);
-void execsh(void);
-void sigchld(int);
-void kpress(XKeyEvent *);
-void resize(XEvent *);
-void run(void);
-
-int escaddc(char);
-int escfinal(char);
-void escdump(void);
-void eschandle(void);
-void escparse(void);
-void escreset(void);
-
-void tclearregion(int, int, int, int);
-void tcpos(int);
-void tcursor(int);
-void tdeletechar(int);
-void tdeleteline(int);
-void tdump(void);
-void tinsertblank(int);
-void tinsertblankline(int);
-void tmoveto(int, int);
-void tnew(int, int);
-void tnewline(void);
-void tputc(char);
-void tputs(char*, int);
-void tresize(int, int);
-void tscroll(void);
-void tsetattr(int*, int);
-void tsetchar(char);
-void tsetscroll(int, int);
-
-void ttynew(void);
-void ttyread(void);
-void ttyresize(int, int);
-void ttywrite(char *, size_t);
-
-unsigned long xgetcol(const char *);
-void xclear(int, int, int, int);
-void xcursor(int);
-void xdrawc(int, int, Glyph);
-void xinit(void);
-void xscroll(void);

From 53937e045aba6cdefd9e8e81556b306976691747 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Tue, 16 Jun 2009 02:41:45 +0200
Subject: [PATCH 0059/1146] clean up.

---
 st.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index a203c72..264fc84 100644
--- a/st.c
+++ b/st.c
@@ -1,5 +1,4 @@
 /* See LICENSE for licence details. */
-/* See LICENSE for licence details. */
 #define _XOPEN_SOURCE
 #include 
 #include 
@@ -37,8 +36,8 @@
 /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
 enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 };
 enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload };
-enum { CRset=1 , CRupdate=2 };
-enum { TMwrap=1 , TMinsert=2, TMaltcharset };
+enum { CRset=1, CRupdate=2 };
+enum { TMwrap=1, TMinsert=2, TMaltcharset };
 enum { SCupdate, SCredraw };
 
 typedef int Color;

From d5f4554431f82424af40600ed6835672ab8e44ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Tue, 16 Jun 2009 12:34:10 +0200
Subject: [PATCH 0060/1146] dump escseq if not handled.

---
 st.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 264fc84..3940bbd 100644
--- a/st.c
+++ b/st.c
@@ -591,10 +591,16 @@ tsetscroll(int t, int b) {
 
 void
 eschandle(void) { 
-	/* escdump(); */
 	switch(escseq.pre) {
+	default:
+		goto unknown_seq;
 	case '[':
 		switch(escseq.mode) {
+		default:
+		unknown_seq:
+			fprintf(stderr, "erresc: unknown sequence\n");
+			escdump();
+			break;
 		case '@': /* Insert  blank char */
 			DEFAULT(escseq.arg[0], 1);
 			tinsertblank(escseq.arg[0]);
@@ -712,15 +718,13 @@ eschandle(void) {
 void
 escdump(void) { 
 	int i;
-	puts("------");
 	printf("rawbuf	: %s\n", escseq.buf);
 	printf("prechar : %c\n", escseq.pre);
 	printf("private : %c\n", escseq.priv ? '?' : ' ');
 	printf("narg	: %d\n", escseq.narg);
-	if(escseq.narg) {
+	if(escseq.narg)
 		for(i = 0; i < escseq.narg; i++)
 			printf("\targ %d = %d\n", i, escseq.arg[i]);
-	}
 	printf("mode	: %c\n", escseq.mode);
 }
 

From b8ffa1d7e9cffda8bd8cc7f4ccf612201a617b34 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 17 Jun 2009 02:58:40 +0200
Subject: [PATCH 0061/1146] fixed the scrolling bug and cleaned some stuff.

---
 st.c | 129 +++++++++++++++++++++++++++++++----------------------------
 1 file changed, 68 insertions(+), 61 deletions(-)

diff --git a/st.c b/st.c
index 3940bbd..661f4fb 100644
--- a/st.c
+++ b/st.c
@@ -37,7 +37,7 @@
 enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 };
 enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload };
 enum { CRset=1, CRupdate=2 };
-enum { TMwrap=1, TMinsert=2, TMaltcharset };
+enum { TMwrap=1, TMinsert=2 };
 enum { SCupdate, SCredraw };
 
 typedef int Color;
@@ -154,6 +154,7 @@ void xdrawc(int, int, Glyph);
 void xinit(void);
 void xscroll(void);
 
+void cursor(int);
 
 /* Globals */
 DC dc;
@@ -201,7 +202,6 @@ sigchld(int a) {
 		exit(EXIT_FAILURE);
 }
 
-
 void
 ttynew(void) {
 	int m, s;
@@ -328,21 +328,19 @@ void
 tscroll(void) {
 	Line temp = term.line[term.top];
 	int i;
-
+	/* X stuff _before_ the line swapping (results in wrong line index) */
+	xscroll();
 	for(i = term.top; i < term.bot; i++)
 		term.line[i] = term.line[i+1];
 	memset(temp, 0, sizeof(Glyph) * term.col);
 	term.line[term.bot] = temp;
-	xscroll();	  
 }
 
 void
 tnewline(void) {
 	int y = term.c.y + 1;
-
-	if(y > term.bot) {
+	if(y > term.bot)
 		tscroll(), y = term.bot;
-	}
 	tmoveto(0, y);
 }
 
@@ -476,6 +474,13 @@ tinsertblank(int n) {
 	tclearregion(src, term.c.y, dst, term.c.y);
 }
 
+void
+tsetlinestate(int n, int state) {
+	int i;
+	for(i = 0; i < term.col; i++)
+		term.line[n][i].state |= state;
+}
+
 void
 tinsertblankline (int n) {
 	int i;
@@ -497,10 +502,11 @@ tinsertblankline (int n) {
 		term.line[i-n] = blank;
 		/* blank it */
 		memset(blank, 0, term.col * sizeof(Glyph));
+		tsetlinestate(i, CRupdate);
+		tsetlinestate(i-n, CRupdate);
 	}
 }
 
-
 void
 tdeleteline(int n) {
 	int i;
@@ -522,6 +528,8 @@ tdeleteline(int n) {
 		term.line[i+n] = blank;
 		/* blank it */
 		memset(blank, 0, term.col * sizeof(Glyph));
+		tsetlinestate(i, CRupdate);
+		tsetlinestate(i-n, CRupdate);
 	}
 }
 
@@ -529,48 +537,48 @@ void
 tsetattr(int *attr, int l) {
 	int i;
 
-		for(i = 0; i < l; i++) {
-			switch(attr[i]) {
-			case 0:
-				memset(&term.c.attr, 0, sizeof(term.c.attr));
-				term.c.attr.fg = DefaultFG;
-				term.c.attr.bg = DefaultBG;
-				break;
-			case 1:
-				term.c.attr.mode |= ATbold;	 
-				break;
-			case 4: 
-				term.c.attr.mode |= ATunderline;
-				break;
-			case 7: 
-				term.c.attr.mode |= ATreverse;	
-				break;
-			case 8:
-				term.c.hidden = CShide;
-				break;
-			case 22: 
-				term.c.attr.mode &= ~ATbold;  
-				break;
-			case 24: 
-				term.c.attr.mode &= ~ATunderline;
-				break;
-			case 27: 
-				term.c.attr.mode &= ~ATreverse;	 
-				break;
-			case 39:
-				term.c.attr.fg = DefaultFG;
-				break;
-			case 49:
-				term.c.attr.fg = 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;
-				break;
-			}
+	for(i = 0; i < l; i++) {
+		switch(attr[i]) {
+		case 0:
+			memset(&term.c.attr, 0, sizeof(term.c.attr));
+			term.c.attr.fg = DefaultFG;
+			term.c.attr.bg = DefaultBG;
+			break;
+		case 1:
+			term.c.attr.mode |= ATbold;	 
+			break;
+		case 4: 
+			term.c.attr.mode |= ATunderline;
+			break;
+		case 7: 
+			term.c.attr.mode |= ATreverse;	
+			break;
+		case 8:
+			term.c.hidden = CShide;
+			break;
+		case 22: 
+			term.c.attr.mode &= ~ATbold;  
+			break;
+		case 24: 
+			term.c.attr.mode &= ~ATunderline;
+			break;
+		case 27: 
+			term.c.attr.mode &= ~ATreverse;	 
+			break;
+		case 39:
+			term.c.attr.fg = DefaultFG;
+			break;
+		case 49:
+			term.c.attr.fg = 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;
+			break;
 		}
+	}
 }
 
 void
@@ -588,9 +596,8 @@ tsetscroll(int t, int b) {
 	term.bot = b;	 
 }
 
-
 void
-eschandle(void) { 
+eschandle(void) {
 	switch(escseq.pre) {
 	default:
 		goto unknown_seq;
@@ -846,7 +853,6 @@ xgetcol(const char *s) {
 	return color.pixel;
 }
 
-
 void
 xclear(int x1, int y1, int x2, int y2) {
 	XClearArea(xw.dis, xw.win, 
@@ -855,7 +861,6 @@ xclear(int x1, int y1, int x2, int y2) {
 			False);
 }
 
-
 void
 xscroll(void) {
 	int srcy = (term.top+1) * xw.ch;
@@ -867,9 +872,6 @@ xscroll(void) {
 	xclear(0, term.bot, term.col-1, term.bot);
 }
 
-
-
-
 void
 xinit(void) {
 	XGCValues values;
@@ -963,14 +965,15 @@ xcursor(int mode) {
 	/* remove the old cursor */
 	if(term.line[oldy][oldx].state & CRset)
 		xdrawc(oldx, oldy, term.line[oldy][oldx]);
-	else xclear(oldx, oldy, oldx, oldy); /* XXX: maybe a bug */
-	if(mode == CSdraw && !term.c.hidden) {
+	else 
+		xclear(oldx, oldy, oldx, oldy);
+	/* draw the new one */
+	if(mode == CSdraw) {
 		xdrawc(term.c.x, term.c.y, g);
 		oldx = term.c.x, oldy = term.c.y;
 	}
 }
 
-
 void
 draw(int redraw_all) {
 	int x, y;
@@ -978,14 +981,18 @@ draw(int redraw_all) {
 
 	if(redraw_all)
 		XClearWindow(xw.dis, xw.win);
+
 	/* XXX: drawing could be optimised */
 	for(y = 0; y < term.row; y++) {
 		for(x = 0; x < term.col; x++) {
 			changed = term.line[y][x].state & CRupdate;
 			set = term.line[y][x].state & CRset;
-			if((changed && set) || (redraw_all && set)) {
+			if(redraw_all || changed) {
 				term.line[y][x].state &= ~CRupdate;
-				xdrawc(x, y, term.line[y][x]);
+				if(set)
+					xdrawc(x, y, term.line[y][x]);
+				else
+					xclear(x, y, x, y);
 			}
 		}
 	}

From 44d8c319a9fe51b011ba6a44779659aec45023a7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 17 Jun 2009 20:44:36 +0200
Subject: [PATCH 0062/1146] removed old unused cursor() proto.

---
 st.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/st.c b/st.c
index 661f4fb..a7f957b 100644
--- a/st.c
+++ b/st.c
@@ -154,8 +154,6 @@ void xdrawc(int, int, Glyph);
 void xinit(void);
 void xscroll(void);
 
-void cursor(int);
-
 /* Globals */
 DC dc;
 XWindow xw;

From 4d794b3479cc586de7796d9b060b2eb469a6500d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sun, 21 Jun 2009 19:37:12 +0200
Subject: [PATCH 0063/1146] updated "key" to a lookup table.

---
 config.h | 21 ++++++++++-----------
 st.c     | 20 +++-----------------
 2 files changed, 13 insertions(+), 28 deletions(-)

diff --git a/config.h b/config.h
index c01354d..b66985f 100644
--- a/config.h
+++ b/config.h
@@ -24,16 +24,15 @@ static char* colorname[] = {
 #define DefaultCS 1
 #define BellCol   DefaultFG
 
-
 /* special keys */
-static Key key[] = {
-	{ XK_Delete, "\033[3~" },
-	{ XK_Home,   "\033[1~" },
-	{ XK_End,    "\033[4~" },
-	{ XK_Prior,  "\033[5~" },
-	{ XK_Next,   "\033[6~" },
-	{ XK_Left,   "\033[D" },
-	{ XK_Right,  "\033[C" },
-	{ XK_Up,     "\033[A" },
-	{ XK_Down,   "\033[B" },
+static char* key[] = {
+	[XK_Delete] = "\033[3~",
+	[XK_Home]   = "\033[1~",
+	[XK_End]    = "\033[4~",
+	[XK_Prior]  = "\033[5~",
+	[XK_Next]   = "\033[6~",
+	[XK_Left]   = "\033[D",
+	[XK_Right]  = "\033[C",
+	[XK_Up]     = "\033[A",
+	[XK_Down]   = "\033[B",
 };
diff --git a/st.c b/st.c
index a7f957b..833805f 100644
--- a/st.c
+++ b/st.c
@@ -40,12 +40,9 @@ enum { CRset=1, CRupdate=2 };
 enum { TMwrap=1, TMinsert=2 };
 enum { SCupdate, SCredraw };
 
-typedef int Color;
+#include "config.h"
 
-typedef struct {
-	KeySym k;
-	char s[ESCSIZ];
-} Key;
+typedef int Color;
 
 typedef struct {
 	char c;     /* character code  */
@@ -98,8 +95,6 @@ typedef struct {
 	int cw; /* char width  */
 } XWindow; 
 
-#include "config.h"
-
 /* Drawing Context */
 typedef struct {
 	unsigned long col[LEN(colorname)];
@@ -997,15 +992,6 @@ draw(int redraw_all) {
 	xcursor(CSdraw);
 }
 
-char*
-kmap(KeySym k) {
-	int i;
-	for(i = 0; i < LEN(key); i++)
-		if(key[i].k == k)
-			return (char*)key[i].s;
-	return NULL;
-}
-
 void
 kpress(XKeyEvent *e) {
 	KeySym ksym;
@@ -1018,7 +1004,7 @@ kpress(XKeyEvent *e) {
 	meta  = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
 	len = XLookupString(e, buf, sizeof(buf), &ksym, NULL);
-	if(skmap = kmap(ksym))
+	if(skmap = key[ksym])
 		ttywrite(skmap, strlen(skmap));
 	else if(len > 0) {
 		buf[sizeof(buf)-1] = '\0';

From 0a5e5102096d65a3ba8e39ea9b9b0eb89fe30e04 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sun, 21 Jun 2009 19:52:06 +0200
Subject: [PATCH 0064/1146] reverted back to the old Key struct.

---
 config.h | 21 +++++++++++----------
 st.c     | 20 +++++++++++++++++---
 2 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/config.h b/config.h
index b66985f..c01354d 100644
--- a/config.h
+++ b/config.h
@@ -24,15 +24,16 @@ static char* colorname[] = {
 #define DefaultCS 1
 #define BellCol   DefaultFG
 
+
 /* special keys */
-static char* key[] = {
-	[XK_Delete] = "\033[3~",
-	[XK_Home]   = "\033[1~",
-	[XK_End]    = "\033[4~",
-	[XK_Prior]  = "\033[5~",
-	[XK_Next]   = "\033[6~",
-	[XK_Left]   = "\033[D",
-	[XK_Right]  = "\033[C",
-	[XK_Up]     = "\033[A",
-	[XK_Down]   = "\033[B",
+static Key key[] = {
+	{ XK_Delete, "\033[3~" },
+	{ XK_Home,   "\033[1~" },
+	{ XK_End,    "\033[4~" },
+	{ XK_Prior,  "\033[5~" },
+	{ XK_Next,   "\033[6~" },
+	{ XK_Left,   "\033[D" },
+	{ XK_Right,  "\033[C" },
+	{ XK_Up,     "\033[A" },
+	{ XK_Down,   "\033[B" },
 };
diff --git a/st.c b/st.c
index 833805f..a7f957b 100644
--- a/st.c
+++ b/st.c
@@ -40,10 +40,13 @@ enum { CRset=1, CRupdate=2 };
 enum { TMwrap=1, TMinsert=2 };
 enum { SCupdate, SCredraw };
 
-#include "config.h"
-
 typedef int Color;
 
+typedef struct {
+	KeySym k;
+	char s[ESCSIZ];
+} Key;
+
 typedef struct {
 	char c;     /* character code  */
 	char mode;  /* attribute flags */
@@ -95,6 +98,8 @@ typedef struct {
 	int cw; /* char width  */
 } XWindow; 
 
+#include "config.h"
+
 /* Drawing Context */
 typedef struct {
 	unsigned long col[LEN(colorname)];
@@ -992,6 +997,15 @@ draw(int redraw_all) {
 	xcursor(CSdraw);
 }
 
+char*
+kmap(KeySym k) {
+	int i;
+	for(i = 0; i < LEN(key); i++)
+		if(key[i].k == k)
+			return (char*)key[i].s;
+	return NULL;
+}
+
 void
 kpress(XKeyEvent *e) {
 	KeySym ksym;
@@ -1004,7 +1018,7 @@ kpress(XKeyEvent *e) {
 	meta  = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
 	len = XLookupString(e, buf, sizeof(buf), &ksym, NULL);
-	if(skmap = key[ksym])
+	if(skmap = kmap(ksym))
 		ttywrite(skmap, strlen(skmap));
 	else if(len > 0) {
 		buf[sizeof(buf)-1] = '\0';

From cf65699a29683bff9d50187c18b160e21a538f48 Mon Sep 17 00:00:00 2001
From: Anselm R Garbe 
Date: Fri, 10 Jul 2009 16:23:11 +0100
Subject: [PATCH 0065/1146] we definately need pixmaps for the drawing,
 currently drawing into the window is painfully slow! much more slower than
 drawing into a pixmap and mapping that when finished -- several optimisations

---
 config.h |  22 ++++----
 st.c     | 160 +++++++++++++++++++++++++------------------------------
 2 files changed, 85 insertions(+), 97 deletions(-)

diff --git a/config.h b/config.h
index c01354d..5d91627 100644
--- a/config.h
+++ b/config.h
@@ -6,7 +6,7 @@
 #define LINESPACE 1 /* additional pixel between each line */
 
 /* Terminal colors */
-static char* colorname[] = {
+static const char *colorname[] = {
 	"black",
 	"red",
 	"green",
@@ -26,14 +26,14 @@ static char* colorname[] = {
 
 
 /* special keys */
-static Key key[] = {
-	{ XK_Delete, "\033[3~" },
-	{ XK_Home,   "\033[1~" },
-	{ XK_End,    "\033[4~" },
-	{ XK_Prior,  "\033[5~" },
-	{ XK_Next,   "\033[6~" },
-	{ XK_Left,   "\033[D" },
-	{ XK_Right,  "\033[C" },
-	{ XK_Up,     "\033[A" },
-	{ XK_Down,   "\033[B" },
+static const char *key[] = {
+	[XK_Delete] = "\033[3~", 
+	[XK_Home]   = "\033[1~",
+	[XK_End]    = "\033[4~",
+	[XK_Prior]  = "\033[5~",
+	[XK_Next]   = "\033[6~",
+	[XK_Left]   = "\033[D",
+	[XK_Right]  = "\033[C",
+	[XK_Up]     = "\033[A",
+	[XK_Down]   = "\033[B",
 };
diff --git a/st.c b/st.c
index a7f957b..559dcda 100644
--- a/st.c
+++ b/st.c
@@ -1,5 +1,5 @@
 /* See LICENSE for licence details. */
-#define _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600
 #include 
 #include 
 #include 
@@ -107,61 +107,68 @@ typedef struct {
 	GC gc;
 } DC;
 
-void die(const char *errstr, ...);
-void draw(int);
-void execsh(void);
-void sigchld(int);
-char* kmap(KeySym);
-void kpress(XKeyEvent *);
-void resize(XEvent *);
-void run(void);
+static void die(const char *errstr, ...);
+static void draw(int);
+static void execsh(void);
+static void sigchld(int);
+static void run(void);
 
-int escaddc(char);
-int escfinal(char);
-void escdump(void);
-void eschandle(void);
-void escparse(void);
-void escreset(void);
+static int escaddc(char);
+static int escfinal(char);
+static void escdump(void);
+static void eschandle(void);
+static void escparse(void);
+static void escreset(void);
 
-void tclearregion(int, int, int, int);
-void tcpos(int);
-void tcursor(int);
-void tdeletechar(int);
-void tdeleteline(int);
-void tdump(void);
-void tinsertblank(int);
-void tinsertblankline(int);
-void tmoveto(int, int);
-void tnew(int, int);
-void tnewline(void);
-void tputc(char);
-void tputs(char*, int);
-void tresize(int, int);
-void tscroll(void);
-void tsetattr(int*, int);
-void tsetchar(char);
-void tsetscroll(int, int);
+static void tclearregion(int, int, int, int);
+static void tcpos(int);
+static void tcursor(int);
+static void tdeletechar(int);
+static void tdeleteline(int);
+static void tdump(void);
+static void tinsertblank(int);
+static void tinsertblankline(int);
+static void tmoveto(int, int);
+static void tnew(int, int);
+static void tnewline(void);
+static void tputc(char);
+static void tputs(char*, int);
+static void tresize(int, int);
+static void tscroll(void);
+static void tsetattr(int*, int);
+static void tsetchar(char);
+static void tsetscroll(int, int);
 
-void ttynew(void);
-void ttyread(void);
-void ttyresize(int, int);
-void ttywrite(char *, size_t);
+static void ttynew(void);
+static void ttyread(void);
+static void ttyresize(int, int);
+static void ttywrite(const char *, size_t);
 
-unsigned long xgetcol(const char *);
-void xclear(int, int, int, int);
-void xcursor(int);
-void xdrawc(int, int, Glyph);
-void xinit(void);
-void xscroll(void);
+static unsigned long xgetcol(const char *);
+static void xclear(int, int, int, int);
+static void xcursor(int);
+static void xdrawc(int, int, Glyph);
+static void xinit(void);
+static void xscroll(void);
+
+static void expose(XEvent *);
+static void kpress(XEvent *);
+static void resize(XEvent *);
+
+static void (*handler[LASTEvent])(XEvent *) = {
+	[KeyPress] = kpress,
+	[Expose] = expose,
+	[ConfigureNotify] = resize
+};
 
 /* Globals */
-DC dc;
-XWindow xw;
-Term term;
-Escseq escseq;
-int cmdfd;
-pid_t pid;
-int running;
+static DC dc;
+static XWindow xw;
+static Term term;
+static Escseq escseq;
+static int cmdfd;
+static pid_t pid;
+static int running;
 
 void
 die(const char *errstr, ...) {
@@ -259,7 +266,7 @@ ttyread(void) {
 }
 
 void
-ttywrite(char *s, size_t n) {
+ttywrite(const char *s, size_t n) {
 	if(write(cmdfd, s, n) == -1)
 		die("write error on tty: %s\n", SERRNO);
 }
@@ -997,29 +1004,25 @@ draw(int redraw_all) {
 	xcursor(CSdraw);
 }
 
-char*
-kmap(KeySym k) {
-	int i;
-	for(i = 0; i < LEN(key); i++)
-		if(key[i].k == k)
-			return (char*)key[i].s;
-	return NULL;
+void
+expose(XEvent *ev) {
+	draw(SCredraw);
 }
 
 void
-kpress(XKeyEvent *e) {
+kpress(XEvent *ev) {
+	XKeyEvent *e = &ev->xkey;
 	KeySym ksym;
 	char buf[32];
 	int len;
 	int meta;
 	int shift;
-	char* skmap;
 
 	meta  = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
 	len = XLookupString(e, buf, sizeof(buf), &ksym, NULL);
-	if(skmap = kmap(ksym))
-		ttywrite(skmap, strlen(skmap));
+	if(key[ksym])
+		ttywrite(key[ksym], strlen(key[ksym]));
 	else if(len > 0) {
 		buf[sizeof(buf)-1] = '\0';
 		if(meta && len == 1)
@@ -1054,7 +1057,6 @@ resize(XEvent *e) {
 
 void
 run(void) {
-	int ret;
 	XEvent ev;
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dis);
@@ -1062,39 +1064,25 @@ run(void) {
 	running = 1;
 	XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNotifyMask);
 	XResizeWindow(xw.dis, xw.win, xw.w , xw.h); /* fix resize bug in wmii (?) */
-	
+
 	while(running) {
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);
-		XFlush(xw.dis);
-		ret = select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL);
-
-		if(ret < 0)
+		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL) == -1) {
+			if(errno == EINTR)
+				continue;
 			die("select failed: %s\n", SERRNO);
-				
-		if(FD_ISSET(xfd, &rfd)) {
-			while(XPending(xw.dis)) {
-				XNextEvent(xw.dis, &ev);
-				switch (ev.type) {
-				default:
-					break;
-				case KeyPress:
-					kpress(&ev.xkey);
-					break;
-				case Expose:
-					draw(SCredraw);
-					break;
-				case ConfigureNotify:
-					resize(&ev);
-					break;
-				}
-			}
 		}
 		if(FD_ISSET(cmdfd, &rfd)) {
 			ttyread();
 			draw(SCupdate);
 		}
+		while(XPending(xw.dis)) {
+			XNextEvent(xw.dis, &ev);
+			if(handler[ev.type])
+				(handler[ev.type])(&ev);
+		}
 	}
 }
 

From dab8326e6428a5db6b7a6e08f40fa1e5ac77bc6f Mon Sep 17 00:00:00 2001
From: Anselm R Garbe 
Date: Fri, 10 Jul 2009 16:27:14 +0100
Subject: [PATCH 0066/1146] only compile tdump if DEBUG flag is set

---
 st.c | 44 ++++++++++++++++++++------------------------
 1 file changed, 20 insertions(+), 24 deletions(-)

diff --git a/st.c b/st.c
index 559dcda..5f40ddd 100644
--- a/st.c
+++ b/st.c
@@ -42,11 +42,6 @@ enum { SCupdate, SCredraw };
 
 typedef int Color;
 
-typedef struct {
-	KeySym k;
-	char s[ESCSIZ];
-} Key;
-
 typedef struct {
 	char c;     /* character code  */
 	char mode;  /* attribute flags */
@@ -125,7 +120,6 @@ static void tcpos(int);
 static void tcursor(int);
 static void tdeletechar(int);
 static void tdeleteline(int);
-static void tdump(void);
 static void tinsertblank(int);
 static void tinsertblankline(int);
 static void tmoveto(int, int);
@@ -170,6 +164,26 @@ static int cmdfd;
 static pid_t pid;
 static int running;
 
+#ifdef DEBUG
+void
+tdump(void) {
+	int row, col;
+	Glyph c;
+
+	for(row = 0; row < term.row; row++) {
+		for(col = 0; col < term.col; col++) {
+			if(col == term.c.x && row == term.c.y)
+				putchar('#');
+			else {
+				c = term.line[row][col];
+				putchar(c.state & CRset ? c.c : '.');
+			}
+		}
+		putchar('\n');
+	}
+}
+#endif
+
 void
 die(const char *errstr, ...) {
 	va_list ap;
@@ -797,24 +811,6 @@ tputs(char *s, int len) {
 		tputc(*s++);
 }
 
-void
-tdump(void) {
-	int row, col;
-	Glyph c;
-
-	for(row = 0; row < term.row; row++) {
-		for(col = 0; col < term.col; col++) {
-			if(col == term.c.x && row == term.c.y)
-				putchar('#');
-			else {
-				c = term.line[row][col];
-				putchar(c.state & CRset ? c.c : '.');
-			}
-		}
-		putchar('\n');
-	}
-}
-
 void
 tresize(int col, int row) {
 	int i;

From 4e6915a16b75c1e79142e15a9b23e761140d4e9b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Mon, 7 Sep 2009 21:19:29 +0200
Subject: [PATCH 0067/1146] Fixed possible segfault by reverting to the key
 struct (again).

---
 config.h | 21 ++++++++++-----------
 st.c     | 21 +++++++++++++++++++--
 2 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/config.h b/config.h
index 5d91627..67c854e 100644
--- a/config.h
+++ b/config.h
@@ -24,16 +24,15 @@ static const char *colorname[] = {
 #define DefaultCS 1
 #define BellCol   DefaultFG
 
-
 /* special keys */
-static const char *key[] = {
-	[XK_Delete] = "\033[3~", 
-	[XK_Home]   = "\033[1~",
-	[XK_End]    = "\033[4~",
-	[XK_Prior]  = "\033[5~",
-	[XK_Next]   = "\033[6~",
-	[XK_Left]   = "\033[D",
-	[XK_Right]  = "\033[C",
-	[XK_Up]     = "\033[A",
-	[XK_Down]   = "\033[B",
+static Key key[] = {
+	{ XK_Delete, "\033[3~" },
+	{ XK_Home,   "\033[1~" },
+	{ XK_End,    "\033[4~" },
+	{ XK_Prior,  "\033[5~" },
+	{ XK_Next,   "\033[6~" },
+	{ XK_Left,   "\033[D" },
+	{ XK_Right,  "\033[C" },
+	{ XK_Up,     "\033[A" },
+	{ XK_Down,   "\033[B" },
 };
diff --git a/st.c b/st.c
index 5f40ddd..62b877f 100644
--- a/st.c
+++ b/st.c
@@ -93,6 +93,11 @@ typedef struct {
 	int cw; /* char width  */
 } XWindow; 
 
+typedef struct {
+	KeySym k;
+	char s[ESCSIZ];
+} Key;
+
 #include "config.h"
 
 /* Drawing Context */
@@ -146,6 +151,7 @@ static void xinit(void);
 static void xscroll(void);
 
 static void expose(XEvent *);
+static char * kmap(KeySym);
 static void kpress(XEvent *);
 static void resize(XEvent *);
 
@@ -1005,11 +1011,21 @@ expose(XEvent *ev) {
 	draw(SCredraw);
 }
 
+char *
+kmap(KeySym k) {
+	int i;
+	for(i = 0; i < LEN(key); i++)
+		if(key[i].k == k)
+			return (char*)key[i].s;
+	return NULL;
+}
+
 void
 kpress(XEvent *ev) {
 	XKeyEvent *e = &ev->xkey;
 	KeySym ksym;
 	char buf[32];
+	char *customkey;
 	int len;
 	int meta;
 	int shift;
@@ -1017,8 +1033,9 @@ kpress(XEvent *ev) {
 	meta  = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
 	len = XLookupString(e, buf, sizeof(buf), &ksym, NULL);
-	if(key[ksym])
-		ttywrite(key[ksym], strlen(key[ksym]));
+
+	if(customkey = kmap(ksym))
+		ttywrite(customkey, strlen(customkey));
 	else if(len > 0) {
 		buf[sizeof(buf)-1] = '\0';
 		if(meta && len == 1)

From f2dff29a16ef0eb1a0b680cdd753471ba406e4f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 28 Oct 2009 14:34:22 +0100
Subject: [PATCH 0068/1146] drawing is faster but the bold attr is not
 supported anymore.

---
 config.h |  2 +-
 st.c     | 64 +++++++++++++++++++++++++++++++++-----------------------
 2 files changed, 39 insertions(+), 27 deletions(-)

diff --git a/config.h b/config.h
index 67c854e..7da5848 100644
--- a/config.h
+++ b/config.h
@@ -3,7 +3,7 @@
 
 #define FONT "fixed"
 #define BORDER 3
-#define LINESPACE 1 /* additional pixel between each line */
+#define LINESPACE 0 /* additional pixel between each line */
 
 /* Terminal colors */
 static const char *colorname[] = {
diff --git a/st.c b/st.c
index 62b877f..17a0709 100644
--- a/st.c
+++ b/st.c
@@ -3,6 +3,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -24,6 +25,7 @@
 /* Arbitrary sizes */
 #define ESCSIZ 256
 #define ESCARG 16
+#define MAXDRAWBUF 1024
 
 #define SERRNO strerror(errno)
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
@@ -32,6 +34,7 @@
 #define DEFAULT(a, b)     (a) = (a) ? (a) : (b)    
 #define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (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)
 
 /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
 enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 };
@@ -933,6 +936,23 @@ xinit(void) {
 	XSync(xw.dis, 0);
 }
 
+void
+xdraws (char *s, Glyph base, int x, int y, int len) {
+	unsigned long xfg, xbg;
+	int winx = x*xw.cw, winy = y*xw.ch + dc.font->ascent, width = len*xw.cw;
+	if(base.mode & ATreverse)
+		xfg = dc.col[base.bg], xbg = dc.col[base.fg];
+	else
+		xfg = dc.col[base.fg], xbg = dc.col[base.bg];
+
+	XSetBackground(xw.dis, dc.gc, xbg);
+	XSetForeground(xw.dis, dc.gc, xfg);
+	XDrawImageString(xw.dis, xw.win, dc.gc, winx, winy, s, len);
+	
+	if(base.mode & ATunderline)
+		XDrawLine(xw.dis, xw.win, dc.gc, winx, winy+1, winx+width-1, winy+1);
+}
+
 void
 xdrawc(int x, int y, Glyph g) {
 	XRectangle r = { x * xw.cw, y * xw.ch, xw.cw, xw.ch };
@@ -944,18 +964,9 @@ xdrawc(int x, int y, Glyph g) {
 	else
 		xfg = dc.col[g.fg], xbg = dc.col[g.bg];
 	/* background */
-	XSetForeground(xw.dis, dc.gc, xbg);
-	XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1);
-	/* string */
+	XSetBackground(xw.dis, dc.gc, xbg);
 	XSetForeground(xw.dis, dc.gc, xfg);
-	XDrawString(xw.dis, xw.win, dc.gc, r.x, r.y+dc.font->ascent, &(g.c), 1);
-	if(g.mode & ATbold)	 /* XXX: bold hack (draw again at x+1) */
-		XDrawString(xw.dis, xw.win, dc.gc, r.x+1, r.y+dc.font->ascent, &(g.c), 1);
-	/* underline */
-	if(g.mode & ATunderline) {
-		r.y += dc.font->ascent + 1;
-		XDrawLine(xw.dis, xw.win, dc.gc, r.x, r.y, r.x+r.width-1, r.y);
-	}
+	XDrawImageString(xw.dis, xw.win, dc.gc, r.x, r.y+dc.font->ascent, &g.c, 1);
 }
 
 void
@@ -983,25 +994,26 @@ xcursor(int mode) {
 
 void
 draw(int redraw_all) {
-	int x, y;
-	int changed, set;
-
-	if(redraw_all)
-		XClearWindow(xw.dis, xw.win);
-
-	/* XXX: drawing could be optimised */
+	int i, x, y, ox;
+	Glyph base, new;
+	char buf[MAXDRAWBUF];
+	
 	for(y = 0; y < term.row; y++) {
+		base = term.line[y][0];
+		i = ox = 0;
 		for(x = 0; x < term.col; x++) {
-			changed = term.line[y][x].state & CRupdate;
-			set = term.line[y][x].state & CRset;
-			if(redraw_all || changed) {
-				term.line[y][x].state &= ~CRupdate;
-				if(set)
-					xdrawc(x, y, term.line[y][x]);
-				else
-					xclear(x, y, x, y);
+			new = term.line[y][x];
+			if(!ATTRCMP(base, new) && i < MAXDRAWBUF)
+				buf[i++] = new.c;
+			else {
+				xdraws(buf, base, ox, y, i);
+				buf[0] = new.c;
+				i = 1;
+				ox = x;
+				base = new;
 			}
 		}
+		xdraws(buf, base, ox, y, i);
 	}
 	xcursor(CSdraw);
 }

From 0981437524b64579cc656f60b0108abdcdf8a0cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 3 Feb 2010 03:25:35 +0100
Subject: [PATCH 0069/1146] TERM set to xterm by default (which broke a lot of
 stuff), better escape handling (title), and a little clean up.

---
 st.c | 393 +++++++++++++++++++++++++++++------------------------------
 1 file changed, 192 insertions(+), 201 deletions(-)

diff --git a/st.c b/st.c
index 17a0709..a84f0e0 100644
--- a/st.c
+++ b/st.c
@@ -20,11 +20,12 @@
 #include 
 #include 
 
-#define TNAME "st"
+#define TNAME "xterm"
 
 /* Arbitrary sizes */
+#define TITLESIZ 256
 #define ESCSIZ 256
-#define ESCARG 16
+#define ESCARGSIZ 16
 #define MAXDRAWBUF 1024
 
 #define SERRNO strerror(errno)
@@ -40,7 +41,8 @@
 enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 };
 enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload };
 enum { CRset=1, CRupdate=2 };
-enum { TMwrap=1, TMinsert=2 };
+enum { TMwrap=1, TMinsert=2, TMtitle=4 };
+enum { ESCin = 1, ESCcsi = 2, ESCosc = 4, ESCtitle = 8 };
 enum { SCupdate, SCredraw };
 
 typedef int Color;
@@ -62,17 +64,16 @@ typedef struct {
 	int y;
 } TCursor;
 
-/* Escape sequence structs */
-/* ESC 
 [[ []  [;]] ] */
+/* CSI Escape sequence structs */
+/* ESC '[' [[ []  [;]] ] */
 typedef struct {
-	char buf[ESCSIZ+1]; /* raw string */
+	char buf[ESCSIZ]; /* raw string */
 	int len;            /* raw string length */
-	char pre;           
 	char priv;
-	int arg[ESCARG+1];
+	int arg[ESCARGSIZ];
 	int narg;           /* nb of args */
 	char mode;
-} Escseq;
+} CSIEscape;
 
 /* Internal representation of the screen */
 typedef struct {
@@ -83,6 +84,9 @@ typedef struct {
 	int top;    /* top    scroll limit */
 	int bot;    /* bottom scroll limit */
 	int mode;   /* terminal mode */
+	int esc;
+	char title[TITLESIZ];
+	int titlelen;
 } Term;
 
 /* Purely graphic info */
@@ -116,12 +120,10 @@ static void execsh(void);
 static void sigchld(int);
 static void run(void);
 
-static int escaddc(char);
-static int escfinal(char);
-static void escdump(void);
-static void eschandle(void);
-static void escparse(void);
-static void escreset(void);
+static void csidump(void);
+static void csihandle(void);
+static void csiparse(void);
+static void csireset(void);
 
 static void tclearregion(int, int, int, int);
 static void tcpos(int);
@@ -168,7 +170,7 @@ static void (*handler[LASTEvent])(XEvent *) = {
 static DC dc;
 static XWindow xw;
 static Term term;
-static Escseq escseq;
+static CSIEscape escseq;
 static int cmdfd;
 static pid_t pid;
 static int running;
@@ -269,7 +271,7 @@ ttynew(void) {
 void
 dump(char c) {
 	static int col;
-	fprintf(stderr, " %02x %c ", c, isprint(c)?c:'.');
+	fprintf(stderr, " %02x '%c' ", c, isprint(c)?c:'.');
 	if(++col % 10 == 0)
 		fprintf(stderr, "\n");
 }
@@ -305,24 +307,6 @@ ttyresize(int x, int y) {
 		fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
 }
 
-int
-escfinal(char c) {
-	if(escseq.len == 1)
-		switch(c) {
-		case '[':
-		case ']':
-		case '(':
-			return 0;
-		case '=':
-		case '>':
-		default:
-			return 1;
-		}
-	else if(BETWEEN(c, 0x40, 0x7E))
-		return 1;
-	return 0;	  
-}
-
 void
 tcpos(int mode) {
 	static int x = 0;
@@ -372,44 +356,27 @@ tnewline(void) {
 	tmoveto(0, y);
 }
 
-int
-escaddc(char c) {
-	escseq.buf[escseq.len++] = c;
-	if(escfinal(c) || escseq.len >= ESCSIZ) {
-		escparse(), eschandle();
-		return 0;
-	}
-	return 1;
-}
-
 void
-escparse(void) {
+csiparse(void) {
 	/* int noarg = 1; */
 	char *p = escseq.buf;
 
 	escseq.narg = 0;
-	switch(escseq.pre = *p++) {
-	case '[': /* CSI */
-		if(*p == '?')
-			escseq.priv = 1, p++;
-
-		while(p < escseq.buf+escseq.len) {
-			while(isdigit(*p)) {
-				escseq.arg[escseq.narg] *= 10;
-				escseq.arg[escseq.narg] += *(p++) - '0'/*, noarg = 0 */;
-			}
-			if(*p == ';')
-				escseq.narg++, p++;
-			else {
-				escseq.mode = *p;
-				escseq.narg++;
-				return;
-			}
+	if(*p == '?')
+		escseq.priv = 1, p++;
+	
+	while(p < escseq.buf+escseq.len) {
+		while(isdigit(*p)) {
+			escseq.arg[escseq.narg] *= 10;
+			escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */;
+		}
+		if(*p == ';' && escseq.narg+1 < ESCARGSIZ)
+			escseq.narg++, p++;
+		else {
+			escseq.mode = *p;
+			escseq.narg++;
+			return;
 		}
-		break;
-	case '(':
-		/* XXX: graphic character set */
-		break;
 	}
 }
 
@@ -625,146 +592,141 @@ tsetscroll(int t, int b) {
 }
 
 void
-eschandle(void) {
-	switch(escseq.pre) {
+csihandle(void) {
+	switch(escseq.mode) {
 	default:
-		goto unknown_seq;
-	case '[':
-		switch(escseq.mode) {
-		default:
-		unknown_seq:
-			fprintf(stderr, "erresc: unknown sequence\n");
-			escdump();
+		fprintf(stderr, "erresc: unknown sequence\n");
+		csidump();
+		/* die(""); */
+		break;
+	case '@': /* Insert  blank char */
+		DEFAULT(escseq.arg[0], 1);
+		tinsertblank(escseq.arg[0]);
+		break;
+	case 'A': /* Cursor  Up */
+	case 'e':
+		DEFAULT(escseq.arg[0], 1);
+		tmoveto(term.c.x, term.c.y-escseq.arg[0]);
+		break;
+	case 'B': /* Cursor  Down */
+		DEFAULT(escseq.arg[0], 1);
+		tmoveto(term.c.x, term.c.y+escseq.arg[0]);
+		break;
+	case 'C': /* Cursor  Forward */
+	case 'a':
+		DEFAULT(escseq.arg[0], 1);
+		tmoveto(term.c.x+escseq.arg[0], term.c.y);
+		break;
+	case 'D': /* Cursor  Backward */
+		DEFAULT(escseq.arg[0], 1);
+		tmoveto(term.c.x-escseq.arg[0], term.c.y);
+		break;
+	case 'E': /* Cursor  Down and first col */
+		DEFAULT(escseq.arg[0], 1);
+		tmoveto(0, term.c.y+escseq.arg[0]);
+		break;
+	case 'F': /* Cursor  Up and first col */
+		DEFAULT(escseq.arg[0], 1);
+		tmoveto(0, term.c.y-escseq.arg[0]);
+		break;
+	case 'G': /* Move to  */
+	case '`':
+		DEFAULT(escseq.arg[0], 1);
+     	tmoveto(escseq.arg[0]-1, term.c.y);
+		break;
+	case 'H': /* Move to   */
+	case 'f':
+		DEFAULT(escseq.arg[0], 1);
+		DEFAULT(escseq.arg[1], 1);
+		tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
+		break;
+	case 'J': /* Clear screen */
+		switch(escseq.arg[0]) {
+		case 0: /* below */
+			tclearregion(term.c.x, term.c.y, term.col-1, term.row-1);
 			break;
-		case '@': /* Insert  blank char */
-			DEFAULT(escseq.arg[0], 1);
-			tinsertblank(escseq.arg[0]);
+		case 1: /* above */
+			tclearregion(0, 0, term.c.x, term.c.y);
 			break;
-		case 'A': /* Cursor  Up */
-		case 'e':
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(term.c.x, term.c.y-escseq.arg[0]);
+		case 2: /* all */
+			tclearregion(0, 0, term.col-1, term.row-1);
+			break;				  
+		}
+		break;
+	case 'K': /* Clear line */
+		switch(escseq.arg[0]) {
+		case 0: /* right */
+			tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
 			break;
-		case 'B': /* Cursor  Down */
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(term.c.x, term.c.y+escseq.arg[0]);
+		case 1: /* left */
+			tclearregion(0, term.c.y, term.c.x, term.c.y);
 			break;
-		case 'C': /* Cursor  Forward */
-		case 'a':
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(term.c.x+escseq.arg[0], term.c.y);
-			break;
-		case 'D': /* Cursor  Backward */
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(term.c.x-escseq.arg[0], term.c.y);
-			break;
-		case 'E': /* Cursor  Down and first col */
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(0, term.c.y+escseq.arg[0]);
-			break;
-		case 'F': /* Cursor  Up and first col */
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(0, term.c.y-escseq.arg[0]);
-			break;
-		case 'G': /* Move to  */
-		case '`':
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(escseq.arg[0]-1, term.c.y);
-			break;
-		case 'H': /* Move to   */
-		case 'f':
-			DEFAULT(escseq.arg[0], 1);
-			DEFAULT(escseq.arg[1], 1);
-			tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
-			break;
-		case 'J': /* Clear screen */
-			switch(escseq.arg[0]) {
-			case 0: /* below */
-				tclearregion(term.c.x, term.c.y, term.col-1, term.row-1);
-				break;
-			case 1: /* above */
-				tclearregion(0, 0, term.c.x, term.c.y);
-				break;
-			case 2: /* all */
-				tclearregion(0, 0, term.col-1, term.row-1);
-				break;				  
-			}
-			break;
-		case 'K': /* Clear line */
-			switch(escseq.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 'L': /* Insert  blank lines */
-			DEFAULT(escseq.arg[0], 1);
-			tinsertblankline(escseq.arg[0]);
-			break;
-		case 'l':
-			if(escseq.priv && escseq.arg[0] == 25)
-				term.c.hidden = 1;
-			break;
-		case 'M': /* Delete  lines */
-			DEFAULT(escseq.arg[0], 1);
-			tdeleteline(escseq.arg[0]);
-			break;
-		case 'P': /* Delete  char */
-			DEFAULT(escseq.arg[0], 1);
-			tdeletechar(escseq.arg[0]);
-			break;
-		case 'd': /* Move to  */
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(term.c.x, escseq.arg[0]-1);
-			break;
-		case 'h': /* Set terminal mode */
-			if(escseq.priv && escseq.arg[0] == 25)
-				term.c.hidden = 0;
-			break;
-		case 'm': /* Terminal attribute (color) */
-			tsetattr(escseq.arg, escseq.narg);
-			break;
-		case 'r':
-			if(escseq.priv)
-				;
-			else {
-				DEFAULT(escseq.arg[0], 1);
-				DEFAULT(escseq.arg[1], term.row);
-				tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
-			}
-			break;
-		case 's': /* Save cursor position */
-			tcpos(CSsave);
-			break;
-		case 'u': /* Load cursor position */
-			tcpos(CSload);
+		case 2: /* all */
+			tclearregion(0, term.c.y, term.col-1, term.c.y);
 			break;
 		}
 		break;
+	case 'S':
+	case 'L': /* Insert  blank lines */
+		DEFAULT(escseq.arg[0], 1);
+		tinsertblankline(escseq.arg[0]);
+		break;
+	case 'l':
+		if(escseq.priv && escseq.arg[0] == 25)
+				term.c.hidden = 1;
+		break;
+	case 'M': /* Delete  lines */
+		DEFAULT(escseq.arg[0], 1);
+		tdeleteline(escseq.arg[0]);
+		break;
+	case 'X':
+	case 'P': /* Delete  char */
+		DEFAULT(escseq.arg[0], 1);
+		tdeletechar(escseq.arg[0]);
+		break;
+	case 'd': /* Move to  */
+		DEFAULT(escseq.arg[0], 1);
+		tmoveto(term.c.x, escseq.arg[0]-1);
+		break;
+	case 'h': /* Set terminal mode */
+		if(escseq.priv && escseq.arg[0] == 25)
+			term.c.hidden = 0;
+		break;
+	case 'm': /* Terminal attribute (color) */
+		tsetattr(escseq.arg, escseq.narg);
+		break;
+	case 'r':
+		if(escseq.priv)
+			;
+		else {
+			DEFAULT(escseq.arg[0], 1);
+			DEFAULT(escseq.arg[1], term.row);
+			tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
+		}
+		break;
+	case 's': /* Save cursor position */
+		tcpos(CSsave);
+		break;
+	case 'u': /* Load cursor position */
+		tcpos(CSload);
+		break;
 	}
 }
 
 void
-escdump(void) { 
+csidump(void) { 
 	int i;
-	printf("rawbuf	: %s\n", escseq.buf);
-	printf("prechar : %c\n", escseq.pre);
-	printf("private : %c\n", escseq.priv ? '?' : ' ');
-	printf("narg	: %d\n", escseq.narg);
+	printf("ESC [ %s", escseq.priv ? "? " : "");
 	if(escseq.narg)
 		for(i = 0; i < escseq.narg; i++)
-			printf("\targ %d = %d\n", i, escseq.arg[i]);
-	printf("mode	: %c\n", escseq.mode);
+			printf("%d ", escseq.arg[i]);
+	if(escseq.mode)
+		putchar(escseq.mode);
+	putchar('\n');
 }
 
 void
-escreset(void) {
+csireset(void) {
 	memset(&escseq, 0, sizeof(escseq));
 }
 
@@ -781,21 +743,41 @@ tputtab(void) {
 
 void
 tputc(char c) {
-	static int inesc = 0;
 #if 0
 	dump(c);
 #endif	
-	/* start of escseq */
-	if(c == '\033')
-		escreset(), inesc = 1;
-	else if(inesc) {
-		inesc = escaddc(c);
-	} /* normal char */ 
-	else switch(c) { 
-		default:
-			tsetchar(c);
-			tcursor(CSright);
-			break;
+	if(term.esc & ESCin) {
+		if(term.esc & ESCcsi) {
+			escseq.buf[escseq.len++] = c;
+			if(BETWEEN(c, 0x40, 0x7E) || escseq.len >= ESCSIZ) {
+				term.esc = 0;
+				csiparse(), csihandle();
+			}
+		} else if (term.esc & ESCosc) {
+			if(c == ';') {
+				term.titlelen = 0;
+				term.esc = ESCin | ESCtitle;
+			}
+		} else if(term.esc & ESCtitle) {
+			if(c == '\a' || term.titlelen+1 >= TITLESIZ) {
+				term.esc = 0;
+				term.title[term.titlelen] = '\0';
+				XStoreName(xw.dis, xw.win, term.title);
+			} else {
+				term.title[term.titlelen++] = c;
+			}
+		} else {		
+			switch(c) {
+			case '[':
+				term.esc |= ESCcsi;
+				break;
+			case ']':
+				term.esc |= ESCosc;
+				break;
+			}
+		}
+	} else {
+		switch(c) {
 		case '\t':
 			tputtab();
 			break;
@@ -811,6 +793,15 @@ tputc(char c) {
 		case '\a':
 			xbell();
 			break;
+		case '\033':
+			csireset();
+			term.esc = ESCin;
+			break;
+		default:
+			tsetchar(c);
+			tcursor(CSright);
+			break;
+		}
 	}
 }
 

From e6b3f5c755349ba7a339dd43958870e4cceb57bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 3 Feb 2010 16:18:04 +0100
Subject: [PATCH 0070/1146] graphic charset and a few more escapes.

---
 config.h | 35 ++++++++++++++++++++++
 st.c     | 91 ++++++++++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 110 insertions(+), 16 deletions(-)

diff --git a/config.h b/config.h
index 7da5848..0e04ab1 100644
--- a/config.h
+++ b/config.h
@@ -36,3 +36,38 @@ static Key key[] = {
 	{ XK_Up,     "\033[A" },
 	{ XK_Down,   "\033[B" },
 };
+
+static char gfx[] = {
+	['}'] = 'f',
+	['.'] = 'v',
+	[','] = '<',
+	['+'] = '>',
+	['-'] = '^',
+	['h'] = '#',
+	['~'] = 'o',
+	['a'] = ':',
+	['f'] = '\\',
+	['`'] = '+',
+	['z'] = '>',
+	['{'] = '*',
+	['q'] = '-',
+	['i'] = '#',
+	['n'] = '+',
+	['y'] = '<',
+	['m'] = '+',
+	['j'] = '+',
+	['|'] = '!',
+	['g'] = '#',
+	['o'] = '~',
+	['p'] = '-',
+	['r'] = '-',
+	['s'] = '_',
+	['0'] = '#',
+	['w'] = '+',
+	['u'] = '+',
+	['t'] = '+',
+	['v'] = '+',
+	['l'] = '+',
+	['k'] = '+',
+	['x'] = '|',
+};
diff --git a/st.c b/st.c
index a84f0e0..ca5fb5d 100644
--- a/st.c
+++ b/st.c
@@ -38,11 +38,11 @@
 #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
 
 /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
-enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 };
-enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload };
+enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4, ATgfx=8 };
+enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSsave, CSload };
 enum { CRset=1, CRupdate=2 };
-enum { TMwrap=1, TMinsert=2, TMtitle=4 };
-enum { ESCin = 1, ESCcsi = 2, ESCosc = 4, ESCtitle = 8 };
+enum { TMwrap=1, TMinsert=2 };
+enum { ESCin=1, ESCcsi=2, ESCosc=4, ESCtitle=8, ESCcharset=16 };
 enum { SCupdate, SCredraw };
 
 typedef int Color;
@@ -68,7 +68,7 @@ typedef struct {
 /* ESC '[' [[ []  [;]] ] */
 typedef struct {
 	char buf[ESCSIZ]; /* raw string */
-	int len;            /* raw string length */
+	int len;          /* raw string length */
 	char priv;
 	int arg[ESCARGSIZ];
 	int narg;           /* nb of args */
@@ -389,7 +389,7 @@ tmoveto(int x, int y) {
 void
 tcursor(int dir) {
 	int xf = term.c.x, yf = term.c.y;
-
+	
 	switch(dir) {
 	case CSup:
 		yf--;
@@ -399,7 +399,7 @@ tcursor(int dir) {
 		break;
 	case CSleft:
 		xf--;
-		if(xf < 0) {
+		if(term.mode & TMwrap && xf < 0) {
 			xf = term.col-1, yf--;
 			if(yf < term.top)
 				yf = term.top, xf = 0;
@@ -407,7 +407,7 @@ tcursor(int dir) {
 		break;
 	case CSright:
 		xf++;
-		if(xf >= term.col) {
+		if(term.mode & TMwrap && xf >= term.col) {
 			xf = 0, yf++;
 			if(yf > term.bot)
 				yf = term.bot, tscroll();
@@ -416,7 +416,7 @@ tcursor(int dir) {
 	}
 	tmoveto(xf, yf);
 }
-
+	
 void
 tsetchar(char c) {
 	term.line[term.c.y][term.c.x] = term.c.attr;
@@ -535,7 +535,7 @@ tsetattr(int *attr, int l) {
 	for(i = 0; i < l; i++) {
 		switch(attr[i]) {
 		case 0:
-			memset(&term.c.attr, 0, sizeof(term.c.attr));
+			term.c.attr.mode &= ~(ATreverse | ATunderline | ATbold);
 			term.c.attr.fg = DefaultFG;
 			term.c.attr.bg = DefaultBG;
 			break;
@@ -593,7 +593,10 @@ tsetscroll(int t, int b) {
 
 void
 csihandle(void) {
+	if(escseq.priv)
+		csidump();
 	switch(escseq.mode) {
+	unknown:
 	default:
 		fprintf(stderr, "erresc: unknown sequence\n");
 		csidump();
@@ -672,8 +675,16 @@ csihandle(void) {
 		tinsertblankline(escseq.arg[0]);
 		break;
 	case 'l':
-		if(escseq.priv && escseq.arg[0] == 25)
+		if(escseq.priv) {
+			switch(escseq.arg[0]) {
+			case 7:
+				term.mode &= ~TMwrap;
+				break;
+			case 25:
 				term.c.hidden = 1;
+				break;
+			}
+		}
 		break;
 	case 'M': /* Delete  lines */
 		DEFAULT(escseq.arg[0], 1);
@@ -689,15 +700,25 @@ csihandle(void) {
 		tmoveto(term.c.x, escseq.arg[0]-1);
 		break;
 	case 'h': /* Set terminal mode */
-		if(escseq.priv && escseq.arg[0] == 25)
-			term.c.hidden = 0;
+		if(escseq.priv)
+			switch(escseq.arg[0]) {
+			case 7:
+				term.mode |= TMwrap;
+				break;
+			case 25:
+				term.c.hidden = 0;
+				break;
+			case 1034:
+				/* XXX: Interpret "meta" key, sets eighth bit. */
+				break;
+			}
 		break;
 	case 'm': /* Terminal attribute (color) */
 		tsetattr(escseq.arg, escseq.narg);
 		break;
 	case 'r':
 		if(escseq.priv)
-			;
+			goto unknown;
 		else {
 			DEFAULT(escseq.arg[0], 1);
 			DEFAULT(escseq.arg[1], term.row);
@@ -766,6 +787,17 @@ tputc(char c) {
 			} else {
 				term.title[term.titlelen++] = c;
 			}
+		} else if(term.esc & ESCcharset) {
+			printf("ESC ( %c\n", c);
+			switch(c) {
+			case '0': /* Line drawing crap */
+				term.c.attr.mode |= ATgfx;
+				break;
+			case 'B': /* Back to regular text */
+				term.c.attr.mode &= ~ATgfx;
+				break;
+			}
+			term.esc = 0;
 		} else {		
 			switch(c) {
 			case '[':
@@ -774,6 +806,23 @@ tputc(char c) {
 			case ']':
 				term.esc |= ESCosc;
 				break;
+			case '(':
+				term.esc |= ESCcharset;
+				break;
+			case 'A':
+				tmoveto(term.c.x, term.c.y-1);
+				break;
+			case 'B':
+				tmoveto(term.c.x, term.c.y+1);
+				break;
+			case 'C':
+				tmoveto(term.c.x+1, term.c.y);
+				break;
+			case 'D':
+				tmoveto(term.c.x-1, term.c.y);
+				break;
+			default:
+				fprintf(stderr, "erresc: unknown sequence ESC %02X '%c'\n", c, isprint(c)?c:'.');
 			}
 		}
 	} else {
@@ -931,6 +980,8 @@ void
 xdraws (char *s, Glyph base, int x, int y, int len) {
 	unsigned long xfg, xbg;
 	int winx = x*xw.cw, winy = y*xw.ch + dc.font->ascent, width = len*xw.cw;
+	int i;
+
 	if(base.mode & ATreverse)
 		xfg = dc.col[base.bg], xbg = dc.col[base.fg];
 	else
@@ -938,6 +989,13 @@ xdraws (char *s, Glyph base, int x, int y, int len) {
 
 	XSetBackground(xw.dis, dc.gc, xbg);
 	XSetForeground(xw.dis, dc.gc, xfg);
+	
+	if(base.mode & ATgfx) {
+	   
+		for(i = 0; i < len; i++)
+			s[i] = gfx[s[i]];
+	}
+	
 	XDrawImageString(xw.dis, xw.win, dc.gc, winx, winy, s, len);
 	
 	if(base.mode & ATunderline)
@@ -1006,7 +1064,8 @@ draw(int redraw_all) {
 		}
 		xdraws(buf, base, ox, y, i);
 	}
-	xcursor(CSdraw);
+	if(!term.c.hidden)
+		xcursor(CSdraw);
 }
 
 void
@@ -1014,7 +1073,7 @@ expose(XEvent *ev) {
 	draw(SCredraw);
 }
 
-char *
+char*
 kmap(KeySym k) {
 	int i;
 	for(i = 0; i < LEN(key); i++)

From eff05c7b90429ac4dddbbc53ac7d4c05dfc5efd4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Mon, 8 Feb 2010 23:16:55 +0100
Subject: [PATCH 0071/1146] more escapes & more compability:

cursor keys are handled in kpress according to the Application Mode (DECPAM).
define & enum were renamed.
tcursor() is now tmovecursor() which is more correct.
tcpos() is now tcursor(), as DECSC is also supposed to save attributes.
capnames are indicated whenever possible.

Currently:
alsamixer looks fine, totally usable.
ncmpc is almost ok.
emacs looks like shit.
---
 config.h |   5 +-
 st.c     | 316 +++++++++++++++++++++++++++++++------------------------
 2 files changed, 177 insertions(+), 144 deletions(-)

diff --git a/config.h b/config.h
index 0e04ab1..a7fc58c 100644
--- a/config.h
+++ b/config.h
@@ -31,10 +31,6 @@ static Key key[] = {
 	{ XK_End,    "\033[4~" },
 	{ XK_Prior,  "\033[5~" },
 	{ XK_Next,   "\033[6~" },
-	{ XK_Left,   "\033[D" },
-	{ XK_Right,  "\033[C" },
-	{ XK_Up,     "\033[A" },
-	{ XK_Down,   "\033[B" },
 };
 
 static char gfx[] = {
@@ -70,4 +66,5 @@ static char gfx[] = {
 	['l'] = '+',
 	['k'] = '+',
 	['x'] = '|',
+	[255] = 0,
 };
diff --git a/st.c b/st.c
index ca5fb5d..fcb3d65 100644
--- a/st.c
+++ b/st.c
@@ -23,10 +23,10 @@
 #define TNAME "xterm"
 
 /* Arbitrary sizes */
-#define TITLESIZ 256
-#define ESCSIZ 256
-#define ESCARGSIZ 16
-#define MAXDRAWBUF 1024
+#define ESC_TITLE_SIZ 256
+#define ESC_BUF_SIZ   256
+#define ESC_ARG_SIZ   16
+#define DRAW_BUF_SIZ  1024
 
 #define SERRNO strerror(errno)
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
@@ -38,21 +38,19 @@
 #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
 
 /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
-enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4, ATgfx=8 };
-enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSsave, CSload };
-enum { CRset=1, CRupdate=2 };
-enum { TMwrap=1, TMinsert=2 };
-enum { ESCin=1, ESCcsi=2, ESCosc=4, ESCtitle=8, ESCcharset=16 };
-enum { SCupdate, SCredraw };
-
-typedef int Color;
+enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 };
+enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HIDE, CURSOR_DRAW, CURSOR_SAVE, CURSOR_LOAD };
+enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
+enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4 };
+enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
+enum { SCREEN_UPDATE, SCREEN_REDRAW };
 
 typedef struct {
 	char c;     /* character code  */
 	char mode;  /* attribute flags */
-	Color fg;   /* foreground      */
-	Color bg;   /* background      */
-	char state; /* state flag      */
+	int fg;     /* foreground      */
+	int bg;     /* background      */
+	char state; /* state flags     */
 } Glyph;
 
 typedef Glyph* Line;
@@ -67,11 +65,11 @@ typedef struct {
 /* CSI Escape sequence structs */
 /* ESC '[' [[ []  [;]] ] */
 typedef struct {
-	char buf[ESCSIZ]; /* raw string */
-	int len;          /* raw string length */
+	char buf[ESC_BUF_SIZ]; /* raw string */
+	int len;               /* raw string length */
 	char priv;
-	int arg[ESCARGSIZ];
-	int narg;           /* nb of args */
+	int arg[ESC_ARG_SIZ];
+	int narg;              /* nb of args */
 	char mode;
 } CSIEscape;
 
@@ -83,9 +81,9 @@ typedef struct {
 	TCursor c;  /* cursor */
 	int top;    /* top    scroll limit */
 	int bot;    /* bottom scroll limit */
-	int mode;   /* terminal mode */
-	int esc;
-	char title[TITLESIZ];
+	int mode;   /* terminal mode flags */
+	int esc;    /* escape state flags */
+	char title[ESC_TITLE_SIZ];
 	int titlelen;
 } Term;
 
@@ -102,7 +100,7 @@ typedef struct {
 
 typedef struct {
 	KeySym k;
-	char s[ESCSIZ];
+	char s[ESC_BUF_SIZ];
 } Key;
 
 #include "config.h"
@@ -126,8 +124,8 @@ static void csiparse(void);
 static void csireset(void);
 
 static void tclearregion(int, int, int, int);
-static void tcpos(int);
 static void tcursor(int);
+static void tmovecursor(int);
 static void tdeletechar(int);
 static void tdeleteline(int);
 static void tinsertblank(int);
@@ -187,7 +185,7 @@ tdump(void) {
 				putchar('#');
 			else {
 				c = term.line[row][col];
-				putchar(c.state & CRset ? c.c : '.');
+				putchar(c.state & GLYPH_SET ? c.c : '.');
 			}
 		}
 		putchar('\n');
@@ -218,7 +216,7 @@ xbell(void) { /* visual bell */
 	XSetForeground(xw.dis, dc.gc, dc.col[BellCol]);
 	XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1);
 	/* usleep(30000); */
-	draw(SCredraw);
+	draw(SCREEN_REDRAW);
 }
 
 void 
@@ -281,13 +279,10 @@ ttyread(void) {
 	char buf[BUFSIZ] = {0};
 	int ret;
 
-	switch(ret = read(cmdfd, buf, BUFSIZ)) {
-	case -1: 
+	if((ret = read(cmdfd, buf, BUFSIZ)) < 0)
 		die("Couldn't read from shell: %s\n", SERRNO);
-		break;
-	default:
+	else
 		tputs(buf, ret);
-	}
 }
 
 void
@@ -308,14 +303,13 @@ ttyresize(int x, int y) {
 }
 
 void
-tcpos(int mode) {
-	static int x = 0;
-	static int y = 0;
+tcursor(int mode) {
+	static TCursor c;
 
-	if(mode == CSsave)
-		x = term.c.x, y = term.c.y;
-	else if(mode == CSload)
-		tmoveto(x, y);
+	if(mode == CURSOR_SAVE)
+		c = term.c;
+	else if(mode == CURSOR_LOAD)
+		term.c = c, tmoveto(c.x, c.y);
 }
 
 void
@@ -323,9 +317,9 @@ tnew(int col, int row) {   /* screen size */
 	term.row = row, term.col = col;
 	term.top = 0, term.bot = term.row - 1;
 	/* mode */
-	term.mode = TMwrap;
+	term.mode = MODE_WRAP;
 	/* cursor */
-	term.c.attr.mode = ATnone;
+	term.c.attr.mode = ATTR_NULL;
 	term.c.attr.fg = DefaultFG;
 	term.c.attr.bg = DefaultBG;
 	term.c.x = term.c.y = 0;
@@ -370,7 +364,7 @@ csiparse(void) {
 			escseq.arg[escseq.narg] *= 10;
 			escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */;
 		}
-		if(*p == ';' && escseq.narg+1 < ESCARGSIZ)
+		if(*p == ';' && escseq.narg+1 < ESC_ARG_SIZ)
 			escseq.narg++, p++;
 		else {
 			escseq.mode = *p;
@@ -387,27 +381,27 @@ tmoveto(int x, int y) {
 }
 
 void
-tcursor(int dir) {
+tmovecursor(int dir) {
 	int xf = term.c.x, yf = term.c.y;
 	
 	switch(dir) {
-	case CSup:
+	case CURSOR_UP:
 		yf--;
 		break;
-	case CSdown:
+	case CURSOR_DOWN:
 		yf++;
 		break;
-	case CSleft:
+	case CURSOR_LEFT:
 		xf--;
-		if(term.mode & TMwrap && xf < 0) {
+		if(term.mode & MODE_WRAP && xf < 0) {
 			xf = term.col-1, yf--;
 			if(yf < term.top)
 				yf = term.top, xf = 0;
 		}
 		break;
-	case CSright:
+	case CURSOR_RIGHT:
 		xf++;
-		if(term.mode & TMwrap && xf >= term.col) {
+		if(term.mode & MODE_WRAP && xf >= term.col) {
 			xf = 0, yf++;
 			if(yf > term.bot)
 				yf = term.bot, tscroll();
@@ -421,7 +415,7 @@ void
 tsetchar(char c) {
 	term.line[term.c.y][term.c.x] = term.c.attr;
 	term.line[term.c.y][term.c.x].c = c;
-	term.line[term.c.y][term.c.x].state |= CRset | CRupdate;
+	term.line[term.c.y][term.c.x].state |= GLYPH_SET | GLYPH_DIRTY;
 }
 
 void
@@ -477,7 +471,7 @@ tsetlinestate(int n, int state) {
 }
 
 void
-tinsertblankline (int n) {
+tinsertblankline(int n) {
 	int i;
 	Line blank;
 	int bot = term.bot;
@@ -497,8 +491,8 @@ tinsertblankline (int n) {
 		term.line[i-n] = blank;
 		/* blank it */
 		memset(blank, 0, term.col * sizeof(Glyph));
-		tsetlinestate(i, CRupdate);
-		tsetlinestate(i-n, CRupdate);
+		tsetlinestate(i, GLYPH_DIRTY);
+		tsetlinestate(i-n, GLYPH_DIRTY);
 	}
 }
 
@@ -523,8 +517,8 @@ tdeleteline(int n) {
 		term.line[i+n] = blank;
 		/* blank it */
 		memset(blank, 0, term.col * sizeof(Glyph));
-		tsetlinestate(i, CRupdate);
-		tsetlinestate(i-n, CRupdate);
+		tsetlinestate(i, GLYPH_DIRTY);
+		tsetlinestate(i-n, GLYPH_DIRTY);
 	}
 }
 
@@ -535,30 +529,30 @@ tsetattr(int *attr, int l) {
 	for(i = 0; i < l; i++) {
 		switch(attr[i]) {
 		case 0:
-			term.c.attr.mode &= ~(ATreverse | ATunderline | ATbold);
+			term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE | ATTR_BOLD);
 			term.c.attr.fg = DefaultFG;
 			term.c.attr.bg = DefaultBG;
 			break;
 		case 1:
-			term.c.attr.mode |= ATbold;	 
+			term.c.attr.mode |= ATTR_BOLD;	 
 			break;
 		case 4: 
-			term.c.attr.mode |= ATunderline;
+			term.c.attr.mode |= ATTR_UNDERLINE;
 			break;
 		case 7: 
-			term.c.attr.mode |= ATreverse;	
+			term.c.attr.mode |= ATTR_REVERSE;	
 			break;
 		case 8:
-			term.c.hidden = CShide;
+			term.c.hidden = CURSOR_HIDE;
 			break;
 		case 22: 
-			term.c.attr.mode &= ~ATbold;  
+			term.c.attr.mode &= ~ATTR_BOLD;  
 			break;
 		case 24: 
-			term.c.attr.mode &= ~ATunderline;
+			term.c.attr.mode &= ~ATTR_UNDERLINE;
 			break;
 		case 27: 
-			term.c.attr.mode &= ~ATreverse;	 
+			term.c.attr.mode &= ~ATTR_REVERSE;	 
 			break;
 		case 39:
 			term.c.attr.fg = DefaultFG;
@@ -593,57 +587,56 @@ tsetscroll(int t, int b) {
 
 void
 csihandle(void) {
-	if(escseq.priv)
-		csidump();
 	switch(escseq.mode) {
-	unknown:
 	default:
-		fprintf(stderr, "erresc: unknown sequence\n");
+	unknown:
+		printf("erresc: unknown sequence -- ");
 		csidump();
 		/* die(""); */
 		break;
-	case '@': /* Insert  blank char */
+	case '@': /* ICH -- Insert  blank char */
 		DEFAULT(escseq.arg[0], 1);
 		tinsertblank(escseq.arg[0]);
 		break;
-	case 'A': /* Cursor  Up */
+	case 'A': /* CUU -- Cursor  Up */
 	case 'e':
 		DEFAULT(escseq.arg[0], 1);
 		tmoveto(term.c.x, term.c.y-escseq.arg[0]);
 		break;
-	case 'B': /* Cursor  Down */
+	case 'B': /* CUD -- Cursor  Down */
 		DEFAULT(escseq.arg[0], 1);
 		tmoveto(term.c.x, term.c.y+escseq.arg[0]);
 		break;
-	case 'C': /* Cursor  Forward */
+	case 'C': /* CUF -- Cursor  Forward */
 	case 'a':
 		DEFAULT(escseq.arg[0], 1);
 		tmoveto(term.c.x+escseq.arg[0], term.c.y);
 		break;
-	case 'D': /* Cursor  Backward */
+	case 'D': /* CUB -- Cursor  Backward */
 		DEFAULT(escseq.arg[0], 1);
 		tmoveto(term.c.x-escseq.arg[0], term.c.y);
 		break;
-	case 'E': /* Cursor  Down and first col */
+	case 'E': /* CNL -- Cursor  Down and first col */
 		DEFAULT(escseq.arg[0], 1);
 		tmoveto(0, term.c.y+escseq.arg[0]);
 		break;
-	case 'F': /* Cursor  Up and first col */
+	case 'F': /* CPL -- Cursor  Up and first col */
 		DEFAULT(escseq.arg[0], 1);
 		tmoveto(0, term.c.y-escseq.arg[0]);
 		break;
-	case 'G': /* Move to  */
-	case '`':
+	case 'G': /* CHA -- Move to  */
+	case '`': /* XXX: HPA -- same? */
 		DEFAULT(escseq.arg[0], 1);
      	tmoveto(escseq.arg[0]-1, term.c.y);
 		break;
-	case 'H': /* Move to   */
-	case 'f':
+	case 'H': /* CUP -- Move to   */
+	case 'f': /* XXX: HVP -- same? */
 		DEFAULT(escseq.arg[0], 1);
 		DEFAULT(escseq.arg[1], 1);
 		tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
 		break;
-	case 'J': /* Clear screen */
+	/* XXX: (CSI n I) CHT -- Cursor Forward Tabulation  tab stops */
+	case 'J': /* ED -- Clear screen */
 		switch(escseq.arg[0]) {
 		case 0: /* below */
 			tclearregion(term.c.x, term.c.y, term.col-1, term.row-1);
@@ -653,10 +646,13 @@ csihandle(void) {
 			break;
 		case 2: /* all */
 			tclearregion(0, 0, term.col-1, term.row-1);
-			break;				  
+			break;
+		case 3: /* XXX: erase saved lines (xterm) */
+		default:
+			goto unknown;
 		}
 		break;
-	case 'K': /* Clear line */
+	case 'K': /* EL -- Clear line */
 		switch(escseq.arg[0]) {
 		case 0: /* right */
 			tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
@@ -669,54 +665,77 @@ csihandle(void) {
 			break;
 		}
 		break;
-	case 'S':
-	case 'L': /* Insert  blank lines */
+	case 'S': /* XXX: SU -- Scroll  line up (faked) */ 
+	case 'L': /* IL -- Insert  blank lines */
 		DEFAULT(escseq.arg[0], 1);
 		tinsertblankline(escseq.arg[0]);
 		break;
-	case 'l':
+	case 'l': /* RM -- Reset Mode */
 		if(escseq.priv) {
 			switch(escseq.arg[0]) {
+			case 1:
+				term.mode &= ~MODE_APPKEYPAD;
+				break;
 			case 7:
-				term.mode &= ~TMwrap;
+				term.mode &= ~MODE_WRAP;
+				break;
+			case 12: /* att610 -- Stop blinking cursor (IGNORED) */
 				break;
 			case 25:
 				term.c.hidden = 1;
 				break;
+			case 1048: /* XXX: no alt. screen to erase/save */
+			case 1049:
+				tcursor(CURSOR_LOAD);
+				tclearregion(0, 0, term.col-1, term.row-1);
+				break;
+			default:
+				goto unknown;
 			}
-		}
+		} else goto unknown;
 		break;
-	case 'M': /* Delete  lines */
+	case 'M': /* DL -- Delete  lines */
 		DEFAULT(escseq.arg[0], 1);
 		tdeleteline(escseq.arg[0]);
 		break;
-	case 'X':
-	case 'P': /* Delete  char */
+	case 'X': /* ECH -- Erase  char XXX: same? */
+	case 'P': /* DCH -- Delete  char */
 		DEFAULT(escseq.arg[0], 1);
 		tdeletechar(escseq.arg[0]);
 		break;
-	case 'd': /* Move to  */
+	/* XXX: (CSI n Z) CBT -- Cursor Backward Tabulation  tab stops */
+	case 'd': /* VPA -- Move to  */
 		DEFAULT(escseq.arg[0], 1);
 		tmoveto(term.c.x, escseq.arg[0]-1);
 		break;
-	case 'h': /* Set terminal mode */
-		if(escseq.priv)
+	case 'h': /* SM -- Set terminal mode */
+		if(escseq.priv) {
 			switch(escseq.arg[0]) {
+			case 1:
+				term.mode |= MODE_APPKEYPAD;
+				break;
 			case 7:
-				term.mode |= TMwrap;
+				term.mode |= MODE_WRAP;
+				break;
+			case 12: /* att610 -- Start blinking cursor (IGNORED) */
 				break;
 			case 25:
 				term.c.hidden = 0;
 				break;
-			case 1034:
-				/* XXX: Interpret "meta" key, sets eighth bit. */
+			case 1048: 
+			case 1049: /* XXX: no alt. screen to erase/save */
+				tcursor(CURSOR_SAVE);
+				tclearregion(0, 0, term.col-1, term.row-1);
 				break;
+			default:
+				goto unknown;
 			}
+		} else goto unknown;
 		break;
-	case 'm': /* Terminal attribute (color) */
+	case 'm': /* SGR -- Terminal attribute (color) */
 		tsetattr(escseq.arg, escseq.narg);
 		break;
-	case 'r':
+	case 'r': /* DECSTBM -- Set Scrolling Region */
 		if(escseq.priv)
 			goto unknown;
 		else {
@@ -725,11 +744,11 @@ csihandle(void) {
 			tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
 		}
 		break;
-	case 's': /* Save cursor position */
-		tcpos(CSsave);
+	case 's': /* DECSC -- Save cursor position (ANSI.SYS) */
+		tcursor(CURSOR_SAVE);
 		break;
-	case 'u': /* Load cursor position */
-		tcpos(CSload);
+	case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
+		tcursor(CURSOR_LOAD);
 		break;
 	}
 }
@@ -759,70 +778,82 @@ tputtab(void) {
 		space--;
 	
 	for(; space > 0; space--)
-		tcursor(CSright);
+		tmovecursor(CURSOR_RIGHT);
 }
 
 void
 tputc(char c) {
-#if 0
-	dump(c);
-#endif	
-	if(term.esc & ESCin) {
-		if(term.esc & ESCcsi) {
+	/* dump(c); */
+	if(term.esc & ESC_START) {
+		if(term.esc & ESC_CSI) {
 			escseq.buf[escseq.len++] = c;
-			if(BETWEEN(c, 0x40, 0x7E) || escseq.len >= ESCSIZ) {
+			if(BETWEEN(c, 0x40, 0x7E) || escseq.len >= ESC_BUF_SIZ) {
 				term.esc = 0;
 				csiparse(), csihandle();
 			}
-		} else if (term.esc & ESCosc) {
+		} else if(term.esc & ESC_OSC) {
 			if(c == ';') {
 				term.titlelen = 0;
-				term.esc = ESCin | ESCtitle;
+				term.esc = ESC_START | ESC_TITLE;
 			}
-		} else if(term.esc & ESCtitle) {
-			if(c == '\a' || term.titlelen+1 >= TITLESIZ) {
+		} else if(term.esc & ESC_TITLE) {
+			if(c == '\a' || term.titlelen+1 >= ESC_TITLE_SIZ) {
 				term.esc = 0;
 				term.title[term.titlelen] = '\0';
 				XStoreName(xw.dis, xw.win, term.title);
 			} else {
 				term.title[term.titlelen++] = c;
 			}
-		} else if(term.esc & ESCcharset) {
-			printf("ESC ( %c\n", c);
+		} else if(term.esc & ESC_ALTCHARSET) {
 			switch(c) {
 			case '0': /* Line drawing crap */
-				term.c.attr.mode |= ATgfx;
+				term.c.attr.mode |= ATTR_GFX;
 				break;
 			case 'B': /* Back to regular text */
-				term.c.attr.mode &= ~ATgfx;
+				term.c.attr.mode &= ~ATTR_GFX;
 				break;
+			default:
+				printf("esc unhandled charset: ESC ( %c\n", c);
 			}
 			term.esc = 0;
 		} else {		
 			switch(c) {
 			case '[':
-				term.esc |= ESCcsi;
+				term.esc |= ESC_CSI;
 				break;
 			case ']':
-				term.esc |= ESCosc;
+				term.esc |= ESC_OSC;
 				break;
 			case '(':
-				term.esc |= ESCcharset;
+				term.esc |= ESC_ALTCHARSET;
 				break;
 			case 'A':
 				tmoveto(term.c.x, term.c.y-1);
+				term.esc = 0;
 				break;
 			case 'B':
 				tmoveto(term.c.x, term.c.y+1);
+				term.esc = 0;
 				break;
 			case 'C':
 				tmoveto(term.c.x+1, term.c.y);
+				term.esc = 0;
 				break;
 			case 'D':
 				tmoveto(term.c.x-1, term.c.y);
+				term.esc = 0;
+				break;
+			case '=': /* DECPAM */
+				term.mode |= MODE_APPKEYPAD;
+				term.esc = 0;
+				break;
+			case '>': /* DECPNM */
+				term.mode &= ~MODE_APPKEYPAD;
+				term.esc = 0;
 				break;
 			default:
 				fprintf(stderr, "erresc: unknown sequence ESC %02X '%c'\n", c, isprint(c)?c:'.');
+				term.esc = 0;
 			}
 		}
 	} else {
@@ -831,7 +862,7 @@ tputc(char c) {
 			tputtab();
 			break;
 		case '\b':
-			tcursor(CSleft);
+			tmovecursor(CURSOR_LEFT);
 			break;
 		case '\r':
 			tmoveto(0, term.c.y);
@@ -844,11 +875,11 @@ tputc(char c) {
 			break;
 		case '\033':
 			csireset();
-			term.esc = ESCin;
+			term.esc = ESC_START;
 			break;
 		default:
 			tsetchar(c);
-			tcursor(CSright);
+			tmovecursor(CURSOR_RIGHT);
 			break;
 		}
 	}
@@ -917,7 +948,7 @@ xscroll(void) {
 	int dsty = term.top * xw.ch;
 	int height = (term.bot-term.top) * xw.ch;
 
-	xcursor(CShide);
+	xcursor(CURSOR_HIDE);
 	XCopyArea(xw.dis, xw.win, xw.win, dc.gc, 0, srcy, xw.w, height, 0, dsty);
 	xclear(0, term.bot, term.col-1, term.bot);
 }
@@ -950,7 +981,7 @@ xinit(void) {
 
 	term.c.attr.fg = DefaultFG;
 	term.c.attr.bg = DefaultBG;
-	term.c.attr.mode = ATnone;
+	term.c.attr.mode = ATTR_NULL;
 	/* windows */
 	xw.h = term.row * xw.ch;
 	xw.w = term.col * xw.cw;
@@ -977,12 +1008,12 @@ xinit(void) {
 }
 
 void
-xdraws (char *s, Glyph base, int x, int y, int len) {
+xdraws(char *s, Glyph base, int x, int y, int len) {
 	unsigned long xfg, xbg;
 	int winx = x*xw.cw, winy = y*xw.ch + dc.font->ascent, width = len*xw.cw;
 	int i;
 
-	if(base.mode & ATreverse)
+	if(base.mode & ATTR_REVERSE)
 		xfg = dc.col[base.bg], xbg = dc.col[base.fg];
 	else
 		xfg = dc.col[base.fg], xbg = dc.col[base.bg];
@@ -990,15 +1021,13 @@ xdraws (char *s, Glyph base, int x, int y, int len) {
 	XSetBackground(xw.dis, dc.gc, xbg);
 	XSetForeground(xw.dis, dc.gc, xfg);
 	
-	if(base.mode & ATgfx) {
-	   
+	if(base.mode & ATTR_GFX)
 		for(i = 0; i < len; i++)
 			s[i] = gfx[s[i]];
-	}
 	
 	XDrawImageString(xw.dis, xw.win, dc.gc, winx, winy, s, len);
 	
-	if(base.mode & ATunderline)
+	if(base.mode & ATTR_UNDERLINE)
 		XDrawLine(xw.dis, xw.win, dc.gc, winx, winy+1, winx+width-1, winy+1);
 }
 
@@ -1008,7 +1037,7 @@ xdrawc(int x, int y, Glyph g) {
 	unsigned long xfg, xbg;
 
 	/* reverse video */
-	if(g.mode & ATreverse)
+	if(g.mode & ATTR_REVERSE)
 		xfg = dc.col[g.bg], xbg = dc.col[g.fg];
 	else
 		xfg = dc.col[g.fg], xbg = dc.col[g.bg];
@@ -1022,20 +1051,20 @@ void
 xcursor(int mode) {
 	static int oldx = 0;
 	static int oldy = 0;
-	Glyph g = {' ', ATnone, DefaultBG, DefaultCS, 0};
+	Glyph g = {' ', ATTR_NULL, DefaultBG, DefaultCS, 0};
 	
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
 	
-	if(term.line[term.c.y][term.c.x].state & CRset)
+	if(term.line[term.c.y][term.c.x].state & GLYPH_SET)
 		g.c = term.line[term.c.y][term.c.x].c;
 	/* remove the old cursor */
-	if(term.line[oldy][oldx].state & CRset)
+	if(term.line[oldy][oldx].state & GLYPH_SET)
 		xdrawc(oldx, oldy, term.line[oldy][oldx]);
 	else 
 		xclear(oldx, oldy, oldx, oldy);
 	/* draw the new one */
-	if(mode == CSdraw) {
+	if(mode == CURSOR_DRAW) {
 		xdrawc(term.c.x, term.c.y, g);
 		oldx = term.c.x, oldy = term.c.y;
 	}
@@ -1045,14 +1074,14 @@ void
 draw(int redraw_all) {
 	int i, x, y, ox;
 	Glyph base, new;
-	char buf[MAXDRAWBUF];
+	char buf[DRAW_BUF_SIZ];
 	
 	for(y = 0; y < term.row; y++) {
 		base = term.line[y][0];
 		i = ox = 0;
 		for(x = 0; x < term.col; x++) {
 			new = term.line[y][x];
-			if(!ATTRCMP(base, new) && i < MAXDRAWBUF)
+			if(!ATTRCMP(base, new) && i < DRAW_BUF_SIZ)
 				buf[i++] = new.c;
 			else {
 				xdraws(buf, base, ox, y, i);
@@ -1065,12 +1094,12 @@ draw(int redraw_all) {
 		xdraws(buf, base, ox, y, i);
 	}
 	if(!term.c.hidden)
-		xcursor(CSdraw);
+		xcursor(CURSOR_DRAW);
 }
 
 void
 expose(XEvent *ev) {
-	draw(SCredraw);
+	draw(SCREEN_REDRAW);
 }
 
 char*
@@ -1105,6 +1134,13 @@ kpress(XEvent *ev) {
 		ttywrite(buf, len);
 	} else
 		switch(ksym) {
+		case XK_Up:
+		case XK_Down:
+		case XK_Left:
+		case XK_Right:
+			sprintf(buf, "\033%c%c", term.mode & MODE_APPKEYPAD ? 'O' : '[', "DACB"[ksym - XK_Left]);
+			ttywrite(buf, 3);
+			break;
 		case XK_Insert:
 			if(shift)
 				/* XXX: paste X clipboard */;
@@ -1126,7 +1162,7 @@ resize(XEvent *e) {
 		ttyresize(col, row);
 		xw.w = e->xconfigure.width;
 		xw.h = e->xconfigure.height;
-		draw(SCredraw);
+		draw(SCREEN_REDRAW);
 	}
 }
 
@@ -1151,7 +1187,7 @@ run(void) {
 		}
 		if(FD_ISSET(cmdfd, &rfd)) {
 			ttyread();
-			draw(SCupdate);
+			draw(SCREEN_UPDATE);
 		}
 		while(XPending(xw.dis)) {
 			XNextEvent(xw.dis, &ev);

From 3ba517e796e0c7a73c5030ad791be1db36a8cec5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sun, 21 Feb 2010 14:14:58 +0100
Subject: [PATCH 0072/1146] ECH handled correctly.

---
 st.c | 27 ++++++++++++++++++++++-----
 1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index fcb3d65..15ff4f8 100644
--- a/st.c
+++ b/st.c
@@ -692,13 +692,24 @@ csihandle(void) {
 			default:
 				goto unknown;
 			}
-		} else goto unknown;
+		} else {
+			switch(escseq.arg[0]) {
+			case 4:
+				term.mode &= ~MODE_INSERT;
+				break;
+			default:
+				goto unknown;
+			}
+		}
 		break;
 	case 'M': /* DL -- Delete  lines */
 		DEFAULT(escseq.arg[0], 1);
 		tdeleteline(escseq.arg[0]);
 		break;
-	case 'X': /* ECH -- Erase  char XXX: same? */
+	case 'X': /* ECH -- Erase  char */
+		DEFAULT(escseq.arg[0], 1);
+		tclearregion(term.c.x, term.c.y, term.c.x + escseq.arg[0], term.c.y);
+		break;
 	case 'P': /* DCH -- Delete  char */
 		DEFAULT(escseq.arg[0], 1);
 		tdeletechar(escseq.arg[0]);
@@ -727,10 +738,16 @@ csihandle(void) {
 				tcursor(CURSOR_SAVE);
 				tclearregion(0, 0, term.col-1, term.row-1);
 				break;
-			default:
-				goto unknown;
+			default: goto unknown;
 			}
-		} else goto unknown;
+		} else {
+			switch(escseq.arg[0]) {
+			case 4:
+				term.mode |= MODE_INSERT;
+				break;
+			default: goto unknown;
+			}
+		};
 		break;
 	case 'm': /* SGR -- Terminal attribute (color) */
 		tsetattr(escseq.arg, escseq.narg);

From 636c369d86b6452a89f54c497a9816ca1f866d4e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sun, 21 Feb 2010 14:28:32 +0100
Subject: [PATCH 0073/1146] added VT100 save&load cursor support.

---
 st.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/st.c b/st.c
index 15ff4f8..84292f5 100644
--- a/st.c
+++ b/st.c
@@ -868,6 +868,12 @@ tputc(char c) {
 				term.mode &= ~MODE_APPKEYPAD;
 				term.esc = 0;
 				break;
+			case '7':
+				tcursor(CURSOR_SAVE);
+				break;
+			case '8':
+				tcursor(CURSOR_LOAD);
+				break;
 			default:
 				fprintf(stderr, "erresc: unknown sequence ESC %02X '%c'\n", c, isprint(c)?c:'.');
 				term.esc = 0;

From 639f16d200eee5e297187c582afd9fd2e3e8ef57 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sun, 21 Feb 2010 14:39:31 +0100
Subject: [PATCH 0074/1146] added VT100 RI.

---
 st.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/st.c b/st.c
index 84292f5..c360900 100644
--- a/st.c
+++ b/st.c
@@ -860,6 +860,13 @@ tputc(char c) {
 				tmoveto(term.c.x-1, term.c.y);
 				term.esc = 0;
 				break;
+			case 'M': /* RI -- Reverse index */
+				if(term.c.y == term.top)
+					tinsertblankline(1);
+				else
+					tmoveto(term.c.x, term.c.y-1);
+				term.esc = 0;
+				break;
 			case '=': /* DECPAM */
 				term.mode |= MODE_APPKEYPAD;
 				term.esc = 0;
@@ -870,9 +877,11 @@ tputc(char c) {
 				break;
 			case '7':
 				tcursor(CURSOR_SAVE);
+				term.esc = 0;
 				break;
 			case '8':
 				tcursor(CURSOR_LOAD);
+				term.esc = 0;
 				break;
 			default:
 				fprintf(stderr, "erresc: unknown sequence ESC %02X '%c'\n", c, isprint(c)?c:'.');

From 7cdaf130b17e4991da9bb3d8d1341e0092474a73 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sun, 21 Feb 2010 14:59:32 +0100
Subject: [PATCH 0075/1146] added VT100 NEL.

---
 st.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index c360900..8bbb1a5 100644
--- a/st.c
+++ b/st.c
@@ -856,10 +856,14 @@ tputc(char c) {
 				tmoveto(term.c.x+1, term.c.y);
 				term.esc = 0;
 				break;
-			case 'D':
+			case 'D': /* XXX: CUP (VT100) or IND (VT52) ... */
 				tmoveto(term.c.x-1, term.c.y);
 				term.esc = 0;
 				break;
+			case 'E': /* NEL -- Next line */
+				tnewline();
+				term.esc = 0;
+				break;
 			case 'M': /* RI -- Reverse index */
 				if(term.c.y == term.top)
 					tinsertblankline(1);

From 0f4dd5035ed920c67133f1a4b8aef5cbd957c7be Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 11 Mar 2010 23:50:50 +0100
Subject: [PATCH 0076/1146] bold attribute is back.

visibility of the cursor is not saved/loaded anymore.
scrolling up/down is fixed.
added RI and RIS sequences.
fixed cursor drawing bug.
---
 config.h |   3 +-
 st.c     | 173 +++++++++++++++++++++++++++++++++++++++----------------
 2 files changed, 126 insertions(+), 50 deletions(-)

diff --git a/config.h b/config.h
index a7fc58c..f881571 100644
--- a/config.h
+++ b/config.h
@@ -1,7 +1,8 @@
 #define SHELL "/bin/bash"
 #define TAB    8
 
-#define FONT "fixed"
+#define FONT "6x13"
+#define BOLDFONT FONT"bold"
 #define BORDER 3
 #define LINESPACE 0 /* additional pixel between each line */
 
diff --git a/st.c b/st.c
index 8bbb1a5..f288f2a 100644
--- a/st.c
+++ b/st.c
@@ -57,7 +57,6 @@ typedef Glyph* Line;
 
 typedef struct {
 	Glyph attr;  /* current char attributes */
-	char hidden;
 	int x;
 	int y;
 } TCursor;
@@ -79,6 +78,7 @@ typedef struct {
 	int col;    /* nb col */
 	Line* line; /* screen */
 	TCursor c;  /* cursor */
+	char hidec;
 	int top;    /* top    scroll limit */
 	int bot;    /* bottom scroll limit */
 	int mode;   /* terminal mode flags */
@@ -109,6 +109,7 @@ typedef struct {
 typedef struct {
 	unsigned long col[LEN(colorname)];
 	XFontStruct* font;
+	XFontStruct* bfont;
 	GC gc;
 } DC;
 
@@ -135,8 +136,11 @@ static void tnew(int, int);
 static void tnewline(void);
 static void tputc(char);
 static void tputs(char*, int);
+static void treset(void);
 static void tresize(int, int);
 static void tscroll(void);
+static void tscrollup(int);
+static void tscrolldown(int);
 static void tsetattr(int*, int);
 static void tsetchar(char);
 static void tsetscroll(int, int);
@@ -149,12 +153,11 @@ static void ttywrite(const char *, size_t);
 static unsigned long xgetcol(const char *);
 static void xclear(int, int, int, int);
 static void xcursor(int);
-static void xdrawc(int, int, Glyph);
 static void xinit(void);
 static void xscroll(void);
 
 static void expose(XEvent *);
-static char * kmap(KeySym);
+static char* kmap(KeySym);
 static void kpress(XEvent *);
 static void resize(XEvent *);
 
@@ -312,6 +315,18 @@ tcursor(int mode) {
 		term.c = c, tmoveto(c.x, c.y);
 }
 
+void
+treset(void) {
+	term.c.attr.mode = ATTR_NULL;
+	term.c.attr.fg = DefaultFG;
+	term.c.attr.bg = DefaultBG;
+	term.c.x = term.c.y = 0;
+	term.hidec = 0;
+	term.top = 0, term.bot = term.row - 1;
+	term.mode = MODE_WRAP;
+	tclearregion(0, 0, term.col-1, term.row-1);
+}
+
 void
 tnew(int col, int row) {   /* screen size */
 	term.row = row, term.col = col;
@@ -323,17 +338,19 @@ tnew(int col, int row) {   /* screen size */
 	term.c.attr.fg = DefaultFG;
 	term.c.attr.bg = DefaultBG;
 	term.c.x = term.c.y = 0;
-	term.c.hidden = 0;
+	term.hidec = 0;
 	/* allocate screen */
 	term.line = calloc(term.row, sizeof(Line));
 	for(row = 0 ; row < term.row; row++)
 		term.line[row] = calloc(term.col, sizeof(Glyph));
 }
 
+/* TODO: Replace with scrollup/scolldown */
 void
 tscroll(void) {
 	Line temp = term.line[term.top];
 	int i;
+	/* No dirty flag to set because of xscroll */
 	/* X stuff _before_ the line swapping (results in wrong line index) */
 	xscroll();
 	for(i = term.top; i < term.bot; i++)
@@ -342,6 +359,41 @@ tscroll(void) {
 	term.line[term.bot] = temp;
 }
 
+void
+tscrolldown (int n) {
+	int i;
+	Line temp;
+	
+	/* TODO: set dirty flag or scroll with some X func */
+	LIMIT(n, 0, term.bot-term.top+1);
+
+	for(i = 0; i < n; i++)
+		memset(term.line[term.bot-i], 0, term.col*sizeof(Glyph));
+   	
+	for(i = term.bot; i >= term.top+n; i--) {
+		temp = term.line[i];
+		term.line[i] = term.line[i-n];
+		term.line[i-n] = temp;
+	}
+}
+
+void
+tscrollup (int n) {
+	int i;
+	Line temp;
+	LIMIT(n, 0, term.bot-term.top+1);
+	
+	/* TODO: set dirty flag or scroll with some X func */
+	for(i = 0; i < n; i++)
+		memset(term.line[term.top+i], 0, term.col*sizeof(Glyph));
+	
+	 for(i = term.top; i <= term.bot-n; i++) { 
+		 temp = term.line[i];
+		 term.line[i] = term.line[i+n]; 
+		 term.line[i+n] = temp;
+	 }
+}
+
 void
 tnewline(void) {
 	int y = term.c.y + 1;
@@ -420,17 +472,20 @@ tsetchar(char c) {
 
 void
 tclearregion(int x1, int y1, int x2, int y2) {
-	int x, y;
+	int y, temp;
+
+	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);
 
-	/* XXX: could be optimized */
-	for(x = x1; x <= x2; x++)
-		for(y = y1; y <= y2; y++)
-			memset(&term.line[y][x], 0, sizeof(Glyph));
+	for(y = y1; y <= y2; y++)
+		memset(&term.line[y][x1], 0, sizeof(Glyph)*(x2-x1+1));
 
 	xclear(x1, y1, x2, y2);
 }
@@ -542,9 +597,6 @@ tsetattr(int *attr, int l) {
 		case 7: 
 			term.c.attr.mode |= ATTR_REVERSE;	
 			break;
-		case 8:
-			term.c.hidden = CURSOR_HIDE;
-			break;
 		case 22: 
 			term.c.attr.mode &= ~ATTR_BOLD;  
 			break;
@@ -565,6 +617,8 @@ tsetattr(int *attr, int l) {
 				term.c.attr.fg = attr[i] - 30;
 			else if(BETWEEN(attr[i], 40, 47))
 				term.c.attr.bg = attr[i] - 40;
+			else 
+				fprintf(stderr, "erresc: gfx attr %d unkown\n", attr[i]); 
 			break;
 		}
 	}
@@ -590,7 +644,7 @@ csihandle(void) {
 	switch(escseq.mode) {
 	default:
 	unknown:
-		printf("erresc: unknown sequence -- ");
+		printf("erresc: unknown csi ");
 		csidump();
 		/* die(""); */
 		break;
@@ -665,7 +719,14 @@ csihandle(void) {
 			break;
 		}
 		break;
-	case 'S': /* XXX: SU -- Scroll  line up (faked) */ 
+	case 'S': /* SU -- Scroll  line up */
+		DEFAULT(escseq.arg[0], 1);
+		tscrollup(escseq.arg[0]);
+		break;
+	case 'T': /* SD -- Scroll  line down */
+		DEFAULT(escseq.arg[0], 1);
+		tscrolldown(escseq.arg[0]);
+		break;
 	case 'L': /* IL -- Insert  blank lines */
 		DEFAULT(escseq.arg[0], 1);
 		tinsertblankline(escseq.arg[0]);
@@ -682,7 +743,7 @@ csihandle(void) {
 			case 12: /* att610 -- Stop blinking cursor (IGNORED) */
 				break;
 			case 25:
-				term.c.hidden = 1;
+				term.hidec = 1;
 				break;
 			case 1048: /* XXX: no alt. screen to erase/save */
 			case 1049:
@@ -731,7 +792,7 @@ csihandle(void) {
 			case 12: /* att610 -- Start blinking cursor (IGNORED) */
 				break;
 			case 25:
-				term.c.hidden = 0;
+				term.hidec = 0;
 				break;
 			case 1048: 
 			case 1049: /* XXX: no alt. screen to erase/save */
@@ -866,11 +927,15 @@ tputc(char c) {
 				break;
 			case 'M': /* RI -- Reverse index */
 				if(term.c.y == term.top)
-					tinsertblankline(1);
+					tscrolldown(1);
 				else
 					tmoveto(term.c.x, term.c.y-1);
 				term.esc = 0;
 				break;
+			case 'c': /* RIS -- Reset to inital state */
+				treset();
+				term.esc = 0;
+				break;
 			case '=': /* DECPAM */
 				term.mode |= MODE_APPKEYPAD;
 				term.esc = 0;
@@ -888,7 +953,7 @@ tputc(char c) {
 				term.esc = 0;
 				break;
 			default:
-				fprintf(stderr, "erresc: unknown sequence ESC %02X '%c'\n", c, isprint(c)?c:'.');
+				fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n", c, isprint(c)?c:'.');
 				term.esc = 0;
 			}
 		}
@@ -991,8 +1056,6 @@ xscroll(void) {
 
 void
 xinit(void) {
-	XGCValues values;
-	unsigned long valuemask;
 	XClassHint chint;
 	XWMHints wmhint;
 	XSizeHints shint;
@@ -1005,9 +1068,10 @@ xinit(void) {
 		die("Can't open display\n");
 	
 	/* font */
-	if(!(dc.font = XLoadQueryFont(xw.dis, FONT)))
-		die("Can't load font %s\n", FONT);
+	if(!(dc.font = XLoadQueryFont(xw.dis, FONT)) || !(dc.bfont = XLoadQueryFont(xw.dis, BOLDFONT)))
+		die("Can't load font %s\n", dc.font ? BOLDFONT : FONT);
 
+	/* XXX: Assuming same size for bold font */
 	xw.cw = dc.font->max_bounds.rbearing - dc.font->min_bounds.lbearing;
 	xw.ch = dc.font->ascent + dc.font->descent + LINESPACE;
 
@@ -1027,10 +1091,7 @@ xinit(void) {
 			dc.col[DefaultBG],
 			dc.col[DefaultBG]);
 	/* gc */
-	values.foreground = XWhitePixel(xw.dis, xw.scr);
-	values.font = dc.font->fid;
-	valuemask = GCForeground | GCFont;
-	dc.gc = XCreateGC(xw.dis, xw.win, valuemask, &values);
+	dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL);
 	XMapWindow(xw.dis, xw.win);
 	/* wm stuff */
 	chint.res_name = TNAME, chint.res_class = TNAME;
@@ -1060,29 +1121,14 @@ xdraws(char *s, Glyph base, int x, int y, int len) {
 	if(base.mode & ATTR_GFX)
 		for(i = 0; i < len; i++)
 			s[i] = gfx[s[i]];
-	
+
+	XSetFont(xw.dis, dc.gc, base.mode & ATTR_BOLD ? dc.bfont->fid : dc.font->fid);	
 	XDrawImageString(xw.dis, xw.win, dc.gc, winx, winy, s, len);
 	
 	if(base.mode & ATTR_UNDERLINE)
 		XDrawLine(xw.dis, xw.win, dc.gc, winx, winy+1, winx+width-1, winy+1);
 }
 
-void
-xdrawc(int x, int y, Glyph g) {
-	XRectangle r = { x * xw.cw, y * xw.ch, xw.cw, xw.ch };
-	unsigned long xfg, xbg;
-
-	/* reverse video */
-	if(g.mode & ATTR_REVERSE)
-		xfg = dc.col[g.bg], xbg = dc.col[g.fg];
-	else
-		xfg = dc.col[g.fg], xbg = dc.col[g.bg];
-	/* background */
-	XSetBackground(xw.dis, dc.gc, xbg);
-	XSetForeground(xw.dis, dc.gc, xfg);
-	XDrawImageString(xw.dis, xw.win, dc.gc, r.x, r.y+dc.font->ascent, &g.c, 1);
-}
-
 void
 xcursor(int mode) {
 	static int oldx = 0;
@@ -1094,24 +1140,54 @@ xcursor(int mode) {
 	
 	if(term.line[term.c.y][term.c.x].state & GLYPH_SET)
 		g.c = term.line[term.c.y][term.c.x].c;
+
 	/* remove the old cursor */
 	if(term.line[oldy][oldx].state & GLYPH_SET)
-		xdrawc(oldx, oldy, term.line[oldy][oldx]);
-	else 
+		xdraws(&term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, 1);
+	else
 		xclear(oldx, oldy, oldx, oldy);
+	
 	/* draw the new one */
 	if(mode == CURSOR_DRAW) {
-		xdrawc(term.c.x, term.c.y, g);
+		xdraws(&g.c, g, term.c.x, term.c.y, 1);
 		oldx = term.c.x, oldy = term.c.y;
 	}
 }
 
+
+#ifdef DEBUG
+/* basic drawing routines */
+void
+xdrawc(int x, int y, Glyph g) {
+	XRectangle r = { x * xw.cw, y * xw.ch, xw.cw, xw.ch };
+	XSetBackground(xw.dis, dc.gc, dc.col[g.bg]);
+	XSetForeground(xw.dis, dc.gc, dc.col[g.fg]);
+	XSetFont(xw.dis, dc.gc, g.mode & ATTR_BOLD ? dc.bfont->fid : dc.font->fid);
+	XDrawImageString(xw.dis, xw.win, dc.gc, r.x, r.y+dc.font->ascent, &g.c, 1);
+}
+
+void
+draw_(int dummy) {
+	int x, y;
+
+	xclear(0, 0, term.col-1, term.row-1);
+	for(y = 0; y < term.row; y++)
+		for(x = 0; x < term.col; x++)
+			if(term.line[y][x].state & GLYPH_SET)
+				xdrawc(x, y, term.line[y][x]);
+
+	if(!term.hidec)
+		xcursor(CURSOR_DRAW);
+}
+#endif
+
 void
 draw(int redraw_all) {
 	int i, x, y, ox;
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
 	
+	/* XXX: optimize with GLYPH_DIRTY hint */
 	for(y = 0; y < term.row; y++) {
 		base = term.line[y][0];
 		i = ox = 0;
@@ -1129,8 +1205,7 @@ draw(int redraw_all) {
 		}
 		xdraws(buf, base, ox, y, i);
 	}
-	if(!term.c.hidden)
-		xcursor(CURSOR_DRAW);
+	xcursor(term.hidec ? CURSOR_HIDE : CURSOR_DRAW);
 }
 
 void
@@ -1179,7 +1254,7 @@ kpress(XEvent *ev) {
 			break;
 		case XK_Insert:
 			if(shift)
-				/* XXX: paste X clipboard */;
+				draw(1), puts("draw!")/* XXX: paste X clipboard */;
 			break;
 		default:
 			fprintf(stderr, "errkey: %d\n", (int)ksym);

From b3b7ffce5f1cb1d82aa26df976f0316d89d15d7f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Mon, 15 Mar 2010 23:56:38 +0100
Subject: [PATCH 0077/1146] double-buffering added using pixmap (finally).

results in a lot of simplification :
	- no more dirty flags (perf are good enough).
	- no more ugly gfx call in emulation functions.
LINESPACE removed from config.h.
BORDER is now handled correctly.
---
 config.h |  3 +--
 st.c     | 69 ++++++++++++++++++++------------------------------------
 2 files changed, 25 insertions(+), 47 deletions(-)
 mode change 100644 => 100755 st.c

diff --git a/config.h b/config.h
index f881571..185b3ff 100644
--- a/config.h
+++ b/config.h
@@ -3,8 +3,7 @@
 
 #define FONT "6x13"
 #define BOLDFONT FONT"bold"
-#define BORDER 3
-#define LINESPACE 0 /* additional pixel between each line */
+#define BORDER 2
 
 /* Terminal colors */
 static const char *colorname[] = {
diff --git a/st.c b/st.c
old mode 100644
new mode 100755
index f288f2a..deb1610
--- a/st.c
+++ b/st.c
@@ -91,6 +91,7 @@ typedef struct {
 typedef struct {
 	Display* dis;
 	Window win;
+	Pixmap buf;
 	int scr;
 	int w;  /* window width  */
 	int h;  /* window height */
@@ -154,7 +155,6 @@ static unsigned long xgetcol(const char *);
 static void xclear(int, int, int, int);
 static void xcursor(int);
 static void xinit(void);
-static void xscroll(void);
 
 static void expose(XEvent *);
 static char* kmap(KeySym);
@@ -215,7 +215,7 @@ execsh(void) {
 
 void
 xbell(void) { /* visual bell */
-	XRectangle r = { 0, 0, xw.w, xw.h };
+	XRectangle r = { BORDER, BORDER, xw.w, xw.h };
 	XSetForeground(xw.dis, dc.gc, dc.col[BellCol]);
 	XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1);
 	/* usleep(30000); */
@@ -350,9 +350,7 @@ void
 tscroll(void) {
 	Line temp = term.line[term.top];
 	int i;
-	/* No dirty flag to set because of xscroll */
-	/* X stuff _before_ the line swapping (results in wrong line index) */
-	xscroll();
+
 	for(i = term.top; i < term.bot; i++)
 		term.line[i] = term.line[i+1];
 	memset(temp, 0, sizeof(Glyph) * term.col);
@@ -364,7 +362,6 @@ tscrolldown (int n) {
 	int i;
 	Line temp;
 	
-	/* TODO: set dirty flag or scroll with some X func */
 	LIMIT(n, 0, term.bot-term.top+1);
 
 	for(i = 0; i < n; i++)
@@ -383,7 +380,6 @@ tscrollup (int n) {
 	Line temp;
 	LIMIT(n, 0, term.bot-term.top+1);
 	
-	/* TODO: set dirty flag or scroll with some X func */
 	for(i = 0; i < n; i++)
 		memset(term.line[term.top+i], 0, term.col*sizeof(Glyph));
 	
@@ -467,7 +463,7 @@ void
 tsetchar(char c) {
 	term.line[term.c.y][term.c.x] = term.c.attr;
 	term.line[term.c.y][term.c.x].c = c;
-	term.line[term.c.y][term.c.x].state |= GLYPH_SET | GLYPH_DIRTY;
+	term.line[term.c.y][term.c.x].state |= GLYPH_SET;
 }
 
 void
@@ -486,8 +482,6 @@ tclearregion(int x1, int y1, int x2, int y2) {
 
 	for(y = y1; y <= y2; y++)
 		memset(&term.line[y][x1], 0, sizeof(Glyph)*(x2-x1+1));
-
-	xclear(x1, y1, x2, y2);
 }
 
 void
@@ -518,13 +512,6 @@ tinsertblank(int n) {
 	tclearregion(src, term.c.y, dst, term.c.y);
 }
 
-void
-tsetlinestate(int n, int state) {
-	int i;
-	for(i = 0; i < term.col; i++)
-		term.line[n][i].state |= state;
-}
-
 void
 tinsertblankline(int n) {
 	int i;
@@ -546,8 +533,6 @@ tinsertblankline(int n) {
 		term.line[i-n] = blank;
 		/* blank it */
 		memset(blank, 0, term.col * sizeof(Glyph));
-		tsetlinestate(i, GLYPH_DIRTY);
-		tsetlinestate(i-n, GLYPH_DIRTY);
 	}
 }
 
@@ -572,8 +557,6 @@ tdeleteline(int n) {
 		term.line[i+n] = blank;
 		/* blank it */
 		memset(blank, 0, term.col * sizeof(Glyph));
-		tsetlinestate(i, GLYPH_DIRTY);
-		tsetlinestate(i-n, GLYPH_DIRTY);
 	}
 }
 
@@ -1037,21 +1020,10 @@ xgetcol(const char *s) {
 
 void
 xclear(int x1, int y1, int x2, int y2) {
-	XClearArea(xw.dis, xw.win, 
-			x1 * xw.cw, y1 * xw.ch, 
-			(x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch, 
-			False);
-}
-
-void
-xscroll(void) {
-	int srcy = (term.top+1) * xw.ch;
-	int dsty = term.top * xw.ch;
-	int height = (term.bot-term.top) * xw.ch;
-
-	xcursor(CURSOR_HIDE);
-	XCopyArea(xw.dis, xw.win, xw.win, dc.gc, 0, srcy, xw.w, height, 0, dsty);
-	xclear(0, term.bot, term.col-1, term.bot);
+	XSetForeground(xw.dis, dc.gc, dc.col[DefaultBG]);
+	XFillRectangle(xw.dis, xw.buf, dc.gc,
+				   x1 * xw.cw, y1 * xw.ch, 
+				   (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
 }
 
 void
@@ -1073,7 +1045,7 @@ xinit(void) {
 
 	/* XXX: Assuming same size for bold font */
 	xw.cw = dc.font->max_bounds.rbearing - dc.font->min_bounds.lbearing;
-	xw.ch = dc.font->ascent + dc.font->descent + LINESPACE;
+	xw.ch = dc.font->ascent + dc.font->descent;
 
 	/* colors */
 	for(i = 0; i < LEN(colorname); i++)
@@ -1085,11 +1057,11 @@ xinit(void) {
 	/* windows */
 	xw.h = term.row * xw.ch;
 	xw.w = term.col * xw.cw;
-	/* XXX: this BORDER is useless after the first resize, handle it in xdraws() */
 	xw.win = XCreateSimpleWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0,
-			xw.w, xw.h, BORDER, 
+			xw.w + 2*BORDER, xw.h + 2*BORDER, 0, 
 			dc.col[DefaultBG],
 			dc.col[DefaultBG]);
+	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.w, xw.h, XDefaultDepth(xw.dis, xw.scr));
 	/* gc */
 	dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL);
 	XMapWindow(xw.dis, xw.win);
@@ -1097,11 +1069,13 @@ xinit(void) {
 	chint.res_name = TNAME, chint.res_class = TNAME;
 	wmhint.input = 1, wmhint.flags = InputHint;
 	shint.height_inc = xw.ch, shint.width_inc = xw.cw;
-	shint.height = xw.h, shint.width = xw.w;
+	shint.height = xw.h + 2*BORDER, shint.width = xw.w + 2*BORDER;
 	shint.flags = PSize | PResizeInc;
 	XSetWMProperties(xw.dis, xw.win, NULL, NULL, &args[0], 0, &shint, &wmhint, &chint);
 	XStoreName(xw.dis, xw.win, TNAME);
+	XFillRectangle(xw.dis, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
 	XSync(xw.dis, 0);
+
 }
 
 void
@@ -1123,10 +1097,10 @@ xdraws(char *s, Glyph base, int x, int y, int len) {
 			s[i] = gfx[s[i]];
 
 	XSetFont(xw.dis, dc.gc, base.mode & ATTR_BOLD ? dc.bfont->fid : dc.font->fid);	
-	XDrawImageString(xw.dis, xw.win, dc.gc, winx, winy, s, len);
+	XDrawImageString(xw.dis, xw.buf, dc.gc, winx, winy, s, len);
 	
 	if(base.mode & ATTR_UNDERLINE)
-		XDrawLine(xw.dis, xw.win, dc.gc, winx, winy+1, winx+width-1, winy+1);
+		XDrawLine(xw.dis, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);
 }
 
 void
@@ -1163,7 +1137,7 @@ xdrawc(int x, int y, Glyph g) {
 	XSetBackground(xw.dis, dc.gc, dc.col[g.bg]);
 	XSetForeground(xw.dis, dc.gc, dc.col[g.fg]);
 	XSetFont(xw.dis, dc.gc, g.mode & ATTR_BOLD ? dc.bfont->fid : dc.font->fid);
-	XDrawImageString(xw.dis, xw.win, dc.gc, r.x, r.y+dc.font->ascent, &g.c, 1);
+	XDrawImageString(xw.dis, xw.buf, dc.gc, r.x, r.y+dc.font->ascent, &g.c, 1);
 }
 
 void
@@ -1178,6 +1152,8 @@ draw_(int dummy) {
 
 	if(!term.hidec)
 		xcursor(CURSOR_DRAW);
+	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.w, xw.h, BORDER, BORDER);
+	XFlush(xw.dis);
 }
 #endif
 
@@ -1187,7 +1163,6 @@ draw(int redraw_all) {
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
 	
-	/* XXX: optimize with GLYPH_DIRTY hint */
 	for(y = 0; y < term.row; y++) {
 		base = term.line[y][0];
 		i = ox = 0;
@@ -1206,6 +1181,8 @@ draw(int redraw_all) {
 		xdraws(buf, base, ox, y, i);
 	}
 	xcursor(term.hidec ? CURSOR_HIDE : CURSOR_DRAW);
+	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.w, xw.h, BORDER, BORDER);
+	XFlush(xw.dis);
 }
 
 void
@@ -1273,6 +1250,8 @@ resize(XEvent *e) {
 		ttyresize(col, row);
 		xw.w = e->xconfigure.width;
 		xw.h = e->xconfigure.height;
+		XFreePixmap(xw.dis, xw.buf);
+		xw.buf = XCreatePixmap(xw.dis, xw.win, xw.w, xw.h, XDefaultDepth(xw.dis, xw.scr));
 		draw(SCREEN_REDRAW);
 	}
 }
@@ -1285,7 +1264,7 @@ run(void) {
 
 	running = 1;
 	XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNotifyMask);
-	XResizeWindow(xw.dis, xw.win, xw.w , xw.h); /* fix resize bug in wmii (?) */
+	XResizeWindow(xw.dis, xw.win, xw.w+2*BORDER, xw.h+2*BORDER); /* fix resize bug in wmii (?) */
 
 	while(running) {
 		FD_ZERO(&rfd);

From d01c55c9ab58588d98239c515aa8db6443ae75ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Mon, 26 Apr 2010 19:20:53 +0200
Subject: [PATCH 0078/1146] use SHELL environment variable (thx Thomas Adam)

---
 config.h |  1 -
 st.c     | 10 ++++++----
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/config.h b/config.h
index 185b3ff..0b0b36d 100644
--- a/config.h
+++ b/config.h
@@ -1,4 +1,3 @@
-#define SHELL "/bin/bash"
 #define TAB    8
 
 #define FONT "6x13"
diff --git a/st.c b/st.c
index deb1610..ee79a33 100755
--- a/st.c
+++ b/st.c
@@ -208,9 +208,12 @@ die(const char *errstr, ...) {
 
 void
 execsh(void) {
-	char *args[3] = {SHELL, "-i", NULL};
+	char *shell = getenv("SHELL");
+	if(!shell)
+		shell = "/bin/sh";
+	char *args[3] = {shell, "-i", NULL};
 	putenv("TERM=" TNAME);
-	execvp(SHELL, args);
+	execvp(shell, args);
 }
 
 void
@@ -844,7 +847,6 @@ tputtab(void) {
 
 void
 tputc(char c) {
-	/* dump(c); */
 	if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {
 			escseq.buf[escseq.len++] = c;
@@ -1277,7 +1279,7 @@ run(void) {
 		}
 		if(FD_ISSET(cmdfd, &rfd)) {
 			ttyread();
-			draw(SCREEN_UPDATE);
+			draw(SCREEN_UPDATE); 
 		}
 		while(XPending(xw.dis)) {
 			XNextEvent(xw.dis, &ev);

From 476f93794acc36ea69dfd33551e311863c8afc9a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Tue, 27 Apr 2010 00:04:29 +0200
Subject: [PATCH 0079/1146] little clean up.

---
 st.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index ee79a33..ff43706 100755
--- a/st.c
+++ b/st.c
@@ -208,12 +208,10 @@ die(const char *errstr, ...) {
 
 void
 execsh(void) {
-	char *shell = getenv("SHELL");
-	if(!shell)
-		shell = "/bin/sh";
-	char *args[3] = {shell, "-i", NULL};
+	char *args[3] = {getenv("SHELL"), "-i", NULL};
+	DEFAULT(args[0], "/bin/sh"); /* default shell if getenv() failed */
 	putenv("TERM=" TNAME);
-	execvp(shell, args);
+	execvp(args[0], args);
 }
 
 void

From 2f5ebe0a4d71aea0bb3aa0e500765a402e4a96f4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 2 Jun 2010 16:01:30 +0200
Subject: [PATCH 0080/1146] rearranged code, resize fixed.

---
 st.c | 106 ++++++++++++++++++++++++++++++++---------------------------
 1 file changed, 58 insertions(+), 48 deletions(-)

diff --git a/st.c b/st.c
index ff43706..db5e04f 100755
--- a/st.c
+++ b/st.c
@@ -56,7 +56,7 @@ typedef struct {
 typedef Glyph* Line;
 
 typedef struct {
-	Glyph attr;  /* current char attributes */
+	Glyph attr;	 /* current char attributes */
 	int x;
 	int y;
 } TCursor;
@@ -65,24 +65,24 @@ typedef struct {
 /* ESC '[' [[ []  [;]] ] */
 typedef struct {
 	char buf[ESC_BUF_SIZ]; /* raw string */
-	int len;               /* raw string length */
+	int len;			   /* raw string length */
 	char priv;
 	int arg[ESC_ARG_SIZ];
-	int narg;              /* nb of args */
+	int narg;			   /* nb of args */
 	char mode;
 } CSIEscape;
 
 /* Internal representation of the screen */
 typedef struct {
-	int row;    /* nb row */  
-	int col;    /* nb col */
+	int row;	/* nb row */  
+	int col;	/* nb col */
 	Line* line; /* screen */
-	TCursor c;  /* cursor */
+	TCursor c;	/* cursor */
 	char hidec;
-	int top;    /* top    scroll limit */
-	int bot;    /* bottom scroll limit */
-	int mode;   /* terminal mode flags */
-	int esc;    /* escape state flags */
+	int top;	/* top	  scroll limit */
+	int bot;	/* bottom scroll limit */
+	int mode;	/* terminal mode flags */
+	int esc;	/* escape state flags */
 	char title[ESC_TITLE_SIZ];
 	int titlelen;
 } Term;
@@ -93,8 +93,10 @@ typedef struct {
 	Window win;
 	Pixmap buf;
 	int scr;
-	int w;  /* window width  */
-	int h;  /* window height */
+	int w;	/* window width	 */
+	int h;	/* window height */
+	int bufw; /* pixmap width  */
+	int bufh; /* pixmap height */
 	int ch; /* char height */
 	int cw; /* char width  */
 } XWindow; 
@@ -216,7 +218,7 @@ execsh(void) {
 
 void
 xbell(void) { /* visual bell */
-	XRectangle r = { BORDER, BORDER, xw.w, xw.h };
+	XRectangle r = { BORDER, BORDER, xw.bufw, xw.bufh };
 	XSetForeground(xw.dis, dc.gc, dc.col[BellCol]);
 	XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1);
 	/* usleep(30000); */
@@ -367,7 +369,7 @@ tscrolldown (int n) {
 
 	for(i = 0; i < n; i++)
 		memset(term.line[term.bot-i], 0, term.col*sizeof(Glyph));
-   	
+	
 	for(i = term.bot; i >= term.top+n; i--) {
 		temp = term.line[i];
 		term.line[i] = term.line[i-n];
@@ -582,7 +584,7 @@ tsetattr(int *attr, int l) {
 			term.c.attr.mode |= ATTR_REVERSE;	
 			break;
 		case 22: 
-			term.c.attr.mode &= ~ATTR_BOLD;  
+			term.c.attr.mode &= ~ATTR_BOLD;	 
 			break;
 		case 24: 
 			term.c.attr.mode &= ~ATTR_UNDERLINE;
@@ -665,7 +667,7 @@ csihandle(void) {
 	case 'G': /* CHA -- Move to  */
 	case '`': /* XXX: HPA -- same? */
 		DEFAULT(escseq.arg[0], 1);
-     	tmoveto(escseq.arg[0]-1, term.c.y);
+		tmoveto(escseq.arg[0]-1, term.c.y);
 		break;
 	case 'H': /* CUP -- Move to   */
 	case 'f': /* XXX: HVP -- same? */
@@ -1026,12 +1028,23 @@ xclear(int x1, int y1, int x2, int y2) {
 				   (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
 }
 
+void
+xhints(void)
+{
+	XClassHint chint = {TNAME, TNAME};
+	XWMHints wmhint	 = {.flags = InputHint, .input = 1};
+	XSizeHints shint = { 
+		.flags = PSize | PResizeInc,
+		.height = xw.h, /* XXX: doesn't seem to work, see run() */
+		.width = xw.w,
+		.height_inc = xw.ch,
+		.width_inc = xw.cw,
+	};
+	XSetWMProperties(xw.dis, xw.win, NULL, NULL, NULL, 0, &shint, &wmhint, &chint);
+}
+
 void
 xinit(void) {
-	XClassHint chint;
-	XWMHints wmhint;
-	XSizeHints shint;
-	char *args[] = {NULL};
 	int i;
 
 	xw.dis = XOpenDisplay(NULL);
@@ -1055,27 +1068,21 @@ xinit(void) {
 	term.c.attr.bg = DefaultBG;
 	term.c.attr.mode = ATTR_NULL;
 	/* windows */
-	xw.h = term.row * xw.ch;
-	xw.w = term.col * xw.cw;
+	xw.h = term.row * xw.ch + 2*BORDER;
+	xw.w = term.col * xw.cw + 2*BORDER;
 	xw.win = XCreateSimpleWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0,
-			xw.w + 2*BORDER, xw.h + 2*BORDER, 0, 
+			xw.w, xw.h, 0, 
 			dc.col[DefaultBG],
 			dc.col[DefaultBG]);
-	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.w, xw.h, XDefaultDepth(xw.dis, xw.scr));
+	xw.bufw = xw.w - 2*BORDER;
+	xw.bufh = xw.h - 2*BORDER;
+	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
 	/* gc */
 	dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL);
 	XMapWindow(xw.dis, xw.win);
-	/* wm stuff */
-	chint.res_name = TNAME, chint.res_class = TNAME;
-	wmhint.input = 1, wmhint.flags = InputHint;
-	shint.height_inc = xw.ch, shint.width_inc = xw.cw;
-	shint.height = xw.h + 2*BORDER, shint.width = xw.w + 2*BORDER;
-	shint.flags = PSize | PResizeInc;
-	XSetWMProperties(xw.dis, xw.win, NULL, NULL, &args[0], 0, &shint, &wmhint, &chint);
+	xhints();
 	XStoreName(xw.dis, xw.win, TNAME);
-	XFillRectangle(xw.dis, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
 	XSync(xw.dis, 0);
-
 }
 
 void
@@ -1152,7 +1159,7 @@ draw_(int dummy) {
 
 	if(!term.hidec)
 		xcursor(CURSOR_DRAW);
-	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.w, xw.h, BORDER, BORDER);
+	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
 	XFlush(xw.dis);
 }
 #endif
@@ -1181,7 +1188,7 @@ draw(int redraw_all) {
 		xdraws(buf, base, ox, y, i);
 	}
 	xcursor(term.hidec ? CURSOR_HIDE : CURSOR_DRAW);
-	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.w, xw.h, BORDER, BORDER);
+	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
 	XFlush(xw.dis);
 }
 
@@ -1209,7 +1216,7 @@ kpress(XEvent *ev) {
 	int meta;
 	int shift;
 
-	meta  = e->state & Mod1Mask;
+	meta = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
 	len = XLookupString(e, buf, sizeof(buf), &ksym, NULL);
 
@@ -1242,18 +1249,21 @@ kpress(XEvent *ev) {
 void
 resize(XEvent *e) {
 	int col, row;
-	col = e->xconfigure.width / xw.cw;
-	row = e->xconfigure.height / xw.ch;
 	
-	if(term.col != col || term.row != row) {
-		tresize(col, row);
-		ttyresize(col, row);
-		xw.w = e->xconfigure.width;
-		xw.h = e->xconfigure.height;
-		XFreePixmap(xw.dis, xw.buf);
-		xw.buf = XCreatePixmap(xw.dis, xw.win, xw.w, xw.h, XDefaultDepth(xw.dis, xw.scr));
-		draw(SCREEN_REDRAW);
-	}
+	if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
+		return;
+	
+	xw.w = e->xconfigure.width;
+	xw.h = e->xconfigure.height;
+	xw.bufw = xw.w - 2*BORDER;
+	xw.bufh = xw.h - 2*BORDER;
+	col = xw.bufw / xw.cw;
+	row = xw.bufh / xw.ch;
+	tresize(col, row);
+	ttyresize(col, row);
+	XFreePixmap(xw.dis, xw.buf);
+	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
+	draw(SCREEN_REDRAW);
 }
 
 void
@@ -1264,7 +1274,7 @@ run(void) {
 
 	running = 1;
 	XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNotifyMask);
-	XResizeWindow(xw.dis, xw.win, xw.w+2*BORDER, xw.h+2*BORDER); /* fix resize bug in wmii (?) */
+	XResizeWindow(xw.dis, xw.win, xw.w, xw.h); /* XXX: fix resize bug in wmii (?) */
 
 	while(running) {
 		FD_ZERO(&rfd);

From 2f96cfeadaac871456e2e2acae3b997c23c93d63 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 3 Jun 2010 23:14:37 +0200
Subject: [PATCH 0081/1146] added PBaseSize hint and set default title to "st".

---
 st.c | 33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index db5e04f..a571a28 100755
--- a/st.c
+++ b/st.c
@@ -39,7 +39,8 @@
 
 /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
 enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 };
-enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HIDE, CURSOR_DRAW, CURSOR_SAVE, CURSOR_LOAD };
+enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HIDE, CURSOR_DRAW, 
+       CURSOR_SAVE, CURSOR_LOAD };
 enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
 enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4 };
 enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
@@ -879,7 +880,7 @@ tputc(char c) {
 				printf("esc unhandled charset: ESC ( %c\n", c);
 			}
 			term.esc = 0;
-		} else {		
+		} else {
 			switch(c) {
 			case '[':
 				term.esc |= ESC_CSI;
@@ -972,7 +973,7 @@ tputc(char c) {
 }
 
 void
-tputs(char *s, int len) { 
+tputs(char *s, int len) {
 	for(; len > 0; len--)
 		tputc(*s++);
 }
@@ -1024,8 +1025,8 @@ void
 xclear(int x1, int y1, int x2, int y2) {
 	XSetForeground(xw.dis, dc.gc, dc.col[DefaultBG]);
 	XFillRectangle(xw.dis, xw.buf, dc.gc,
-				   x1 * xw.cw, y1 * xw.ch, 
-				   (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
+	               x1 * xw.cw, y1 * xw.ch,
+	               (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
 }
 
 void
@@ -1033,12 +1034,14 @@ xhints(void)
 {
 	XClassHint chint = {TNAME, TNAME};
 	XWMHints wmhint	 = {.flags = InputHint, .input = 1};
-	XSizeHints shint = { 
-		.flags = PSize | PResizeInc,
-		.height = xw.h, /* XXX: doesn't seem to work, see run() */
+	XSizeHints shint = {
+		.flags = PSize | PResizeInc | PBaseSize,
+		.height = xw.h,
 		.width = xw.w,
 		.height_inc = xw.ch,
 		.width_inc = xw.cw,
+		.base_height = 2*BORDER,
+		.base_width = 2*BORDER,
 	};
 	XSetWMProperties(xw.dis, xw.win, NULL, NULL, NULL, 0, &shint, &wmhint, &chint);
 }
@@ -1071,7 +1074,7 @@ xinit(void) {
 	xw.h = term.row * xw.ch + 2*BORDER;
 	xw.w = term.col * xw.cw + 2*BORDER;
 	xw.win = XCreateSimpleWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0,
-			xw.w, xw.h, 0, 
+			xw.w, xw.h, 0,
 			dc.col[DefaultBG],
 			dc.col[DefaultBG]);
 	xw.bufw = xw.w - 2*BORDER;
@@ -1081,7 +1084,7 @@ xinit(void) {
 	dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL);
 	XMapWindow(xw.dis, xw.win);
 	xhints();
-	XStoreName(xw.dis, xw.win, TNAME);
+	XStoreName(xw.dis, xw.win, "st");
 	XSync(xw.dis, 0);
 }
 
@@ -1103,7 +1106,7 @@ xdraws(char *s, Glyph base, int x, int y, int len) {
 		for(i = 0; i < len; i++)
 			s[i] = gfx[s[i]];
 
-	XSetFont(xw.dis, dc.gc, base.mode & ATTR_BOLD ? dc.bfont->fid : dc.font->fid);	
+	XSetFont(xw.dis, dc.gc, base.mode & ATTR_BOLD ? dc.bfont->fid : dc.font->fid);
 	XDrawImageString(xw.dis, xw.buf, dc.gc, winx, winy, s, len);
 	
 	if(base.mode & ATTR_UNDERLINE)
@@ -1135,7 +1138,6 @@ xcursor(int mode) {
 	}
 }
 
-
 #ifdef DEBUG
 /* basic drawing routines */
 void
@@ -1148,7 +1150,7 @@ xdrawc(int x, int y, Glyph g) {
 }
 
 void
-draw_(int dummy) {
+draw(int dummy) {
 	int x, y;
 
 	xclear(0, 0, term.col-1, term.row-1);
@@ -1162,8 +1164,9 @@ draw_(int dummy) {
 	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
 	XFlush(xw.dis);
 }
-#endif
 
+#else
+/* optimized drawing routine */
 void
 draw(int redraw_all) {
 	int i, x, y, ox;
@@ -1192,6 +1195,8 @@ draw(int redraw_all) {
 	XFlush(xw.dis);
 }
 
+#endif
+
 void
 expose(XEvent *ev) {
 	draw(SCREEN_REDRAW);

From 499c70cda048e9d62ab9085efb3a6d484c64bf37 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 8 Jul 2010 16:31:41 +0200
Subject: [PATCH 0082/1146] fixed background color bug (thx Devin J. Pohly).

---
 st.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index a571a28..6b525c3 100755
--- a/st.c
+++ b/st.c
@@ -597,7 +597,7 @@ tsetattr(int *attr, int l) {
 			term.c.attr.fg = DefaultFG;
 			break;
 		case 49:
-			term.c.attr.fg = DefaultBG;
+			term.c.attr.bg = DefaultBG;
 			break;
 		default:
 			if(BETWEEN(attr[i], 30, 37))
@@ -1032,9 +1032,9 @@ xclear(int x1, int y1, int x2, int y2) {
 void
 xhints(void)
 {
-	XClassHint chint = {TNAME, TNAME};
-	XWMHints wmhint	 = {.flags = InputHint, .input = 1};
-	XSizeHints shint = {
+	XClassHint class = {TNAME, TNAME};
+	XWMHints wm = {.flags = InputHint, .input = 1};
+	XSizeHints size = {
 		.flags = PSize | PResizeInc | PBaseSize,
 		.height = xw.h,
 		.width = xw.w,
@@ -1043,7 +1043,7 @@ xhints(void)
 		.base_height = 2*BORDER,
 		.base_width = 2*BORDER,
 	};
-	XSetWMProperties(xw.dis, xw.win, NULL, NULL, NULL, 0, &shint, &wmhint, &chint);
+	XSetWMProperties(xw.dis, xw.win, NULL, NULL, NULL, 0, &size, &wm, &class);
 }
 
 void

From 9e8f5f1348e3a38d5c0d90bddcf40c9c03caa098 Mon Sep 17 00:00:00 2001
From: "pancake@nopcode.org" 
Date: Thu, 8 Jul 2010 17:34:02 +0200
Subject: [PATCH 0083/1146] fix gcc warnings

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 6b525c3..c64c25e 100755
--- a/st.c
+++ b/st.c
@@ -1104,7 +1104,7 @@ xdraws(char *s, Glyph base, int x, int y, int len) {
 	
 	if(base.mode & ATTR_GFX)
 		for(i = 0; i < len; i++)
-			s[i] = gfx[s[i]];
+			s[i] = gfx[(int)s[i]];
 
 	XSetFont(xw.dis, dc.gc, base.mode & ATTR_BOLD ? dc.bfont->fid : dc.font->fid);
 	XDrawImageString(xw.dis, xw.buf, dc.gc, winx, winy, s, len);
@@ -1225,7 +1225,7 @@ kpress(XEvent *ev) {
 	shift = e->state & ShiftMask;
 	len = XLookupString(e, buf, sizeof(buf), &ksym, NULL);
 
-	if(customkey = kmap(ksym))
+	if((customkey = kmap(ksym)))
 		ttywrite(customkey, strlen(customkey));
 	else if(len > 0) {
 		buf[sizeof(buf)-1] = '\0';

From 10e49a0505a250fc78c41842d93eb2a0abaf4c93 Mon Sep 17 00:00:00 2001
From: Anselm R Garbe 
Date: Sat, 24 Jul 2010 12:09:14 +0100
Subject: [PATCH 0084/1146] applied Devin J Pohly's st color info patches,
 thanks Devin!

---
 Makefile |  1 +
 config.h | 22 +++++++++++-----
 st.c     | 80 ++++++++++++++++++++++++++++++++++++++++++++++----------
 st.info  | 12 ++++-----
 4 files changed, 88 insertions(+), 27 deletions(-)
 mode change 100755 => 100644 st.c

diff --git a/Makefile b/Makefile
index 9ec8d21..14da7a5 100644
--- a/Makefile
+++ b/Makefile
@@ -42,6 +42,7 @@ install: all
 	@cp -f st ${DESTDIR}${PREFIX}/bin
 	@chmod 755 ${DESTDIR}${PREFIX}/bin/st
 	@tic st.info
+	@tic st-256color.info
 
 uninstall:
 	@echo removing executable file from ${DESTDIR}${PREFIX}/bin
diff --git a/config.h b/config.h
index 0b0b36d..aee8057 100644
--- a/config.h
+++ b/config.h
@@ -7,13 +7,21 @@
 /* Terminal colors */
 static const char *colorname[] = {
 	"black",
-	"red",
-	"green",
-	"yellow",
-	"blue",
-	"magenta",
-	"cyan",
-	"white",
+	"#CC0000",
+	"#4E9A06",
+	"#C4A000",
+	"#3465A4",
+	"#75507B",
+	"#06989A",
+	"#888a85",
+	"#555753",
+	"#EF2929",
+	"#8AE234",
+	"#FCE94F",
+	"#729FCF",
+	"#AD7FA8",
+	"#34E2E2",
+	"#EEEEEC"
 };
 
 /* Default colors (colorname index) */
diff --git a/st.c b/st.c
old mode 100755
new mode 100644
index c64c25e..5715f0f
--- a/st.c
+++ b/st.c
@@ -20,7 +20,7 @@
 #include 
 #include 
 
-#define TNAME "xterm"
+#define TNAME "st-256color"
 
 /* Arbitrary sizes */
 #define ESC_TITLE_SIZ 256
@@ -111,7 +111,7 @@ typedef struct {
 
 /* Drawing Context */
 typedef struct {
-	unsigned long col[LEN(colorname)];
+	unsigned long col[256];
 	XFontStruct* font;
 	XFontStruct* bfont;
 	GC gc;
@@ -154,7 +154,6 @@ static void ttyread(void);
 static void ttyresize(int, int);
 static void ttywrite(const char *, size_t);
 
-static unsigned long xgetcol(const char *);
 static void xclear(int, int, int, int);
 static void xcursor(int);
 static void xinit(void);
@@ -593,9 +592,31 @@ tsetattr(int *attr, int l) {
 		case 27: 
 			term.c.attr.mode &= ~ATTR_REVERSE;	 
 			break;
+		case 38:
+			if (i + 2 < l && attr[i + 1] == 5) {
+				i += 2;
+				if (BETWEEN(attr[i], 0, 255))
+					term.c.attr.fg = attr[i];
+				else
+					fprintf(stderr, "erresc: bad fgcolor %d\n", attr[i]);
+			}
+			else
+				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]); 
+			break;
 		case 39:
 			term.c.attr.fg = DefaultFG;
 			break;
+		case 48:
+			if (i + 2 < l && attr[i + 1] == 5) {
+				i += 2;
+				if (BETWEEN(attr[i], 0, 255))
+					term.c.attr.bg = attr[i];
+				else
+					fprintf(stderr, "erresc: bad bgcolor %d\n", attr[i]);
+			}
+			else
+				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]); 
+			break;
 		case 49:
 			term.c.attr.bg = DefaultBG;
 			break;
@@ -604,8 +625,12 @@ tsetattr(int *attr, int l) {
 				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.fg = attr[i] - 100 + 8;
 			else 
-				fprintf(stderr, "erresc: gfx attr %d unkown\n", attr[i]); 
+				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]); 
 			break;
 		}
 	}
@@ -1009,16 +1034,44 @@ tresize(int col, int row) {
 	term.col = col, term.row = row;
 }
 
-unsigned long
-xgetcol(const char *s) {
+void
+tloadcols(void) {
+	int i, r, g, b;
 	XColor color;
 	Colormap cmap = DefaultColormap(xw.dis, xw.scr);
+	unsigned long white = WhitePixel(xw.dis, xw.scr);
 
-	if(!XAllocNamedColor(xw.dis, cmap, s, &color, &color)) {
-		color.pixel = WhitePixel(xw.dis, xw.scr);
-		fprintf(stderr, "Could not allocate color '%s'\n", s);
+	for(i = 0; i < 16; i++) {
+		if (!XAllocNamedColor(xw.dis, cmap, colorname[i], &color, &color)) {
+			dc.col[i] = white;
+			fprintf(stderr, "Could not allocate color '%s'\n", colorname[i]);
+		} else
+			dc.col[i] = color.pixel;
+	}
+
+	/* same colors as xterm */
+	for(r = 0; r < 6; r++)
+		for(g = 0; g < 6; g++)
+			for(b = 0; b < 6; b++) {
+				color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r;
+				color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g;
+				color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b;
+				if (!XAllocColor(xw.dis, cmap, &color)) {
+					dc.col[i] = white;
+					fprintf(stderr, "Could not allocate color %d\n", i);
+				} else
+					dc.col[i] = color.pixel;
+				i++;
+			}
+
+	for(r = 0; r < 24; r++, i++) {
+		color.red = color.green = color.blue = 0x0808 + 0x0a0a * r;
+		if (!XAllocColor(xw.dis, cmap, &color)) {
+			dc.col[i] = white;
+			fprintf(stderr, "Could not allocate color %d\n", i);
+		} else
+			dc.col[i] = color.pixel;
 	}
-	return color.pixel;
 }
 
 void
@@ -1048,8 +1101,6 @@ xhints(void)
 
 void
 xinit(void) {
-	int i;
-
 	xw.dis = XOpenDisplay(NULL);
 	xw.scr = XDefaultScreen(xw.dis);
 	if(!xw.dis)
@@ -1064,8 +1115,7 @@ xinit(void) {
 	xw.ch = dc.font->ascent + dc.font->descent;
 
 	/* colors */
-	for(i = 0; i < LEN(colorname); i++)
-		dc.col[i] = xgetcol(colorname[i]);
+	tloadcols();
 
 	term.c.attr.fg = DefaultFG;
 	term.c.attr.bg = DefaultBG;
@@ -1173,6 +1223,8 @@ draw(int redraw_all) {
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
 	
+	XSetForeground(xw.dis, dc.gc, dc.col[DefaultBG]);
+	XFillRectangle(xw.dis, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
 	for(y = 0; y < term.row; y++) {
 		base = term.line[y][0];
 		i = ox = 0;
diff --git a/st.info b/st.info
index 1ded6b5..1cf6344 100644
--- a/st.info
+++ b/st.info
@@ -1,7 +1,6 @@
-#	Reconstructed via infocmp from file: /lib/terminfo/p/pcansi
 st| simpleterm,
 	am,
-    ul,
+	ul,
 	mir,
 	msgr,
 	colors#8,
@@ -10,7 +9,7 @@ st| simpleterm,
 	lines#24,
 	ncv#3,
 	pairs#64,
-    acsc=*`#aof+g+j+k+l+m+n-o-p-q-r-s+t+u+v+w|xz{{||}}-~,
+	acsc=*`#aof+g+j+k+l+m+n-o-p-q-r-s+t+u+v+w|xz{{||}}-~,
 	bel=^G,
 	bold=\E[1m,
 	cbt=\E[Z,
@@ -36,9 +35,11 @@ st| simpleterm,
 	kcud1=\E[B,
 	kcuf1=\E[C,
 	kcuu1=\E[A,
+	kdch1=\E[3~,
+	kend=\E[4~,
 	khome=\E[1~,
-    knp=\E[6~,
-    kpp=\E[5~,
+	knp=\E[6~,
+	kpp=\E[5~,
 	op=\E[37;40m,
 	rev=\E[7m,
 	rmacs=\E[10m,
@@ -46,7 +47,6 @@ st| simpleterm,
 	rmul=\E[m,
 	setab=\E[4%p1%dm,
 	setaf=\E[3%p1%dm,
-#	sgr=\E[0;10%?%p1%t;7%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p6%t;1%;%?%p7%t;8%;%?%p9%t;12%;m,
 	sgr0=\E[0m,
 	smacs=\E[12m,
 	smso=\E[7m,

From d2f157c7418e2762316e5471f819ec1e5c49e93c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Fri, 13 Aug 2010 22:43:30 +0200
Subject: [PATCH 0085/1146] renamed a function.

---
 st.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 5715f0f..deddb0d 100644
--- a/st.c
+++ b/st.c
@@ -157,6 +157,7 @@ static void ttywrite(const char *, size_t);
 static void xclear(int, int, int, int);
 static void xcursor(int);
 static void xinit(void);
+static void xloadcols(void);
 
 static void expose(XEvent *);
 static char* kmap(KeySym);
@@ -1035,7 +1036,7 @@ tresize(int col, int row) {
 }
 
 void
-tloadcols(void) {
+xloadcols(void) {
 	int i, r, g, b;
 	XColor color;
 	Colormap cmap = DefaultColormap(xw.dis, xw.scr);
@@ -1115,7 +1116,7 @@ xinit(void) {
 	xw.ch = dc.font->ascent + dc.font->descent;
 
 	/* colors */
-	tloadcols();
+	xloadcols();
 
 	term.c.attr.fg = DefaultFG;
 	term.c.attr.bg = DefaultBG;

From ce3f4fc647be3ab28f934db9365445a56ebd85bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 19 Aug 2010 12:46:54 +0200
Subject: [PATCH 0086/1146] fixed backspace problem, updated terminfo entry and
 moved TNAME in config.h.

---
 Makefile | 1 -
 config.h | 3 ++-
 st.c     | 6 ++----
 st.info  | 9 ++++++++-
 4 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/Makefile b/Makefile
index 14da7a5..9ec8d21 100644
--- a/Makefile
+++ b/Makefile
@@ -42,7 +42,6 @@ install: all
 	@cp -f st ${DESTDIR}${PREFIX}/bin
 	@chmod 755 ${DESTDIR}${PREFIX}/bin/st
 	@tic st.info
-	@tic st-256color.info
 
 uninstall:
 	@echo removing executable file from ${DESTDIR}${PREFIX}/bin
diff --git a/config.h b/config.h
index aee8057..c3c4e41 100644
--- a/config.h
+++ b/config.h
@@ -1,5 +1,5 @@
 #define TAB    8
-
+#define TNAME "st-256color"
 #define FONT "6x13"
 #define BOLDFONT FONT"bold"
 #define BORDER 2
@@ -33,6 +33,7 @@ static const char *colorname[] = {
 
 /* special keys */
 static Key key[] = {
+	{ XK_BackSpace, "\177" },
 	{ XK_Delete, "\033[3~" },
 	{ XK_Home,   "\033[1~" },
 	{ XK_End,    "\033[4~" },
diff --git a/st.c b/st.c
index deddb0d..f8d2257 100644
--- a/st.c
+++ b/st.c
@@ -20,8 +20,6 @@
 #include 
 #include 
 
-#define TNAME "st-256color"
-
 /* Arbitrary sizes */
 #define ESC_TITLE_SIZ 256
 #define ESC_BUF_SIZ   256
@@ -107,8 +105,6 @@ typedef struct {
 	char s[ESC_BUF_SIZ];
 } Key;
 
-#include "config.h"
-
 /* Drawing Context */
 typedef struct {
 	unsigned long col[256];
@@ -117,6 +113,8 @@ typedef struct {
 	GC gc;
 } DC;
 
+#include "config.h"
+
 static void die(const char *errstr, ...);
 static void draw(int);
 static void execsh(void);
diff --git a/st.info b/st.info
index 1cf6344..b2669dd 100644
--- a/st.info
+++ b/st.info
@@ -30,7 +30,7 @@ st| simpleterm,
 	il1=\E[L,
 	ind=^J,
 	invis=\E[8m,
-	kbs=^H,
+	kbs=\177,
 	kcub1=\E[D,
 	kcud1=\E[B,
 	kcuf1=\E[C,
@@ -52,3 +52,10 @@ st| simpleterm,
 	smso=\E[7m,
 	smul=\E[4m,
 	tbc=\E[2g,
+
+st-256color| simpleterm with 256 colors,
+	colors#256,
+#	Nicked from xterm-256color
+	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,
+	use=st,

From a7922bd1d94ace6d14e40a27820e217cd6c4e632 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sun, 22 Aug 2010 19:46:46 +0200
Subject: [PATCH 0087/1146] added F1-12 key, fixed DCH and ICH.

---
 config.h | 12 ++++++++++++
 st.c     |  8 ++++----
 st.info  | 12 ++++++++++++
 3 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/config.h b/config.h
index c3c4e41..bb490ab 100644
--- a/config.h
+++ b/config.h
@@ -39,6 +39,18 @@ static Key key[] = {
 	{ XK_End,    "\033[4~" },
 	{ XK_Prior,  "\033[5~" },
 	{ XK_Next,   "\033[6~" },
+	{ XK_F1,        "\033OP"   },
+	{ XK_F2,        "\033OQ"   },
+	{ XK_F3,        "\033OR"   },
+	{ XK_F4,        "\033OS"   },
+	{ XK_F5,        "\033[15~" },
+	{ XK_F6,        "\033[17~" },
+	{ XK_F7,        "\033[18~" },
+	{ XK_F8,        "\033[19~" },
+	{ XK_F9,        "\033[20~" },
+	{ XK_F10,       "\033[21~" },
+	{ XK_F11,       "\033[23~" },
+	{ XK_F12,       "\033[24~" },
 };
 
 static char gfx[] = {
diff --git a/st.c b/st.c
index f8d2257..6e34f1e 100644
--- a/st.c
+++ b/st.c
@@ -497,21 +497,21 @@ tdeletechar(int n) {
 		return;
 	}
 	memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph));
-	tclearregion(term.col-size, term.c.y, term.col-1, term.c.y);
+	tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
 }
 
 void
 tinsertblank(int n) {
 	int src = term.c.x;
 	int dst = src + n;
-	int size = term.col - n - src;
+	int size = term.col - dst;
 
 	if(dst >= term.col) {
 		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
 		return;
 	}
 	memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph));
-	tclearregion(src, term.c.y, dst, term.c.y);
+	tclearregion(src, term.c.y, dst - 1, term.c.y);
 }
 
 void
@@ -1173,7 +1173,7 @@ xcursor(int mode) {
 	
 	if(term.line[term.c.y][term.c.x].state & GLYPH_SET)
 		g.c = term.line[term.c.y][term.c.x].c;
-
+	
 	/* remove the old cursor */
 	if(term.line[oldy][oldx].state & GLYPH_SET)
 		xdraws(&term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, 1);
diff --git a/st.info b/st.info
index b2669dd..2cc645b 100644
--- a/st.info
+++ b/st.info
@@ -37,6 +37,18 @@ st| simpleterm,
 	kcuu1=\E[A,
 	kdch1=\E[3~,
 	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~,
 	khome=\E[1~,
 	knp=\E[6~,
 	kpp=\E[5~,

From b09401b96b640a796d11774664c49031cee3245a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 26 Aug 2010 21:32:34 +0200
Subject: [PATCH 0088/1146] fix \b and clean \t.

---
 st.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/st.c b/st.c
index 6e34f1e..2e0ef70 100644
--- a/st.c
+++ b/st.c
@@ -443,11 +443,6 @@ tmovecursor(int dir) {
 		break;
 	case CURSOR_LEFT:
 		xf--;
-		if(term.mode & MODE_WRAP && xf < 0) {
-			xf = term.col-1, yf--;
-			if(yf < term.top)
-				yf = term.top, xf = 0;
-		}
 		break;
 	case CURSOR_RIGHT:
 		xf++;

From 44226483fb0a3d6270970399d8a91abb2d16146b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 26 Aug 2010 21:33:53 +0200
Subject: [PATCH 0089/1146] update function prototypes.

---
 st.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/st.c b/st.c
index 2e0ef70..04ff1b9 100644
--- a/st.c
+++ b/st.c
@@ -136,6 +136,7 @@ static void tinsertblankline(int);
 static void tmoveto(int, int);
 static void tnew(int, int);
 static void tnewline(void);
+static void tputtab(void);
 static void tputc(char);
 static void tputs(char*, int);
 static void treset(void);
@@ -152,6 +153,9 @@ static void ttyread(void);
 static void ttyresize(int, int);
 static void ttywrite(const char *, size_t);
 
+static void xbell(void);
+static void xdraws(char *, Glyph, int, int, int);
+static void xhints(void);
 static void xclear(int, int, int, int);
 static void xcursor(int);
 static void xinit(void);

From 5c93f399c564f3475ffa4d3b3314a06db533e410 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 26 Aug 2010 21:34:37 +0200
Subject: [PATCH 0090/1146] clean \t.

---
 st.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/st.c b/st.c
index 04ff1b9..bef3039 100644
--- a/st.c
+++ b/st.c
@@ -861,12 +861,7 @@ csireset(void) {
 void
 tputtab(void) {
 	int space = TAB - term.c.x % TAB;
-	
-	if(term.c.x + space >= term.col)
-		space--;
-	
-	for(; space > 0; space--)
-		tmovecursor(CURSOR_RIGHT);
+	tmoveto(term.c.x + space, term.c.y);
 }
 
 void

From e8c13ebe8001a7870a70b698d8b8fa80b7c90fd3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 26 Aug 2010 21:36:21 +0200
Subject: [PATCH 0091/1146] close master/slave pty in the shell process.

---
 st.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index bef3039..e288902 100644
--- a/st.c
+++ b/st.c
@@ -247,7 +247,7 @@ ttynew(void) {
 	if((m = posix_openpt(O_RDWR | O_NOCTTY)) < 0)
 		die("openpt failed: %s\n", SERRNO);
 	if(grantpt(m) < 0)
-		die("grandpt failed: %s\n", SERRNO);
+		die("grantpt failed: %s\n", SERRNO);
 	if(unlockpt(m) < 0)
 		die("unlockpt failed: %s\n", SERRNO);
 	if(!(pts = ptsname(m)))
@@ -265,7 +265,9 @@ ttynew(void) {
 		dup2(s, STDOUT_FILENO);
 		dup2(s, STDERR_FILENO);
 		if(ioctl(s, TIOCSCTTY, NULL) < 0)
-			die("ioctl TTIOCSTTY failed: %s\n", SERRNO);
+			die("ioctl TIOCSCTTY failed: %s\n", SERRNO);
+		close(s);
+		close(m);
 		execsh();
 		break;
 	default:

From 4db3df312ada9d92564d5580fb4e67f7704efff8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 26 Aug 2010 21:37:12 +0200
Subject: [PATCH 0092/1146] faster resizing.

---
 st.c | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/st.c b/st.c
index e288902..f44db79 100644
--- a/st.c
+++ b/st.c
@@ -1001,23 +1001,21 @@ tputs(char *s, int len) {
 void
 tresize(int col, int row) {
 	int i;
-	Line *line;
 	int minrow = MIN(row, term.row);
 	int mincol = MIN(col, term.col);
 
 	if(col < 1 || row < 1)
 		return;
-	/* alloc */
-	line = calloc(row, sizeof(Line));
-	for(i = 0 ; i < row; i++)
-		line[i] = calloc(col, sizeof(Glyph));
-	/* copy */
-	for(i = 0 ; i < minrow; i++)
-		memcpy(line[i], term.line[i], mincol * sizeof(Glyph));
-	/* free */
-	for(i = 0; i < term.row; i++)
+
+	for(i = row; i < term.row; i++)
 		free(term.line[i]);
-	free(term.line);
+	term.line = realloc(term.line, row * sizeof(Line));
+	for(i = 0; i < minrow; i++) {
+		term.line[i] = realloc(term.line[i], col * sizeof(Glyph));
+		memset(term.line[i] + mincol, 0, (col - mincol) * sizeof(Glyph));
+	}
+	for(/* i == minrow */; i < row; i++)
+		term.line[i] = calloc(col, sizeof(Glyph));
 	
 	LIMIT(term.c.x, 0, col-1);
 	LIMIT(term.c.y, 0, row-1);
@@ -1025,7 +1023,6 @@ tresize(int col, int row) {
 	LIMIT(term.bot, 0, row-1);
 	
 	term.bot = row-1;
-	term.line = line;
 	term.col = col, term.row = row;
 }
 

From 5d611cd5476b56884077120bc2a6ba9727fcdd2c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 26 Aug 2010 23:43:08 +0200
Subject: [PATCH 0093/1146] added macro to test flags, removed tmovecursor().

---
 st.c | 42 +++++++++++++++---------------------------
 1 file changed, 15 insertions(+), 27 deletions(-)

diff --git a/st.c b/st.c
index f44db79..8b0e510 100644
--- a/st.c
+++ b/st.c
@@ -34,6 +34,7 @@
 #define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (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 IS_SET(flag) (term.mode & flag)
 
 /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
 enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 };
@@ -128,7 +129,7 @@ static void csireset(void);
 
 static void tclearregion(int, int, int, int);
 static void tcursor(int);
-static void tmovecursor(int);
+static void twrapcursor(void);
 static void tdeletechar(int);
 static void tdeleteline(int);
 static void tinsertblank(int);
@@ -437,29 +438,13 @@ tmoveto(int x, int y) {
 }
 
 void
-tmovecursor(int dir) {
-	int xf = term.c.x, yf = term.c.y;
-	
-	switch(dir) {
-	case CURSOR_UP:
-		yf--;
-		break;
-	case CURSOR_DOWN:
-		yf++;
-		break;
-	case CURSOR_LEFT:
-		xf--;
-		break;
-	case CURSOR_RIGHT:
-		xf++;
-		if(term.mode & MODE_WRAP && xf >= term.col) {
-			xf = 0, yf++;
-			if(yf > term.bot)
-				yf = term.bot, tscroll();
-		}
-		break;
-	}
-	tmoveto(xf, yf);
+twrapcursor(void) {
+	int y = term.c.y+1;
+    if(y > term.bot) {
+        tmoveto(0, term.bot);
+        tscroll();
+    } else 
+        tmoveto(0, y);
 }
 	
 void
@@ -969,7 +954,7 @@ tputc(char c) {
 			tputtab();
 			break;
 		case '\b':
-			tmovecursor(CURSOR_LEFT);
+			tmoveto(term.c.x-1, term.c.y);
 			break;
 		case '\r':
 			tmoveto(0, term.c.y);
@@ -986,7 +971,10 @@ tputc(char c) {
 			break;
 		default:
 			tsetchar(c);
-			tmovecursor(CURSOR_RIGHT);
+            if(term.c.x+1 < term.col) {
+                tmoveto(term.c.x+1, term.c.y);
+            } else if(IS_SET(MODE_WRAP))
+                twrapcursor();
 			break;
 		}
 	}
@@ -1282,7 +1270,7 @@ kpress(XEvent *ev) {
 		case XK_Down:
 		case XK_Left:
 		case XK_Right:
-			sprintf(buf, "\033%c%c", term.mode & MODE_APPKEYPAD ? 'O' : '[', "DACB"[ksym - XK_Left]);
+			sprintf(buf, "\033%c%c", IS_SET(MODE_APPKEYPAD) ? 'O' : '[', "DACB"[ksym - XK_Left]);
 			ttywrite(buf, 3);
 			break;
 		case XK_Insert:

From 42b2912e2151f02e181bd014ce1610f7e03a7d07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Fri, 27 Aug 2010 00:05:50 +0200
Subject: [PATCH 0094/1146] cleaned some spaces.

---
 st.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index 8b0e510..9667dbd 100644
--- a/st.c
+++ b/st.c
@@ -440,11 +440,11 @@ tmoveto(int x, int y) {
 void
 twrapcursor(void) {
 	int y = term.c.y+1;
-    if(y > term.bot) {
-        tmoveto(0, term.bot);
-        tscroll();
-    } else 
-        tmoveto(0, y);
+	if(y > term.bot) {
+		tmoveto(0, term.bot);
+		tscroll();
+	} else 
+		tmoveto(0, y);
 }
 	
 void
@@ -971,10 +971,10 @@ tputc(char c) {
 			break;
 		default:
 			tsetchar(c);
-            if(term.c.x+1 < term.col) {
-                tmoveto(term.c.x+1, term.c.y);
-            } else if(IS_SET(MODE_WRAP))
-                twrapcursor();
+			if(term.c.x+1 < term.col) {
+				tmoveto(term.c.x+1, term.c.y);
+			} else if(IS_SET(MODE_WRAP))
+				twrapcursor();
 			break;
 		}
 	}

From fbb66da9a9ef3c12c1e8dee7433d003b85d70e9c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Fri, 27 Aug 2010 00:28:27 +0200
Subject: [PATCH 0095/1146] merged tcursorwrap() with tnewline(), added few
 comments and updated copyright.

---
 st.c | 25 +++++++++++--------------
 1 file changed, 11 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index 9667dbd..ebe896c 100644
--- a/st.c
+++ b/st.c
@@ -129,7 +129,6 @@ static void csireset(void);
 
 static void tclearregion(int, int, int, int);
 static void tcursor(int);
-static void twrapcursor(void);
 static void tdeletechar(int);
 static void tdeleteline(int);
 static void tinsertblank(int);
@@ -337,7 +336,8 @@ treset(void) {
 }
 
 void
-tnew(int col, int row) {   /* screen size */
+tnew(int col, int row) {
+	/* screen size */
 	term.row = row, term.col = col;
 	term.top = 0, term.bot = term.row - 1;
 	/* mode */
@@ -437,16 +437,6 @@ tmoveto(int x, int y) {
 	term.c.y = y < 0 ? 0 : y >= term.row ? term.row-1 : y;
 }
 
-void
-twrapcursor(void) {
-	int y = term.c.y+1;
-	if(y > term.bot) {
-		tmoveto(0, term.bot);
-		tscroll();
-	} else 
-		tmoveto(0, y);
-}
-	
 void
 tsetchar(char c) {
 	term.line[term.c.y][term.c.x] = term.c.attr;
@@ -974,7 +964,7 @@ tputc(char c) {
 			if(term.c.x+1 < term.col) {
 				tmoveto(term.c.x+1, term.c.y);
 			} else if(IS_SET(MODE_WRAP))
-				twrapcursor();
+				tnewline();
 			break;
 		}
 	}
@@ -995,13 +985,20 @@ tresize(int col, int row) {
 	if(col < 1 || row < 1)
 		return;
 
+	/* free uneeded rows */
 	for(i = row; i < term.row; i++)
 		free(term.line[i]);
+
+	/* resize to new height */
 	term.line = realloc(term.line, row * sizeof(Line));
+
+	/* resize each row to new width, zero-pad if needed */
 	for(i = 0; i < minrow; i++) {
 		term.line[i] = realloc(term.line[i], col * sizeof(Glyph));
 		memset(term.line[i] + mincol, 0, (col - mincol) * sizeof(Glyph));
 	}
+
+	/* allocate any new rows */
 	for(/* i == minrow */; i < row; i++)
 		term.line[i] = calloc(col, sizeof(Glyph));
 	
@@ -1337,7 +1334,7 @@ run(void) {
 int
 main(int argc, char *argv[]) {
 	if(argc == 2 && !strncmp("-v", argv[1], 3))
-		die("st-" VERSION ", © 2009 st engineers\n");
+		die("st-" VERSION ", (c) 2010 st engineers\n");
 	else if(argc != 1)
 		die("usage: st [-v]\n");
 	setlocale(LC_CTYPE, "");

From a1018e0e9e52f29fe220a6af85a237a1a02a732c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Fri, 27 Aug 2010 00:58:28 +0200
Subject: [PATCH 0096/1146] fixed potential bug in IS_SET().

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index ebe896c..8dfd4a7 100644
--- a/st.c
+++ b/st.c
@@ -34,7 +34,7 @@
 #define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (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 IS_SET(flag) (term.mode & flag)
+#define IS_SET(flag) (term.mode & (flag))
 
 /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
 enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 };

From c56332857145d1c6741d4f6c1bbc87dcc6c6ab97 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Fri, 27 Aug 2010 13:53:27 +0200
Subject: [PATCH 0097/1146] removed XINERAMA from config.mk and fixed a
 segfault when st is

started without a display. (thx Hiltjo Posthuma)
---
 config.mk | 8 ++------
 st.c      | 5 ++---
 2 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/config.mk b/config.mk
index 62eb48f..2827e98 100644
--- a/config.mk
+++ b/config.mk
@@ -10,16 +10,12 @@ MANPREFIX = ${PREFIX}/share/man
 X11INC = /usr/X11R6/include
 X11LIB = /usr/X11R6/lib
 
-# Xinerama, comment if you don't want it
-#XINERAMALIBS = -L${X11LIB} -lXinerama
-#XINERAMAFLAGS = -DXINERAMA
-
 # includes and libs
 INCS = -I. -I/usr/include -I${X11INC}
-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS}
+LIBS = -L/usr/lib -lc -L${X11LIB} -lX11
 
 # flags
-CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
+CPPFLAGS = -DVERSION=\"${VERSION}\"
 CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
 LDFLAGS = -s ${LIBS}
 
diff --git a/st.c b/st.c
index 8dfd4a7..623ca29 100644
--- a/st.c
+++ b/st.c
@@ -1078,10 +1078,9 @@ xhints(void)
 
 void
 xinit(void) {
-	xw.dis = XOpenDisplay(NULL);
-	xw.scr = XDefaultScreen(xw.dis);
-	if(!xw.dis)
+	if(!(xw.dis = XOpenDisplay(NULL)))
 		die("Can't open display\n");
+	xw.scr = XDefaultScreen(xw.dis);
 	
 	/* font */
 	if(!(dc.font = XLoadQueryFont(xw.dis, FONT)) || !(dc.bfont = XLoadQueryFont(xw.dis, BOLDFONT)))

From 6db6980e27bdde6f2d444dd3cdd7a46985fa84fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sat, 28 Aug 2010 03:18:22 +0200
Subject: [PATCH 0098/1146] st now runs on Linux, OpenBSD and FreeBSD.

---
 Makefile  |  5 +++--
 config.mk | 13 +++++++------
 st.c      | 25 +++++++++++++------------
 3 files changed, 23 insertions(+), 20 deletions(-)

diff --git a/Makefile b/Makefile
index 9ec8d21..ef3bf09 100644
--- a/Makefile
+++ b/Makefile
@@ -10,6 +10,7 @@ all: options st
 
 options:
 	@echo st build options:
+	@echo "SYSTEM   = ${SYSTEM}"
 	@echo "CFLAGS   = ${CFLAGS}"
 	@echo "LDFLAGS  = ${LDFLAGS}"
 	@echo "CC       = ${CC}"
@@ -31,7 +32,7 @@ clean:
 dist: clean
 	@echo creating dist tarball
 	@mkdir -p st-${VERSION}
-	@cp -R LICENSE Makefile README config.mk st.h ${SRC} st-${VERSION}
+	@cp -R LICENSE Makefile README config.mk config.h st.info ${SRC} st-${VERSION}
 	@tar -cf st-${VERSION}.tar st-${VERSION}
 	@gzip st-${VERSION}.tar
 	@rm -rf st-${VERSION}
@@ -41,7 +42,7 @@ install: all
 	@mkdir -p ${DESTDIR}${PREFIX}/bin
 	@cp -f st ${DESTDIR}${PREFIX}/bin
 	@chmod 755 ${DESTDIR}${PREFIX}/bin/st
-	@tic st.info
+	@tic -s st.info
 
 uninstall:
 	@echo removing executable file from ${DESTDIR}${PREFIX}/bin
diff --git a/config.mk b/config.mk
index 2827e98..216e7df 100644
--- a/config.mk
+++ b/config.mk
@@ -12,16 +12,17 @@ X11LIB = /usr/X11R6/lib
 
 # includes and libs
 INCS = -I. -I/usr/include -I${X11INC}
-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11
+LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil
+
+# uncomment your system #
+#SYSTEM = -DLINUX
+#SYSTEM = -DOPENBSD
+#SYSTEM = -DFREEBSD
 
 # flags
-CPPFLAGS = -DVERSION=\"${VERSION}\"
+CPPFLAGS = -DVERSION=\"${VERSION}\" ${SYSTEM}
 CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
 LDFLAGS = -s ${LIBS}
 
-# Solaris
-#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
-#LDFLAGS = ${LIBS}
-
 # compiler and linker
 CC = cc
diff --git a/st.c b/st.c
index 623ca29..9ca032f 100644
--- a/st.c
+++ b/st.c
@@ -20,6 +20,14 @@
 #include 
 #include 
 
+#if   defined(LINUX)
+ #include 
+#elif defined(OPENBSD)
+ #include 
+#elif defined(FREEBSD)
+ #include 
+#endif
+
 /* Arbitrary sizes */
 #define ESC_TITLE_SIZ 256
 #define ESC_BUF_SIZ   256
@@ -242,19 +250,12 @@ sigchld(int a) {
 void
 ttynew(void) {
 	int m, s;
-	char *pts;
+	
+	/* seems to work fine on linux, openbsd and freebsd */
+	struct winsize w = {term.row, term.col, 0, 0};
+	if(openpty(&m, &s, NULL, NULL, &w) < 0)
+		die("openpty failed: %s\n", SERRNO);
 
-	if((m = posix_openpt(O_RDWR | O_NOCTTY)) < 0)
-		die("openpt failed: %s\n", SERRNO);
-	if(grantpt(m) < 0)
-		die("grantpt failed: %s\n", SERRNO);
-	if(unlockpt(m) < 0)
-		die("unlockpt failed: %s\n", SERRNO);
-	if(!(pts = ptsname(m)))
-		die("ptsname failed: %s\n", SERRNO);
-	if((s = open(pts, O_RDWR | O_NOCTTY)) < 0)
-		die("Couldn't open slave: %s\n", SERRNO);
-	fcntl(s, F_SETFL, O_NDELAY);
 	switch(pid = fork()) {
 	case -1:
 		die("fork failed\n");

From c186c8ef9a995616384c425c5568b6913676b252 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sun, 29 Aug 2010 12:27:59 +0200
Subject: [PATCH 0099/1146] merged tscroll() with tscrollup().

---
 st.c | 15 +--------------
 1 file changed, 1 insertion(+), 14 deletions(-)

diff --git a/st.c b/st.c
index 9ca032f..eabc0c5 100644
--- a/st.c
+++ b/st.c
@@ -149,7 +149,6 @@ static void tputc(char);
 static void tputs(char*, int);
 static void treset(void);
 static void tresize(int, int);
-static void tscroll(void);
 static void tscrollup(int);
 static void tscrolldown(int);
 static void tsetattr(int*, int);
@@ -355,18 +354,6 @@ tnew(int col, int row) {
 		term.line[row] = calloc(term.col, sizeof(Glyph));
 }
 
-/* TODO: Replace with scrollup/scolldown */
-void
-tscroll(void) {
-	Line temp = term.line[term.top];
-	int i;
-
-	for(i = term.top; i < term.bot; i++)
-		term.line[i] = term.line[i+1];
-	memset(temp, 0, sizeof(Glyph) * term.col);
-	term.line[term.bot] = temp;
-}
-
 void
 tscrolldown (int n) {
 	int i;
@@ -404,7 +391,7 @@ void
 tnewline(void) {
 	int y = term.c.y + 1;
 	if(y > term.bot)
-		tscroll(), y = term.bot;
+		tscrollup(1), y = term.bot;
 	tmoveto(0, y);
 }
 

From 2181040594ae63f2821899caba0bef34257a6c2b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sun, 29 Aug 2010 18:55:15 +0200
Subject: [PATCH 0100/1146] moved term.hidec in term.c for consistency, put
 back delay in xbell()

along with duration in config.h, factored some code in tnew()/treset()
and cleaned some code.
---
 config.h |  1 +
 st.c     | 48 ++++++++++++++++++++----------------------------
 2 files changed, 21 insertions(+), 28 deletions(-)

diff --git a/config.h b/config.h
index bb490ab..53795c6 100644
--- a/config.h
+++ b/config.h
@@ -30,6 +30,7 @@ static const char *colorname[] = {
 #define DefaultBG 0
 #define DefaultCS 1
 #define BellCol   DefaultFG
+#define BellTime  30000 /* microseconds */
 
 /* special keys */
 static Key key[] = {
diff --git a/st.c b/st.c
index eabc0c5..9b77a0b 100644
--- a/st.c
+++ b/st.c
@@ -67,6 +67,7 @@ typedef struct {
 	Glyph attr;	 /* current char attributes */
 	int x;
 	int y;
+	char hide;
 } TCursor;
 
 /* CSI Escape sequence structs */
@@ -86,7 +87,6 @@ typedef struct {
 	int col;	/* nb col */
 	Line* line; /* screen */
 	TCursor c;	/* cursor */
-	char hidec;
 	int top;	/* top	  scroll limit */
 	int bot;	/* bottom scroll limit */
 	int mode;	/* terminal mode flags */
@@ -221,17 +221,16 @@ die(const char *errstr, ...) {
 void
 execsh(void) {
 	char *args[3] = {getenv("SHELL"), "-i", NULL};
-	DEFAULT(args[0], "/bin/sh"); /* default shell if getenv() failed */
+	DEFAULT(args[0], "/bin/sh"); /* if getenv() failed */
 	putenv("TERM=" TNAME);
 	execvp(args[0], args);
 }
 
 void
-xbell(void) { /* visual bell */
-	XRectangle r = { BORDER, BORDER, xw.bufw, xw.bufh };
+xbell(void) {
 	XSetForeground(xw.dis, dc.gc, dc.col[BellCol]);
-	XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1);
-	/* usleep(30000); */
+	XFillRectangle(xw.dis, xw.win, dc.gc, BORDER, BORDER, xw.bufw, xw.bufh);
+	usleep(BellTime);
 	draw(SCREEN_REDRAW);
 }
 
@@ -325,11 +324,12 @@ tcursor(int mode) {
 
 void
 treset(void) {
-	term.c.attr.mode = ATTR_NULL;
-	term.c.attr.fg = DefaultFG;
-	term.c.attr.bg = DefaultBG;
-	term.c.x = term.c.y = 0;
-	term.hidec = 0;
+	term.c = (TCursor){{
+		.mode = ATTR_NULL, 
+		.fg = DefaultFG, 
+		.bg = DefaultBG
+	}, .x = 0, .y = 0, .hide = 0};
+	
 	term.top = 0, term.bot = term.row - 1;
 	term.mode = MODE_WRAP;
 	tclearregion(0, 0, term.col-1, term.row-1);
@@ -337,21 +337,13 @@ treset(void) {
 
 void
 tnew(int col, int row) {
-	/* screen size */
+	/* set screen size */
 	term.row = row, term.col = col;
-	term.top = 0, term.bot = term.row - 1;
-	/* mode */
-	term.mode = MODE_WRAP;
-	/* cursor */
-	term.c.attr.mode = ATTR_NULL;
-	term.c.attr.fg = DefaultFG;
-	term.c.attr.bg = DefaultBG;
-	term.c.x = term.c.y = 0;
-	term.hidec = 0;
-	/* allocate screen */
-	term.line = calloc(term.row, sizeof(Line));
+	term.line = malloc(term.row * sizeof(Line));
 	for(row = 0 ; row < term.row; row++)
-		term.line[row] = calloc(term.col, sizeof(Glyph));
+		term.line[row] = malloc(term.col * sizeof(Glyph));
+	/* setup screen */
+	treset();
 }
 
 void
@@ -718,7 +710,7 @@ csihandle(void) {
 			case 12: /* att610 -- Stop blinking cursor (IGNORED) */
 				break;
 			case 25:
-				term.hidec = 1;
+				term.c.hide = 1;
 				break;
 			case 1048: /* XXX: no alt. screen to erase/save */
 			case 1049:
@@ -767,7 +759,7 @@ csihandle(void) {
 			case 12: /* att610 -- Start blinking cursor (IGNORED) */
 				break;
 			case 25:
-				term.hidec = 0;
+				term.c.hide = 0;
 				break;
 			case 1048: 
 			case 1049: /* XXX: no alt. screen to erase/save */
@@ -1173,7 +1165,7 @@ draw(int dummy) {
 			if(term.line[y][x].state & GLYPH_SET)
 				xdrawc(x, y, term.line[y][x]);
 
-	if(!term.hidec)
+	if(!term.c.hide)
 		xcursor(CURSOR_DRAW);
 	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
 	XFlush(xw.dis);
@@ -1206,7 +1198,7 @@ draw(int redraw_all) {
 		}
 		xdraws(buf, base, ox, y, i);
 	}
-	xcursor(term.hidec ? CURSOR_HIDE : CURSOR_DRAW);
+	xcursor(term.c.hide ? CURSOR_HIDE : CURSOR_DRAW);
 	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
 	XFlush(xw.dis);
 }

From eab9aad1dcd87ba1721bc63ef987203b7a643c69 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sun, 29 Aug 2010 19:14:05 +0200
Subject: [PATCH 0101/1146] added a XFlush() in xbell().

---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 9b77a0b..8f6aa04 100644
--- a/st.c
+++ b/st.c
@@ -230,6 +230,7 @@ void
 xbell(void) {
 	XSetForeground(xw.dis, dc.gc, dc.col[BellCol]);
 	XFillRectangle(xw.dis, xw.win, dc.gc, BORDER, BORDER, xw.bufw, xw.bufh);
+	XFlush(xw.dis);
 	usleep(BellTime);
 	draw(SCREEN_REDRAW);
 }
@@ -1293,7 +1294,7 @@ run(void) {
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);
-		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL) == -1) {
+		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL) < 0) {
 			if(errno == EINTR)
 				continue;
 			die("select failed: %s\n", SERRNO);

From b4f623f9109cc38a87469c6430d5e780e9a01989 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sun, 29 Aug 2010 19:41:36 +0200
Subject: [PATCH 0102/1146] fixed pixmap buffer drawing.

---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 8f6aa04..5f206fd 100644
--- a/st.c
+++ b/st.c
@@ -373,11 +373,11 @@ tscrollup (int n) {
 	for(i = 0; i < n; i++)
 		memset(term.line[term.top+i], 0, term.col*sizeof(Glyph));
 	
-	 for(i = term.top; i <= term.bot-n; i++) { 
+	for(i = term.top; i <= term.bot-n; i++) { 
 		 temp = term.line[i];
 		 term.line[i] = term.line[i+n]; 
 		 term.line[i+n] = temp;
-	 }
+	}
 }
 
 void
@@ -1181,7 +1181,7 @@ draw(int redraw_all) {
 	char buf[DRAW_BUF_SIZ];
 	
 	XSetForeground(xw.dis, dc.gc, dc.col[DefaultBG]);
-	XFillRectangle(xw.dis, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
+	XFillRectangle(xw.dis, xw.buf, dc.gc, 0, 0, xw.bufw, xw.bufh);
 	for(y = 0; y < term.row; y++) {
 		base = term.line[y][0];
 		i = ox = 0;

From 5258d6054599e456c260984b8619500d0b4b75b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Sun, 29 Aug 2010 20:12:44 +0200
Subject: [PATCH 0103/1146] fixed optimized drawing routine and factored some
 code.

---
 st.c | 33 ++++++++++++++++++---------------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/st.c b/st.c
index 5f206fd..5c7d855 100644
--- a/st.c
+++ b/st.c
@@ -46,8 +46,8 @@
 
 /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
 enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 };
-enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HIDE, CURSOR_DRAW, 
-       CURSOR_SAVE, CURSOR_LOAD };
+enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HIDE = 1, 
+       CURSOR_DRAW = 0, CURSOR_SAVE, CURSOR_LOAD };
 enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
 enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4 };
 enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
@@ -711,7 +711,7 @@ csihandle(void) {
 			case 12: /* att610 -- Stop blinking cursor (IGNORED) */
 				break;
 			case 25:
-				term.c.hide = 1;
+				term.c.hide = CURSOR_HIDE;
 				break;
 			case 1048: /* XXX: no alt. screen to erase/save */
 			case 1049:
@@ -760,7 +760,7 @@ csihandle(void) {
 			case 12: /* att610 -- Start blinking cursor (IGNORED) */
 				break;
 			case 25:
-				term.c.hide = 0;
+				term.c.hide = CURSOR_DRAW;
 				break;
 			case 1048: 
 			case 1049: /* XXX: no alt. screen to erase/save */
@@ -1166,8 +1166,7 @@ draw(int dummy) {
 			if(term.line[y][x].state & GLYPH_SET)
 				xdrawc(x, y, term.line[y][x]);
 
-	if(!term.c.hide)
-		xcursor(CURSOR_DRAW);
+	xcursor(term.c.hide);
 	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
 	XFlush(xw.dis);
 }
@@ -1187,19 +1186,23 @@ draw(int redraw_all) {
 		i = ox = 0;
 		for(x = 0; x < term.col; x++) {
 			new = term.line[y][x];
-			if(!ATTRCMP(base, new) && i < DRAW_BUF_SIZ)
-				buf[i++] = new.c;
-			else {
+			if(i > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) ||
+						i >= DRAW_BUF_SIZ)) {
 				xdraws(buf, base, ox, y, i);
-				buf[0] = new.c;
-				i = 1;
-				ox = x;
-				base = new;
+				i = 0;
+			}
+			if(new.state & GLYPH_SET) {
+				if(i == 0) {
+					ox = x;
+					base = new;
+				}
+				buf[i++] = new.c;
 			}
 		}
-		xdraws(buf, base, ox, y, i);
+		if(i > 0)
+			xdraws(buf, base, ox, y, i);
 	}
-	xcursor(term.c.hide ? CURSOR_HIDE : CURSOR_DRAW);
+	xcursor(term.c.hide);
 	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
 	XFlush(xw.dis);
 }

From 581ae58b4182c2d472b30d11dbbef813704642f1 Mon Sep 17 00:00:00 2001
From: pancake 
Date: Mon, 30 Aug 2010 00:32:49 +0200
Subject: [PATCH 0104/1146] fix warning

---
 st.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index 5c7d855..1692f81 100644
--- a/st.c
+++ b/st.c
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 

From 1f6e7b84c6131612cb8cb7751a2b373af9957c6d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Mon, 30 Aug 2010 01:19:05 +0200
Subject: [PATCH 0105/1146] removed old VT52 escapes, fixed VT100 IND.

---
 st.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index 5c7d855..6a51581 100644
--- a/st.c
+++ b/st.c
@@ -867,20 +867,11 @@ tputc(char c) {
 			case '(':
 				term.esc |= ESC_ALTCHARSET;
 				break;
-			case 'A':
-				tmoveto(term.c.x, term.c.y-1);
-				term.esc = 0;
-				break;
-			case 'B':
-				tmoveto(term.c.x, term.c.y+1);
-				term.esc = 0;
-				break;
-			case 'C':
-				tmoveto(term.c.x+1, term.c.y);
-				term.esc = 0;
-				break;
-			case 'D': /* XXX: CUP (VT100) or IND (VT52) ... */
-				tmoveto(term.c.x-1, term.c.y);
+			case 'D': /* IND -- Linefeed */
+				if(term.c.y == term.bot)
+					tscrollup(1);
+				else
+					tmoveto(term.c.x, term.c.y+1);
 				term.esc = 0;
 				break;
 			case 'E': /* NEL -- Next line */

From 7d88cf88d05c5f5fffbe096da9fac79d7d8957f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Mon, 30 Aug 2010 01:35:37 +0200
Subject: [PATCH 0106/1146] added support for the "magic margin", changed
 c.hide to c.state, changed xcursor() to use term instead of a

parameter and fixed the cursor position after setting a scrolling region.
---
 st.c | 52 +++++++++++++++++++++++++++++-----------------------
 1 file changed, 29 insertions(+), 23 deletions(-)

diff --git a/st.c b/st.c
index 6a51581..6dcded5 100644
--- a/st.c
+++ b/st.c
@@ -46,8 +46,9 @@
 
 /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
 enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 };
-enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HIDE = 1, 
-       CURSOR_DRAW = 0, CURSOR_SAVE, CURSOR_LOAD };
+enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT,
+       CURSOR_SAVE, CURSOR_LOAD };
+enum { CURSOR_DEFAULT = 0, CURSOR_HIDE = 1, CURSOR_WRAPNEXT = 2 };
 enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
 enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4 };
 enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
@@ -67,7 +68,7 @@ typedef struct {
 	Glyph attr;	 /* current char attributes */
 	int x;
 	int y;
-	char hide;
+	char state;
 } TCursor;
 
 /* CSI Escape sequence structs */
@@ -164,7 +165,7 @@ static void xbell(void);
 static void xdraws(char *, Glyph, int, int, int);
 static void xhints(void);
 static void xclear(int, int, int, int);
-static void xcursor(int);
+static void xcursor(void);
 static void xinit(void);
 static void xloadcols(void);
 
@@ -329,7 +330,7 @@ treset(void) {
 		.mode = ATTR_NULL, 
 		.fg = DefaultFG, 
 		.bg = DefaultBG
-	}, .x = 0, .y = 0, .hide = 0};
+	}, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
 	
 	term.top = 0, term.bot = term.row - 1;
 	term.mode = MODE_WRAP;
@@ -414,8 +415,11 @@ csiparse(void) {
 
 void
 tmoveto(int x, int y) {
-	term.c.x = x < 0 ? 0 : x >= term.col ? term.col-1 : x;
-	term.c.y = y < 0 ? 0 : y >= term.row ? term.row-1 : y;
+	LIMIT(x, 0, term.col-1);
+	LIMIT(y, 0, term.row-1);
+	term.c.state &= ~CURSOR_WRAPNEXT;
+	term.c.x = x;
+	term.c.y = y;
 }
 
 void
@@ -711,7 +715,7 @@ csihandle(void) {
 			case 12: /* att610 -- Stop blinking cursor (IGNORED) */
 				break;
 			case 25:
-				term.c.hide = CURSOR_HIDE;
+				term.c.state |= CURSOR_HIDE;
 				break;
 			case 1048: /* XXX: no alt. screen to erase/save */
 			case 1049:
@@ -760,7 +764,7 @@ csihandle(void) {
 			case 12: /* att610 -- Start blinking cursor (IGNORED) */
 				break;
 			case 25:
-				term.c.hide = CURSOR_DRAW;
+				term.c.state &= ~CURSOR_HIDE;
 				break;
 			case 1048: 
 			case 1049: /* XXX: no alt. screen to erase/save */
@@ -788,6 +792,7 @@ csihandle(void) {
 			DEFAULT(escseq.arg[0], 1);
 			DEFAULT(escseq.arg[1], term.row);
 			tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
+			tmoveto(0, 0);
 		}
 		break;
 	case 's': /* DECSC -- Save cursor position (ANSI.SYS) */
@@ -932,11 +937,13 @@ tputc(char c) {
 			term.esc = ESC_START;
 			break;
 		default:
-			tsetchar(c);
-			if(term.c.x+1 < term.col) {
-				tmoveto(term.c.x+1, term.c.y);
-			} else if(IS_SET(MODE_WRAP))
+			if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
 				tnewline();
+			tsetchar(c);
+			if(term.c.x+1 < term.col)
+				tmoveto(term.c.x+1, term.c.y);
+			else
+				term.c.state |= CURSOR_WRAPNEXT;
 			break;
 		}
 	}
@@ -974,13 +981,12 @@ tresize(int col, int row) {
 	for(/* i == minrow */; i < row; i++)
 		term.line[i] = calloc(col, sizeof(Glyph));
 	
-	LIMIT(term.c.x, 0, col-1);
-	LIMIT(term.c.y, 0, row-1);
-	LIMIT(term.top, 0, row-1);
-	LIMIT(term.bot, 0, row-1);
-	
-	term.bot = row-1;
+	/* update terminal size */
 	term.col = col, term.row = row;
+	/* make use of the LIMIT in tmoveto */
+	tmoveto(term.c.x, term.c.y);
+	/* reset scrolling region */
+	tsetscroll(0, row-1);
 }
 
 void
@@ -1112,7 +1118,7 @@ xdraws(char *s, Glyph base, int x, int y, int len) {
 }
 
 void
-xcursor(int mode) {
+xcursor(void) {
 	static int oldx = 0;
 	static int oldy = 0;
 	Glyph g = {' ', ATTR_NULL, DefaultBG, DefaultCS, 0};
@@ -1130,7 +1136,7 @@ xcursor(int mode) {
 		xclear(oldx, oldy, oldx, oldy);
 	
 	/* draw the new one */
-	if(mode == CURSOR_DRAW) {
+	if(!(term.c.state & CURSOR_HIDE)) {
 		xdraws(&g.c, g, term.c.x, term.c.y, 1);
 		oldx = term.c.x, oldy = term.c.y;
 	}
@@ -1157,7 +1163,7 @@ draw(int dummy) {
 			if(term.line[y][x].state & GLYPH_SET)
 				xdrawc(x, y, term.line[y][x]);
 
-	xcursor(term.c.hide);
+	xcursor();
 	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
 	XFlush(xw.dis);
 }
@@ -1193,7 +1199,7 @@ draw(int redraw_all) {
 		if(i > 0)
 			xdraws(buf, base, ox, y, i);
 	}
-	xcursor(term.c.hide);
+	xcursor();
 	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
 	XFlush(xw.dis);
 }

From 188293c828033fd7ff74d753239b3a5052b372a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Mon, 30 Aug 2010 01:45:57 +0200
Subject: [PATCH 0107/1146] removed useless cursor init. and renamed xcursor()
 to xdrawcursor().

---
 st.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index 6dcded5..36ff43c 100644
--- a/st.c
+++ b/st.c
@@ -165,7 +165,7 @@ static void xbell(void);
 static void xdraws(char *, Glyph, int, int, int);
 static void xhints(void);
 static void xclear(int, int, int, int);
-static void xcursor(void);
+static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
 
@@ -1071,9 +1071,6 @@ xinit(void) {
 	/* colors */
 	xloadcols();
 
-	term.c.attr.fg = DefaultFG;
-	term.c.attr.bg = DefaultBG;
-	term.c.attr.mode = ATTR_NULL;
 	/* windows */
 	xw.h = term.row * xw.ch + 2*BORDER;
 	xw.w = term.col * xw.cw + 2*BORDER;
@@ -1118,7 +1115,7 @@ xdraws(char *s, Glyph base, int x, int y, int len) {
 }
 
 void
-xcursor(void) {
+xdrawcursor(void) {
 	static int oldx = 0;
 	static int oldy = 0;
 	Glyph g = {' ', ATTR_NULL, DefaultBG, DefaultCS, 0};
@@ -1163,7 +1160,7 @@ draw(int dummy) {
 			if(term.line[y][x].state & GLYPH_SET)
 				xdrawc(x, y, term.line[y][x]);
 
-	xcursor();
+	xdrawcursor();
 	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
 	XFlush(xw.dis);
 }
@@ -1199,7 +1196,7 @@ draw(int redraw_all) {
 		if(i > 0)
 			xdraws(buf, base, ox, y, i);
 	}
-	xcursor();
+	xdrawcursor();
 	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
 	XFlush(xw.dis);
 }

From e851736e8bd6c04f1805659d4783de2314ecb263 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Mon, 30 Aug 2010 03:05:05 +0200
Subject: [PATCH 0108/1146] removed (visual) bell. '\a' sets the urgency flag
 if st is unfocused.

---
 config.h |  2 --
 st.c     | 42 ++++++++++++++++++++++++++----------------
 2 files changed, 26 insertions(+), 18 deletions(-)

diff --git a/config.h b/config.h
index 53795c6..5494b3b 100644
--- a/config.h
+++ b/config.h
@@ -29,8 +29,6 @@ static const char *colorname[] = {
 #define DefaultFG 7
 #define DefaultBG 0
 #define DefaultCS 1
-#define BellCol   DefaultFG
-#define BellTime  30000 /* microseconds */
 
 /* special keys */
 static Key key[] = {
diff --git a/st.c b/st.c
index 36ff43c..436533c 100644
--- a/st.c
+++ b/st.c
@@ -108,6 +108,7 @@ typedef struct {
 	int bufh; /* pixmap height */
 	int ch; /* char height */
 	int cw; /* char width  */
+	int hasfocus;
 } XWindow; 
 
 typedef struct {
@@ -161,23 +162,27 @@ static void ttyread(void);
 static void ttyresize(int, int);
 static void ttywrite(const char *, size_t);
 
-static void xbell(void);
 static void xdraws(char *, Glyph, int, int, int);
 static void xhints(void);
 static void xclear(int, int, int, int);
 static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
+static void xseturgency(int);
 
 static void expose(XEvent *);
 static char* kmap(KeySym);
 static void kpress(XEvent *);
 static void resize(XEvent *);
+static void focus(XEvent *);
+
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
 	[Expose] = expose,
-	[ConfigureNotify] = resize
+	[ConfigureNotify] = resize,
+	[FocusIn] = focus,
+	[FocusOut] = focus,
 };
 
 /* Globals */
@@ -187,7 +192,6 @@ static Term term;
 static CSIEscape escseq;
 static int cmdfd;
 static pid_t pid;
-static int running;
 
 #ifdef DEBUG
 void
@@ -227,15 +231,6 @@ execsh(void) {
 	execvp(args[0], args);
 }
 
-void
-xbell(void) {
-	XSetForeground(xw.dis, dc.gc, dc.col[BellCol]);
-	XFillRectangle(xw.dis, xw.win, dc.gc, BORDER, BORDER, xw.bufw, xw.bufh);
-	XFlush(xw.dis);
-	usleep(BellTime);
-	draw(SCREEN_REDRAW);
-}
-
 void 
 sigchld(int a) {
 	int stat = 0;
@@ -930,7 +925,8 @@ tputc(char c) {
 			tnewline();
 			break;
 		case '\a':
-			xbell();
+			if(!xw.hasfocus)
+				xseturgency(1);
 			break;
 		case '\033':
 			csireset();
@@ -1208,6 +1204,20 @@ expose(XEvent *ev) {
 	draw(SCREEN_REDRAW);
 }
 
+void
+xseturgency(int add) {
+	XWMHints *h = XGetWMHints(xw.dis, xw.win);
+	h->flags = add ? (h->flags | XUrgencyHint) : (h->flags & ~XUrgencyHint);
+	XSetWMHints(xw.dis, xw.win, h);
+	XFree(h);
+}
+
+void
+focus(XEvent *ev) {
+	if((xw.hasfocus = ev->type == FocusIn))
+		xseturgency(0);
+}
+
 char*
 kmap(KeySym k) {
 	int i;
@@ -1282,12 +1292,12 @@ run(void) {
 	XEvent ev;
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dis);
+	long mask = ExposureMask | KeyPressMask | StructureNotifyMask | FocusChangeMask;
 
-	running = 1;
-	XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNotifyMask);
+	XSelectInput(xw.dis, xw.win, mask);
 	XResizeWindow(xw.dis, xw.win, xw.w, xw.h); /* XXX: fix resize bug in wmii (?) */
 
-	while(running) {
+	while(1) {
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);

From bef87acd0d0e22ba4689be6f1c39ce2d90812317 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Mon, 30 Aug 2010 01:20:38 +0200
Subject: [PATCH 0109/1146] st should compile on NetBSD.

---
 config.mk | 1 +
 st.c      | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index b41a949..f0c7e2e 100644
--- a/config.mk
+++ b/config.mk
@@ -19,6 +19,7 @@ SYSTEM = -D`uname | tr a-z A-Z`
 #SYSTEM = -DLINUX
 #SYSTEM = -DOPENBSD
 #SYSTEM = -DFREEBSD
+#SYSTEM = -DNETBSD
 
 # flags
 CPPFLAGS = -DVERSION=\"${VERSION}\" ${SYSTEM}
diff --git a/st.c b/st.c
index 436533c..af3ec6d 100644
--- a/st.c
+++ b/st.c
@@ -22,7 +22,7 @@
 
 #if   defined(LINUX)
  #include 
-#elif defined(OPENBSD)
+#elif defined(OPENBSD) || defined(NETBSD)
  #include 
 #elif defined(FREEBSD)
  #include 

From ae5baac932af877cb18df6853d45f033ed9b270f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Mon, 30 Aug 2010 13:04:19 +0200
Subject: [PATCH 0110/1146] use predefined OS macro instead of uname.

---
 Makefile  | 1 -
 config.mk | 9 +--------
 st.c      | 6 +++---
 3 files changed, 4 insertions(+), 12 deletions(-)

diff --git a/Makefile b/Makefile
index ef3bf09..2fb13ae 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,6 @@ all: options st
 
 options:
 	@echo st build options:
-	@echo "SYSTEM   = ${SYSTEM}"
 	@echo "CFLAGS   = ${CFLAGS}"
 	@echo "LDFLAGS  = ${LDFLAGS}"
 	@echo "CC       = ${CC}"
diff --git a/config.mk b/config.mk
index f0c7e2e..46efc0c 100644
--- a/config.mk
+++ b/config.mk
@@ -14,15 +14,8 @@ X11LIB = /usr/X11R6/lib
 INCS = -I. -I/usr/include -I${X11INC}
 LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil
 
-# uncomment manualy your system if compilation fail
-SYSTEM = -D`uname | tr a-z A-Z`
-#SYSTEM = -DLINUX
-#SYSTEM = -DOPENBSD
-#SYSTEM = -DFREEBSD
-#SYSTEM = -DNETBSD
-
 # flags
-CPPFLAGS = -DVERSION=\"${VERSION}\" ${SYSTEM}
+CPPFLAGS = -DVERSION=\"${VERSION}\"
 CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
 LDFLAGS = -s ${LIBS}
 
diff --git a/st.c b/st.c
index af3ec6d..f42797f 100644
--- a/st.c
+++ b/st.c
@@ -20,11 +20,11 @@
 #include 
 #include 
 
-#if   defined(LINUX)
+#if   defined(__linux)
  #include 
-#elif defined(OPENBSD) || defined(NETBSD)
+#elif defined(__OpenBSD__) || defined(__NetBSD__)
  #include 
-#elif defined(FREEBSD)
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
  #include 
 #endif
 

From 326586ba434fb873ebdb81f385ebe838419a98a7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Mon, 30 Aug 2010 15:28:29 +0200
Subject: [PATCH 0111/1146] cursor is hid when unfocused.

---
 config.h | 2 +-
 st.c     | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/config.h b/config.h
index 5494b3b..8c37b16 100644
--- a/config.h
+++ b/config.h
@@ -1,7 +1,7 @@
 #define TAB    8
 #define TNAME "st-256color"
 #define FONT "6x13"
-#define BOLDFONT FONT"bold"
+#define BOLDFONT "6x13bold"
 #define BORDER 2
 
 /* Terminal colors */
diff --git a/st.c b/st.c
index f42797f..73121ef 100644
--- a/st.c
+++ b/st.c
@@ -1129,7 +1129,7 @@ xdrawcursor(void) {
 		xclear(oldx, oldy, oldx, oldy);
 	
 	/* draw the new one */
-	if(!(term.c.state & CURSOR_HIDE)) {
+	if(!(term.c.state & CURSOR_HIDE) && xw.hasfocus) {
 		xdraws(&g.c, g, term.c.x, term.c.y, 1);
 		oldx = term.c.x, oldy = term.c.y;
 	}
@@ -1216,6 +1216,7 @@ void
 focus(XEvent *ev) {
 	if((xw.hasfocus = ev->type == FocusIn))
 		xseturgency(0);
+	draw(SCREEN_UPDATE);
 }
 
 char*

From 12c25bcea973ced6e3b3b03f05cdb3f45fcd9f7f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Mon, 30 Aug 2010 16:48:18 +0200
Subject: [PATCH 0112/1146] added support for alternate screen.

---
 st.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 56 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index 73121ef..d928f0d 100644
--- a/st.c
+++ b/st.c
@@ -50,7 +50,7 @@ enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT,
        CURSOR_SAVE, CURSOR_LOAD };
 enum { CURSOR_DEFAULT = 0, CURSOR_HIDE = 1, CURSOR_WRAPNEXT = 2 };
 enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
-enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4 };
+enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8 };
 enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
 enum { SCREEN_UPDATE, SCREEN_REDRAW };
 
@@ -86,7 +86,8 @@ typedef struct {
 typedef struct {
 	int row;	/* nb row */  
 	int col;	/* nb col */
-	Line* line; /* screen */
+	Line* line;	/* screen */
+	Line* alt;	/* alternate screen */
 	TCursor c;	/* cursor */
 	int top;	/* top	  scroll limit */
 	int bot;	/* bottom scroll limit */
@@ -156,6 +157,7 @@ static void tscrolldown(int);
 static void tsetattr(int*, int);
 static void tsetchar(char);
 static void tsetscroll(int, int);
+static void tswapscreen(void);
 
 static void ttynew(void);
 static void ttyread(void);
@@ -337,12 +339,23 @@ tnew(int col, int row) {
 	/* set screen size */
 	term.row = row, term.col = col;
 	term.line = malloc(term.row * sizeof(Line));
-	for(row = 0 ; row < term.row; row++)
+	term.alt  = malloc(term.row * sizeof(Line));
+	for(row = 0 ; row < term.row; row++) {
 		term.line[row] = malloc(term.col * sizeof(Glyph));
+		term.alt [row] = malloc(term.col * sizeof(Glyph));
+	}
 	/* setup screen */
 	treset();
 }
 
+void
+tswapscreen(void) {
+	Line* tmp = term.line;
+	term.line = term.alt;
+	term.alt = tmp;
+	term.mode ^= MODE_ALTSCREEN;
+}
+
 void
 tscrolldown (int n) {
 	int i;
@@ -712,10 +725,21 @@ csihandle(void) {
 			case 25:
 				term.c.state |= CURSOR_HIDE;
 				break;
-			case 1048: /* XXX: no alt. screen to erase/save */
+			case 1047:
+				if(IS_SET(MODE_ALTSCREEN)) {
+					tclearregion(0, 0, term.col-1, term.row-1);
+					tswapscreen();
+				}
+				break;
+			case 1048:
+				tcursor(CURSOR_LOAD);
+				break;
 			case 1049:
 				tcursor(CURSOR_LOAD);
-				tclearregion(0, 0, term.col-1, term.row-1);
+				if(IS_SET(MODE_ALTSCREEN)) {
+					tclearregion(0, 0, term.col-1, term.row-1);
+					tswapscreen();
+				}
 				break;
 			default:
 				goto unknown;
@@ -761,10 +785,21 @@ csihandle(void) {
 			case 25:
 				term.c.state &= ~CURSOR_HIDE;
 				break;
-			case 1048: 
-			case 1049: /* XXX: no alt. screen to erase/save */
+			case 1047:
+				if(IS_SET(MODE_ALTSCREEN))
+					tclearregion(0, 0, term.col-1, term.row-1);
+				else
+					tswapscreen();
+				break;				
+			case 1048:
 				tcursor(CURSOR_SAVE);
-				tclearregion(0, 0, term.col-1, term.row-1);
+				break;
+			case 1049:
+				tcursor(CURSOR_SAVE);
+				if(IS_SET(MODE_ALTSCREEN))
+					tclearregion(0, 0, term.col-1, term.row-1);
+				else
+					tswapscreen();
 				break;
 			default: goto unknown;
 			}
@@ -889,19 +924,19 @@ tputc(char c) {
 				treset();
 				term.esc = 0;
 				break;
-			case '=': /* DECPAM */
+			case '=': /* DECPAM -- Application keypad */
 				term.mode |= MODE_APPKEYPAD;
 				term.esc = 0;
 				break;
-			case '>': /* DECPNM */
+			case '>': /* DECPNM -- Normal keypad */
 				term.mode &= ~MODE_APPKEYPAD;
 				term.esc = 0;
 				break;
-			case '7':
+			case '7': /* DECSC -- Save Cursor*/
 				tcursor(CURSOR_SAVE);
 				term.esc = 0;
 				break;
-			case '8':
+			case '8': /* DECRC -- Restore Cursor */
 				tcursor(CURSOR_LOAD);
 				term.esc = 0;
 				break;
@@ -961,21 +996,28 @@ tresize(int col, int row) {
 		return;
 
 	/* free uneeded rows */
-	for(i = row; i < term.row; i++)
+	for(i = row; i < term.row; i++) {
 		free(term.line[i]);
+		free(term.alt[i]);
+	}
 
 	/* resize to new height */
 	term.line = realloc(term.line, row * sizeof(Line));
+	term.line = realloc(term.alt,  row * sizeof(Line));
 
 	/* resize each row to new width, zero-pad if needed */
 	for(i = 0; i < minrow; i++) {
 		term.line[i] = realloc(term.line[i], col * sizeof(Glyph));
+		term.alt[i]  = realloc(term.alt[i],  col * sizeof(Glyph));
 		memset(term.line[i] + mincol, 0, (col - mincol) * sizeof(Glyph));
+		memset(term.alt[i]  + mincol, 0, (col - mincol) * sizeof(Glyph));
 	}
 
 	/* allocate any new rows */
-	for(/* i == minrow */; i < row; i++)
+	for(/* i == minrow */; i < row; i++) {
 		term.line[i] = calloc(col, sizeof(Glyph));
+		term.alt [i] = calloc(col, sizeof(Glyph));
+	}
 	
 	/* update terminal size */
 	term.col = col, term.row = row;

From e1ce89f2678628b1c0e904800822a553de2817de Mon Sep 17 00:00:00 2001
From: "pancake@nopcode.org" 
Date: Mon, 30 Aug 2010 17:07:54 +0200
Subject: [PATCH 0113/1146] fix segfault

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index d928f0d..fb1172a 100644
--- a/st.c
+++ b/st.c
@@ -1003,7 +1003,7 @@ tresize(int col, int row) {
 
 	/* resize to new height */
 	term.line = realloc(term.line, row * sizeof(Line));
-	term.line = realloc(term.alt,  row * sizeof(Line));
+	term.alt = realloc(term.alt,  row * sizeof(Line));
 
 	/* resize each row to new width, zero-pad if needed */
 	for(i = 0; i < minrow; i++) {

From 0ba53e48c76a2a2668dfa270cfd0227461c3a91b Mon Sep 17 00:00:00 2001
From: pancake 
Date: Mon, 30 Aug 2010 23:41:37 +0200
Subject: [PATCH 0114/1146] initial implementation of selection and clipboard

---
 st.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 108 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index fb1172a..864dfc7 100644
--- a/st.c
+++ b/st.c
@@ -177,6 +177,9 @@ static char* kmap(KeySym);
 static void kpress(XEvent *);
 static void resize(XEvent *);
 static void focus(XEvent *);
+static void brelease(XEvent *e);
+static void bpress(XEvent *e);
+static void bmotion(XEvent *e);
 
 
 static void (*handler[LASTEvent])(XEvent *) = {
@@ -185,6 +188,9 @@ static void (*handler[LASTEvent])(XEvent *) = {
 	[ConfigureNotify] = resize,
 	[FocusIn] = focus,
 	[FocusOut] = focus,
+	[MotionNotify] = bmotion,
+	[ButtonPress] = bpress,
+	[ButtonRelease] = brelease,
 };
 
 /* Globals */
@@ -195,6 +201,103 @@ static CSIEscape escseq;
 static int cmdfd;
 static pid_t pid;
 
+/* selection */
+// TODO: use X11 clipboard
+static int selmode = 0;
+static int selbx = -1, selby;
+static int selex, seley;
+int sb[2], se[2];
+static const char *clipboard = NULL;
+
+static inline int selected(int x, int y) {
+	if ((seley==y && selby==y)) {
+		int bx = MIN(selbx, selex);
+		int ex = MAX(selbx, selex);
+		return if(x>=bx && x<=ex)
+	}
+	return (((y>sb[1] && y=sb[0] && (x<=se[0] || sb[1]!=se[1])))
+}
+
+static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
+	if(b) *b = e->xbutton.state,
+		*b=*b==4096?5:*b==2048?4:*b==1024?3:*b==512?2:*b==256?1:-1;
+	*x = e->xbutton.x/xw.cw;
+	*y = e->xbutton.y/xw.ch;
+	sb[0] = selbyxbutton.x/xw.cw;
+	seley = selby = e->xbutton.y/xw.ch;
+}
+
+static char *getseltext() {
+	char *str, *ptr;
+	int ls, x, y, sz;
+	if(selbx==-1)
+		return NULL;
+	sz = ((xw.w/xw.ch) * (se[1]-sb[1]+2));
+	ptr = str = malloc (sz);
+	for(y = 0; y < term.row; y++) {
+		for(x = 0; x < term.col; x++) {
+			if(term.line[y][x].c && (ls=selected(x, y))) {
+				*ptr = term.line[y][x].c;
+				ptr++;
+			}
+		}
+		if (ls) {
+			*ptr = '\n';
+			ptr++;
+		}
+	}
+	*ptr = 0;
+	return str;
+}
+
+static void clipboard_copy(const char *str) {
+	free((void *)clipboard);
+	clipboard = str;
+}
+
+static void clipboard_paste() {
+	if(clipboard)
+		ttywrite(clipboard, strlen(clipboard));
+}
+
+// TODO: doubleclick to select word
+static void brelease(XEvent *e) {
+	int b;
+	selmode = 0;
+	getbuttoninfo(e, &b, &selex, &seley);
+	if(b==4)
+		tscrollup(1);
+	else
+	if(b==5)
+		tscrolldown(1);
+	else
+	if(selbx==selex && selby==seley) {
+		selbx = -1;
+		if(b==2)
+			clipboard_paste();
+	} else {
+		if(b==1)
+			clipboard_copy(getseltext());
+	}
+	draw(1);
+}
+
+static void bmotion(XEvent *e) {
+	if (selmode) {
+		getbuttoninfo(e, NULL, &selex, &seley);
+		draw(1);
+	}
+}
+
 #ifdef DEBUG
 void
 tdump(void) {
@@ -1210,7 +1313,7 @@ draw(int redraw_all) {
 	int i, x, y, ox;
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
-	
+
 	XSetForeground(xw.dis, dc.gc, dc.col[DefaultBG]);
 	XFillRectangle(xw.dis, xw.buf, dc.gc, 0, 0, xw.bufw, xw.bufh);
 	for(y = 0; y < term.row; y++) {
@@ -1218,8 +1321,10 @@ draw(int redraw_all) {
 		i = ox = 0;
 		for(x = 0; x < term.col; x++) {
 			new = term.line[y][x];
+			if(selbx!=-1 && new.c && selected(x, y))
+				new.mode = ATTR_REVERSE;
 			if(i > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) ||
-						i >= DRAW_BUF_SIZ)) {
+					i >= DRAW_BUF_SIZ)) {
 				xdraws(buf, base, ox, y, i);
 				i = 0;
 			}
@@ -1335,7 +1440,7 @@ run(void) {
 	XEvent ev;
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dis);
-	long mask = ExposureMask | KeyPressMask | StructureNotifyMask | FocusChangeMask;
+	long mask = ExposureMask | KeyPressMask | StructureNotifyMask | FocusChangeMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
 
 	XSelectInput(xw.dis, xw.win, mask);
 	XResizeWindow(xw.dis, xw.win, xw.w, xw.h); /* XXX: fix resize bug in wmii (?) */

From 596bb133a55a6aba13b55795a9a38e29fcf1b38b Mon Sep 17 00:00:00 2001
From: pancake 
Date: Mon, 30 Aug 2010 23:49:15 +0200
Subject: [PATCH 0115/1146] fix build

use config.def.h mechanism
add SHELL in config.h
---
 Makefile                 |  5 ++++-
 config.h => config.def.h | 11 ++++++-----
 st.c                     |  6 +++---
 3 files changed, 13 insertions(+), 9 deletions(-)
 rename config.h => config.def.h (89%)

diff --git a/Makefile b/Makefile
index 2fb13ae..5267411 100644
--- a/Makefile
+++ b/Makefile
@@ -8,12 +8,15 @@ OBJ = ${SRC:.c=.o}
 
 all: options st
 
-options:
+options: options
 	@echo st build options:
 	@echo "CFLAGS   = ${CFLAGS}"
 	@echo "LDFLAGS  = ${LDFLAGS}"
 	@echo "CC       = ${CC}"
 
+config.h:
+	cp config.def.h config.h
+
 .c.o:
 	@echo CC $<
 	@${CC} -c ${CFLAGS} $<
diff --git a/config.h b/config.def.h
similarity index 89%
rename from config.h
rename to config.def.h
index 8c37b16..9506bc6 100644
--- a/config.h
+++ b/config.def.h
@@ -3,6 +3,7 @@
 #define FONT "6x13"
 #define BOLDFONT "6x13bold"
 #define BORDER 2
+#define SHELL "/bin/sh"
 
 /* Terminal colors */
 static const char *colorname[] = {
@@ -33,11 +34,11 @@ static const char *colorname[] = {
 /* special keys */
 static Key key[] = {
 	{ XK_BackSpace, "\177" },
-	{ XK_Delete, "\033[3~" },
-	{ XK_Home,   "\033[1~" },
-	{ XK_End,    "\033[4~" },
-	{ XK_Prior,  "\033[5~" },
-	{ XK_Next,   "\033[6~" },
+	{ XK_Delete,    "\033[3~" },
+	{ XK_Home,      "\033[1~" },
+	{ XK_End,       "\033[4~" },
+	{ XK_Prior,     "\033[5~" },
+	{ XK_Next,      "\033[6~" },
 	{ XK_F1,        "\033OP"   },
 	{ XK_F2,        "\033OQ"   },
 	{ XK_F3,        "\033OR"   },
diff --git a/st.c b/st.c
index 864dfc7..0b21404 100644
--- a/st.c
+++ b/st.c
@@ -213,10 +213,10 @@ static inline int selected(int x, int y) {
 	if ((seley==y && selby==y)) {
 		int bx = MIN(selbx, selex);
 		int ex = MAX(selbx, selex);
-		return if(x>=bx && x<=ex)
+		return (x>=bx && x<=ex);
 	}
 	return (((y>sb[1] && y=sb[0] && (x<=se[0] || sb[1]!=se[1])))
+		(y==sb[1] && x>=sb[0] && (x<=se[0] || sb[1]!=se[1])));
 }
 
 static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
@@ -331,7 +331,7 @@ die(const char *errstr, ...) {
 void
 execsh(void) {
 	char *args[3] = {getenv("SHELL"), "-i", NULL};
-	DEFAULT(args[0], "/bin/sh"); /* if getenv() failed */
+	DEFAULT(args[0], SHELL); /* if getenv() failed */
 	putenv("TERM=" TNAME);
 	execvp(args[0], args);
 }

From 160bda1b60148ce8f7d3b001ada2b12f1da9e152 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Tue, 31 Aug 2010 11:02:17 +0200
Subject: [PATCH 0116/1146] toggle ATTR_REVERSE on selected text, factored some
 code and fixed Makefile.

---
 Makefile |  2 +-
 st.c     | 25 ++++++++-----------------
 2 files changed, 9 insertions(+), 18 deletions(-)

diff --git a/Makefile b/Makefile
index 5267411..920bd9a 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ OBJ = ${SRC:.c=.o}
 
 all: options st
 
-options: options
+options:
 	@echo st build options:
 	@echo "CFLAGS   = ${CFLAGS}"
 	@echo "LDFLAGS  = ${LDFLAGS}"
diff --git a/st.c b/st.c
index 0b21404..6a90176 100644
--- a/st.c
+++ b/st.c
@@ -828,22 +828,17 @@ csihandle(void) {
 			case 25:
 				term.c.state |= CURSOR_HIDE;
 				break;
+			case 1049: /* = 1047 and 1048 */
 			case 1047:
 				if(IS_SET(MODE_ALTSCREEN)) {
 					tclearregion(0, 0, term.col-1, term.row-1);
 					tswapscreen();
 				}
-				break;
+				if(escseq.arg[0] == 1047)
+					break;
 			case 1048:
 				tcursor(CURSOR_LOAD);
 				break;
-			case 1049:
-				tcursor(CURSOR_LOAD);
-				if(IS_SET(MODE_ALTSCREEN)) {
-					tclearregion(0, 0, term.col-1, term.row-1);
-					tswapscreen();
-				}
-				break;
 			default:
 				goto unknown;
 			}
@@ -888,22 +883,17 @@ csihandle(void) {
 			case 25:
 				term.c.state &= ~CURSOR_HIDE;
 				break;
+			case 1049: /* = 1047 and 1048 */
 			case 1047:
 				if(IS_SET(MODE_ALTSCREEN))
 					tclearregion(0, 0, term.col-1, term.row-1);
 				else
 					tswapscreen();
-				break;				
+				if(escseq.arg[0] == 1047)
+					break;
 			case 1048:
 				tcursor(CURSOR_SAVE);
 				break;
-			case 1049:
-				tcursor(CURSOR_SAVE);
-				if(IS_SET(MODE_ALTSCREEN))
-					tclearregion(0, 0, term.col-1, term.row-1);
-				else
-					tswapscreen();
-				break;
 			default: goto unknown;
 			}
 		} else {
@@ -1222,6 +1212,7 @@ xinit(void) {
 	xw.bufw = xw.w - 2*BORDER;
 	xw.bufh = xw.h - 2*BORDER;
 	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
+	xw.hasfocus = 1;
 	/* gc */
 	dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL);
 	XMapWindow(xw.dis, xw.win);
@@ -1322,7 +1313,7 @@ draw(int redraw_all) {
 		for(x = 0; x < term.col; x++) {
 			new = term.line[y][x];
 			if(selbx!=-1 && new.c && selected(x, y))
-				new.mode = ATTR_REVERSE;
+				new.mode ^= ATTR_REVERSE;
 			if(i > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) ||
 					i >= DRAW_BUF_SIZ)) {
 				xdraws(buf, base, ox, y, i);

From 23cc3fc5715a650c91e3b99074c31aaf63e2102c Mon Sep 17 00:00:00 2001
From: "pancake@nopcode.org" 
Date: Tue, 31 Aug 2010 11:40:57 +0200
Subject: [PATCH 0117/1146] fix crash for small windows

use unconditional infinite loops
---
 st.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 6a90176..7567e57 100644
--- a/st.c
+++ b/st.c
@@ -1422,6 +1422,10 @@ resize(XEvent *e) {
 	tresize(col, row);
 	ttyresize(col, row);
 	XFreePixmap(xw.dis, xw.buf);
+	if(xw.bufh<1)
+		xw.bufh = 1;
+	if(xw.bufw<1)
+		xw.bufw = 1;
 	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
 	draw(SCREEN_REDRAW);
 }
@@ -1436,7 +1440,7 @@ run(void) {
 	XSelectInput(xw.dis, xw.win, mask);
 	XResizeWindow(xw.dis, xw.win, xw.w, xw.h); /* XXX: fix resize bug in wmii (?) */
 
-	while(1) {
+	for(;;) {
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);

From 80f70f1c224ec6fb10f04c29ea2205f47ae553ff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Tue, 31 Aug 2010 14:52:52 +0200
Subject: [PATCH 0118/1146] use GLYPH_SET to test if a char is set; cleanup.

---
 st.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index 7567e57..665dc1a 100644
--- a/st.c
+++ b/st.c
@@ -245,7 +245,7 @@ static char *getseltext() {
 	ptr = str = malloc (sz);
 	for(y = 0; y < term.row; y++) {
 		for(x = 0; x < term.col; x++) {
-			if(term.line[y][x].c && (ls=selected(x, y))) {
+			if(term.line[y][x].state & GLYPH_SET && (ls=selected(x, y))) {
 				*ptr = term.line[y][x].c;
 				ptr++;
 			}
@@ -1421,11 +1421,9 @@ resize(XEvent *e) {
 	row = xw.bufh / xw.ch;
 	tresize(col, row);
 	ttyresize(col, row);
+	xw.bufh = MAX(1, xw.bufh);
+	xw.bufw = MAX(1, xw.bufw);
 	XFreePixmap(xw.dis, xw.buf);
-	if(xw.bufh<1)
-		xw.bufh = 1;
-	if(xw.bufw<1)
-		xw.bufw = 1;
 	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
 	draw(SCREEN_REDRAW);
 }
@@ -1435,7 +1433,9 @@ run(void) {
 	XEvent ev;
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dis);
-	long mask = ExposureMask | KeyPressMask | StructureNotifyMask | FocusChangeMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
+	long mask = ExposureMask | KeyPressMask | StructureNotifyMask
+		| FocusChangeMask | PointerMotionMask | ButtonPressMask 
+		| ButtonReleaseMask;
 
 	XSelectInput(xw.dis, xw.win, mask);
 	XResizeWindow(xw.dis, xw.win, xw.w, xw.h); /* XXX: fix resize bug in wmii (?) */

From ee858b4805aec3e12bff48cf27433ebcd3f6ac34 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Tue, 31 Aug 2010 15:36:13 +0200
Subject: [PATCH 0119/1146] use one global struct instead of many vars for
 selection. Cleanup.

---
 st.c | 74 +++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 38 insertions(+), 36 deletions(-)

diff --git a/st.c b/st.c
index 665dc1a..4a89876 100644
--- a/st.c
+++ b/st.c
@@ -125,6 +125,14 @@ typedef struct {
 	GC gc;
 } DC;
 
+typedef struct {
+	int mode;
+	int bx, by;
+	int ex, ey;
+	int b[2], e[2];
+	char *clip;
+} Selection;
+
 #include "config.h"
 
 static void die(const char *errstr, ...);
@@ -200,23 +208,18 @@ static Term term;
 static CSIEscape escseq;
 static int cmdfd;
 static pid_t pid;
+static Selection sel;
 
-/* selection */
-// TODO: use X11 clipboard
-static int selmode = 0;
-static int selbx = -1, selby;
-static int selex, seley;
-int sb[2], se[2];
-static const char *clipboard = NULL;
+/* TODO: use X11 clipboard */
 
 static inline int selected(int x, int y) {
-	if ((seley==y && selby==y)) {
-		int bx = MIN(selbx, selex);
-		int ex = MAX(selbx, selex);
+	if ((sel.ey==y && sel.by==y)) {
+		int bx = MIN(sel.bx, sel.ex);
+		int ex = MAX(sel.bx, sel.ex);
 		return (x>=bx && x<=ex);
 	}
-	return (((y>sb[1] && y=sb[0] && (x<=se[0] || sb[1]!=se[1])));
+	return (((y>sel.b[1] && y=sel.b[0] && (x<=sel.e[0] || sel.b[1]!=sel.e[1])));
 }
 
 static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
@@ -224,24 +227,24 @@ static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
 		*b=*b==4096?5:*b==2048?4:*b==1024?3:*b==512?2:*b==256?1:-1;
 	*x = e->xbutton.x/xw.cw;
 	*y = e->xbutton.y/xw.ch;
-	sb[0] = selbyxbutton.x/xw.cw;
-	seley = selby = e->xbutton.y/xw.ch;
+	sel.mode = 1;
+	sel.ex = sel.bx = e->xbutton.x/xw.cw;
+	sel.ey = sel.by = e->xbutton.y/xw.ch;
 }
 
 static char *getseltext() {
 	char *str, *ptr;
 	int ls, x, y, sz;
-	if(selbx==-1)
+	if(sel.bx==-1)
 		return NULL;
-	sz = ((xw.w/xw.ch) * (se[1]-sb[1]+2));
+	sz = ((xw.w/xw.ch) * (sel.e[1]-sel.b[1]+2));
 	ptr = str = malloc (sz);
 	for(y = 0; y < term.row; y++) {
 		for(x = 0; x < term.col; x++) {
@@ -259,29 +262,29 @@ static char *getseltext() {
 	return str;
 }
 
-static void clipboard_copy(const char *str) {
-	free((void *)clipboard);
-	clipboard = str;
+static void clipboard_copy(char *str) {
+	free(sel.clip);
+	sel.clip = str;
 }
 
 static void clipboard_paste() {
-	if(clipboard)
-		ttywrite(clipboard, strlen(clipboard));
+	if(sel.clip)
+		ttywrite(sel.clip, strlen(sel.clip));
 }
 
 // TODO: doubleclick to select word
 static void brelease(XEvent *e) {
 	int b;
-	selmode = 0;
-	getbuttoninfo(e, &b, &selex, &seley);
+	sel.mode = 0;
+	getbuttoninfo(e, &b, &sel.ex, &sel.ey);
 	if(b==4)
 		tscrollup(1);
 	else
 	if(b==5)
 		tscrolldown(1);
 	else
-	if(selbx==selex && selby==seley) {
-		selbx = -1;
+	if(sel.bx==sel.ex && sel.by==sel.ey) {
+		sel.bx = -1;
 		if(b==2)
 			clipboard_paste();
 	} else {
@@ -292,8 +295,8 @@ static void brelease(XEvent *e) {
 }
 
 static void bmotion(XEvent *e) {
-	if (selmode) {
-		getbuttoninfo(e, NULL, &selex, &seley);
+	if (sel.mode) {
+		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
 		draw(1);
 	}
 }
@@ -784,7 +787,6 @@ csihandle(void) {
 		case 2: /* all */
 			tclearregion(0, 0, term.col-1, term.row-1);
 			break;
-		case 3: /* XXX: erase saved lines (xterm) */
 		default:
 			goto unknown;
 		}
@@ -1025,7 +1027,7 @@ tputc(char c) {
 				term.mode &= ~MODE_APPKEYPAD;
 				term.esc = 0;
 				break;
-			case '7': /* DECSC -- Save Cursor*/
+			case '7': /* DECSC -- Save Cursor */
 				tcursor(CURSOR_SAVE);
 				term.esc = 0;
 				break;
@@ -1096,7 +1098,7 @@ tresize(int col, int row) {
 
 	/* resize to new height */
 	term.line = realloc(term.line, row * sizeof(Line));
-	term.alt = realloc(term.alt,  row * sizeof(Line));
+	term.alt  = realloc(term.alt,  row * sizeof(Line));
 
 	/* resize each row to new width, zero-pad if needed */
 	for(i = 0; i < minrow; i++) {
@@ -1312,7 +1314,7 @@ draw(int redraw_all) {
 		i = ox = 0;
 		for(x = 0; x < term.col; x++) {
 			new = term.line[y][x];
-			if(selbx!=-1 && new.c && selected(x, y))
+			if(sel.bx!=-1 && new.c && selected(x, y))
 				new.mode ^= ATTR_REVERSE;
 			if(i > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) ||
 					i >= DRAW_BUF_SIZ)) {

From f211bc2eedaa8ea86dc66ad04ccd08938c73a93c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Tue, 31 Aug 2010 16:30:11 +0200
Subject: [PATCH 0120/1146] move event configuration in xinit().

---
 st.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/st.c b/st.c
index 4a89876..1497dd2 100644
--- a/st.c
+++ b/st.c
@@ -210,8 +210,6 @@ static int cmdfd;
 static pid_t pid;
 static Selection sel;
 
-/* TODO: use X11 clipboard */
-
 static inline int selected(int x, int y) {
 	if ((sel.ey==y && sel.by==y)) {
 		int bx = MIN(sel.bx, sel.ex);
@@ -262,6 +260,7 @@ static char *getseltext() {
 	return str;
 }
 
+/* TODO: use X11 clipboard */
 static void clipboard_copy(char *str) {
 	free(sel.clip);
 	sel.clip = str;
@@ -272,7 +271,7 @@ static void clipboard_paste() {
 		ttywrite(sel.clip, strlen(sel.clip));
 }
 
-// TODO: doubleclick to select word
+/* TODO: doubleclick to select word */
 static void brelease(XEvent *e) {
 	int b;
 	sel.mode = 0;
@@ -1214,9 +1213,14 @@ xinit(void) {
 	xw.bufw = xw.w - 2*BORDER;
 	xw.bufh = xw.h - 2*BORDER;
 	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
-	xw.hasfocus = 1;
 	/* gc */
 	dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL);
+	
+	/* event mask */
+	XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask
+		| StructureNotifyMask | FocusChangeMask | PointerMotionMask
+		| ButtonPressMask | ButtonReleaseMask);
+	
 	XMapWindow(xw.dis, xw.win);
 	xhints();
 	XStoreName(xw.dis, xw.win, "st");
@@ -1435,12 +1439,6 @@ run(void) {
 	XEvent ev;
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dis);
-	long mask = ExposureMask | KeyPressMask | StructureNotifyMask
-		| FocusChangeMask | PointerMotionMask | ButtonPressMask 
-		| ButtonReleaseMask;
-
-	XSelectInput(xw.dis, xw.win, mask);
-	XResizeWindow(xw.dis, xw.win, xw.w, xw.h); /* XXX: fix resize bug in wmii (?) */
 
 	for(;;) {
 		FD_ZERO(&rfd);

From c4225bdcc9da2eb87e49608cc1821757cbd69dee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Tue, 31 Aug 2010 16:53:34 +0200
Subject: [PATCH 0121/1146] add selinit() and renamed clipboard_* to sel*.

---
 st.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 1497dd2..67ba8d5 100644
--- a/st.c
+++ b/st.c
@@ -185,9 +185,9 @@ static char* kmap(KeySym);
 static void kpress(XEvent *);
 static void resize(XEvent *);
 static void focus(XEvent *);
-static void brelease(XEvent *e);
-static void bpress(XEvent *e);
-static void bmotion(XEvent *e);
+static void brelease(XEvent *);
+static void bpress(XEvent *);
+static void bmotion(XEvent *);
 
 
 static void (*handler[LASTEvent])(XEvent *) = {
@@ -210,6 +210,13 @@ static int cmdfd;
 static pid_t pid;
 static Selection sel;
 
+void
+selinit(void) {
+	sel.mode = 0;
+	sel.bx = -1;
+	sel.clip = NULL;
+}
+
 static inline int selected(int x, int y) {
 	if ((sel.ey==y && sel.by==y)) {
 		int bx = MIN(sel.bx, sel.ex);
@@ -261,12 +268,12 @@ static char *getseltext() {
 }
 
 /* TODO: use X11 clipboard */
-static void clipboard_copy(char *str) {
+static void selcopy(char *str) {
 	free(sel.clip);
 	sel.clip = str;
 }
 
-static void clipboard_paste() {
+static void selpaste() {
 	if(sel.clip)
 		ttywrite(sel.clip, strlen(sel.clip));
 }
@@ -1471,6 +1478,7 @@ main(int argc, char *argv[]) {
 	tnew(80, 24);
 	ttynew();
 	xinit();
+	selinit();
 	run();
 	return 0;
 }

From 1132d9e2d65f469dedd9c5b6f356495c7a87b743 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Tue, 31 Aug 2010 16:56:27 +0200
Subject: [PATCH 0122/1146] fix build.

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 67ba8d5..1474c53 100644
--- a/st.c
+++ b/st.c
@@ -292,10 +292,10 @@ static void brelease(XEvent *e) {
 	if(sel.bx==sel.ex && sel.by==sel.ey) {
 		sel.bx = -1;
 		if(b==2)
-			clipboard_paste();
+			selpaste();
 	} else {
 		if(b==1)
-			clipboard_copy(getseltext());
+			selcopy(getseltext());
 	}
 	draw(1);
 }

From 591d147af7d59f31a68513f613124d49f25f9859 Mon Sep 17 00:00:00 2001
From: "pancake@nopcode.org" 
Date: Tue, 31 Aug 2010 17:36:55 +0200
Subject: [PATCH 0123/1146] fix segfault when selecting big buffers

shift+insert paste clipboard
honor CFLAGS and LDFLAGS in config.mk
---
 config.mk |  6 +++---
 st.c      | 22 ++++++----------------
 2 files changed, 9 insertions(+), 19 deletions(-)

diff --git a/config.mk b/config.mk
index 46efc0c..01a3779 100644
--- a/config.mk
+++ b/config.mk
@@ -16,8 +16,8 @@ LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil
 
 # flags
 CPPFLAGS = -DVERSION=\"${VERSION}\"
-CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
-LDFLAGS = -s ${LIBS}
+CFLAGS += -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
+LDFLAGS += -s ${LIBS}
 
 # compiler and linker
-CC = cc
+CC ?= cc
diff --git a/st.c b/st.c
index 1474c53..c2f294a 100644
--- a/st.c
+++ b/st.c
@@ -249,19 +249,15 @@ static char *getseltext() {
 	int ls, x, y, sz;
 	if(sel.bx==-1)
 		return NULL;
-	sz = ((xw.w/xw.ch) * (sel.e[1]-sel.b[1]+2));
+	sz = ((term.col+1) * (sel.e[1]-sel.b[1]+1));
 	ptr = str = malloc (sz);
 	for(y = 0; y < term.row; y++) {
 		for(x = 0; x < term.col; x++) {
-			if(term.line[y][x].state & GLYPH_SET && (ls=selected(x, y))) {
-				*ptr = term.line[y][x].c;
-				ptr++;
-			}
-		}
-		if (ls) {
-			*ptr = '\n';
-			ptr++;
+			if(term.line[y][x].state & GLYPH_SET && (ls=selected(x, y)))
+				*ptr = term.line[y][x].c, ptr++;
 		}
+		if (ls)
+			*ptr = '\n', ptr++;
 	}
 	*ptr = 0;
 	return str;
@@ -283,12 +279,6 @@ static void brelease(XEvent *e) {
 	int b;
 	sel.mode = 0;
 	getbuttoninfo(e, &b, &sel.ex, &sel.ey);
-	if(b==4)
-		tscrollup(1);
-	else
-	if(b==5)
-		tscrolldown(1);
-	else
 	if(sel.bx==sel.ex && sel.by==sel.ey) {
 		sel.bx = -1;
 		if(b==2)
@@ -1411,7 +1401,7 @@ kpress(XEvent *ev) {
 			break;
 		case XK_Insert:
 			if(shift)
-				draw(1), puts("draw!")/* XXX: paste X clipboard */;
+				selpaste(), draw(1);
 			break;
 		default:
 			fprintf(stderr, "errkey: %d\n", (int)ksym);

From 9703859e6c1e2280036dc7992cb4c54688f719f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Tue, 31 Aug 2010 18:22:59 +0200
Subject: [PATCH 0124/1146] cleanup.

---
 st.c | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/st.c b/st.c
index c2f294a..bff500b 100644
--- a/st.c
+++ b/st.c
@@ -218,13 +218,13 @@ selinit(void) {
 }
 
 static inline int selected(int x, int y) {
-	if ((sel.ey==y && sel.by==y)) {
+	if(sel.ey == y && sel.by == y) {
 		int bx = MIN(sel.bx, sel.ex);
 		int ex = MAX(sel.bx, sel.ex);
-		return (x>=bx && x<=ex);
+		return BETWEEN(x, bx, ex);
 	}
-	return (((y>sel.b[1] && y=sel.b[0] && (x<=sel.e[0] || sel.b[1]!=sel.e[1])));
+	return ((sel.b[1] < y&&y < sel.e[1]) || (y==sel.e[1] && x<=sel.e[0])) 
+		|| (y==sel.b[1] && x>=sel.b[0] && (x<=sel.e[0] || sel.b[1]!=sel.e[1]));
 }
 
 static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
@@ -232,9 +232,9 @@ static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
 		*b=*b==4096?5:*b==2048?4:*b==1024?3:*b==512?2:*b==256?1:-1;
 	*x = e->xbutton.x/xw.cw;
 	*y = e->xbutton.y/xw.ch;
-	sel.b[0] = sel.by
Date: Tue, 31 Aug 2010 18:30:18 +0200
Subject: [PATCH 0125/1146] use struct instead of array.

---
 st.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/st.c b/st.c
index bff500b..a5cca17 100644
--- a/st.c
+++ b/st.c
@@ -125,11 +125,12 @@ typedef struct {
 	GC gc;
 } DC;
 
+/* TODO: use better name for vars... */
 typedef struct {
 	int mode;
 	int bx, by;
 	int ex, ey;
-	int b[2], e[2];
+	struct {int x, y;}  b, e;
 	char *clip;
 } Selection;
 
@@ -223,8 +224,8 @@ static inline int selected(int x, int y) {
 		int ex = MAX(sel.bx, sel.ex);
 		return BETWEEN(x, bx, ex);
 	}
-	return ((sel.b[1] < y&&y < sel.e[1]) || (y==sel.e[1] && x<=sel.e[0])) 
-		|| (y==sel.b[1] && x>=sel.b[0] && (x<=sel.e[0] || sel.b[1]!=sel.e[1]));
+	return ((sel.b.y < y&&y < sel.e.y) || (y==sel.e.y && x<=sel.e.x)) 
+		|| (y==sel.b.y && x>=sel.b.x && (x<=sel.e.x || sel.b.y!=sel.e.y));
 }
 
 static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
@@ -232,10 +233,10 @@ static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
 		*b=*b==4096?5:*b==2048?4:*b==1024?3:*b==512?2:*b==256?1:-1;
 	*x = e->xbutton.x/xw.cw;
 	*y = e->xbutton.y/xw.ch;
-	sel.b[0] = sel.by < sel.ey ? sel.bx : sel.ex;
-	sel.b[1] = MIN(sel.by, sel.ey);
-	sel.e[0] = sel.by < sel.ey ? sel.ex : sel.bx;
-	sel.e[1] = MAX(sel.by, sel.ey);
+	sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex;
+	sel.b.y = MIN(sel.by, sel.ey);
+	sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx;
+	sel.e.y = MAX(sel.by, sel.ey);
 }
 
 static void bpress(XEvent *e) {
@@ -249,7 +250,7 @@ static char *getseltext() {
 	int ls, x, y, sz;
 	if(sel.bx == -1)
 		return NULL;
-	sz = (term.col+1) * (sel.e[1]-sel.b[1]+1);
+	sz = (term.col+1) * (sel.e.y-sel.b.y+1);
 	ptr = str = malloc(sz);
 	for(y = 0; y < term.row; y++) {
 		for(x = 0; x < term.col; x++)

From f732ca5f1f03a0a496a07aa6bda15f6c363a2484 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 1 Sep 2010 00:30:39 +0200
Subject: [PATCH 0126/1146] added correct line drawing characters for default
 font.

---
 config.def.h | 65 ++++++++++++++++++++++++++--------------------------
 1 file changed, 33 insertions(+), 32 deletions(-)

diff --git a/config.def.h b/config.def.h
index 9506bc6..01f6a7c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,7 +1,7 @@
 #define TAB    8
 #define TNAME "st-256color"
-#define FONT "6x13"
-#define BOLDFONT "6x13bold"
+#define FONT "-misc-*-medium-r-semicondensed-*-13-*-*-*-*-*-iso8859-*"
+#define BOLDFONT "-misc-*-bold-r-semicondensed-*-13-*-*-*-*-*-iso8859-*"
 #define BORDER 2
 #define SHELL "/bin/sh"
 
@@ -26,7 +26,7 @@ static const char *colorname[] = {
 };
 
 /* Default colors (colorname index) */
-/* foreground, background, cursor, visual bell */
+/* foreground, background, cursor */
 #define DefaultFG 7
 #define DefaultBG 0
 #define DefaultCS 1
@@ -53,38 +53,39 @@ static Key key[] = {
 	{ XK_F12,       "\033[24~" },
 };
 
+/* line drawing characters (sometime specific to each font...) */
 static char gfx[] = {
-	['}'] = 'f',
-	['.'] = 'v',
-	[','] = '<',
 	['+'] = '>',
+	[','] = '<',
 	['-'] = '^',
-	['h'] = '#',
-	['~'] = 'o',
-	['a'] = ':',
-	['f'] = '\\',
-	['`'] = '+',
-	['z'] = '>',
-	['{'] = '*',
-	['q'] = '-',
-	['i'] = '#',
-	['n'] = '+',
-	['y'] = '<',
-	['m'] = '+',
-	['j'] = '+',
-	['|'] = '!',
-	['g'] = '#',
-	['o'] = '~',
-	['p'] = '-',
-	['r'] = '-',
-	['s'] = '_',
+	['.'] = 'v',
 	['0'] = '#',
-	['w'] = '+',
-	['u'] = '+',
-	['t'] = '+',
-	['v'] = '+',
-	['l'] = '+',
-	['k'] = '+',
-	['x'] = '|',
+	['`'] = 0x01,
+	['a'] = 0x02,
+	['f'] = 'o',
+	['g'] = '+',
+	['h'] = '#',
+	['i'] = '#',
+	['j'] = 0x0B,
+	['k'] = 0x0C,
+	['l'] = 0x0D,
+	['m'] = 0x0E,
+	['n'] = 0x0F,
+	['o'] = 0x10,
+	['p'] = 0x11,
+	['q'] = 0x12,
+	['r'] = 0x13,
+	['s'] = 0x14,
+	['t'] = 0x15,
+	['u'] = 0x16,
+	['v'] = 0x17,
+	['w'] = 0x18,
+	['x'] = 0x19,
+	['y'] = 0x1A,
+	['z'] = 0x1B,
+	['{'] = 0x1C,
+	['|'] = 0x1D,
+	['}'] = 0x1E,
+	['~'] = 0x1F,
 	[255] = 0,
 };

From ef69118028afad1938951a1f7dff8db2aa557879 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 1 Sep 2010 16:26:12 +0200
Subject: [PATCH 0127/1146] factor and cleanup code.

---
 st.c | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/st.c b/st.c
index a5cca17..6abdc3f 100644
--- a/st.c
+++ b/st.c
@@ -387,10 +387,10 @@ dump(char c) {
 
 void
 ttyread(void) {
-	char buf[BUFSIZ] = {0};
+	char buf[BUFSIZ];
 	int ret;
 
-	if((ret = read(cmdfd, buf, BUFSIZ)) < 0)
+	if((ret = read(cmdfd, buf, LEN(buf))) < 0)
 		die("Couldn't read from shell: %s\n", SERRNO);
 	else
 		tputs(buf, ret);
@@ -465,8 +465,7 @@ tscrolldown (int n) {
 	
 	LIMIT(n, 0, term.bot-term.top+1);
 
-	for(i = 0; i < n; i++)
-		memset(term.line[term.bot-i], 0, term.col*sizeof(Glyph));
+	tclearregion(0, term.bot-n+1, term.col-1, term.bot);
 	
 	for(i = term.bot; i >= term.top+n; i--) {
 		temp = term.line[i];
@@ -481,8 +480,7 @@ tscrollup (int n) {
 	Line temp;
 	LIMIT(n, 0, term.bot-term.top+1);
 	
-	for(i = 0; i < n; i++)
-		memset(term.line[term.top+i], 0, term.col*sizeof(Glyph));
+	tclearregion(0, term.top, term.col-1, term.top+n-1);
 	
 	for(i = term.top; i <= term.bot-n; i++) { 
 		 temp = term.line[i];
@@ -957,7 +955,8 @@ tputc(char c) {
 				term.esc = 0;
 				csiparse(), csihandle();
 			}
-		} else if(term.esc & ESC_OSC) {
+			/* TODO: handle other OSC */
+		} else if(term.esc & ESC_OSC) { 
 			if(c == ';') {
 				term.titlelen = 0;
 				term.esc = ESC_START | ESC_TITLE;
@@ -1201,18 +1200,18 @@ xinit(void) {
 	xloadcols();
 
 	/* windows */
-	xw.h = term.row * xw.ch + 2*BORDER;
-	xw.w = term.col * xw.cw + 2*BORDER;
+	xw.bufh = term.row * xw.ch;
+	xw.bufw = term.col * xw.cw;
+	xw.h = xw.bufh + 2*BORDER;
+	xw.w = xw.bufw + 2*BORDER;
 	xw.win = XCreateSimpleWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0,
 			xw.w, xw.h, 0,
 			dc.col[DefaultBG],
 			dc.col[DefaultBG]);
-	xw.bufw = xw.w - 2*BORDER;
-	xw.bufh = xw.h - 2*BORDER;
 	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
 	/* gc */
 	dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL);
-	
+
 	/* event mask */
 	XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask
 		| StructureNotifyMask | FocusChangeMask | PointerMotionMask

From 5ce6c5c0324ef3b7d0f5b9e6e2ba4d87ae0d3bb1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 1 Sep 2010 17:21:09 +0200
Subject: [PATCH 0128/1146] fixed IL and DL.

---
 st.c | 30 +++++++++++-------------------
 1 file changed, 11 insertions(+), 19 deletions(-)

diff --git a/st.c b/st.c
index 6abdc3f..65829a8 100644
--- a/st.c
+++ b/st.c
@@ -392,8 +392,10 @@ ttyread(void) {
 
 	if((ret = read(cmdfd, buf, LEN(buf))) < 0)
 		die("Couldn't read from shell: %s\n", SERRNO);
-	else
+	else {
+		printf("ttyread %d\n", ret);
 		tputs(buf, ret);
+	}
 }
 
 void
@@ -589,21 +591,16 @@ tinsertblankline(int n) {
 	Line blank;
 	int bot = term.bot;
 
-	if(term.c.y > term.bot)
-		bot = term.row - 1;
-	else if(term.c.y < term.top)
-		bot = term.top - 1;
-	if(term.c.y + n >= bot) {
-		tclearregion(0, term.c.y, term.col-1, bot);
+	if(term.c.y < term.top || term.c.y > term.bot)
 		return;
-	}
+
+	LIMIT(n, 0, bot-term.c.y+1);
+	tclearregion(0, bot-n+1, term.col-1, bot);
 	for(i = bot; i >= term.c.y+n; i--) {
 		/* swap deleted line <-> blanked line */
 		blank = term.line[i];
 		term.line[i] = term.line[i-n];
 		term.line[i-n] = blank;
-		/* blank it */
-		memset(blank, 0, term.col * sizeof(Glyph));
 	}
 }
 
@@ -613,21 +610,16 @@ tdeleteline(int n) {
 	Line blank;
 	int bot = term.bot;
 
-	if(term.c.y > term.bot)
-		bot = term.row - 1;
-	else if(term.c.y < term.top)
-		bot = term.top - 1;
-	if(term.c.y + n >= bot) {
-		tclearregion(0, term.c.y, term.col-1, bot);
+	if(term.c.y < term.top || term.c.y > term.bot)
 		return;
-	}
+
+	LIMIT(n, 0, bot-term.c.y+1);
+	tclearregion(0, term.c.y, term.col-1, term.c.y+n-1);
 	for(i = term.c.y; i <= bot-n; i++) {
 		/* swap deleted line <-> blanked line */
 		blank = term.line[i];
 		term.line[i] = term.line[i+n];
 		term.line[i+n] = blank;
-		/* blank it */
-		memset(blank, 0, term.col * sizeof(Glyph));
 	}
 }
 

From df5c5ed04547986ad2fd22226aaa3da430310374 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 1 Sep 2010 18:12:54 +0200
Subject: [PATCH 0129/1146] removed debug code.

---
 st.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 65829a8..0c876f5 100644
--- a/st.c
+++ b/st.c
@@ -392,10 +392,8 @@ ttyread(void) {
 
 	if((ret = read(cmdfd, buf, LEN(buf))) < 0)
 		die("Couldn't read from shell: %s\n", SERRNO);
-	else {
-		printf("ttyread %d\n", ret);
+	else
 		tputs(buf, ret);
-	}
 }
 
 void

From a79bc96c94e786c0e542539f80b622147d7385ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 1 Sep 2010 19:47:46 +0200
Subject: [PATCH 0130/1146] capabilities sorted by capname in st.info. copy
 acsc from xterm.

---
 st.info | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/st.info b/st.info
index 2cc645b..3cb993c 100644
--- a/st.info
+++ b/st.info
@@ -1,19 +1,12 @@
 st| simpleterm,
+	acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
 	am,
-	ul,
-	mir,
-	msgr,
-	colors#8,
-	cols#80,
-	it#8,
-	lines#24,
-	ncv#3,
-	pairs#64,
-	acsc=*`#aof+g+j+k+l+m+n-o-p-q-r-s+t+u+v+w|xz{{||}}-~,
 	bel=^G,
 	bold=\E[1m,
 	cbt=\E[Z,
 	clear=\E[H\E[2J,
+	colors#8,
+	cols#80,
 	cr=^M,
 	cub1=\E[D,
 	cud1=\E[B,
@@ -30,6 +23,7 @@ st| simpleterm,
 	il1=\E[L,
 	ind=^J,
 	invis=\E[8m,
+	it#8,
 	kbs=\177,
 	kcub1=\E[D,
 	kcud1=\E[B,
@@ -37,6 +31,9 @@ st| simpleterm,
 	kcuu1=\E[A,
 	kdch1=\E[3~,
 	kend=\E[4~,
+	kf10=\E[21~,
+	kf11=\E[23~,
+	kf12=\E[24~,
 	kf1=\EOP,
 	kf2=\EOQ,
 	kf3=\EOR,
@@ -46,13 +43,15 @@ st| simpleterm,
 	kf7=\E[18~,
 	kf8=\E[19~,
 	kf9=\E[20~,
-	kf10=\E[21~,
-	kf11=\E[23~,
-	kf12=\E[24~,
 	khome=\E[1~,
 	knp=\E[6~,
 	kpp=\E[5~,
+	lines#24,
+	mir,
+	msgr,
+	ncv#3,
 	op=\E[37;40m,
+	pairs#64,
 	rev=\E[7m,
 	rmacs=\E[10m,
 	rmso=\E[m,
@@ -64,6 +63,7 @@ st| simpleterm,
 	smso=\E[7m,
 	smul=\E[4m,
 	tbc=\E[2g,
+	ul,
 
 st-256color| simpleterm with 256 colors,
 	colors#256,

From 42344b715420a26a5711bb687a0e5f68bbcd3c86 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 1 Sep 2010 22:54:07 +0200
Subject: [PATCH 0131/1146] started to go through st.info and fix things.

---
 st.info | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.info b/st.info
index 3cb993c..ca4679b 100644
--- a/st.info
+++ b/st.info
@@ -4,10 +4,13 @@ st| simpleterm,
 	bel=^G,
 	bold=\E[1m,
 	cbt=\E[Z,
+	civis=\E[?25l
 	clear=\E[H\E[2J,
+	cnorm=\E[?12l\E[?25h,
 	colors#8,
 	cols#80,
 	cr=^M,
+	csr=\E[%i%p1%d;%p2%dr,
 	cub1=\E[D,
 	cud1=\E[B,
 	cuf1=\E[C,

From 32e160c939ba1c6bdda7b2181c72ca6df06d94ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 1 Sep 2010 22:54:28 +0200
Subject: [PATCH 0132/1146] updated TODO.

---
 TODO | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/TODO b/TODO
index de7743f..3b2774b 100644
--- a/TODO
+++ b/TODO
@@ -1,3 +1,15 @@
-  - total rewrite of X code (pixmap, mouse, copy-paste, ...)
-  - write a clean terminfo entry
-  - handle utf8 
+vt emulation
+------------
+
+* screen erased with background color ## capname:bce
+* back tab                            ## capname:cbt ## seq:CSI Z
+* ...
+
+code & interface
+----------------
+
+* clean selection code
+* use the real x11 clipboard
+* clean terminfo entry
+* utf8
+* ...

From 97695baf4f9bc3632792a3330fb46e188ef166a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Wed, 1 Sep 2010 23:20:54 +0200
Subject: [PATCH 0133/1146] factored code and fixed behaviour of tnewline().

---
 st.c | 60 ++++++++++++++++++++----------------------------------------
 1 file changed, 20 insertions(+), 40 deletions(-)

diff --git a/st.c b/st.c
index 0c876f5..5633e40 100644
--- a/st.c
+++ b/st.c
@@ -161,8 +161,8 @@ static void tputc(char);
 static void tputs(char*, int);
 static void treset(void);
 static void tresize(int, int);
-static void tscrollup(int);
-static void tscrolldown(int);
+static void tscrollup(int, int);
+static void tscrolldown(int, int);
 static void tsetattr(int*, int);
 static void tsetchar(char);
 static void tsetscroll(int, int);
@@ -459,15 +459,15 @@ tswapscreen(void) {
 }
 
 void
-tscrolldown (int n) {
+tscrolldown(int orig, int n) {
 	int i;
 	Line temp;
 	
-	LIMIT(n, 0, term.bot-term.top+1);
+	LIMIT(n, 0, term.bot-orig+1);
 
 	tclearregion(0, term.bot-n+1, term.col-1, term.bot);
 	
-	for(i = term.bot; i >= term.top+n; i--) {
+	for(i = term.bot; i >= orig+n; i--) {
 		temp = term.line[i];
 		term.line[i] = term.line[i-n];
 		term.line[i-n] = temp;
@@ -475,14 +475,14 @@ tscrolldown (int n) {
 }
 
 void
-tscrollup (int n) {
+tscrollup(int orig, int n) {
 	int i;
 	Line temp;
-	LIMIT(n, 0, term.bot-term.top+1);
+	LIMIT(n, 0, term.bot-orig+1);
 	
-	tclearregion(0, term.top, term.col-1, term.top+n-1);
+	tclearregion(0, orig, term.col-1, orig+n-1);
 	
-	for(i = term.top; i <= term.bot-n; i++) { 
+	for(i = orig; i <= term.bot-n; i++) { 
 		 temp = term.line[i];
 		 term.line[i] = term.line[i+n]; 
 		 term.line[i+n] = temp;
@@ -491,9 +491,11 @@ tscrollup (int n) {
 
 void
 tnewline(void) {
-	int y = term.c.y + 1;
-	if(y > term.bot)
-		tscrollup(1), y = term.bot;
+	int y = term.c.y;
+	if(term.c.y == term.bot)
+		tscrollup(term.top, 1);
+	else
+		y++;
 	tmoveto(0, y);
 }
 
@@ -585,40 +587,18 @@ tinsertblank(int n) {
 
 void
 tinsertblankline(int n) {
-	int i;
-	Line blank;
-	int bot = term.bot;
-
 	if(term.c.y < term.top || term.c.y > term.bot)
 		return;
 
-	LIMIT(n, 0, bot-term.c.y+1);
-	tclearregion(0, bot-n+1, term.col-1, bot);
-	for(i = bot; i >= term.c.y+n; i--) {
-		/* swap deleted line <-> blanked line */
-		blank = term.line[i];
-		term.line[i] = term.line[i-n];
-		term.line[i-n] = blank;
-	}
+	tscrolldown(term.c.y, n);
 }
 
 void
 tdeleteline(int n) {
-	int i;
-	Line blank;
-	int bot = term.bot;
-
 	if(term.c.y < term.top || term.c.y > term.bot)
 		return;
 
-	LIMIT(n, 0, bot-term.c.y+1);
-	tclearregion(0, term.c.y, term.col-1, term.c.y+n-1);
-	for(i = term.c.y; i <= bot-n; i++) {
-		/* swap deleted line <-> blanked line */
-		blank = term.line[i];
-		term.line[i] = term.line[i+n];
-		term.line[i+n] = blank;
-	}
+	tscrollup(term.c.y, n);
 }
 
 void
@@ -790,11 +770,11 @@ csihandle(void) {
 		break;
 	case 'S': /* SU -- Scroll  line up */
 		DEFAULT(escseq.arg[0], 1);
-		tscrollup(escseq.arg[0]);
+		tscrollup(term.top, escseq.arg[0]);
 		break;
 	case 'T': /* SD -- Scroll  line down */
 		DEFAULT(escseq.arg[0], 1);
-		tscrolldown(escseq.arg[0]);
+		tscrolldown(term.top, escseq.arg[0]);
 		break;
 	case 'L': /* IL -- Insert  blank lines */
 		DEFAULT(escseq.arg[0], 1);
@@ -984,7 +964,7 @@ tputc(char c) {
 				break;
 			case 'D': /* IND -- Linefeed */
 				if(term.c.y == term.bot)
-					tscrollup(1);
+					tscrollup(term.top, 1);
 				else
 					tmoveto(term.c.x, term.c.y+1);
 				term.esc = 0;
@@ -995,7 +975,7 @@ tputc(char c) {
 				break;
 			case 'M': /* RI -- Reverse index */
 				if(term.c.y == term.top)
-					tscrolldown(1);
+					tscrolldown(term.top, 1);
 				else
 					tmoveto(term.c.x, term.c.y-1);
 				term.esc = 0;

From 9d82bdd94708fa2daabc0b53f8b71bca2a3c6f0a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 2 Sep 2010 01:37:01 +0200
Subject: [PATCH 0134/1146] added -e and -t option.

---
 st.c | 36 ++++++++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/st.c b/st.c
index 5633e40..f7f9de8 100644
--- a/st.c
+++ b/st.c
@@ -28,6 +28,10 @@
  #include 
 #endif
 
+#define USAGE \
+	"st-" VERSION ", (c) 2010 st engineers\n" \
+	"usage: st [-t title] [-e cmd] [-v]\n"
+
 /* Arbitrary sizes */
 #define ESC_TITLE_SIZ 256
 #define ESC_BUF_SIZ   256
@@ -210,6 +214,8 @@ static CSIEscape escseq;
 static int cmdfd;
 static pid_t pid;
 static Selection sel;
+static char *opt_cmd   = NULL;
+static char *opt_title = NULL;
 
 void
 selinit(void) {
@@ -329,9 +335,12 @@ die(const char *errstr, ...) {
 
 void
 execsh(void) {
-	char *args[3] = {getenv("SHELL"), "-i", NULL};
-	DEFAULT(args[0], SHELL); /* if getenv() failed */
-	putenv("TERM=" TNAME);
+	char *args[] = {getenv("SHELL"), "-i", NULL};
+	if(opt_cmd)
+		args[0] = opt_cmd, args[1] = NULL;
+	else
+		DEFAULT(args[0], SHELL);
+	putenv("TERM="TNAME);
 	execvp(args[0], args);
 }
 
@@ -1189,7 +1198,7 @@ xinit(void) {
 	
 	XMapWindow(xw.dis, xw.win);
 	xhints();
-	XStoreName(xw.dis, xw.win, "st");
+	XStoreName(xw.dis, xw.win, opt_title ? opt_title : "st");
 	XSync(xw.dis, 0);
 }
 
@@ -1429,10 +1438,21 @@ run(void) {
 
 int
 main(int argc, char *argv[]) {
-	if(argc == 2 && !strncmp("-v", argv[1], 3))
-		die("st-" VERSION ", (c) 2010 st engineers\n");
-	else if(argc != 1)
-		die("usage: st [-v]\n");
+	int i;
+	
+	for(i = 1; i < argc; i++) {
+		switch(argv[i][0] != '-' || argv[i][2] ? -1 : argv[i][1]) {
+		case 't':
+			if(++i < argc) opt_title = argv[i];
+			break;
+		case 'e':
+			if(++i < argc) opt_cmd = argv[i];
+			break;
+		case 'v':
+		default:
+			die(USAGE);
+		}
+	}
 	setlocale(LC_CTYPE, "");
 	tnew(80, 24);
 	ttynew();

From fbc6ec3207fa1298ec8347697ddea6b3e78f13d0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 2 Sep 2010 01:42:03 +0200
Subject: [PATCH 0135/1146] resize from the top.

---
 st.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index f7f9de8..ed5481d 100644
--- a/st.c
+++ b/st.c
@@ -1060,12 +1060,25 @@ tresize(int col, int row) {
 	int i;
 	int minrow = MIN(row, term.row);
 	int mincol = MIN(col, term.col);
+	int slide = term.c.y - row + 1;
 
 	if(col < 1 || row < 1)
 		return;
 
-	/* free uneeded rows */
-	for(i = row; i < term.row; i++) {
+	/* free unneeded rows */
+	i = 0;
+	if(slide > 0) {
+		/* 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 < slide; i++) {
+			free(term.line[i]);
+			free(term.alt[i]);
+		}
+		memmove(term.line, term.line + slide, row * sizeof(Line));
+		memmove(term.alt, term.alt + slide, row * sizeof(Line));
+	}
+	for(i += row; i < term.row; i++) {
 		free(term.line[i]);
 		free(term.alt[i]);
 	}

From 2080dfebeaf82c6426c9ec2708ec8d96a7af76bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= 
Date: Thu, 2 Sep 2010 02:02:56 +0200
Subject: [PATCH 0136/1146] added manpage.

---
 Makefile |  8 +++++++-
 st.1     | 21 +++++++++++++++++++++
 2 files changed, 28 insertions(+), 1 deletion(-)
 create mode 100644 st.1

diff --git a/Makefile b/Makefile
index 920bd9a..2da8beb 100644
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,7 @@ clean:
 dist: clean
 	@echo creating dist tarball
 	@mkdir -p st-${VERSION}
-	@cp -R LICENSE Makefile README config.mk config.h st.info ${SRC} st-${VERSION}
+	@cp -R LICENSE Makefile README config.mk config.def.h st.info st.1 ${SRC} st-${VERSION}
 	@tar -cf st-${VERSION}.tar st-${VERSION}
 	@gzip st-${VERSION}.tar
 	@rm -rf st-${VERSION}
@@ -44,10 +44,16 @@ install: all
 	@mkdir -p ${DESTDIR}${PREFIX}/bin
 	@cp -f st ${DESTDIR}${PREFIX}/bin
 	@chmod 755 ${DESTDIR}${PREFIX}/bin/st
+	@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
+	@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 -s st.info
 
 uninstall:
 	@echo removing executable file from ${DESTDIR}${PREFIX}/bin
 	@rm -f ${DESTDIR}${PREFIX}/bin/st
+	@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
+	@rm -f ${DESTDIR}${MANPREFIX}/man1/sic.1
 
 .PHONY: all options clean dist install uninstall
diff --git a/st.1 b/st.1
new file mode 100644
index 0000000..4d00d2f
--- /dev/null
+++ b/st.1
@@ -0,0 +1,21 @@
+.TH ST 1 st-VERSION
+.SH NAME
+st \- simple terminal
+.SH SYNOPSIS
+.B st
+.RB [ \-e " "]
+.RB [ \-t " "]
+.RB [ \-v ]
+.SH DESCRIPTION
+.B st
+is a simple terminal emulator.
+.SH OPTIONS
+.TP
+.B \-e <cmd>
+Execute cmd instead of the shell
+.TP
+.B \-t <title>
+Overrides the default title (st)
+.TP
+.BI \-v
+Prints version information to standard output, then exits.

From b6af0fdc20cd79861fbf770c71484ec04405e744 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 2 Sep 2010 02:03:53 +0200
Subject: [PATCH 0137/1146] fixed makefile.

---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 2da8beb..041eadb 100644
--- a/Makefile
+++ b/Makefile
@@ -54,6 +54,6 @@ uninstall:
 	@echo removing executable file from ${DESTDIR}${PREFIX}/bin
 	@rm -f ${DESTDIR}${PREFIX}/bin/st
 	@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
-	@rm -f ${DESTDIR}${MANPREFIX}/man1/sic.1
+	@rm -f ${DESTDIR}${MANPREFIX}/man1/st.1
 
 .PHONY: all options clean dist install uninstall

From 223909e008bae6fce33cc1ad72e8480fc36805ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 2 Sep 2010 20:21:40 +0200
Subject: [PATCH 0138/1146] undefined gfx doesn't draw \0.

---
 st.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index ed5481d..9e66d09 100644
--- a/st.c
+++ b/st.c
@@ -677,7 +677,8 @@ tsetattr(int *attr, int l) {
 			else if(BETWEEN(attr[i], 100, 107))
 				term.c.attr.fg = attr[i] - 100 + 8;
 			else 
-				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]); 
+				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]), csidump();
+			
 			break;
 		}
 	}
@@ -1230,8 +1231,13 @@ xdraws(char *s, Glyph base, int x, int y, int len) {
 	XSetForeground(xw.dis, dc.gc, xfg);
 	
 	if(base.mode & ATTR_GFX)
-		for(i = 0; i < len; i++)
-			s[i] = gfx[(int)s[i]];
+		for(i = 0; i < len; i++) {
+			char c = gfx[(unsigned int)s[i] % 256];
+			if(c)
+				s[i] = c;
+			else if(s[i] > 0x5f)
+				s[i] -= 0x5f;
+		}
 
 	XSetFont(xw.dis, dc.gc, base.mode & ATTR_BOLD ? dc.bfont->fid : dc.font->fid);
 	XDrawImageString(xw.dis, xw.buf, dc.gc, winx, winy, s, len);

From 7d325a3797006297e47cbdcb4a5de61348c82664 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 2 Sep 2010 20:24:33 +0200
Subject: [PATCH 0139/1146] fixed start/end sequence of gfx.

---
 st.info | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.info b/st.info
index ca4679b..bcff5e0 100644
--- a/st.info
+++ b/st.info
@@ -56,13 +56,13 @@ st| simpleterm,
 	op=\E[37;40m,
 	pairs#64,
 	rev=\E[7m,
-	rmacs=\E[10m,
+	rmacs=\E(B,
 	rmso=\E[m,
 	rmul=\E[m,
 	setab=\E[4%p1%dm,
 	setaf=\E[3%p1%dm,
 	sgr0=\E[0m,
-	smacs=\E[12m,
+	smacs=\E(0,
 	smso=\E[7m,
 	smul=\E[4m,
 	tbc=\E[2g,

From ebc287271cd1c31a0a44826915257093867733ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 2 Sep 2010 21:59:05 +0200
Subject: [PATCH 0140/1146] removed gfx chars not present in xterm acsc.

---
 config.def.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/config.def.h b/config.def.h
index 01f6a7c..d729a5f 100644
--- a/config.def.h
+++ b/config.def.h
@@ -55,16 +55,10 @@ static Key key[] = {
 
 /* line drawing characters (sometime specific to each font...) */
 static char gfx[] = {
-	['+'] = '>',
-	[','] = '<',
-	['-'] = '^',
-	['.'] = 'v',
-	['0'] = '#',
 	['`'] = 0x01,
 	['a'] = 0x02,
 	['f'] = 'o',
 	['g'] = '+',
-	['h'] = '#',
 	['i'] = '#',
 	['j'] = 0x0B,
 	['k'] = 0x0C,

From 58083da61f53cdcea2112bfe835f8aeebd44850b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 2 Sep 2010 22:35:55 +0200
Subject: [PATCH 0141/1146] set terminal colors to xterm default ones.

---
 config.def.h | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/config.def.h b/config.def.h
index d729a5f..36982db 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,4 +1,4 @@
-#define TAB    8
+#define TAB 8
 #define TNAME "st-256color"
 #define FONT "-misc-*-medium-r-semicondensed-*-13-*-*-*-*-*-iso8859-*"
 #define BOLDFONT "-misc-*-bold-r-semicondensed-*-13-*-*-*-*-*-iso8859-*"
@@ -8,21 +8,21 @@
 /* Terminal colors */
 static const char *colorname[] = {
 	"black",
-	"#CC0000",
-	"#4E9A06",
-	"#C4A000",
-	"#3465A4",
-	"#75507B",
-	"#06989A",
-	"#888a85",
-	"#555753",
-	"#EF2929",
-	"#8AE234",
-	"#FCE94F",
-	"#729FCF",
-	"#AD7FA8",
-	"#34E2E2",
-	"#EEEEEC"
+	"red3",
+	"green3",
+	"yellow3",
+	"blue2",
+	"magenta3",
+	"cyan3",
+	"gray90",
+	"gray50",
+	"red",
+	"green",
+	"yellow",
+	"#5c5cff",
+	"magenta",
+	"cyan",
+	"white"
 };
 
 /* Default colors (colorname index) */
@@ -31,7 +31,7 @@ static const char *colorname[] = {
 #define DefaultBG 0
 #define DefaultCS 1
 
-/* special keys */
+/* Special keys */
 static Key key[] = {
 	{ XK_BackSpace, "\177" },
 	{ XK_Delete,    "\033[3~" },
@@ -53,7 +53,7 @@ static Key key[] = {
 	{ XK_F12,       "\033[24~" },
 };
 
-/* line drawing characters (sometime specific to each font...) */
+/* Line drawing characters (sometime specific to each font...) */
 static char gfx[] = {
 	['`'] = 0x01,
 	['a'] = 0x02,

From c43526153fbe368351f6139f5e672e1798f6d2f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Fri, 3 Sep 2010 00:00:41 +0200
Subject: [PATCH 0142/1146] cleaning st.info. fixed cvvis.

---
 st.c    |  4 +++-
 st.info | 15 +++++++++++++--
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 9e66d09..ab43a43 100644
--- a/st.c
+++ b/st.c
@@ -855,7 +855,9 @@ csihandle(void) {
 				term.mode |= MODE_WRAP;
 				break;
 			case 12: /* att610 -- Start blinking cursor (IGNORED) */
-				break;
+				 /* fallthrough for xterm cvvis = CSI [ ? 12 ; 25 h */
+				if(escseq.narg > 1 && escseq.arg[1] != 25)
+					break;
 			case 25:
 				term.c.state &= ~CURSOR_HIDE;
 				break;
diff --git a/st.info b/st.info
index bcff5e0..3778f74 100644
--- a/st.info
+++ b/st.info
@@ -1,7 +1,11 @@
+# unsupported xterm caps are (getting) commented. 
+# as soon as they work, uncomment them.
 st| simpleterm,
 	acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
 	am,
+#	bce,
 	bel=^G,
+#	blink=\E[5m
 	bold=\E[1m,
 	cbt=\E[Z,
 	civis=\E[?25l
@@ -11,11 +15,14 @@ st| simpleterm,
 	cols#80,
 	cr=^M,
 	csr=\E[%i%p1%d;%p2%dr,
-	cub1=\E[D,
-	cud1=\E[B,
+	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,
 	dch1=\E[P,
 	dl1=\E[M,
 	ed=\E[J,
@@ -55,13 +62,16 @@ st| simpleterm,
 	ncv#3,
 	op=\E[37;40m,
 	pairs#64,
+	rc=\E8,
 	rev=\E[7m,
 	rmacs=\E(B,
 	rmso=\E[m,
 	rmul=\E[m,
+	sc=\E7,
 	setab=\E[4%p1%dm,
 	setaf=\E[3%p1%dm,
 	sgr0=\E[0m,
+	sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
 	smacs=\E(0,
 	smso=\E[7m,
 	smul=\E[4m,
@@ -70,6 +80,7 @@ st| simpleterm,
 
 st-256color| simpleterm with 256 colors,
 	colors#256,
+	pairs#32767,
 #	Nicked from xterm-256color
 	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,

From 273d4ba938dc6bf7edb2b1154ea36c19bfcd22d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Fri, 3 Sep 2010 00:15:43 +0200
Subject: [PATCH 0143/1146] cleaning st.info. added comment in st.c for
 DECSCNM.

---
 st.c    | 5 +++++
 st.info | 8 ++++++--
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index ab43a43..261612f 100644
--- a/st.c
+++ b/st.c
@@ -796,6 +796,8 @@ csihandle(void) {
 			case 1:
 				term.mode &= ~MODE_APPKEYPAD;
 				break;
+			case 5: /* TODO: DECSCNM -- Remove reverse video */
+				break;
 			case 7:
 				term.mode &= ~MODE_WRAP;
 				break;
@@ -851,6 +853,9 @@ csihandle(void) {
 			case 1:
 				term.mode |= MODE_APPKEYPAD;
 				break;
+			case 5: /* DECSCNM -- Reverve video */
+				/* TODO: set REVERSE on the whole screen (f) */
+				break;
 			case 7:
 				term.mode |= MODE_WRAP;
 				break;
diff --git a/st.info b/st.info
index 3778f74..0145411 100644
--- a/st.info
+++ b/st.info
@@ -5,10 +5,10 @@ st| simpleterm,
 	am,
 #	bce,
 	bel=^G,
-#	blink=\E[5m
+#	blink=\E[5m,
 	bold=\E[1m,
 	cbt=\E[Z,
-	civis=\E[?25l
+	civis=\E[?25l,
 	clear=\E[H\E[2J,
 	cnorm=\E[?12l\E[?25h,
 	colors#8,
@@ -28,10 +28,14 @@ st| simpleterm,
 	ed=\E[J,
 	el=\E[K,
 	home=\E[H,
+	hpa=\E[%i%p1%dG,
 	ht=^I,
 	hts=\EH,
+	ich=\E[%p1%d@,
 	il1=\E[L,
+	il=\E[%p1%dL,
 	ind=^J,
+	indn=\E[%p1%dS,
 	invis=\E[8m,
 	it#8,
 	kbs=\177,

From 8c3757986a41ff8fa95b175be40f67d67d7e27b1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sat, 11 Sep 2010 15:59:54 +0200
Subject: [PATCH 0144/1146] use XCreateWindow(), set gravity bit.

---
 st.c | 42 +++++++++++++++++++++++++-----------------
 1 file changed, 25 insertions(+), 17 deletions(-)

diff --git a/st.c b/st.c
index 261612f..7974629 100644
--- a/st.c
+++ b/st.c
@@ -104,6 +104,7 @@ typedef struct {
 /* Purely graphic info */
 typedef struct {
 	Display* dis;
+	Colormap cmap;
 	Window win;
 	Pixmap buf;
 	int scr;
@@ -1121,11 +1122,10 @@ void
 xloadcols(void) {
 	int i, r, g, b;
 	XColor color;
-	Colormap cmap = DefaultColormap(xw.dis, xw.scr);
 	unsigned long white = WhitePixel(xw.dis, xw.scr);
 
 	for(i = 0; i < 16; i++) {
-		if (!XAllocNamedColor(xw.dis, cmap, colorname[i], &color, &color)) {
+		if (!XAllocNamedColor(xw.dis, xw.cmap, colorname[i], &color, &color)) {
 			dc.col[i] = white;
 			fprintf(stderr, "Could not allocate color '%s'\n", colorname[i]);
 		} else
@@ -1139,7 +1139,7 @@ xloadcols(void) {
 				color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r;
 				color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g;
 				color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b;
-				if (!XAllocColor(xw.dis, cmap, &color)) {
+				if (!XAllocColor(xw.dis, xw.cmap, &color)) {
 					dc.col[i] = white;
 					fprintf(stderr, "Could not allocate color %d\n", i);
 				} else
@@ -1149,7 +1149,7 @@ xloadcols(void) {
 
 	for(r = 0; r < 24; r++, i++) {
 		color.red = color.green = color.blue = 0x0808 + 0x0a0a * r;
-		if (!XAllocColor(xw.dis, cmap, &color)) {
+		if (!XAllocColor(xw.dis, xw.cmap, &color)) {
 			dc.col[i] = white;
 			fprintf(stderr, "Could not allocate color %d\n", i);
 		} else
@@ -1184,6 +1184,8 @@ xhints(void)
 
 void
 xinit(void) {
+	XSetWindowAttributes attrs;
+
 	if(!(xw.dis = XOpenDisplay(NULL)))
 		die("Can't open display\n");
 	xw.scr = XDefaultScreen(xw.dis);
@@ -1197,25 +1199,32 @@ xinit(void) {
 	xw.ch = dc.font->ascent + dc.font->descent;
 
 	/* colors */
+	xw.cmap = XDefaultColormap(xw.dis, xw.scr);
 	xloadcols();
 
-	/* windows */
-	xw.bufh = term.row * xw.ch;
-	xw.bufw = term.col * xw.cw;
+	/* window - default size */
+	xw.bufh = 24 * xw.ch;
+	xw.bufw = 80 * xw.cw;
 	xw.h = xw.bufh + 2*BORDER;
 	xw.w = xw.bufw + 2*BORDER;
-	xw.win = XCreateSimpleWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0,
-			xw.w, xw.h, 0,
-			dc.col[DefaultBG],
-			dc.col[DefaultBG]);
+
+	attrs.background_pixel = dc.col[DefaultBG];
+	attrs.border_pixel = dc.col[DefaultBG];
+	attrs.bit_gravity = NorthWestGravity;
+	attrs.event_mask = ExposureMask | KeyPressMask
+		| StructureNotifyMask | FocusChangeMask | PointerMotionMask
+		| ButtonPressMask | ButtonReleaseMask;
+	attrs.colormap = xw.cmap;
+
+	xw.win = XCreateWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0,
+			xw.w, xw.h, 0, XDefaultDepth(xw.dis, xw.scr), InputOutput,
+			XDefaultVisual(xw.dis, xw.scr),
+			CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
+			| CWColormap,
+			&attrs);
 	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
 	/* gc */
 	dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL);
-
-	/* event mask */
-	XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask
-		| StructureNotifyMask | FocusChangeMask | PointerMotionMask
-		| ButtonPressMask | ButtonReleaseMask);
 	
 	XMapWindow(xw.dis, xw.win);
 	xhints();
@@ -1432,7 +1441,6 @@ resize(XEvent *e) {
 	xw.bufw = MAX(1, xw.bufw);
 	XFreePixmap(xw.dis, xw.buf);
 	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
-	draw(SCREEN_REDRAW);
 }
 
 void

From f693476365c9383ac83420319dd69372c55f9f50 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sat, 11 Sep 2010 16:01:41 +0200
Subject: [PATCH 0145/1146] use xclear() in draw().

---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 7974629..d2f8c2e 100644
--- a/st.c
+++ b/st.c
@@ -1321,8 +1321,7 @@ draw(int redraw_all) {
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
 
-	XSetForeground(xw.dis, dc.gc, dc.col[DefaultBG]);
-	XFillRectangle(xw.dis, xw.buf, dc.gc, 0, 0, xw.bufw, xw.bufh);
+	xclear(0, 0, term.col-1, term.row-1);
 	for(y = 0; y < term.row; y++) {
 		base = term.line[y][0];
 		i = ox = 0;

From ab7037cb33b4be4d16e3197d907066ed5b8ab16b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sat, 11 Sep 2010 16:05:57 +0200
Subject: [PATCH 0146/1146] don't draw if the window is not visible.

---
 st.c | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index d2f8c2e..c9d0fb8 100644
--- a/st.c
+++ b/st.c
@@ -115,6 +115,7 @@ typedef struct {
 	int ch; /* char height */
 	int cw; /* char width  */
 	int hasfocus;
+	int vis; /* is visible */
 } XWindow; 
 
 typedef struct {
@@ -187,6 +188,8 @@ static void xloadcols(void);
 static void xseturgency(int);
 
 static void expose(XEvent *);
+static void visibility(XEvent *);
+static void unmap(XEvent *);
 static char* kmap(KeySym);
 static void kpress(XEvent *);
 static void resize(XEvent *);
@@ -198,8 +201,10 @@ static void bmotion(XEvent *);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
-	[Expose] = expose,
 	[ConfigureNotify] = resize,
+	[VisibilityNotify] = visibility,
+	[UnmapNotify] = unmap,
+	[Expose] = expose,
 	[FocusIn] = focus,
 	[FocusOut] = focus,
 	[MotionNotify] = bmotion,
@@ -1211,9 +1216,9 @@ xinit(void) {
 	attrs.background_pixel = dc.col[DefaultBG];
 	attrs.border_pixel = dc.col[DefaultBG];
 	attrs.bit_gravity = NorthWestGravity;
-	attrs.event_mask = ExposureMask | KeyPressMask
-		| StructureNotifyMask | FocusChangeMask | PointerMotionMask
-		| ButtonPressMask | ButtonReleaseMask;
+	attrs.event_mask = FocusChangeMask | KeyPressMask
+		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
+		| PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
 	attrs.colormap = xw.cmap;
 
 	xw.win = XCreateWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0,
@@ -1321,6 +1326,9 @@ draw(int redraw_all) {
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
 
+	if(!xw.vis)
+		return;
+
 	xclear(0, 0, term.col-1, term.row-1);
 	for(y = 0; y < term.row; y++) {
 		base = term.line[y][0];
@@ -1357,6 +1365,19 @@ expose(XEvent *ev) {
 	draw(SCREEN_REDRAW);
 }
 
+void
+visibility(XEvent *ev) {
+	XVisibilityEvent *e = &ev->xvisibility;
+	/* XXX if this goes from 0 to 1, need a full redraw for next Expose,
+	 * not just a buf copy */
+	xw.vis = e->state != VisibilityFullyObscured;
+}
+
+void
+unmap(XEvent *ev) {
+	xw.vis = 0;
+}
+
 void
 xseturgency(int add) {
 	XWMHints *h = XGetWMHints(xw.dis, xw.win);

From 6faedce53a8de8a81da1ba045ffbc2b7603128cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sat, 11 Sep 2010 16:07:36 +0200
Subject: [PATCH 0147/1146] s/hasfocus/focus/ for consistency.

---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index c9d0fb8..99ab085 100644
--- a/st.c
+++ b/st.c
@@ -114,7 +114,7 @@ typedef struct {
 	int bufh; /* pixmap height */
 	int ch; /* char height */
 	int cw; /* char width  */
-	int hasfocus;
+	int focus;
 	int vis; /* is visible */
 } XWindow; 
 
@@ -1043,7 +1043,7 @@ tputc(char c) {
 			tnewline();
 			break;
 		case '\a':
-			if(!xw.hasfocus)
+			if(!xw.focus)
 				xseturgency(1);
 			break;
 		case '\033':
@@ -1286,7 +1286,7 @@ xdrawcursor(void) {
 		xclear(oldx, oldy, oldx, oldy);
 	
 	/* draw the new one */
-	if(!(term.c.state & CURSOR_HIDE) && xw.hasfocus) {
+	if(!(term.c.state & CURSOR_HIDE) && xw.focus) {
 		xdraws(&g.c, g, term.c.x, term.c.y, 1);
 		oldx = term.c.x, oldy = term.c.y;
 	}
@@ -1388,7 +1388,7 @@ xseturgency(int add) {
 
 void
 focus(XEvent *ev) {
-	if((xw.hasfocus = ev->type == FocusIn))
+	if((xw.focus = ev->type == FocusIn))
 		xseturgency(0);
 	draw(SCREEN_UPDATE);
 }

From 3470e3af23f4b98ce4293f6090c8df59a08329d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Tue, 21 Sep 2010 16:04:13 +0200
Subject: [PATCH 0148/1146] compose key patch. thx federico luna.

---
 st.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 99ab085..d1b90ef 100644
--- a/st.c
+++ b/st.c
@@ -107,6 +107,8 @@ typedef struct {
 	Colormap cmap;
 	Window win;
 	Pixmap buf;
+	XIM xim;
+	XIC xic;
 	int scr;
 	int w;	/* window width	 */
 	int h;	/* window height */
@@ -1228,6 +1230,13 @@ xinit(void) {
 			| CWColormap,
 			&attrs);
 	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
+
+
+	/* input methods */
+	xw.xim = XOpenIM(xw.dis, NULL, NULL, NULL);
+	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing 
+					   | XIMStatusNothing, XNClientWindow, xw.win, 
+					   XNFocusWindow, xw.win, NULL);
 	/* gc */
 	dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL);
 	
@@ -1411,10 +1420,11 @@ kpress(XEvent *ev) {
 	int len;
 	int meta;
 	int shift;
+	Status status;
 
 	meta = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
-	len = XLookupString(e, buf, sizeof(buf), &ksym, NULL);
+	len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status);
 
 	if((customkey = kmap(ksym)))
 		ttywrite(customkey, strlen(customkey));
@@ -1484,6 +1494,8 @@ run(void) {
 		}
 		while(XPending(xw.dis)) {
 			XNextEvent(xw.dis, &ev);
+			if (XFilterEvent(&ev, xw.win))
+				continue;
 			if(handler[ev.type])
 				(handler[ev.type])(&ev);
 		}

From 3a50a4fd931ed58454b680c9fc5c1bc2278e67f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 13 Oct 2010 00:50:18 +0200
Subject: [PATCH 0149/1146] clean button selection code.

---
 st.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index d1b90ef..5d5ac30 100644
--- a/st.c
+++ b/st.c
@@ -243,8 +243,9 @@ static inline int selected(int x, int y) {
 }
 
 static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
-	if(b) *b = e->xbutton.state,
-		*b=*b==4096?5:*b==2048?4:*b==1024?3:*b==512?2:*b==256?1:-1;
+	if(b) 
+		*b = e->xbutton.button;
+
 	*x = e->xbutton.x/xw.cw;
 	*y = e->xbutton.y/xw.ch;
 	sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex;

From d693b304c78708acb911773fe24971ef969d237e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 13 Oct 2010 01:24:11 +0200
Subject: [PATCH 0150/1146] applied xclipboard patch. thx David Isaac Wolinsky.

---
 st.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 125 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index 5d5ac30..e636b63 100644
--- a/st.c
+++ b/st.c
@@ -17,6 +17,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 #include <X11/Xlib.h>
+#include <X11/Xatom.h>
 #include <X11/keysym.h>
 #include <X11/Xutil.h>
 
@@ -199,7 +200,8 @@ static void focus(XEvent *);
 static void brelease(XEvent *);
 static void bpress(XEvent *);
 static void bmotion(XEvent *);
-
+static void selection_notify(XEvent *);
+static void selection_request(XEvent *);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
@@ -212,6 +214,8 @@ static void (*handler[LASTEvent])(XEvent *) = {
 	[MotionNotify] = bmotion,
 	[ButtonPress] = bpress,
 	[ButtonRelease] = brelease,
+	[SelectionNotify] = selection_notify,
+	[SelectionRequest] = selection_request,
 };
 
 /* Globals */
@@ -278,15 +282,129 @@ static char *getseltext() {
 	return str;
 }
 
-/* TODO: use X11 clipboard */
-static void selcopy(char *str) {
-	free(sel.clip);
-	sel.clip = str;
+static void selection_notify(XEvent *e) {
+	unsigned long nitems;
+	unsigned long length;
+	int format, res;
+	unsigned char *data;
+	Atom type;
+
+	res = XGetWindowProperty(xw.dis, xw.win, XA_PRIMARY, 0, 0, False, 
+				AnyPropertyType, &type, &format, &nitems, &length, &data);
+	switch(res) {
+		case BadAtom:
+		case BadValue:
+		case BadWindow:
+			fprintf(stderr, "Invalid paste, XGetWindowProperty0");
+			return;
+	}
+
+	res = XGetWindowProperty(xw.dis, xw.win, XA_PRIMARY, 0, length, False,
+				AnyPropertyType, &type, &format, &nitems, &length, &data);
+	switch(res) {
+		case BadAtom:
+		case BadValue:
+		case BadWindow:
+			fprintf(stderr, "Invalid paste, XGetWindowProperty0");
+			return;
+	}
+
+	if(data) {
+		ttywrite((const char *) data, nitems * format / 8);
+		XFree(data);
+	}
 }
 
 static void selpaste() {
-	if(sel.clip)
-		ttywrite(sel.clip, strlen(sel.clip));
+	XConvertSelection(xw.dis, XA_PRIMARY, XA_STRING, XA_PRIMARY, xw.win, CurrentTime);
+}
+
+static void selection_request(XEvent *e)
+{
+	XSelectionRequestEvent *xsre;
+	XSelectionEvent xev;
+	int res;
+	Atom xa_targets;
+
+	xsre = (XSelectionRequestEvent *) e;
+	xev.type = SelectionNotify;
+	xev.requestor = xsre->requestor;
+	xev.selection = xsre->selection;
+	xev.target = xsre->target;
+	xev.time = xsre->time;
+	/* reject */
+	xev.property = None;
+
+	xa_targets = XInternAtom(xw.dis, "TARGETS", 0);
+	if(xsre->target == xa_targets) {
+		/* respond with the supported type */
+		Atom string = XA_STRING;
+		res = XChangeProperty(xsre->display, xsre->requestor, xsre->property, XA_ATOM, 32,
+				PropModeReplace, (unsigned char *) &string, 1);
+		switch(res) {
+			case BadAlloc:
+			case BadAtom:
+			case BadMatch:
+			case BadValue:
+			case BadWindow:
+				fprintf(stderr, "Error in selection_request, TARGETS");
+				break;
+			default:
+				xev.property = xsre->property;
+		}
+	} else if(xsre->target == XA_STRING) {
+		res = XChangeProperty(xsre->display, xsre->requestor, xsre->property,
+				xsre->target, 8, PropModeReplace, (unsigned char *) sel.clip,
+				strlen(sel.clip));
+		switch(res) {
+			case BadAlloc:
+			case BadAtom:
+			case BadMatch:
+			case BadValue:
+			case BadWindow:
+				fprintf(stderr, "Error in selection_request, XA_STRING");
+				break;
+			default:
+			 xev.property = xsre->property;
+		}
+	}
+
+	/* all done, send a notification to the listener */
+	res = XSendEvent(xsre->display, xsre->requestor, True, 0, (XEvent *) &xev);
+	switch(res) {
+		case 0:
+		case BadValue:
+		case BadWindow:
+			fprintf(stderr, "Error in selection_requested, XSendEvent");
+	}
+}
+
+static void selcopy(char *str) {
+	/* register the selection for both the clipboard and the primary */
+	Atom clipboard;
+	int res;
+
+	free(sel.clip);
+	sel.clip = str;
+
+	res = XSetSelectionOwner(xw.dis, XA_PRIMARY, xw.win, CurrentTime);
+	switch(res) {
+		case BadAtom:
+		case BadWindow:
+			fprintf(stderr, "Invalid copy, XSetSelectionOwner");
+			return;
+	}
+
+	clipboard = XInternAtom(xw.dis, "CLIPBOARD", 0);
+	res = XSetSelectionOwner(xw.dis, clipboard, xw.win, CurrentTime);
+	switch(res) {
+		case BadAtom:
+		case BadWindow:
+			fprintf(stderr, "Invalid copy, XSetSelectionOwner");
+			return;
+	}
+
+	XFlush(xw.dis);
 }
 
 /* TODO: doubleclick to select word */

From e4bf56ae1a9e2612ec9a6faf2aaecd6eadcccaa7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 13 Oct 2010 01:25:04 +0200
Subject: [PATCH 0151/1146] remove useless draw().

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index e636b63..37c4048 100644
--- a/st.c
+++ b/st.c
@@ -1563,7 +1563,7 @@ kpress(XEvent *ev) {
 			break;
 		case XK_Insert:
 			if(shift)
-				selpaste(), draw(1);
+				selpaste();
 			break;
 		default:
 			fprintf(stderr, "errkey: %d\n", (int)ksym);

From 68d8fcf62a4f016c0292db543c1c2e694afc5b54 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 13 Oct 2010 01:27:09 +0200
Subject: [PATCH 0152/1146] replaced memset by loops in tresize(); turns out
 it's faster.

---
 st.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 37c4048..0042204 100644
--- a/st.c
+++ b/st.c
@@ -677,7 +677,7 @@ tsetchar(char c) {
 
 void
 tclearregion(int x1, int y1, int x2, int y2) {
-	int y, temp;
+	int x, y, temp;
 
 	if(x1 > x2)
 		temp = x1, x1 = x2, x2 = temp;
@@ -690,7 +690,8 @@ tclearregion(int x1, int y1, int x2, int y2) {
 	LIMIT(y2, 0, term.row-1);
 
 	for(y = y1; y <= y2; y++)
-		memset(&term.line[y][x1], 0, sizeof(Glyph)*(x2-x1+1));
+		for(x = x1; x <= x2; x++)
+			term.line[y][x].state = 0;
 }
 
 void
@@ -1192,7 +1193,7 @@ tputs(char *s, int len) {
 
 void
 tresize(int col, int row) {
-	int i;
+	int i, x;
 	int minrow = MIN(row, term.row);
 	int mincol = MIN(col, term.col);
 	int slide = term.c.y - row + 1;
@@ -1226,8 +1227,10 @@ tresize(int col, int row) {
 	for(i = 0; i < minrow; i++) {
 		term.line[i] = realloc(term.line[i], col * sizeof(Glyph));
 		term.alt[i]  = realloc(term.alt[i],  col * sizeof(Glyph));
-		memset(term.line[i] + mincol, 0, (col - mincol) * sizeof(Glyph));
-		memset(term.alt[i]  + mincol, 0, (col - mincol) * sizeof(Glyph));
+		for(x = mincol; x < col; x++) {
+			term.line[i][x].state = 0;
+			term.alt[i][x].state = 0;
+		}
 	}
 
 	/* allocate any new rows */

From 9e004846def39ee73eeb06ba9b1be0e389752441 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 14 Oct 2010 19:21:12 +0200
Subject: [PATCH 0153/1146] fixed newline bug.

---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 0042204..0c6423a 100644
--- a/st.c
+++ b/st.c
@@ -627,12 +627,13 @@ tscrollup(int orig, int n) {
 
 void
 tnewline(void) {
+	int x = term.c.x+1 < term.col ? term.c.x : 0;
 	int y = term.c.y;
 	if(term.c.y == term.bot)
 		tscrollup(term.top, 1);
 	else
 		y++;
-	tmoveto(0, y);
+	tmoveto(x, y);
 }
 
 void

From ce27e634910e10c470b2dcb2edcd20f05d25343b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sat, 16 Oct 2010 17:13:22 +0200
Subject: [PATCH 0154/1146] redraw optimization.

---
 st.c | 36 ++++++++++++++++++++++++------------
 1 file changed, 24 insertions(+), 12 deletions(-)

diff --git a/st.c b/st.c
index 0c6423a..4f17752 100644
--- a/st.c
+++ b/st.c
@@ -58,6 +58,7 @@ enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
 enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8 };
 enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
 enum { SCREEN_UPDATE, SCREEN_REDRAW };
+enum { WIN_VISIBLE=1, WIN_REDRAW=2, WIN_FOCUSED=4 };
 
 typedef struct {
 	char c;     /* character code  */
@@ -117,8 +118,7 @@ typedef struct {
 	int bufh; /* pixmap height */
 	int ch; /* char height */
 	int cw; /* char width  */
-	int focus;
-	int vis; /* is visible */
+	char state; /* focus, redraw, visible */
 } XWindow; 
 
 typedef struct {
@@ -1166,7 +1166,7 @@ tputc(char c) {
 			tnewline();
 			break;
 		case '\a':
-			if(!xw.focus)
+			if(!(xw.state & WIN_FOCUSED))
 				xseturgency(1);
 			break;
 		case '\033':
@@ -1418,7 +1418,7 @@ xdrawcursor(void) {
 		xclear(oldx, oldy, oldx, oldy);
 	
 	/* draw the new one */
-	if(!(term.c.state & CURSOR_HIDE) && xw.focus) {
+	if(!(term.c.state & CURSOR_HIDE) && (xw.state & WIN_FOCUSED)) {
 		xdraws(&g.c, g, term.c.x, term.c.y, 1);
 		oldx = term.c.x, oldy = term.c.y;
 	}
@@ -1458,7 +1458,7 @@ draw(int redraw_all) {
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
 
-	if(!xw.vis)
+	if(!(xw.state & WIN_VISIBLE))
 		return;
 
 	xclear(0, 0, term.col-1, term.row-1);
@@ -1487,27 +1487,36 @@ draw(int redraw_all) {
 	}
 	xdrawcursor();
 	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
-	XFlush(xw.dis);
 }
 
 #endif
 
 void
 expose(XEvent *ev) {
-	draw(SCREEN_REDRAW);
+	XExposeEvent *e = &ev->xexpose;
+	if(xw.state & WIN_REDRAW) {
+		if(!e->count) {
+			xw.state &= ~WIN_REDRAW;
+			draw(SCREEN_REDRAW);
+		}
+	} else
+		XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, e->x-BORDER, e->y-BORDER,
+				e->width, e->height, e->x, e->y);
 }
 
 void
 visibility(XEvent *ev) {
 	XVisibilityEvent *e = &ev->xvisibility;
-	/* XXX if this goes from 0 to 1, need a full redraw for next Expose,
-	 * not just a buf copy */
-	xw.vis = e->state != VisibilityFullyObscured;
+	if(e->state == VisibilityFullyObscured)
+		xw.state &= ~WIN_VISIBLE;
+	else if(!(xw.state & WIN_VISIBLE))
+		/* need a full redraw for next Expose, not just a buf copy */
+		xw.state |= WIN_VISIBLE | WIN_REDRAW;
 }
 
 void
 unmap(XEvent *ev) {
-	xw.vis = 0;
+	xw.state &= ~WIN_VISIBLE;
 }
 
 void
@@ -1520,8 +1529,11 @@ xseturgency(int add) {
 
 void
 focus(XEvent *ev) {
-	if((xw.focus = ev->type == FocusIn))
+	if(ev->type == FocusIn) {
+		xw.state |= WIN_FOCUSED;
 		xseturgency(0);
+	} else
+		xw.state &= ~WIN_FOCUSED;
 	draw(SCREEN_UPDATE);
 }
 

From 6f87a39444166674daa94860d365e72343e0b882 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sat, 16 Oct 2010 20:50:29 +0200
Subject: [PATCH 0155/1146] added LNM mode; re-organized kpress() to handle it.

---
 st.c | 51 ++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 34 insertions(+), 17 deletions(-)

diff --git a/st.c b/st.c
index 4f17752..16462c7 100644
--- a/st.c
+++ b/st.c
@@ -55,7 +55,8 @@ enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT,
        CURSOR_SAVE, CURSOR_LOAD };
 enum { CURSOR_DEFAULT = 0, CURSOR_HIDE = 1, CURSOR_WRAPNEXT = 2 };
 enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
-enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8 };
+enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8, 
+       MODE_CRLF=16 };
 enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
 enum { SCREEN_UPDATE, SCREEN_REDRAW };
 enum { WIN_VISIBLE=1, WIN_REDRAW=2, WIN_FOCUSED=4 };
@@ -164,7 +165,7 @@ static void tinsertblank(int);
 static void tinsertblankline(int);
 static void tmoveto(int, int);
 static void tnew(int, int);
-static void tnewline(void);
+static void tnewline(int);
 static void tputtab(void);
 static void tputc(char);
 static void tputs(char*, int);
@@ -626,14 +627,13 @@ tscrollup(int orig, int n) {
 }
 
 void
-tnewline(void) {
-	int x = term.c.x+1 < term.col ? term.c.x : 0;
+tnewline(int first_col) {
 	int y = term.c.y;
-	if(term.c.y == term.bot)
+	if(y == term.bot)
 		tscrollup(term.top, 1);
 	else
 		y++;
-	tmoveto(x, y);
+	tmoveto(first_col ? 0 : term.c.x, y);
 }
 
 void
@@ -932,6 +932,9 @@ csihandle(void) {
 				break;
 			case 12: /* att610 -- Stop blinking cursor (IGNORED) */
 				break;
+			case 20:
+				term.mode &= ~MODE_CRLF;
+				break;
 			case 25:
 				term.c.state |= CURSOR_HIDE;
 				break;
@@ -988,6 +991,9 @@ csihandle(void) {
 			case 7:
 				term.mode |= MODE_WRAP;
 				break;
+			case 20:
+				term.mode |= MODE_CRLF;
+				break;
 			case 12: /* att610 -- Start blinking cursor (IGNORED) */
 				 /* fallthrough for xterm cvvis = CSI [ ? 12 ; 25 h */
 				if(escseq.narg > 1 && escseq.arg[1] != 25)
@@ -1116,7 +1122,7 @@ tputc(char c) {
 				term.esc = 0;
 				break;
 			case 'E': /* NEL -- Next line */
-				tnewline();
+				tnewline(1); /* always go to first col */
 				term.esc = 0;
 				break;
 			case 'M': /* RI -- Reverse index */
@@ -1163,7 +1169,8 @@ tputc(char c) {
 			tmoveto(0, term.c.y);
 			break;
 		case '\n':
-			tnewline();
+			/* go to first col if the mode is set */
+			tnewline(IS_SET(MODE_CRLF));
 			break;
 		case '\a':
 			if(!(xw.state & WIN_FOCUSED))
@@ -1175,7 +1182,7 @@ tputc(char c) {
 			break;
 		default:
 			if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
-				tnewline();
+				tnewline(1); /* always go to first col */
 			tsetchar(c);
 			if(term.c.x+1 < term.col)
 				tmoveto(term.c.x+1, term.c.y);
@@ -1560,15 +1567,12 @@ kpress(XEvent *ev) {
 	meta = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
 	len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status);
-
+	
+	/* 1. custom keys from config.h */
 	if((customkey = kmap(ksym)))
 		ttywrite(customkey, strlen(customkey));
-	else if(len > 0) {
-		buf[sizeof(buf)-1] = '\0';
-		if(meta && len == 1)
-			ttywrite("\033", 1);
-		ttywrite(buf, len);
-	} else
+	/* 2. hardcoded (overrides X lookup) */
+	else
 		switch(ksym) {
 		case XK_Up:
 		case XK_Down:
@@ -1581,8 +1585,21 @@ kpress(XEvent *ev) {
 			if(shift)
 				selpaste();
 			break;
+		case XK_Return:
+			if(IS_SET(MODE_CRLF))
+				ttywrite("\r\n", 2);
+			else
+				ttywrite("\r", 1);
+			break;
+			/* 3. X lookup  */
 		default:
-			fprintf(stderr, "errkey: %d\n", (int)ksym);
+			if(len > 0) {
+				buf[sizeof(buf)-1] = '\0';
+				if(meta && len == 1)
+					ttywrite("\033", 1);
+				ttywrite(buf, len);
+			} else /* 4. nothing to send */
+				fprintf(stderr, "errkey: %d\n", (int)ksym);
 			break;
 		}
 }

From 722688d989bae9ce5e71507be5656c9b78ae7834 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sat, 16 Oct 2010 20:54:19 +0200
Subject: [PATCH 0156/1146] \v and \f are have the same behaviour of \n.

---
 st.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.c b/st.c
index 16462c7..147a6fa 100644
--- a/st.c
+++ b/st.c
@@ -1168,6 +1168,8 @@ tputc(char c) {
 		case '\r':
 			tmoveto(0, term.c.y);
 			break;
+		case '\f':
+		case '\v':
 		case '\n':
 			/* go to first col if the mode is set */
 			tnewline(IS_SET(MODE_CRLF));

From 12435817723b44189bd412937403c401e5bbc136 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@djpohly.com>
Date: Mon, 25 Oct 2010 15:10:41 -0400
Subject: [PATCH 0157/1146] move code into new xresize func, add early exit to
 resize

---
 st.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/st.c b/st.c
index 147a6fa..594b0d3 100644
--- a/st.c
+++ b/st.c
@@ -190,6 +190,7 @@ static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
 static void xseturgency(int);
+static void xresize(int, int);
 
 static void expose(XEvent *);
 static void visibility(XEvent *);
@@ -1257,6 +1258,14 @@ tresize(int col, int row) {
 	tsetscroll(0, row-1);
 }
 
+void
+xresize(int col, int row) {
+	xw.bufw = MAX(1, col * xw.cw);
+	xw.bufh = MAX(1, row * xw.ch);
+	XFreePixmap(xw.dis, xw.buf);
+	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
+}
+
 void
 xloadcols(void) {
 	int i, r, g, b;
@@ -1615,16 +1624,13 @@ resize(XEvent *e) {
 	
 	xw.w = e->xconfigure.width;
 	xw.h = e->xconfigure.height;
-	xw.bufw = xw.w - 2*BORDER;
-	xw.bufh = xw.h - 2*BORDER;
-	col = xw.bufw / xw.cw;
-	row = xw.bufh / xw.ch;
+	col = (xw.w - 2*BORDER) / xw.cw;
+	row = (xw.h - 2*BORDER) / xw.ch;
+	if(col == term.col && row == term.row)
+		return;
 	tresize(col, row);
 	ttyresize(col, row);
-	xw.bufh = MAX(1, xw.bufh);
-	xw.bufw = MAX(1, xw.bufw);
-	XFreePixmap(xw.dis, xw.buf);
-	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
+	xresize(col, row);
 }
 
 void

From d85f7319a2c0d0bc53c1e0be6539284823fe7389 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@djpohly.com>
Date: Mon, 25 Oct 2010 15:26:47 -0400
Subject: [PATCH 0158/1146] copy old pixmap to new on resize

---
 st.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 594b0d3..734ad0a 100644
--- a/st.c
+++ b/st.c
@@ -1260,10 +1260,24 @@ tresize(int col, int row) {
 
 void
 xresize(int col, int row) {
+	Pixmap newbuf;
+	int oldw, oldh;
+
+	oldw = xw.bufw;
+	oldh = xw.bufh;
 	xw.bufw = MAX(1, col * xw.cw);
 	xw.bufh = MAX(1, row * xw.ch);
+	newbuf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
+	XCopyArea(xw.dis, xw.buf, newbuf, dc.gc, 0, 0, xw.bufw, xw.bufh, 0, 0);
 	XFreePixmap(xw.dis, xw.buf);
-	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
+	XSetForeground(xw.dis, dc.gc, dc.col[DefaultBG]);
+	if(xw.bufw > oldw)
+		XFillRectangle(xw.dis, newbuf, dc.gc, oldw, 0,
+				xw.bufw-oldw, MIN(xw.bufh, oldh));
+	if(xw.bufh > oldh)
+		XFillRectangle(xw.dis, newbuf, dc.gc, 0, oldh,
+				xw.bufw, xw.bufh-oldh);
+	xw.buf = newbuf;
 }
 
 void

From 638a30359d26c1f84a87f0f8df17df1765068029 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@djpohly.com>
Date: Mon, 25 Oct 2010 16:00:10 -0400
Subject: [PATCH 0159/1146] get rid of artifacts in border on resize down

---
 st.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/st.c b/st.c
index 734ad0a..1089087 100644
--- a/st.c
+++ b/st.c
@@ -1274,9 +1274,17 @@ xresize(int col, int row) {
 	if(xw.bufw > oldw)
 		XFillRectangle(xw.dis, newbuf, dc.gc, oldw, 0,
 				xw.bufw-oldw, MIN(xw.bufh, oldh));
+	else if(xw.bufw < oldw && (BORDER > 0 || xw.w > xw.bufw))
+		XClearArea(xw.dis, xw.win, BORDER+xw.bufw, BORDER,
+				xw.w-xw.bufh-BORDER, BORDER+MIN(xw.bufh, oldh),
+				False);
 	if(xw.bufh > oldh)
 		XFillRectangle(xw.dis, newbuf, dc.gc, 0, oldh,
 				xw.bufw, xw.bufh-oldh);
+	else if(xw.bufh < oldh && (BORDER > 0 || xw.h > xw.bufh))
+		XClearArea(xw.dis, xw.win, BORDER, BORDER+xw.bufh,
+				xw.w-2*BORDER, xw.h-xw.bufh-BORDER,
+				False);
 	xw.buf = newbuf;
 }
 

From edfbc9b432bc779ec9c41f7523be52b99edeec85 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@djpohly.com>
Date: Mon, 25 Oct 2010 16:45:13 -0400
Subject: [PATCH 0160/1146] redraw if we scroll on resize

---
 st.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 1089087..ed8e2a8 100644
--- a/st.c
+++ b/st.c
@@ -170,7 +170,7 @@ static void tputtab(void);
 static void tputc(char);
 static void tputs(char*, int);
 static void treset(void);
-static void tresize(int, int);
+static int tresize(int, int);
 static void tscrollup(int, int);
 static void tscrolldown(int, int);
 static void tsetattr(int*, int);
@@ -1202,7 +1202,7 @@ tputs(char *s, int len) {
 		tputc(*s++);
 }
 
-void
+int
 tresize(int col, int row) {
 	int i, x;
 	int minrow = MIN(row, term.row);
@@ -1210,7 +1210,7 @@ tresize(int col, int row) {
 	int slide = term.c.y - row + 1;
 
 	if(col < 1 || row < 1)
-		return;
+		return 0;
 
 	/* free unneeded rows */
 	i = 0;
@@ -1256,6 +1256,7 @@ tresize(int col, int row) {
 	tmoveto(term.c.x, term.c.y);
 	/* reset scrolling region */
 	tsetscroll(0, row-1);
+	return (slide > 0);
 }
 
 void
@@ -1650,7 +1651,8 @@ resize(XEvent *e) {
 	row = (xw.h - 2*BORDER) / xw.ch;
 	if(col == term.col && row == term.row)
 		return;
-	tresize(col, row);
+	if(tresize(col, row))
+		draw(SCREEN_REDRAW);
 	ttyresize(col, row);
 	xresize(col, row);
 }

From b1e6099220f7e10d88adb8d960db27f63f1d8ccb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 31 Oct 2010 20:29:22 +0100
Subject: [PATCH 0161/1146] fixed ED.

---
 st.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index ed8e2a8..76a2016 100644
--- a/st.c
+++ b/st.c
@@ -883,10 +883,14 @@ csihandle(void) {
 	case 'J': /* ED -- Clear screen */
 		switch(escseq.arg[0]) {
 		case 0: /* below */
-			tclearregion(term.c.x, term.c.y, term.col-1, term.row-1);
+			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 */
-			tclearregion(0, 0, term.c.x, term.c.y);
+			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);

From d581bfccd7c2987e12809383d8ce1f833529b715 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Mon, 8 Nov 2010 19:49:13 +0100
Subject: [PATCH 0162/1146] selection code cleanup.

---
 st.c | 97 +++++++++++++++---------------------------------------------
 1 file changed, 24 insertions(+), 73 deletions(-)

diff --git a/st.c b/st.c
index 76a2016..895519d 100644
--- a/st.c
+++ b/st.c
@@ -286,35 +286,24 @@ static char *getseltext() {
 
 static void selection_notify(XEvent *e) {
 	unsigned long nitems;
-	unsigned long length;
-	int format, res;
+	unsigned long ofs, rem;
+	int format;
 	unsigned char *data;
 	Atom type;
 
-	res = XGetWindowProperty(xw.dis, xw.win, XA_PRIMARY, 0, 0, False, 
-				AnyPropertyType, &type, &format, &nitems, &length, &data);
-	switch(res) {
-		case BadAtom:
-		case BadValue:
-		case BadWindow:
-			fprintf(stderr, "Invalid paste, XGetWindowProperty0");
+	ofs = 0;
+	do {
+		if(XGetWindowProperty(xw.dis, xw.win, XA_PRIMARY, ofs, BUFSIZ/4,
+					False, AnyPropertyType, &type, &format,
+					&nitems, &rem, &data)) {
+			fprintf(stderr, "Clipboard allocation failed\n");
 			return;
-	}
-
-	res = XGetWindowProperty(xw.dis, xw.win, XA_PRIMARY, 0, length, False,
-				AnyPropertyType, &type, &format, &nitems, &length, &data);
-	switch(res) {
-		case BadAtom:
-		case BadValue:
-		case BadWindow:
-			fprintf(stderr, "Invalid paste, XGetWindowProperty0");
-			return;
-	}
-
-	if(data) {
+		}
 		ttywrite((const char *) data, nitems * format / 8);
 		XFree(data);
-	}
+		/* number of 32-bit chunks returned */
+		ofs += nitems * format / 32;
+	} while(rem > 0);
 }
 
 static void selpaste() {
@@ -325,7 +314,6 @@ static void selection_request(XEvent *e)
 {
 	XSelectionRequestEvent *xsre;
 	XSelectionEvent xev;
-	int res;
 	Atom xa_targets;
 
 	xsre = (XSelectionRequestEvent *) e;
@@ -341,70 +329,33 @@ static void selection_request(XEvent *e)
 	if(xsre->target == xa_targets) {
 		/* respond with the supported type */
 		Atom string = XA_STRING;
-		res = XChangeProperty(xsre->display, xsre->requestor, xsre->property, XA_ATOM, 32,
-				PropModeReplace, (unsigned char *) &string, 1);
-		switch(res) {
-			case BadAlloc:
-			case BadAtom:
-			case BadMatch:
-			case BadValue:
-			case BadWindow:
-				fprintf(stderr, "Error in selection_request, TARGETS");
-				break;
-			default:
-				xev.property = xsre->property;
-		}
+		XChangeProperty(xsre->display, xsre->requestor, xsre->property,
+				XA_ATOM, 32, PropModeReplace,
+				(unsigned char *) &string, 1);
+		xev.property = xsre->property;
 	} else if(xsre->target == XA_STRING) {
-		res = XChangeProperty(xsre->display, xsre->requestor, xsre->property,
-				xsre->target, 8, PropModeReplace, (unsigned char *) sel.clip,
-				strlen(sel.clip));
-		switch(res) {
-			case BadAlloc:
-			case BadAtom:
-			case BadMatch:
-			case BadValue:
-			case BadWindow:
-				fprintf(stderr, "Error in selection_request, XA_STRING");
-				break;
-			default:
-			 xev.property = xsre->property;
-		}
+		XChangeProperty(xsre->display, xsre->requestor, xsre->property,
+				xsre->target, 8, PropModeReplace,
+				(unsigned char *) sel.clip, strlen(sel.clip));
+		xev.property = xsre->property;
 	}
 
 	/* all done, send a notification to the listener */
-	res = XSendEvent(xsre->display, xsre->requestor, True, 0, (XEvent *) &xev);
-	switch(res) {
-		case 0:
-		case BadValue:
-		case BadWindow:
-			fprintf(stderr, "Error in selection_requested, XSendEvent");
-	}
+	if(!XSendEvent(xsre->display, xsre->requestor, True, 0, (XEvent *) &xev))
+		fprintf(stderr, "Error sending SelectionNotify event\n");
 }
 
 static void selcopy(char *str) {
 	/* register the selection for both the clipboard and the primary */
 	Atom clipboard;
-	int res;
 
 	free(sel.clip);
 	sel.clip = str;
 
-	res = XSetSelectionOwner(xw.dis, XA_PRIMARY, xw.win, CurrentTime);
-	switch(res) {
-		case BadAtom:
-		case BadWindow:
-			fprintf(stderr, "Invalid copy, XSetSelectionOwner");
-			return;
-	}
+	XSetSelectionOwner(xw.dis, XA_PRIMARY, xw.win, CurrentTime);
 
 	clipboard = XInternAtom(xw.dis, "CLIPBOARD", 0);
-	res = XSetSelectionOwner(xw.dis, clipboard, xw.win, CurrentTime);
-	switch(res) {
-		case BadAtom:
-		case BadWindow:
-			fprintf(stderr, "Invalid copy, XSetSelectionOwner");
-			return;
-	}
+	XSetSelectionOwner(xw.dis, clipboard, xw.win, CurrentTime);
 
 	XFlush(xw.dis);
 }

From 9b74fcadc46ee78b38b20e9663c6924cd9df7e84 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 18 Nov 2010 01:00:04 +0100
Subject: [PATCH 0163/1146] utf8 support! print text in delicious unicode
 greatness! all hail to the glorious Damian Okrasa for the patch!

TERM set back to xterm.
changed default fonts.
Note: drawing is now (even) slower.
---
 config.def.h |  29 +----
 st.c         | 322 ++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 260 insertions(+), 91 deletions(-)

diff --git a/config.def.h b/config.def.h
index 36982db..b33e9b6 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,7 +1,7 @@
 #define TAB 8
-#define TNAME "st-256color"
-#define FONT "-misc-*-medium-r-semicondensed-*-13-*-*-*-*-*-iso8859-*"
-#define BOLDFONT "-misc-*-bold-r-semicondensed-*-13-*-*-*-*-*-iso8859-*"
+#define TNAME "xterm"
+#define FONT "-*-*-medium-r-*-*-*-120-75-75-*-60-*-*"
+#define BOLDFONT "-*-*-bold-r-*-*-*-120-75-75-*-60-*-*"
 #define BORDER 2
 #define SHELL "/bin/sh"
 
@@ -55,31 +55,8 @@ static Key key[] = {
 
 /* Line drawing characters (sometime specific to each font...) */
 static char gfx[] = {
-	['`'] = 0x01,
-	['a'] = 0x02,
 	['f'] = 'o',
 	['g'] = '+',
 	['i'] = '#',
-	['j'] = 0x0B,
-	['k'] = 0x0C,
-	['l'] = 0x0D,
-	['m'] = 0x0E,
-	['n'] = 0x0F,
-	['o'] = 0x10,
-	['p'] = 0x11,
-	['q'] = 0x12,
-	['r'] = 0x13,
-	['s'] = 0x14,
-	['t'] = 0x15,
-	['u'] = 0x16,
-	['v'] = 0x17,
-	['w'] = 0x18,
-	['x'] = 0x19,
-	['y'] = 0x1A,
-	['z'] = 0x1B,
-	['{'] = 0x1C,
-	['|'] = 0x1D,
-	['}'] = 0x1E,
-	['~'] = 0x1F,
 	[255] = 0,
 };
diff --git a/st.c b/st.c
index 895519d..da72497 100644
--- a/st.c
+++ b/st.c
@@ -38,6 +38,7 @@
 #define ESC_BUF_SIZ   256
 #define ESC_ARG_SIZ   16
 #define DRAW_BUF_SIZ  1024
+#define UTF_SIZ       4
 
 #define SERRNO strerror(errno)
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
@@ -61,8 +62,11 @@ enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
 enum { SCREEN_UPDATE, SCREEN_REDRAW };
 enum { WIN_VISIBLE=1, WIN_REDRAW=2, WIN_FOCUSED=4 };
 
+#undef B0
+enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 };
+
 typedef struct {
-	char c;     /* character code  */
+	char c[UTF_SIZ];     /* character code */
 	char mode;  /* attribute flags */
 	int fg;     /* foreground      */
 	int bg;     /* background      */
@@ -127,11 +131,19 @@ typedef struct {
 	char s[ESC_BUF_SIZ];
 } Key;
 
+typedef struct {
+	XFontSet fs;
+	short lbearing;
+	short rbearing;
+	int ascent;
+	int descent;
+} FontInfo;
+
 /* Drawing Context */
 typedef struct {
 	unsigned long col[256];
-	XFontStruct* font;
-	XFontStruct* bfont;
+	FontInfo font;
+	FontInfo bfont;
 	GC gc;
 } DC;
 
@@ -167,14 +179,13 @@ static void tmoveto(int, int);
 static void tnew(int, int);
 static void tnewline(int);
 static void tputtab(void);
-static void tputc(char);
-static void tputs(char*, int);
+static void tputc(char*);
 static void treset(void);
 static int tresize(int, int);
 static void tscrollup(int, int);
 static void tscrolldown(int, int);
 static void tsetattr(int*, int);
-static void tsetchar(char);
+static void tsetchar(char*);
 static void tsetscroll(int, int);
 static void tswapscreen(void);
 
@@ -183,7 +194,7 @@ static void ttyread(void);
 static void ttyresize(int, int);
 static void ttywrite(const char *, size_t);
 
-static void xdraws(char *, Glyph, int, int, int);
+static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
 static void xclear(int, int, int, int);
 static void xdrawcursor(void);
@@ -205,6 +216,11 @@ static void bmotion(XEvent *);
 static void selection_notify(XEvent *);
 static void selection_request(XEvent *);
 
+static int stou(char *, long *);
+static int utos(long *, char *);
+static int slen(char *);
+static int canstou(char *, int);
+
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
 	[ConfigureNotify] = resize,
@@ -231,6 +247,133 @@ static Selection sel;
 static char *opt_cmd   = NULL;
 static char *opt_title = NULL;
 
+/* UTF-8 decode */
+static int
+stou(char *s, long *u)
+{
+	unsigned char c;
+	int i, n, rtn;
+
+	rtn = 1;
+	c = *s;
+	if(~c&B7) { /* 0xxxxxxx */
+		*u = c;
+		return rtn;
+	} else if ((c&(B7|B6|B5)) == (B7|B6)) { /* 110xxxxx */
+		*u = c&(B4|B3|B2|B1|B0);
+		n = 1;
+	} else if ((c&(B7|B6|B5|B4)) == (B7|B6|B5)) { /* 1110xxxx */
+		*u = c&(B3|B2|B1|B0);
+		n = 2;
+	} else if ((c&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4)) { /* 11110xxx */
+		*u = c&(B2|B1|B0);
+		n = 3;
+	} else
+		goto invalid;
+	for (i=n,++s; i>0; --i,++rtn,++s) {
+		c = *s;
+		if ((c&(B7|B6)) != B7) /* 10xxxxxx */
+			goto invalid;
+		*u <<= 6;
+		*u |= c&(B5|B4|B3|B2|B1|B0);
+	}
+	if ((n == 1 && *u < 0x80) ||
+	    (n == 2 && *u < 0x800) ||
+	    (n == 3 && *u < 0x10000) ||
+	    (*u >= 0xD800 && *u <= 0xDFFF))
+		goto invalid;
+	return rtn;
+invalid:
+	*u = 0xFFFD;
+	return rtn;
+}
+
+/* UTF-8 encode */
+static int
+utos(long *u, char *s) 
+{
+	unsigned char *sp;
+	unsigned long uc;
+	int i, n;
+
+	sp = (unsigned char*) s;
+	uc = *u;
+	if (uc < 0x80) {
+		*sp = uc; /* 0xxxxxxx */
+		return 1;
+	} else if (*u < 0x800) {
+		*sp = (uc >> 6) | (B7|B6); /* 110xxxxx */
+		n = 1;
+	} else if (uc < 0x10000) {
+		*sp = (uc >> 12) | (B7|B6|B5); /* 1110xxxx */
+		n = 2;
+	} else if (uc <= 0x10FFFF) {
+		*sp = (uc >> 18) | (B7|B6|B5|B4); /* 11110xxx */
+		n = 3;
+	} else {
+		goto invalid;
+	}
+	for (i=n,++sp; i>0; --i,++sp)
+		*sp = ((uc >> 6*(i-1)) & (B5|B4|B3|B2|B1|B0)) | B7; /* 10xxxxxx */
+	return n+1;
+invalid:
+	/* U+FFFD */
+	*s++ = '\xEF';
+	*s++ = '\xBF';
+	*s = '\xBD';
+	return 3;
+}
+
+/*
+ * use this if your buffer is less than UTF_SIZ, it returns 1 if you can decode UTF-8
+ * otherwise return 0
+ */
+static int
+canstou(char *s, int b)
+{
+	unsigned char c;
+	int n;
+
+	c = *s;
+	if (b < 1)
+		return 0;
+	else if (~c&B7)
+		return 1;
+	else if ((c&(B7|B6|B5)) == (B7|B6))
+		n = 1;
+	else if ((c&(B7|B6|B5|B4)) == (B7|B6|B5))
+		n = 2;
+	else if ((c&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4))
+		n = 3;
+	else
+		return 1;
+	for (--b,++s; n>0&&b>0; --n,--b,++s) {
+		c = *s;
+		if ((c&(B7|B6)) != B7)
+			break; 
+	}
+	if (n > 0 && b == 0)
+		return 0;
+	else
+		return 1;
+}
+
+static int
+slen(char *s)
+{
+	unsigned char c;
+
+	c = *s;
+	if (~c&B7)
+		return 1;
+	else if ((c&(B7|B6|B5)) == (B7|B6))
+		return 2;
+	else if ((c&(B7|B6|B5|B4)) == (B7|B6|B5))
+		return 3;
+	else 
+		return 4;
+}
+
 void
 selinit(void) {
 	sel.mode = 0;
@@ -268,15 +411,18 @@ static void bpress(XEvent *e) {
 
 static char *getseltext() {
 	char *str, *ptr;
-	int ls, x, y, sz;
+	int ls, x, y, sz, sl;
 	if(sel.bx == -1)
 		return NULL;
-	sz = (term.col+1) * (sel.e.y-sel.b.y+1);
+	sz = (term.col+1) * (sel.e.y-sel.b.y+1) * UTF_SIZ;
 	ptr = str = malloc(sz);
 	for(y = 0; y < term.row; y++) {
 		for(x = 0; x < term.col; x++)
-			if(term.line[y][x].state & GLYPH_SET && (ls = selected(x, y)))
-				*ptr = term.line[y][x].c, ptr++;
+			if(term.line[y][x].state & GLYPH_SET && (ls = selected(x, y))) {
+				sl = slen(term.line[y][x].c);
+				memcpy(ptr, term.line[y][x].c, sl);
+				ptr += sl;
+			}
 		if(ls)
 			*ptr = '\n', ptr++;
 	}
@@ -476,13 +622,24 @@ dump(char c) {
 
 void
 ttyread(void) {
-	char buf[BUFSIZ];
-	int ret;
+	char buf[BUFSIZ], *ptr;
+	char s[UTF_SIZ];
+	int ret, br;
+	static int buflen = 0;
+	long u;
 
-	if((ret = read(cmdfd, buf, LEN(buf))) < 0)
+	if((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
 		die("Couldn't read from shell: %s\n", SERRNO);
-	else
-		tputs(buf, ret);
+	else {
+		buflen += ret;
+		for(ptr=buf; buflen>=UTF_SIZ||canstou(ptr,buflen); buflen-=br) {
+			br = stou(ptr, &u);
+			utos(&u, s);
+			tputc(s);
+			ptr += br;
+		}
+		memcpy(buf, ptr, buflen);
+	}
 }
 
 void
@@ -622,9 +779,9 @@ tmoveto(int x, int y) {
 }
 
 void
-tsetchar(char c) {
+tsetchar(char *c) {
 	term.line[term.c.y][term.c.x] = term.c.attr;
-	term.line[term.c.y][term.c.x].c = c;
+	memcpy(term.line[term.c.y][term.c.x].c, c, UTF_SIZ);
 	term.line[term.c.y][term.c.x].state |= GLYPH_SET;
 }
 
@@ -1025,30 +1182,31 @@ tputtab(void) {
 }
 
 void
-tputc(char c) {
+tputc(char *c) {
+	char ascii = *c;
 	if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {
-			escseq.buf[escseq.len++] = c;
-			if(BETWEEN(c, 0x40, 0x7E) || escseq.len >= ESC_BUF_SIZ) {
+			escseq.buf[escseq.len++] = ascii;
+			if(BETWEEN(ascii, 0x40, 0x7E) || escseq.len >= ESC_BUF_SIZ) {
 				term.esc = 0;
 				csiparse(), csihandle();
 			}
 			/* TODO: handle other OSC */
 		} else if(term.esc & ESC_OSC) { 
-			if(c == ';') {
+			if(ascii == ';') {
 				term.titlelen = 0;
 				term.esc = ESC_START | ESC_TITLE;
 			}
 		} else if(term.esc & ESC_TITLE) {
-			if(c == '\a' || term.titlelen+1 >= ESC_TITLE_SIZ) {
+			if(ascii == '\a' || term.titlelen+1 >= ESC_TITLE_SIZ) {
 				term.esc = 0;
 				term.title[term.titlelen] = '\0';
 				XStoreName(xw.dis, xw.win, term.title);
 			} else {
-				term.title[term.titlelen++] = c;
+				term.title[term.titlelen++] = ascii;
 			}
 		} else if(term.esc & ESC_ALTCHARSET) {
-			switch(c) {
+			switch(ascii) {
 			case '0': /* Line drawing crap */
 				term.c.attr.mode |= ATTR_GFX;
 				break;
@@ -1056,11 +1214,11 @@ tputc(char c) {
 				term.c.attr.mode &= ~ATTR_GFX;
 				break;
 			default:
-				printf("esc unhandled charset: ESC ( %c\n", c);
+				printf("esc unhandled charset: ESC ( %c\n", ascii);
 			}
 			term.esc = 0;
 		} else {
-			switch(c) {
+			switch(ascii) {
 			case '[':
 				term.esc |= ESC_CSI;
 				break;
@@ -1109,12 +1267,13 @@ tputc(char c) {
 				term.esc = 0;
 				break;
 			default:
-				fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n", c, isprint(c)?c:'.');
+				fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
+				    (unsigned char) ascii, isprint(ascii)?ascii:'.');
 				term.esc = 0;
 			}
 		}
 	} else {
-		switch(c) {
+		switch(ascii) {
 		case '\t':
 			tputtab();
 			break;
@@ -1151,12 +1310,6 @@ tputc(char c) {
 	}
 }
 
-void
-tputs(char *s, int len) {
-	for(; len > 0; len--)
-		tputc(*s++);
-}
-
 int
 tresize(int col, int row) {
 	int i, x;
@@ -1308,21 +1461,53 @@ xhints(void)
 	XSetWMProperties(xw.dis, xw.win, NULL, NULL, NULL, 0, &size, &wm, &class);
 }
 
+void
+xsetfontinfo(FontInfo *fi)
+{
+	XFontStruct **xfonts;
+	int fnum;
+	int i;
+	char **fontnames;
+
+	fi->lbearing = 0;
+	fi->rbearing = 0;
+	fi->ascent = 0;
+	fi->descent = 0;
+	fnum = XFontsOfFontSet(fi->fs, &xfonts, &fontnames);
+	for(i=0; i<fnum; i++,xfonts++,fontnames++) {
+		puts(*fontnames);
+		if(fi->ascent < (*xfonts)->ascent)
+			fi->ascent = (*xfonts)->ascent;
+		if(fi->descent < (*xfonts)->descent)
+			fi->descent = (*xfonts)->descent;
+		if(fi->rbearing < (*xfonts)->max_bounds.rbearing)
+			fi->rbearing = (*xfonts)->max_bounds.rbearing;
+		if(fi->lbearing < (*xfonts)->min_bounds.lbearing)
+			fi->lbearing = (*xfonts)->min_bounds.lbearing;
+	}
+}
+
 void
 xinit(void) {
 	XSetWindowAttributes attrs;
+	char **mc;
+	char *ds;
+	int nmc;
 
 	if(!(xw.dis = XOpenDisplay(NULL)))
 		die("Can't open display\n");
 	xw.scr = XDefaultScreen(xw.dis);
 	
 	/* font */
-	if(!(dc.font = XLoadQueryFont(xw.dis, FONT)) || !(dc.bfont = XLoadQueryFont(xw.dis, BOLDFONT)))
-		die("Can't load font %s\n", dc.font ? BOLDFONT : FONT);
+	if ((dc.font.fs = XCreateFontSet(xw.dis, FONT, &mc, &nmc, &ds)) == NULL ||
+	    (dc.bfont.fs = XCreateFontSet(xw.dis, BOLDFONT, &mc, &nmc, &ds)) == NULL)
+		die("Can't load font %s\n", dc.font.fs ? BOLDFONT : FONT); 
+	xsetfontinfo(&dc.font);
+	xsetfontinfo(&dc.bfont);
 
 	/* XXX: Assuming same size for bold font */
-	xw.cw = dc.font->max_bounds.rbearing - dc.font->min_bounds.lbearing;
-	xw.ch = dc.font->ascent + dc.font->descent;
+ 	xw.cw = dc.font.rbearing - dc.font.lbearing;
+	xw.ch = dc.font.ascent + dc.font.descent;
 
 	/* colors */
 	xw.cmap = XDefaultColormap(xw.dis, xw.scr);
@@ -1366,9 +1551,9 @@ xinit(void) {
 }
 
 void
-xdraws(char *s, Glyph base, int x, int y, int len) {
+xdraws(char *s, Glyph base, int x, int y, int cl, int sl) {
 	unsigned long xfg, xbg;
-	int winx = x*xw.cw, winy = y*xw.ch + dc.font->ascent, width = len*xw.cw;
+	int winx = x*xw.cw, winy = y*xw.ch + dc.font.ascent, width = cl*xw.cw;
 	int i;
 
 	if(base.mode & ATTR_REVERSE)
@@ -1378,9 +1563,9 @@ xdraws(char *s, Glyph base, int x, int y, int len) {
 
 	XSetBackground(xw.dis, dc.gc, xbg);
 	XSetForeground(xw.dis, dc.gc, xfg);
-	
+
 	if(base.mode & ATTR_GFX)
-		for(i = 0; i < len; i++) {
+		for(i = 0; i < cl; i++) {
 			char c = gfx[(unsigned int)s[i] % 256];
 			if(c)
 				s[i] = c;
@@ -1388,8 +1573,8 @@ xdraws(char *s, Glyph base, int x, int y, int len) {
 				s[i] -= 0x5f;
 		}
 
-	XSetFont(xw.dis, dc.gc, base.mode & ATTR_BOLD ? dc.bfont->fid : dc.font->fid);
-	XDrawImageString(xw.dis, xw.buf, dc.gc, winx, winy, s, len);
+	XmbDrawImageString(xw.dis, xw.buf, base.mode & ATTR_BOLD ? dc.bfont.fs : dc.font.fs,
+	    dc.gc, winx, winy, s, sl);
 	
 	if(base.mode & ATTR_UNDERLINE)
 		XDrawLine(xw.dis, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);
@@ -1399,23 +1584,26 @@ void
 xdrawcursor(void) {
 	static int oldx = 0;
 	static int oldy = 0;
-	Glyph g = {' ', ATTR_NULL, DefaultBG, DefaultCS, 0};
+	int sl;
+	Glyph g = {{' '}, ATTR_NULL, DefaultBG, DefaultCS, 0};
 	
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
 	
 	if(term.line[term.c.y][term.c.x].state & GLYPH_SET)
-		g.c = term.line[term.c.y][term.c.x].c;
-	
+		memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
+
 	/* remove the old cursor */
-	if(term.line[oldy][oldx].state & GLYPH_SET)
-		xdraws(&term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, 1);
-	else
+	if(term.line[oldy][oldx].state & GLYPH_SET) {
+		sl = slen(term.line[oldy][oldx].c);
+		xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, 1, sl);
+	} else
 		xclear(oldx, oldy, oldx, oldy);
 	
 	/* draw the new one */
 	if(!(term.c.state & CURSOR_HIDE) && (xw.state & WIN_FOCUSED)) {
-		xdraws(&g.c, g, term.c.x, term.c.y, 1);
+		sl = slen(g.c);
+		xdraws(g.c, g, term.c.x, term.c.y, 1, sl);
 		oldx = term.c.x, oldy = term.c.y;
 	}
 }
@@ -1424,11 +1612,12 @@ xdrawcursor(void) {
 /* basic drawing routines */
 void
 xdrawc(int x, int y, Glyph g) {
+	int sl = slen(g.c);
 	XRectangle r = { x * xw.cw, y * xw.ch, xw.cw, xw.ch };
 	XSetBackground(xw.dis, dc.gc, dc.col[g.bg]);
 	XSetForeground(xw.dis, dc.gc, dc.col[g.fg]);
-	XSetFont(xw.dis, dc.gc, g.mode & ATTR_BOLD ? dc.bfont->fid : dc.font->fid);
-	XDrawImageString(xw.dis, xw.buf, dc.gc, r.x, r.y+dc.font->ascent, &g.c, 1);
+	XmbDrawImageString(xw.dis, xw.buf, g.mode&ATTR_BOLD?dc.bfont.fs:dc.font.fs,
+	    dc.gc, r.x, r.y+dc.font.ascent, g.c, sl);
 }
 
 void
@@ -1450,7 +1639,7 @@ draw(int dummy) {
 /* optimized drawing routine */
 void
 draw(int redraw_all) {
-	int i, x, y, ox;
+	int ic, ib, x, y, ox, sl;
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
 
@@ -1460,26 +1649,29 @@ draw(int redraw_all) {
 	xclear(0, 0, term.col-1, term.row-1);
 	for(y = 0; y < term.row; y++) {
 		base = term.line[y][0];
-		i = ox = 0;
+		ic = ib = ox = 0;
 		for(x = 0; x < term.col; x++) {
 			new = term.line[y][x];
-			if(sel.bx!=-1 && new.c && selected(x, y))
+			if(sel.bx!=-1 && *(new.c) && selected(x, y))
 				new.mode ^= ATTR_REVERSE;
-			if(i > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) ||
-					i >= DRAW_BUF_SIZ)) {
-				xdraws(buf, base, ox, y, i);
-				i = 0;
+			if(ib > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) ||
+					ib >= DRAW_BUF_SIZ-UTF_SIZ)) {
+				xdraws(buf, base, ox, y, ic, ib);
+				ic = ib = 0;
 			}
 			if(new.state & GLYPH_SET) {
-				if(i == 0) {
+				if(ib == 0) {
 					ox = x;
 					base = new;
 				}
-				buf[i++] = new.c;
+				sl = slen(new.c);
+				memcpy(buf+ib, new.c, sl);
+				ib += sl;
+				++ic;
 			}
 		}
-		if(i > 0)
-			xdraws(buf, base, ox, y, i);
+		if(ib > 0)
+			xdraws(buf, base, ox, y, ic, ib);
 	}
 	xdrawcursor();
 	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);

From 70464e208060746ad9184dfc298005fff3035d72 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 18 Nov 2010 12:43:33 +0100
Subject: [PATCH 0164/1146] some code cleaning.

---
 st.c | 88 +++++++++++++++++++++++++++++-------------------------------
 1 file changed, 42 insertions(+), 46 deletions(-)

diff --git a/st.c b/st.c
index da72497..b25fe89 100644
--- a/st.c
+++ b/st.c
@@ -201,6 +201,7 @@ static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
 static void xseturgency(int);
+static void xsetsel(char*);
 static void xresize(int, int);
 
 static void expose(XEvent *);
@@ -213,8 +214,13 @@ static void focus(XEvent *);
 static void brelease(XEvent *);
 static void bpress(XEvent *);
 static void bmotion(XEvent *);
-static void selection_notify(XEvent *);
-static void selection_request(XEvent *);
+static void selnotify(XEvent *);
+static void selrequest(XEvent *);
+
+static void selinit(void);
+static inline int selected(int, int);
+static void selcopy(void);
+static void selpaste(void);
 
 static int stou(char *, long *);
 static int utos(long *, char *);
@@ -232,8 +238,8 @@ static void (*handler[LASTEvent])(XEvent *) = {
 	[MotionNotify] = bmotion,
 	[ButtonPress] = bpress,
 	[ButtonRelease] = brelease,
-	[SelectionNotify] = selection_notify,
-	[SelectionRequest] = selection_request,
+	[SelectionNotify] = selnotify,
+	[SelectionRequest] = selrequest,
 };
 
 /* Globals */
@@ -248,9 +254,7 @@ static char *opt_cmd   = NULL;
 static char *opt_title = NULL;
 
 /* UTF-8 decode */
-static int
-stou(char *s, long *u)
-{
+static int stou(char *s, long *u) {
 	unsigned char c;
 	int i, n, rtn;
 
@@ -289,9 +293,7 @@ invalid:
 }
 
 /* UTF-8 encode */
-static int
-utos(long *u, char *s) 
-{
+static int utos(long *u, char *s) {
 	unsigned char *sp;
 	unsigned long uc;
 	int i, n;
@@ -324,17 +326,12 @@ invalid:
 	return 3;
 }
 
-/*
- * use this if your buffer is less than UTF_SIZ, it returns 1 if you can decode UTF-8
- * otherwise return 0
- */
-static int
-canstou(char *s, int b)
-{
-	unsigned char c;
+/* use this if your buffer is less than UTF_SIZ, it returns 1 if you can decode
+   UTF-8 otherwise return 0 */
+static int canstou(char *s, int b) {
+	unsigned char c = *s;
 	int n;
 
-	c = *s;
 	if (b < 1)
 		return 0;
 	else if (~c&B7)
@@ -358,12 +355,9 @@ canstou(char *s, int b)
 		return 1;
 }
 
-static int
-slen(char *s)
-{
-	unsigned char c;
+static int slen(char *s) {
+	unsigned char c = *s;
 
-	c = *s;
 	if (~c&B7)
 		return 1;
 	else if ((c&(B7|B6|B5)) == (B7|B6))
@@ -374,8 +368,7 @@ slen(char *s)
 		return 4;
 }
 
-void
-selinit(void) {
+static void selinit(void) {
 	sel.mode = 0;
 	sel.bx = -1;
 	sel.clip = NULL;
@@ -409,28 +402,31 @@ static void bpress(XEvent *e) {
 	sel.ey = sel.by = e->xbutton.y/xw.ch;
 }
 
-static char *getseltext() {
+static void selcopy() {
 	char *str, *ptr;
 	int ls, x, y, sz, sl;
+
 	if(sel.bx == -1)
-		return NULL;
-	sz = (term.col+1) * (sel.e.y-sel.b.y+1) * UTF_SIZ;
-	ptr = str = malloc(sz);
-	for(y = 0; y < term.row; y++) {
-		for(x = 0; x < term.col; x++)
-			if(term.line[y][x].state & GLYPH_SET && (ls = selected(x, y))) {
-				sl = slen(term.line[y][x].c);
-				memcpy(ptr, term.line[y][x].c, sl);
-				ptr += sl;
-			}
-		if(ls)
-			*ptr = '\n', ptr++;
+		str = NULL;
+	else {
+		sz = (term.col+1) * (sel.e.y-sel.b.y+1) * UTF_SIZ;
+		ptr = str = malloc(sz);
+		for(y = 0; y < term.row; y++) {
+			for(x = 0; x < term.col; x++)
+				if(term.line[y][x].state & GLYPH_SET && (ls = selected(x, y))) {
+					sl = slen(term.line[y][x].c);
+					memcpy(ptr, term.line[y][x].c, sl);
+					ptr += sl;
+				}
+			if(ls)
+				*ptr = '\n', ptr++;
+		}
+		*ptr = 0;
 	}
-	*ptr = 0;
-	return str;
+	xsetsel(str);
 }
 
-static void selection_notify(XEvent *e) {
+static void selnotify(XEvent *e) {
 	unsigned long nitems;
 	unsigned long ofs, rem;
 	int format;
@@ -456,7 +452,7 @@ static void selpaste() {
 	XConvertSelection(xw.dis, XA_PRIMARY, XA_STRING, XA_PRIMARY, xw.win, CurrentTime);
 }
 
-static void selection_request(XEvent *e)
+static void selrequest(XEvent *e)
 {
 	XSelectionRequestEvent *xsre;
 	XSelectionEvent xev;
@@ -491,7 +487,7 @@ static void selection_request(XEvent *e)
 		fprintf(stderr, "Error sending SelectionNotify event\n");
 }
 
-static void selcopy(char *str) {
+static void xsetsel(char *str) {
 	/* register the selection for both the clipboard and the primary */
 	Atom clipboard;
 
@@ -517,7 +513,7 @@ static void brelease(XEvent *e) {
 			selpaste();
 	} else {
 		if(b==1)
-			selcopy(getseltext());
+			selcopy();
 	}
 	draw(1);
 }
@@ -525,7 +521,7 @@ static void brelease(XEvent *e) {
 static void bmotion(XEvent *e) {
 	if (sel.mode) {
 		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
-		draw(1);
+		//	draw(1);
 	}
 }
 

From b61afd24be566d8c8d7d5310fdad973441139428 Mon Sep 17 00:00:00 2001
From: Gregor Best <gbe@ring0.de>
Date: Fri, 19 Nov 2010 17:13:13 +0100
Subject: [PATCH 0165/1146] Add -c option to override the default window class

---
 st.1 | 4 ++++
 st.c | 8 ++++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/st.1 b/st.1
index 4d00d2f..29bdda6 100644
--- a/st.1
+++ b/st.1
@@ -4,6 +4,7 @@ st \- simple terminal
 .SH SYNOPSIS
 .B st
 .RB [ \-e " <cmd>"]
+.RB [ \-c " <class>"]
 .RB [ \-t " <title>"]
 .RB [ \-v ]
 .SH DESCRIPTION
@@ -17,5 +18,8 @@ Execute cmd instead of the shell
 .B \-t <title>
 Overrides the default title (st)
 .TP
+.B \-c <class>
+Overrides the default class ($TERM)
+.TP
 .BI \-v
 Prints version information to standard output, then exits.
diff --git a/st.c b/st.c
index b25fe89..bed7e8d 100644
--- a/st.c
+++ b/st.c
@@ -31,7 +31,7 @@
 
 #define USAGE \
 	"st-" VERSION ", (c) 2010 st engineers\n" \
-	"usage: st [-t title] [-e cmd] [-v]\n"
+	"usage: st [-t title] [-c class] [-e cmd] [-v]\n"
 
 /* Arbitrary sizes */
 #define ESC_TITLE_SIZ 256
@@ -252,6 +252,7 @@ static pid_t pid;
 static Selection sel;
 static char *opt_cmd   = NULL;
 static char *opt_title = NULL;
+static char *opt_class = NULL;
 
 /* UTF-8 decode */
 static int stou(char *s, long *u) {
@@ -1443,7 +1444,7 @@ xclear(int x1, int y1, int x2, int y2) {
 void
 xhints(void)
 {
-	XClassHint class = {TNAME, TNAME};
+	XClassHint class = {opt_class ? opt_class : TNAME, TNAME};
 	XWMHints wm = {.flags = InputHint, .input = 1};
 	XSizeHints size = {
 		.flags = PSize | PResizeInc | PBaseSize,
@@ -1838,6 +1839,9 @@ main(int argc, char *argv[]) {
 		case 't':
 			if(++i < argc) opt_title = argv[i];
 			break;
+		case 'c':
+			if(++i < argc) opt_class = argv[i];
+			break;
 		case 'e':
 			if(++i < argc) opt_cmd = argv[i];
 			break;

From 81a048d6cfda84a06353911130fee029df077c8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Fri, 19 Nov 2010 22:32:39 +0100
Subject: [PATCH 0166/1146] clean comment regarding redrawing in bmotion().

---
 st.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index bed7e8d..38c8658 100644
--- a/st.c
+++ b/st.c
@@ -522,7 +522,9 @@ static void brelease(XEvent *e) {
 static void bmotion(XEvent *e) {
 	if (sel.mode) {
 		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
-		//	draw(1);
+		/* XXX: draw() can't keep up, disabled for now.
+		   selection is visible on button release.
+		   draw(1); */
 	}
 }
 

From b61925b5d6fd8af0ad0ccc922db60dff1746cfe2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sat, 20 Nov 2010 22:24:04 +0100
Subject: [PATCH 0167/1146] cleanup & bugfix in xdraws().

---
 st.c | 249 +++++++++++++++++++++++++++++------------------------------
 1 file changed, 124 insertions(+), 125 deletions(-)

diff --git a/st.c b/st.c
index 38c8658..e7e292f 100644
--- a/st.c
+++ b/st.c
@@ -131,20 +131,17 @@ typedef struct {
 	char s[ESC_BUF_SIZ];
 } Key;
 
-typedef struct {
-	XFontSet fs;
-	short lbearing;
-	short rbearing;
-	int ascent;
-	int descent;
-} FontInfo;
-
 /* Drawing Context */
 typedef struct {
 	unsigned long col[256];
-	FontInfo font;
-	FontInfo bfont;
 	GC gc;
+	struct {
+		int ascent;
+		int descent;
+		short lbearing;
+		short rbearing;
+		XFontSet set;
+	} font, bfont;
 } DC;
 
 /* TODO: use better name for vars... */
@@ -222,10 +219,10 @@ static inline int selected(int, int);
 static void selcopy(void);
 static void selpaste(void);
 
-static int stou(char *, long *);
-static int utos(long *, char *);
-static int slen(char *);
-static int canstou(char *, int);
+static int utf8decode(char *, long *);
+static int utf8encode(long *, char *);
+static int utf8size(char *);
+static int isfullutf8(char *, int);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
@@ -254,8 +251,8 @@ static char *opt_cmd   = NULL;
 static char *opt_title = NULL;
 static char *opt_class = NULL;
 
-/* UTF-8 decode */
-static int stou(char *s, long *u) {
+int
+utf8decode(char *s, long *u) {
 	unsigned char c;
 	int i, n, rtn;
 
@@ -264,28 +261,28 @@ static int stou(char *s, long *u) {
 	if(~c&B7) { /* 0xxxxxxx */
 		*u = c;
 		return rtn;
-	} else if ((c&(B7|B6|B5)) == (B7|B6)) { /* 110xxxxx */
+	} else if((c&(B7|B6|B5)) == (B7|B6)) { /* 110xxxxx */
 		*u = c&(B4|B3|B2|B1|B0);
 		n = 1;
-	} else if ((c&(B7|B6|B5|B4)) == (B7|B6|B5)) { /* 1110xxxx */
+	} else if((c&(B7|B6|B5|B4)) == (B7|B6|B5)) { /* 1110xxxx */
 		*u = c&(B3|B2|B1|B0);
 		n = 2;
-	} else if ((c&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4)) { /* 11110xxx */
+	} else if((c&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4)) { /* 11110xxx */
 		*u = c&(B2|B1|B0);
 		n = 3;
 	} else
 		goto invalid;
-	for (i=n,++s; i>0; --i,++rtn,++s) {
+	for(i=n,++s; i>0; --i,++rtn,++s) {
 		c = *s;
-		if ((c&(B7|B6)) != B7) /* 10xxxxxx */
+		if((c&(B7|B6)) != B7) /* 10xxxxxx */
 			goto invalid;
 		*u <<= 6;
 		*u |= c&(B5|B4|B3|B2|B1|B0);
 	}
-	if ((n == 1 && *u < 0x80) ||
-	    (n == 2 && *u < 0x800) ||
-	    (n == 3 && *u < 0x10000) ||
-	    (*u >= 0xD800 && *u <= 0xDFFF))
+	if((n == 1 && *u < 0x80) ||
+	   (n == 2 && *u < 0x800) ||
+	   (n == 3 && *u < 0x10000) ||
+	   (*u >= 0xD800 && *u <= 0xDFFF))
 		goto invalid;
 	return rtn;
 invalid:
@@ -293,30 +290,30 @@ invalid:
 	return rtn;
 }
 
-/* UTF-8 encode */
-static int utos(long *u, char *s) {
+int
+utf8encode(long *u, char *s) {
 	unsigned char *sp;
 	unsigned long uc;
 	int i, n;
 
 	sp = (unsigned char*) s;
 	uc = *u;
-	if (uc < 0x80) {
+	if(uc < 0x80) {
 		*sp = uc; /* 0xxxxxxx */
 		return 1;
-	} else if (*u < 0x800) {
+	} else if(*u < 0x800) {
 		*sp = (uc >> 6) | (B7|B6); /* 110xxxxx */
 		n = 1;
-	} else if (uc < 0x10000) {
+	} else if(uc < 0x10000) {
 		*sp = (uc >> 12) | (B7|B6|B5); /* 1110xxxx */
 		n = 2;
-	} else if (uc <= 0x10FFFF) {
+	} else if(uc <= 0x10FFFF) {
 		*sp = (uc >> 18) | (B7|B6|B5|B4); /* 11110xxx */
 		n = 3;
 	} else {
 		goto invalid;
 	}
-	for (i=n,++sp; i>0; --i,++sp)
+	for(i=n,++sp; i>0; --i,++sp)
 		*sp = ((uc >> 6*(i-1)) & (B5|B4|B3|B2|B1|B0)) | B7; /* 10xxxxxx */
 	return n+1;
 invalid:
@@ -329,34 +326,32 @@ invalid:
 
 /* use this if your buffer is less than UTF_SIZ, it returns 1 if you can decode
    UTF-8 otherwise return 0 */
-static int canstou(char *s, int b) {
-	unsigned char c = *s;
-	int n;
+int
+isfullutf8(char *s, int b) {
+	unsigned char *c1, *c2, *c3;
 
-	if (b < 1)
+	c1 = (unsigned char *) s;
+	c2 = (unsigned char *) ++s;
+	c3 = (unsigned char *) ++s;
+	if(b < 1)
 		return 0;
-	else if (~c&B7)
-		return 1;
-	else if ((c&(B7|B6|B5)) == (B7|B6))
-		n = 1;
-	else if ((c&(B7|B6|B5|B4)) == (B7|B6|B5))
-		n = 2;
-	else if ((c&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4))
-		n = 3;
-	else
-		return 1;
-	for (--b,++s; n>0&&b>0; --n,--b,++s) {
-		c = *s;
-		if ((c&(B7|B6)) != B7)
-			break; 
-	}
-	if (n > 0 && b == 0)
+	else if((*c1&(B7|B6|B5)) == (B7|B6) && b == 1)
+		return 0;
+	else if((*c1&(B7|B6|B5|B4)) == (B7|B6|B5) &&
+	    ((b == 1) || 
+	    ((b == 2) && (*c2&(B7|B6)) == B7)))
+		return 0;
+	else if((*c1&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4) &&
+	    ((b == 1) ||
+	    ((b == 2) && (*c2&(B7|B6)) == B7) ||
+	    ((b == 3) && (*c2&(B7|B6)) == B7 && (*c3&(B7|B6)) == B7)))
 		return 0;
 	else
 		return 1;
 }
 
-static int slen(char *s) {
+int
+utf8size(char *s) {
 	unsigned char c = *s;
 
 	if (~c&B7)
@@ -369,13 +364,15 @@ static int slen(char *s) {
 		return 4;
 }
 
-static void selinit(void) {
+void
+selinit(void) {
 	sel.mode = 0;
 	sel.bx = -1;
 	sel.clip = NULL;
 }
 
-static inline int selected(int x, int y) {
+static inline int 
+selected(int x, int y) {
 	if(sel.ey == y && sel.by == y) {
 		int bx = MIN(sel.bx, sel.ex);
 		int ex = MAX(sel.bx, sel.ex);
@@ -385,7 +382,8 @@ static inline int selected(int x, int y) {
 		|| (y==sel.b.y && x>=sel.b.x && (x<=sel.e.x || sel.b.y!=sel.e.y));
 }
 
-static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
+void
+getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
 	if(b) 
 		*b = e->xbutton.button;
 
@@ -397,13 +395,15 @@ static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
 	sel.e.y = MAX(sel.by, sel.ey);
 }
 
-static void bpress(XEvent *e) {
+void
+bpress(XEvent *e) {
 	sel.mode = 1;
 	sel.ex = sel.bx = e->xbutton.x/xw.cw;
 	sel.ey = sel.by = e->xbutton.y/xw.ch;
 }
 
-static void selcopy() {
+void
+selcopy(void) {
 	char *str, *ptr;
 	int ls, x, y, sz, sl;
 
@@ -415,7 +415,7 @@ static void selcopy() {
 		for(y = 0; y < term.row; y++) {
 			for(x = 0; x < term.col; x++)
 				if(term.line[y][x].state & GLYPH_SET && (ls = selected(x, y))) {
-					sl = slen(term.line[y][x].c);
+					sl = utf8size(term.line[y][x].c);
 					memcpy(ptr, term.line[y][x].c, sl);
 					ptr += sl;
 				}
@@ -427,7 +427,8 @@ static void selcopy() {
 	xsetsel(str);
 }
 
-static void selnotify(XEvent *e) {
+void
+selnotify(XEvent *e) {
 	unsigned long nitems;
 	unsigned long ofs, rem;
 	int format;
@@ -449,12 +450,13 @@ static void selnotify(XEvent *e) {
 	} while(rem > 0);
 }
 
-static void selpaste() {
+void
+selpaste() {
 	XConvertSelection(xw.dis, XA_PRIMARY, XA_STRING, XA_PRIMARY, xw.win, CurrentTime);
 }
 
-static void selrequest(XEvent *e)
-{
+void
+selrequest(XEvent *e) {
 	XSelectionRequestEvent *xsre;
 	XSelectionEvent xev;
 	Atom xa_targets;
@@ -488,7 +490,8 @@ static void selrequest(XEvent *e)
 		fprintf(stderr, "Error sending SelectionNotify event\n");
 }
 
-static void xsetsel(char *str) {
+void
+xsetsel(char *str) {
 	/* register the selection for both the clipboard and the primary */
 	Atom clipboard;
 
@@ -504,7 +507,8 @@ static void xsetsel(char *str) {
 }
 
 /* TODO: doubleclick to select word */
-static void brelease(XEvent *e) {
+void
+brelease(XEvent *e) {
 	int b;
 	sel.mode = 0;
 	getbuttoninfo(e, &b, &sel.ex, &sel.ey);
@@ -519,7 +523,8 @@ static void brelease(XEvent *e) {
 	draw(1);
 }
 
-static void bmotion(XEvent *e) {
+void
+bmotion(XEvent *e) {
 	if (sel.mode) {
 		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
 		/* XXX: draw() can't keep up, disabled for now.
@@ -528,26 +533,6 @@ static void bmotion(XEvent *e) {
 	}
 }
 
-#ifdef DEBUG
-void
-tdump(void) {
-	int row, col;
-	Glyph c;
-
-	for(row = 0; row < term.row; row++) {
-		for(col = 0; col < term.col; col++) {
-			if(col == term.c.x && row == term.c.y)
-				putchar('#');
-			else {
-				c = term.line[row][col];
-				putchar(c.state & GLYPH_SET ? c.c : '.');
-			}
-		}
-		putchar('\n');
-	}
-}
-#endif
-
 void
 die(const char *errstr, ...) {
 	va_list ap;
@@ -631,9 +616,9 @@ ttyread(void) {
 		die("Couldn't read from shell: %s\n", SERRNO);
 	else {
 		buflen += ret;
-		for(ptr=buf; buflen>=UTF_SIZ||canstou(ptr,buflen); buflen-=br) {
-			br = stou(ptr, &u);
-			utos(&u, s);
+		for(ptr=buf; buflen>=UTF_SIZ||isfullutf8(ptr,buflen); buflen-=br) {
+			br = utf8decode(ptr, &u);
+			utf8encode(&u, s);
 			tputc(s);
 			ptr += br;
 		}
@@ -1460,49 +1445,63 @@ xhints(void)
 	XSetWMProperties(xw.dis, xw.win, NULL, NULL, NULL, 0, &size, &wm, &class);
 }
 
+XFontSet
+xinitfont(char *fontstr)
+{
+	XFontSet set;
+	char *def, **missing;
+	int n;
+
+	missing = NULL;
+	set = XCreateFontSet(xw.dis, fontstr, &missing, &n, &def);
+	if(missing) {
+		while(n--)
+			fprintf(stderr, "st: missing fontset: %s\n", missing[n]);
+		XFreeStringList(missing);
+	}
+	return set;
+}
+
 void
-xsetfontinfo(FontInfo *fi)
+xgetfontinfo(XFontSet set, int *ascent, int *descent, short *lbearing, short *rbearing)
 {
 	XFontStruct **xfonts;
-	int fnum;
-	int i;
-	char **fontnames;
+	char **font_names;
+	int i, n;
 
-	fi->lbearing = 0;
-	fi->rbearing = 0;
-	fi->ascent = 0;
-	fi->descent = 0;
-	fnum = XFontsOfFontSet(fi->fs, &xfonts, &fontnames);
-	for(i=0; i<fnum; i++,xfonts++,fontnames++) {
-		puts(*fontnames);
-		if(fi->ascent < (*xfonts)->ascent)
-			fi->ascent = (*xfonts)->ascent;
-		if(fi->descent < (*xfonts)->descent)
-			fi->descent = (*xfonts)->descent;
-		if(fi->rbearing < (*xfonts)->max_bounds.rbearing)
-			fi->rbearing = (*xfonts)->max_bounds.rbearing;
-		if(fi->lbearing < (*xfonts)->min_bounds.lbearing)
-			fi->lbearing = (*xfonts)->min_bounds.lbearing;
+	*ascent = *descent = *lbearing = *rbearing = 0;
+	n = XFontsOfFontSet(set, &xfonts, &font_names);
+	for(i = 0; i < n; i++) {
+		*ascent = MAX(*ascent, (*xfonts)->ascent);
+		*descent = MAX(*descent, (*xfonts)->descent);
+		*lbearing = MAX(*lbearing, (*xfonts)->min_bounds.lbearing);
+		*rbearing = MAX(*rbearing, (*xfonts)->max_bounds.rbearing);
+		xfonts++;
 	}
 }
 
+void
+initfonts(char *fontstr, char *bfontstr)
+{
+	if((dc.font.set = xinitfont(fontstr)) == NULL ||
+	   (dc.bfont.set = xinitfont(bfontstr)) == NULL)
+		die("Can't load font %s\n", dc.font.set ? BOLDFONT : FONT);
+	xgetfontinfo(dc.font.set, &dc.font.ascent, &dc.font.descent,
+	    &dc.font.lbearing, &dc.font.rbearing);
+	xgetfontinfo(dc.bfont.set, &dc.bfont.ascent, &dc.bfont.descent,
+	    &dc.bfont.lbearing, &dc.bfont.rbearing);
+}
+
 void
 xinit(void) {
 	XSetWindowAttributes attrs;
-	char **mc;
-	char *ds;
-	int nmc;
 
 	if(!(xw.dis = XOpenDisplay(NULL)))
 		die("Can't open display\n");
 	xw.scr = XDefaultScreen(xw.dis);
 	
 	/* font */
-	if ((dc.font.fs = XCreateFontSet(xw.dis, FONT, &mc, &nmc, &ds)) == NULL ||
-	    (dc.bfont.fs = XCreateFontSet(xw.dis, BOLDFONT, &mc, &nmc, &ds)) == NULL)
-		die("Can't load font %s\n", dc.font.fs ? BOLDFONT : FONT); 
-	xsetfontinfo(&dc.font);
-	xsetfontinfo(&dc.bfont);
+	initfonts(FONT, BOLDFONT);
 
 	/* XXX: Assuming same size for bold font */
  	xw.cw = dc.font.rbearing - dc.font.lbearing;
@@ -1550,9 +1549,9 @@ xinit(void) {
 }
 
 void
-xdraws(char *s, Glyph base, int x, int y, int cl, int sl) {
+xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	unsigned long xfg, xbg;
-	int winx = x*xw.cw, winy = y*xw.ch + dc.font.ascent, width = cl*xw.cw;
+	int winx = x*xw.cw, winy = y*xw.ch + dc.font.ascent, width = charlen*xw.cw;
 	int i;
 
 	if(base.mode & ATTR_REVERSE)
@@ -1564,7 +1563,7 @@ xdraws(char *s, Glyph base, int x, int y, int cl, int sl) {
 	XSetForeground(xw.dis, dc.gc, xfg);
 
 	if(base.mode & ATTR_GFX)
-		for(i = 0; i < cl; i++) {
+		for(i = 0; i < bytelen; i++) {
 			char c = gfx[(unsigned int)s[i] % 256];
 			if(c)
 				s[i] = c;
@@ -1572,8 +1571,8 @@ xdraws(char *s, Glyph base, int x, int y, int cl, int sl) {
 				s[i] -= 0x5f;
 		}
 
-	XmbDrawImageString(xw.dis, xw.buf, base.mode & ATTR_BOLD ? dc.bfont.fs : dc.font.fs,
-	    dc.gc, winx, winy, s, sl);
+	XmbDrawImageString(xw.dis, xw.buf, base.mode & ATTR_BOLD ? dc.bfont.set : dc.font.set,
+	    dc.gc, winx, winy, s, bytelen);
 	
 	if(base.mode & ATTR_UNDERLINE)
 		XDrawLine(xw.dis, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);
@@ -1594,14 +1593,14 @@ xdrawcursor(void) {
 
 	/* remove the old cursor */
 	if(term.line[oldy][oldx].state & GLYPH_SET) {
-		sl = slen(term.line[oldy][oldx].c);
+		sl = utf8size(term.line[oldy][oldx].c);
 		xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, 1, sl);
 	} else
 		xclear(oldx, oldy, oldx, oldy);
 	
 	/* draw the new one */
 	if(!(term.c.state & CURSOR_HIDE) && (xw.state & WIN_FOCUSED)) {
-		sl = slen(g.c);
+		sl = utf8size(g.c);
 		xdraws(g.c, g, term.c.x, term.c.y, 1, sl);
 		oldx = term.c.x, oldy = term.c.y;
 	}
@@ -1611,7 +1610,7 @@ xdrawcursor(void) {
 /* basic drawing routines */
 void
 xdrawc(int x, int y, Glyph g) {
-	int sl = slen(g.c);
+	int sl = utf8size(g.c);
 	XRectangle r = { x * xw.cw, y * xw.ch, xw.cw, xw.ch };
 	XSetBackground(xw.dis, dc.gc, dc.col[g.bg]);
 	XSetForeground(xw.dis, dc.gc, dc.col[g.fg]);
@@ -1663,7 +1662,7 @@ draw(int redraw_all) {
 					ox = x;
 					base = new;
 				}
-				sl = slen(new.c);
+				sl = utf8size(new.c);
 				memcpy(buf+ib, new.c, sl);
 				ib += sl;
 				++ic;

From eaf38bf310a3c7850df2444fcdd77683ab8e4dc2 Mon Sep 17 00:00:00 2001
From: "pancake@nopcode.org" <unknown>
Date: Wed, 24 Nov 2010 14:27:44 +0100
Subject: [PATCH 0168/1146] Fix unused variable issue and OSX includes

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index e7e292f..35945b0 100644
--- a/st.c
+++ b/st.c
@@ -23,7 +23,7 @@
 
 #if   defined(__linux)
  #include <pty.h>
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
+#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
  #include <util.h>
 #elif defined(__FreeBSD__) || defined(__DragonFly__)
  #include <libutil.h>
@@ -405,7 +405,7 @@ bpress(XEvent *e) {
 void
 selcopy(void) {
 	char *str, *ptr;
-	int ls, x, y, sz, sl;
+	int x, y, sz, sl, ls = 0;
 
 	if(sel.bx == -1)
 		str = NULL;

From 00ba6969f863c75536910a0138b5161bbd0638c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Fri, 26 Nov 2010 22:11:31 +0100
Subject: [PATCH 0169/1146] s/xw.dis/xw.dpy/

---
 st.c | 109 ++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 55 insertions(+), 54 deletions(-)

diff --git a/st.c b/st.c
index e7e292f..8e3d72f 100644
--- a/st.c
+++ b/st.c
@@ -110,7 +110,7 @@ typedef struct {
 
 /* Purely graphic info */
 typedef struct {
-	Display* dis;
+	Display* dpy;
 	Colormap cmap;
 	Window win;
 	Pixmap buf;
@@ -437,7 +437,7 @@ selnotify(XEvent *e) {
 
 	ofs = 0;
 	do {
-		if(XGetWindowProperty(xw.dis, xw.win, XA_PRIMARY, ofs, BUFSIZ/4,
+		if(XGetWindowProperty(xw.dpy, xw.win, XA_PRIMARY, ofs, BUFSIZ/4,
 					False, AnyPropertyType, &type, &format,
 					&nitems, &rem, &data)) {
 			fprintf(stderr, "Clipboard allocation failed\n");
@@ -452,7 +452,7 @@ selnotify(XEvent *e) {
 
 void
 selpaste() {
-	XConvertSelection(xw.dis, XA_PRIMARY, XA_STRING, XA_PRIMARY, xw.win, CurrentTime);
+	XConvertSelection(xw.dpy, XA_PRIMARY, XA_STRING, XA_PRIMARY, xw.win, CurrentTime);
 }
 
 void
@@ -470,7 +470,7 @@ selrequest(XEvent *e) {
 	/* reject */
 	xev.property = None;
 
-	xa_targets = XInternAtom(xw.dis, "TARGETS", 0);
+	xa_targets = XInternAtom(xw.dpy, "TARGETS", 0);
 	if(xsre->target == xa_targets) {
 		/* respond with the supported type */
 		Atom string = XA_STRING;
@@ -498,12 +498,12 @@ xsetsel(char *str) {
 	free(sel.clip);
 	sel.clip = str;
 
-	XSetSelectionOwner(xw.dis, XA_PRIMARY, xw.win, CurrentTime);
+	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, CurrentTime);
 
-	clipboard = XInternAtom(xw.dis, "CLIPBOARD", 0);
-	XSetSelectionOwner(xw.dis, clipboard, xw.win, CurrentTime);
+	clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+	XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
 
-	XFlush(xw.dis);
+	XFlush(xw.dpy);
 }
 
 /* TODO: doubleclick to select word */
@@ -1185,7 +1185,7 @@ tputc(char *c) {
 			if(ascii == '\a' || term.titlelen+1 >= ESC_TITLE_SIZ) {
 				term.esc = 0;
 				term.title[term.titlelen] = '\0';
-				XStoreName(xw.dis, xw.win, term.title);
+				XStoreName(xw.dpy, xw.win, term.title);
 			} else {
 				term.title[term.titlelen++] = ascii;
 			}
@@ -1360,22 +1360,22 @@ xresize(int col, int row) {
 	oldh = xw.bufh;
 	xw.bufw = MAX(1, col * xw.cw);
 	xw.bufh = MAX(1, row * xw.ch);
-	newbuf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
-	XCopyArea(xw.dis, xw.buf, newbuf, dc.gc, 0, 0, xw.bufw, xw.bufh, 0, 0);
-	XFreePixmap(xw.dis, xw.buf);
-	XSetForeground(xw.dis, dc.gc, dc.col[DefaultBG]);
+	newbuf = XCreatePixmap(xw.dpy, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dpy, xw.scr));
+	XCopyArea(xw.dpy, xw.buf, newbuf, dc.gc, 0, 0, xw.bufw, xw.bufh, 0, 0);
+	XFreePixmap(xw.dpy, xw.buf);
+	XSetForeground(xw.dpy, dc.gc, dc.col[DefaultBG]);
 	if(xw.bufw > oldw)
-		XFillRectangle(xw.dis, newbuf, dc.gc, oldw, 0,
+		XFillRectangle(xw.dpy, newbuf, dc.gc, oldw, 0,
 				xw.bufw-oldw, MIN(xw.bufh, oldh));
 	else if(xw.bufw < oldw && (BORDER > 0 || xw.w > xw.bufw))
-		XClearArea(xw.dis, xw.win, BORDER+xw.bufw, BORDER,
+		XClearArea(xw.dpy, xw.win, BORDER+xw.bufw, BORDER,
 				xw.w-xw.bufh-BORDER, BORDER+MIN(xw.bufh, oldh),
 				False);
 	if(xw.bufh > oldh)
-		XFillRectangle(xw.dis, newbuf, dc.gc, 0, oldh,
+		XFillRectangle(xw.dpy, newbuf, dc.gc, 0, oldh,
 				xw.bufw, xw.bufh-oldh);
 	else if(xw.bufh < oldh && (BORDER > 0 || xw.h > xw.bufh))
-		XClearArea(xw.dis, xw.win, BORDER, BORDER+xw.bufh,
+		XClearArea(xw.dpy, xw.win, BORDER, BORDER+xw.bufh,
 				xw.w-2*BORDER, xw.h-xw.bufh-BORDER,
 				False);
 	xw.buf = newbuf;
@@ -1385,10 +1385,10 @@ void
 xloadcols(void) {
 	int i, r, g, b;
 	XColor color;
-	unsigned long white = WhitePixel(xw.dis, xw.scr);
+	unsigned long white = WhitePixel(xw.dpy, xw.scr);
 
 	for(i = 0; i < 16; i++) {
-		if (!XAllocNamedColor(xw.dis, xw.cmap, colorname[i], &color, &color)) {
+		if (!XAllocNamedColor(xw.dpy, xw.cmap, colorname[i], &color, &color)) {
 			dc.col[i] = white;
 			fprintf(stderr, "Could not allocate color '%s'\n", colorname[i]);
 		} else
@@ -1402,7 +1402,7 @@ xloadcols(void) {
 				color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r;
 				color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g;
 				color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b;
-				if (!XAllocColor(xw.dis, xw.cmap, &color)) {
+				if (!XAllocColor(xw.dpy, xw.cmap, &color)) {
 					dc.col[i] = white;
 					fprintf(stderr, "Could not allocate color %d\n", i);
 				} else
@@ -1412,7 +1412,7 @@ xloadcols(void) {
 
 	for(r = 0; r < 24; r++, i++) {
 		color.red = color.green = color.blue = 0x0808 + 0x0a0a * r;
-		if (!XAllocColor(xw.dis, xw.cmap, &color)) {
+		if (!XAllocColor(xw.dpy, xw.cmap, &color)) {
 			dc.col[i] = white;
 			fprintf(stderr, "Could not allocate color %d\n", i);
 		} else
@@ -1422,8 +1422,8 @@ xloadcols(void) {
 
 void
 xclear(int x1, int y1, int x2, int y2) {
-	XSetForeground(xw.dis, dc.gc, dc.col[DefaultBG]);
-	XFillRectangle(xw.dis, xw.buf, dc.gc,
+	XSetForeground(xw.dpy, dc.gc, dc.col[DefaultBG]);
+	XFillRectangle(xw.dpy, xw.buf, dc.gc,
 	               x1 * xw.cw, y1 * xw.ch,
 	               (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
 }
@@ -1442,7 +1442,7 @@ xhints(void)
 		.base_height = 2*BORDER,
 		.base_width = 2*BORDER,
 	};
-	XSetWMProperties(xw.dis, xw.win, NULL, NULL, NULL, 0, &size, &wm, &class);
+	XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, &size, &wm, &class);
 }
 
 XFontSet
@@ -1453,7 +1453,7 @@ xinitfont(char *fontstr)
 	int n;
 
 	missing = NULL;
-	set = XCreateFontSet(xw.dis, fontstr, &missing, &n, &def);
+	set = XCreateFontSet(xw.dpy, fontstr, &missing, &n, &def);
 	if(missing) {
 		while(n--)
 			fprintf(stderr, "st: missing fontset: %s\n", missing[n]);
@@ -1496,9 +1496,9 @@ void
 xinit(void) {
 	XSetWindowAttributes attrs;
 
-	if(!(xw.dis = XOpenDisplay(NULL)))
+	if(!(xw.dpy = XOpenDisplay(NULL)))
 		die("Can't open display\n");
-	xw.scr = XDefaultScreen(xw.dis);
+	xw.scr = XDefaultScreen(xw.dpy);
 	
 	/* font */
 	initfonts(FONT, BOLDFONT);
@@ -1508,7 +1508,7 @@ xinit(void) {
 	xw.ch = dc.font.ascent + dc.font.descent;
 
 	/* colors */
-	xw.cmap = XDefaultColormap(xw.dis, xw.scr);
+	xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
 	xloadcols();
 
 	/* window - default size */
@@ -1525,27 +1525,27 @@ xinit(void) {
 		| PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
 	attrs.colormap = xw.cmap;
 
-	xw.win = XCreateWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0,
-			xw.w, xw.h, 0, XDefaultDepth(xw.dis, xw.scr), InputOutput,
-			XDefaultVisual(xw.dis, xw.scr),
+	xw.win = XCreateWindow(xw.dpy, XRootWindow(xw.dpy, xw.scr), 0, 0,
+			xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
+			XDefaultVisual(xw.dpy, xw.scr),
 			CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
 			| CWColormap,
 			&attrs);
-	xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr));
+	xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dpy, xw.scr));
 
 
 	/* input methods */
-	xw.xim = XOpenIM(xw.dis, NULL, NULL, NULL);
+	xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
 	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing 
 					   | XIMStatusNothing, XNClientWindow, xw.win, 
 					   XNFocusWindow, xw.win, NULL);
 	/* gc */
-	dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL);
+	dc.gc = XCreateGC(xw.dpy, xw.win, 0, NULL);
 	
-	XMapWindow(xw.dis, xw.win);
+	XMapWindow(xw.dpy, xw.win);
 	xhints();
-	XStoreName(xw.dis, xw.win, opt_title ? opt_title : "st");
-	XSync(xw.dis, 0);
+	XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st");
+	XSync(xw.dpy, 0);
 }
 
 void
@@ -1559,10 +1559,10 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	else
 		xfg = dc.col[base.fg], xbg = dc.col[base.bg];
 
-	XSetBackground(xw.dis, dc.gc, xbg);
-	XSetForeground(xw.dis, dc.gc, xfg);
+	XSetBackground(xw.dpy, dc.gc, xbg);
+	XSetForeground(xw.dpy, dc.gc, xfg);
 
-	if(base.mode & ATTR_GFX)
+	if(base.mode & ATTR_GFX) {
 		for(i = 0; i < bytelen; i++) {
 			char c = gfx[(unsigned int)s[i] % 256];
 			if(c)
@@ -1570,12 +1570,13 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			else if(s[i] > 0x5f)
 				s[i] -= 0x5f;
 		}
+	}
 
-	XmbDrawImageString(xw.dis, xw.buf, base.mode & ATTR_BOLD ? dc.bfont.set : dc.font.set,
+	XmbDrawImageString(xw.dpy, xw.buf, base.mode & ATTR_BOLD ? dc.bfont.set : dc.font.set,
 	    dc.gc, winx, winy, s, bytelen);
 	
 	if(base.mode & ATTR_UNDERLINE)
-		XDrawLine(xw.dis, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);
+		XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);
 }
 
 void
@@ -1612,9 +1613,9 @@ void
 xdrawc(int x, int y, Glyph g) {
 	int sl = utf8size(g.c);
 	XRectangle r = { x * xw.cw, y * xw.ch, xw.cw, xw.ch };
-	XSetBackground(xw.dis, dc.gc, dc.col[g.bg]);
-	XSetForeground(xw.dis, dc.gc, dc.col[g.fg]);
-	XmbDrawImageString(xw.dis, xw.buf, g.mode&ATTR_BOLD?dc.bfont.fs:dc.font.fs,
+	XSetBackground(xw.dpy, dc.gc, dc.col[g.bg]);
+	XSetForeground(xw.dpy, dc.gc, dc.col[g.fg]);
+	XmbDrawImageString(xw.dpy, xw.buf, g.mode&ATTR_BOLD?dc.bfont.fs:dc.font.fs,
 	    dc.gc, r.x, r.y+dc.font.ascent, g.c, sl);
 }
 
@@ -1629,8 +1630,8 @@ draw(int dummy) {
 				xdrawc(x, y, term.line[y][x]);
 
 	xdrawcursor();
-	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
-	XFlush(xw.dis);
+	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
+	XFlush(xw.dpy);
 }
 
 #else
@@ -1672,7 +1673,7 @@ draw(int redraw_all) {
 			xdraws(buf, base, ox, y, ic, ib);
 	}
 	xdrawcursor();
-	XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
+	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
 }
 
 #endif
@@ -1686,7 +1687,7 @@ expose(XEvent *ev) {
 			draw(SCREEN_REDRAW);
 		}
 	} else
-		XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, e->x-BORDER, e->y-BORDER,
+		XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, e->x-BORDER, e->y-BORDER,
 				e->width, e->height, e->x, e->y);
 }
 
@@ -1707,9 +1708,9 @@ unmap(XEvent *ev) {
 
 void
 xseturgency(int add) {
-	XWMHints *h = XGetWMHints(xw.dis, xw.win);
+	XWMHints *h = XGetWMHints(xw.dpy, xw.win);
 	h->flags = add ? (h->flags | XUrgencyHint) : (h->flags & ~XUrgencyHint);
-	XSetWMHints(xw.dis, xw.win, h);
+	XSetWMHints(xw.dpy, xw.win, h);
 	XFree(h);
 }
 
@@ -1806,7 +1807,7 @@ void
 run(void) {
 	XEvent ev;
 	fd_set rfd;
-	int xfd = XConnectionNumber(xw.dis);
+	int xfd = XConnectionNumber(xw.dpy);
 
 	for(;;) {
 		FD_ZERO(&rfd);
@@ -1821,8 +1822,8 @@ run(void) {
 			ttyread();
 			draw(SCREEN_UPDATE); 
 		}
-		while(XPending(xw.dis)) {
-			XNextEvent(xw.dis, &ev);
+		while(XPending(xw.dpy)) {
+			XNextEvent(xw.dpy, &ev);
 			if (XFilterEvent(&ev, xw.win))
 				continue;
 			if(handler[ev.type])

From af75c433e56e74d2ad7a315d504a9303ea532f18 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sat, 27 Nov 2010 21:19:31 +0100
Subject: [PATCH 0170/1146] fix and clean ttyread(). buf wasn't static.

---
 st.c | 34 ++++++++++++++++++++--------------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index e988696..3829e73 100644
--- a/st.c
+++ b/st.c
@@ -606,24 +606,31 @@ dump(char c) {
 
 void
 ttyread(void) {
-	char buf[BUFSIZ], *ptr;
+	static char buf[BUFSIZ];
+	static int buflen = 0; 
+	char *ptr;
 	char s[UTF_SIZ];
-	int ret, br;
-	static int buflen = 0;
-	long u;
+	int charsize; /* size of utf8 char in bytes */
+	long utf8c;
+	int ret;
 
+	/* append read bytes to unprocessed bytes */
 	if((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
 		die("Couldn't read from shell: %s\n", SERRNO);
-	else {
-		buflen += ret;
-		for(ptr=buf; buflen>=UTF_SIZ||isfullutf8(ptr,buflen); buflen-=br) {
-			br = utf8decode(ptr, &u);
-			utf8encode(&u, s);
-			tputc(s);
-			ptr += br;
-		}
-		memcpy(buf, ptr, buflen);
+
+	/* process every complete utf8 char */
+	buflen += ret;
+	ptr = buf;
+	while(buflen >= UTF_SIZ || isfullutf8(ptr,buflen)) {
+		charsize = utf8decode(ptr, &utf8c);
+		utf8encode(&utf8c, s);
+		tputc(s);
+		ptr    += charsize;
+		buflen -= charsize;
 	}
+
+	/* keep any uncomplete utf8 char for the next call */
+	memcpy(buf, ptr, buflen);
 }
 
 void
@@ -1774,7 +1781,6 @@ kpress(XEvent *ev) {
 			/* 3. X lookup  */
 		default:
 			if(len > 0) {
-				buf[sizeof(buf)-1] = '\0';
 				if(meta && len == 1)
 					ttywrite("\033", 1);
 				ttywrite(buf, len);

From 54bc450dbf057e66bed5f10d13d90a469e5ca8ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 28 Nov 2010 01:40:39 +0100
Subject: [PATCH 0171/1146] use memmove() instead of memcpy() in ttyread().

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 3829e73..4d04416 100644
--- a/st.c
+++ b/st.c
@@ -630,7 +630,7 @@ ttyread(void) {
 	}
 
 	/* keep any uncomplete utf8 char for the next call */
-	memcpy(buf, ptr, buflen);
+	memmove(buf, ptr, buflen);
 }
 
 void

From 732b9601ed2543b1fa6acbc08ddc05818279265f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 28 Nov 2010 13:17:20 +0100
Subject: [PATCH 0172/1146] -e flag handles arguments.

---
 st.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 4d04416..d43c30c 100644
--- a/st.c
+++ b/st.c
@@ -545,11 +545,15 @@ die(const char *errstr, ...) {
 
 void
 execsh(void) {
-	char *args[] = {getenv("SHELL"), "-i", NULL};
+	char **args;
+	char *envshell = getenv("SHELL");
+	DEFAULT(envshell, "sh");
+
 	if(opt_cmd)
-		args[0] = opt_cmd, args[1] = NULL;
+		args = (char*[]){"sh", "-c", opt_cmd, NULL};
 	else
-		DEFAULT(args[0], SHELL);
+		args = (char*[]){envshell, "-i", NULL};
+	
 	putenv("TERM="TNAME);
 	execvp(args[0], args);
 }

From 86c5cb6de6644aeea3c480f66bdeb5e685aab86f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Tue, 30 Nov 2010 22:55:44 +0100
Subject: [PATCH 0173/1146] change -e behaviour and update man page.

---
 st.1 | 25 ++++++++++++++++---------
 st.c | 16 ++++++++--------
 2 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/st.1 b/st.1
index 29bdda6..f1f41a7 100644
--- a/st.1
+++ b/st.1
@@ -3,23 +3,30 @@
 st \- simple terminal
 .SH SYNOPSIS
 .B st
-.RB [ \-e " <cmd>"]
-.RB [ \-c " <class>"]
-.RB [ \-t " <title>"]
+.RB [ \-c
+.IR class ]
+.RB [ \-t 
+.IR title ]
 .RB [ \-v ]
+.RB [ \-e
+.IR cmd ]
 .SH DESCRIPTION
 .B st
 is a simple terminal emulator.
 .SH OPTIONS
 .TP
-.B \-e <cmd>
-Execute cmd instead of the shell
-.TP
-.B \-t <title>
+.B \-t title
 Overrides the default title (st)
 .TP
-.B \-c <class>
+.B \-c class
 Overrides the default class ($TERM)
 .TP
-.BI \-v
+.B \-v
 Prints version information to standard output, then exits.
+.TP
+.B \-e cmd [arguments]
+Execute cmd instead of the shell. Type your command as you would on your
+shell. If this option is used, it
+.BI "must be the last"
+on the command-line. This is the same behaviour as xterm/rxvt.
+
diff --git a/st.c b/st.c
index d43c30c..2be6772 100644
--- a/st.c
+++ b/st.c
@@ -247,7 +247,7 @@ static CSIEscape escseq;
 static int cmdfd;
 static pid_t pid;
 static Selection sel;
-static char *opt_cmd   = NULL;
+static char **opt_cmd  = NULL;
 static char *opt_title = NULL;
 static char *opt_class = NULL;
 
@@ -547,15 +547,12 @@ void
 execsh(void) {
 	char **args;
 	char *envshell = getenv("SHELL");
-	DEFAULT(envshell, "sh");
 
-	if(opt_cmd)
-		args = (char*[]){"sh", "-c", opt_cmd, NULL};
-	else
-		args = (char*[]){envshell, "-i", NULL};
-	
+	DEFAULT(envshell, "sh");
 	putenv("TERM="TNAME);
+	args = opt_cmd ? opt_cmd : (char*[]){envshell, "-i", NULL};
 	execvp(args[0], args);
+	exit(EXIT_FAILURE);
 }
 
 void 
@@ -1855,12 +1852,15 @@ main(int argc, char *argv[]) {
 			if(++i < argc) opt_class = argv[i];
 			break;
 		case 'e':
-			if(++i < argc) opt_cmd = argv[i];
+			if(++i < argc) opt_cmd = &argv[i];
 			break;
 		case 'v':
 		default:
 			die(USAGE);
 		}
+		/* -e eats every remaining arguments */
+		if(opt_cmd)
+			break;
 	}
 	setlocale(LC_CTYPE, "");
 	tnew(80, 24);

From fd1149866f5bc4e3cfdbd281cdd3a45d7db56b40 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 8 Dec 2010 18:09:39 +0100
Subject: [PATCH 0174/1146] add new line glitch to terminfo entry.

---
 st.info | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.info b/st.info
index 0145411..3dc92f8 100644
--- a/st.info
+++ b/st.info
@@ -81,6 +81,7 @@ st| simpleterm,
 	smul=\E[4m,
 	tbc=\E[2g,
 	ul,
+	xenl,
 
 st-256color| simpleterm with 256 colors,
 	colors#256,

From e8b18dd97b34d29670484b3850c315213f01dfa5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 8 Dec 2010 18:41:55 +0100
Subject: [PATCH 0175/1146] update terminfo entry.

---
 st.info | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/st.info b/st.info
index 3dc92f8..39402eb 100644
--- a/st.info
+++ b/st.info
@@ -8,6 +8,7 @@ st| simpleterm,
 #	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,
@@ -15,6 +16,7 @@ st| simpleterm,
 	cols#80,
 	cr=^M,
 	csr=\E[%i%p1%d;%p2%dr,
+	cub=\E[%p1%dD,
 	cub1=^H,
 	cud1=^J,
 	cud=\E[%p1%dB,
@@ -23,10 +25,14 @@ st| simpleterm,
 	cup=\E[%i%p1%d;%p2%dH,
 	cuu1=\E[A,
 	cuu=\E[%p1%dA,
+	dch=\E[%p1%dP,
 	dch1=\E[P,
+	dl=\E[%p1%dM,
 	dl1=\E[M,
+	ech=\E[%p1%dX,
 	ed=\E[J,
 	el=\E[K,
+	el1=\E[1K,
 	home=\E[H,
 	hpa=\E[%i%p1%dG,
 	ht=^I,
@@ -68,6 +74,7 @@ st| simpleterm,
 	pairs#64,
 	rc=\E8,
 	rev=\E[7m,
+	ri=\EM,
 	rmacs=\E(B,
 	rmso=\E[m,
 	rmul=\E[m,

From 0a208cb6168a0acc9b5692b84ef061b25a5e81f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 12 Dec 2010 13:32:13 +0100
Subject: [PATCH 0176/1146] change X cursor to "I".

---
 st.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 2be6772..d528828 100644
--- a/st.c
+++ b/st.c
@@ -16,10 +16,11 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
-#include <X11/Xlib.h>
 #include <X11/Xatom.h>
-#include <X11/keysym.h>
+#include <X11/Xlib.h>
 #include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
 
 #if   defined(__linux)
  #include <pty.h>
@@ -1503,6 +1504,7 @@ initfonts(char *fontstr, char *bfontstr)
 void
 xinit(void) {
 	XSetWindowAttributes attrs;
+	Cursor cursor;
 
 	if(!(xw.dpy = XOpenDisplay(NULL)))
 		die("Can't open display\n");
@@ -1550,6 +1552,13 @@ xinit(void) {
 	/* gc */
 	dc.gc = XCreateGC(xw.dpy, xw.win, 0, NULL);
 	
+	/* white cursor, black outline */
+	cursor = XCreateFontCursor(xw.dpy, XC_xterm);
+	XDefineCursor(xw.dpy, xw.win, cursor);
+	XRecolorCursor(xw.dpy, cursor, 
+		&(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff},
+		&(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
+
 	XMapWindow(xw.dpy, xw.win);
 	xhints();
 	XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st");

From 4d649c240326aa3292adf629c90ea528ecbe844f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 23 Jan 2011 12:30:01 +0100
Subject: [PATCH 0177/1146] fix insert key, terminfo and changed TERM back to
 st. (thx Ondrej Martinek)

---
 config.def.h | 3 ++-
 st.info      | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/config.def.h b/config.def.h
index b33e9b6..ced3000 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,5 +1,5 @@
 #define TAB 8
-#define TNAME "xterm"
+#define TNAME "st-256color"
 #define FONT "-*-*-medium-r-*-*-*-120-75-75-*-60-*-*"
 #define BOLDFONT "-*-*-bold-r-*-*-*-120-75-75-*-60-*-*"
 #define BORDER 2
@@ -34,6 +34,7 @@ static const char *colorname[] = {
 /* Special keys */
 static Key key[] = {
 	{ XK_BackSpace, "\177" },
+	{ XK_Insert,    "\033[2~" },
 	{ XK_Delete,    "\033[3~" },
 	{ XK_Home,      "\033[1~" },
 	{ XK_End,       "\033[4~" },
diff --git a/st.info b/st.info
index 39402eb..863c387 100644
--- a/st.info
+++ b/st.info
@@ -50,6 +50,7 @@ st| simpleterm,
 	kcuf1=\E[C,
 	kcuu1=\E[A,
 	kdch1=\E[3~,
+	kich1=\E[2~,
 	kend=\E[4~,
 	kf10=\E[21~,
 	kf11=\E[23~,
@@ -91,9 +92,9 @@ st| simpleterm,
 	xenl,
 
 st-256color| simpleterm with 256 colors,
+	use=st,
 	colors#256,
 	pairs#32767,
 #	Nicked from xterm-256color
 	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,
-	use=st,

From 1ab42fd49e68a11bfbbe5990ebdab2d3ca502178 Mon Sep 17 00:00:00 2001
From: "pancake@nopcode.org" <unknown>
Date: Fri, 1 Apr 2011 09:32:41 +0200
Subject: [PATCH 0178/1146] apply Nick's patch to fix some error printf to use
 stderr

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index d528828..1310426 100644
--- a/st.c
+++ b/st.c
@@ -935,7 +935,7 @@ csihandle(void) {
 	switch(escseq.mode) {
 	default:
 	unknown:
-		printf("erresc: unknown csi ");
+		fprintf(stderr, "erresc: unknown csi ");
 		csidump();
 		/* die(""); */
 		break;
@@ -1207,7 +1207,7 @@ tputc(char *c) {
 				term.c.attr.mode &= ~ATTR_GFX;
 				break;
 			default:
-				printf("esc unhandled charset: ESC ( %c\n", ascii);
+				fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
 			}
 			term.esc = 0;
 		} else {

From fe724836866d16a6dfd6de3ca3664033d9146a54 Mon Sep 17 00:00:00 2001
From: "pancake@nopcode.org" <unknown>
Date: Fri, 1 Apr 2011 09:33:28 +0200
Subject: [PATCH 0179/1146] remove debugging printf

---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 1310426..d0a607b 100644
--- a/st.c
+++ b/st.c
@@ -1794,8 +1794,7 @@ kpress(XEvent *ev) {
 				if(meta && len == 1)
 					ttywrite("\033", 1);
 				ttywrite(buf, len);
-			} else /* 4. nothing to send */
-				fprintf(stderr, "errkey: %d\n", (int)ksym);
+			}
 			break;
 		}
 }

From a047431d34aa77ac7a8fab08151fb569bbe2148e Mon Sep 17 00:00:00 2001
From: "pancake@nopcode.org" <unknown>
Date: Fri, 1 Apr 2011 09:35:38 +0200
Subject: [PATCH 0180/1146] do not add newline to selection text if next line
 not selected (Nick)

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index d0a607b..561d5b0 100644
--- a/st.c
+++ b/st.c
@@ -420,8 +420,8 @@ selcopy(void) {
 					memcpy(ptr, term.line[y][x].c, sl);
 					ptr += sl;
 				}
-			if(ls)
-				*ptr = '\n', ptr++;
+			if(ls && y < sel.e.y)
+				*ptr++ = '\n';
 		}
 		*ptr = 0;
 	}

From 674434ef6f75247fb25d8e5b39786bca9a0cabec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 3 Apr 2011 00:35:02 +0200
Subject: [PATCH 0181/1146] add support for utf8 clipboard. fix usage message.

---
 st.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 561d5b0..ed750e6 100644
--- a/st.c
+++ b/st.c
@@ -32,7 +32,7 @@
 
 #define USAGE \
 	"st-" VERSION ", (c) 2010 st engineers\n" \
-	"usage: st [-t title] [-c class] [-e cmd] [-v]\n"
+	"usage: st [-t title] [-c class] [-v] [-e cmd]\n"
 
 /* Arbitrary sizes */
 #define ESC_TITLE_SIZ 256
@@ -152,6 +152,7 @@ typedef struct {
 	int ex, ey;
 	struct {int x, y;}  b, e;
 	char *clip;
+	Atom xtarget;
 } Selection;
 
 #include "config.h"
@@ -370,6 +371,9 @@ selinit(void) {
 	sel.mode = 0;
 	sel.bx = -1;
 	sel.clip = NULL;
+	sel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
+	if(sel.xtarget == None)
+		sel.xtarget = XA_STRING;
 }
 
 static inline int 
@@ -453,7 +457,7 @@ selnotify(XEvent *e) {
 
 void
 selpaste() {
-	XConvertSelection(xw.dpy, XA_PRIMARY, XA_STRING, XA_PRIMARY, xw.win, CurrentTime);
+	XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY, xw.win, CurrentTime);
 }
 
 void
@@ -474,7 +478,7 @@ selrequest(XEvent *e) {
 	xa_targets = XInternAtom(xw.dpy, "TARGETS", 0);
 	if(xsre->target == xa_targets) {
 		/* respond with the supported type */
-		Atom string = XA_STRING;
+		Atom string = sel.xtarget;
 		XChangeProperty(xsre->display, xsre->requestor, xsre->property,
 				XA_ATOM, 32, PropModeReplace,
 				(unsigned char *) &string, 1);

From 1adf2e3978365c1e530d79372dd9d67f17fb19f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 3 Apr 2011 02:02:31 +0200
Subject: [PATCH 0182/1146] Added tag 0.1 for changeset cbc18c988236

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 .hgtags

diff --git a/.hgtags b/.hgtags
new file mode 100644
index 0000000..66ee2f3
--- /dev/null
+++ b/.hgtags
@@ -0,0 +1 @@
+cbc18c988236c63a58ed24031805e8d36a3ad01a 0.1

From 9b63dd9f435408caf3f91b4dfa9144a611302dd6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 3 Apr 2011 21:00:55 +0200
Subject: [PATCH 0183/1146] fix utf8 clipboard. (thx Petr Sabata)

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index ed750e6..d0f2f5e 100644
--- a/st.c
+++ b/st.c
@@ -483,7 +483,7 @@ selrequest(XEvent *e) {
 				XA_ATOM, 32, PropModeReplace,
 				(unsigned char *) &string, 1);
 		xev.property = xsre->property;
-	} else if(xsre->target == XA_STRING) {
+	} else if(xsre->target == sel.xtarget) {
 		XChangeProperty(xsre->display, xsre->requestor, xsre->property,
 				xsre->target, 8, PropModeReplace,
 				(unsigned char *) sel.clip, strlen(sel.clip));

From 89c8a3a2d9735fe10bcd85b90c8405fa20b4199e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 3 Apr 2011 21:03:48 +0200
Subject: [PATCH 0184/1146] take BORDER into account for selection. (thx Petr
 Sabata)

---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index d0f2f5e..a6fb766 100644
--- a/st.c
+++ b/st.c
@@ -392,8 +392,8 @@ getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
 	if(b) 
 		*b = e->xbutton.button;
 
-	*x = e->xbutton.x/xw.cw;
-	*y = e->xbutton.y/xw.ch;
+	*x = (e->xbutton.x - BORDER)/xw.cw;
+	*y = (e->xbutton.y - BORDER)/xw.ch;
 	sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex;
 	sel.b.y = MIN(sel.by, sel.ey);
 	sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx;
@@ -403,8 +403,8 @@ getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
 void
 bpress(XEvent *e) {
 	sel.mode = 1;
-	sel.ex = sel.bx = e->xbutton.x/xw.cw;
-	sel.ey = sel.by = e->xbutton.y/xw.ch;
+	sel.ex = sel.bx = (e->xbutton.x - BORDER)/xw.cw;
+	sel.ey = sel.by = (e->xbutton.y - BORDER)/xw.ch;
 }
 
 void

From 73e37f562964c2d1cb6029693d1d79a69a22ff14 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 3 Apr 2011 21:04:45 +0200
Subject: [PATCH 0185/1146] update VERSION.

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 01a3779..ea5b5ef 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.0
+VERSION = 0.1.1
 
 # Customize below to fit your system
 

From 742a4a18c2a071bf48133a7db6791ec7b74c68b4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 3 Apr 2011 21:05:41 +0200
Subject: [PATCH 0186/1146] quick bug-fixing 0.1.1 release.

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 66ee2f3..4959fd3 100644
--- a/.hgtags
+++ b/.hgtags
@@ -1 +1,2 @@
 cbc18c988236c63a58ed24031805e8d36a3ad01a 0.1
+f245ac2efd8ac2f1ac6bffae876c2663e794f79d 0.1.1

From d3c5aba2d9b0f6046e4cc72fb056cbd56c6314e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 3 Apr 2011 21:40:33 +0200
Subject: [PATCH 0187/1146] update README.

---
 README | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/README b/README
index 09a7fff..f6c5d78 100644
--- a/README
+++ b/README
@@ -21,7 +21,14 @@ necessary as root):
 
 Running st
 ----------
-See the man page for details.
+If you don't install st, define TNAME to "xterm" in config.h or make sure to at
+least compile st terminfo entry with the following command:
+
+    tic -s st.info
+
+It should print the path of the compiled terminfo entry. You can
+safely remove it if you don't plan to use st anymore.
+See the man page for additional details.
 
 Credits
 -------

From 9d5ea14b9dffac863b41432e4ce12b5624592000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Fri, 22 Apr 2011 00:18:53 +0200
Subject: [PATCH 0188/1146] selection clicks, shift+arrow keys, fast(er)
 redraw, key mask in config.h (thx Magnus Leuthner)

---
 config.def.h |  47 ++++++++++--------
 st.c         | 136 ++++++++++++++++++++++++++++++++++++---------------
 st.info      |   4 ++
 3 files changed, 126 insertions(+), 61 deletions(-)

diff --git a/config.def.h b/config.def.h
index ced3000..c1afd88 100644
--- a/config.def.h
+++ b/config.def.h
@@ -26,32 +26,33 @@ static const char *colorname[] = {
 };
 
 /* Default colors (colorname index) */
-/* foreground, background, cursor */
+/* foreground, background, cursor   */
 #define DefaultFG 7
 #define DefaultBG 0
 #define DefaultCS 1
 
-/* Special keys */
+/* Special keys (change & recompile st.info accordingly) */
+/*    key,        mask,  output */
 static Key key[] = {
-	{ XK_BackSpace, "\177" },
-	{ XK_Insert,    "\033[2~" },
-	{ XK_Delete,    "\033[3~" },
-	{ XK_Home,      "\033[1~" },
-	{ XK_End,       "\033[4~" },
-	{ XK_Prior,     "\033[5~" },
-	{ XK_Next,      "\033[6~" },
-	{ XK_F1,        "\033OP"   },
-	{ XK_F2,        "\033OQ"   },
-	{ XK_F3,        "\033OR"   },
-	{ XK_F4,        "\033OS"   },
-	{ XK_F5,        "\033[15~" },
-	{ XK_F6,        "\033[17~" },
-	{ XK_F7,        "\033[18~" },
-	{ XK_F8,        "\033[19~" },
-	{ XK_F9,        "\033[20~" },
-	{ XK_F10,       "\033[21~" },
-	{ XK_F11,       "\033[23~" },
-	{ XK_F12,       "\033[24~" },
+	{ XK_BackSpace, 0, "\177" },
+	{ XK_Insert,    0, "\033[2~" },
+	{ XK_Delete,    0, "\033[3~" },
+	{ XK_Home,      0, "\033[1~" },
+	{ XK_End,       0, "\033[4~" },
+	{ XK_Prior,     0, "\033[5~" },
+	{ XK_Next,      0, "\033[6~" },
+	{ XK_F1,        0, "\033OP"   },
+	{ XK_F2,        0, "\033OQ"   },
+	{ XK_F3,        0, "\033OR"   },
+	{ XK_F4,        0, "\033OS"   },
+	{ XK_F5,        0, "\033[15~" },
+	{ XK_F6,        0, "\033[17~" },
+	{ XK_F7,        0, "\033[18~" },
+	{ XK_F8,        0, "\033[19~" },
+	{ XK_F9,        0, "\033[20~" },
+	{ XK_F10,       0, "\033[21~" },
+	{ XK_F11,       0, "\033[23~" },
+	{ XK_F12,       0, "\033[24~" },
 };
 
 /* Line drawing characters (sometime specific to each font...) */
@@ -61,3 +62,7 @@ static char gfx[] = {
 	['i'] = '#',
 	[255] = 0,
 };
+
+/* double-click timeout (in milliseconds) between clicks for selection */
+#define DOUBLECLICK_TIMEOUT 300
+#define TRIPLECLICK_TIMEOUT (2*DOUBLECLICK_TIMEOUT)
diff --git a/st.c b/st.c
index a6fb766..11ea9fc 100644
--- a/st.c
+++ b/st.c
@@ -22,6 +22,9 @@
 #include <X11/cursorfont.h>
 #include <X11/keysym.h>
 
+#include <sys/time.h>
+#include <time.h>
+
 #if   defined(__linux)
  #include <pty.h>
 #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
@@ -45,11 +48,12 @@
 #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 DEFAULT(a, b)     (a) = (a) ? (a) : (b)    
+#define DEFAULT(a, b)     (a) = (a) ? (a) : (b)
 #define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (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 IS_SET(flag) (term.mode & (flag))
+#define TIMEDIFFERENCE(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
 
 /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
 enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 };
@@ -57,10 +61,9 @@ enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT,
        CURSOR_SAVE, CURSOR_LOAD };
 enum { CURSOR_DEFAULT = 0, CURSOR_HIDE = 1, CURSOR_WRAPNEXT = 2 };
 enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
-enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8, 
+enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8,
        MODE_CRLF=16 };
 enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
-enum { SCREEN_UPDATE, SCREEN_REDRAW };
 enum { WIN_VISIBLE=1, WIN_REDRAW=2, WIN_FOCUSED=4 };
 
 #undef B0
@@ -87,21 +90,21 @@ typedef struct {
 /* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
 typedef struct {
 	char buf[ESC_BUF_SIZ]; /* raw string */
-	int len;			   /* raw string length */
+	int len;               /* raw string length */
 	char priv;
 	int arg[ESC_ARG_SIZ];
-	int narg;			   /* nb of args */
+	int narg;              /* nb of args */
 	char mode;
 } CSIEscape;
 
 /* Internal representation of the screen */
 typedef struct {
-	int row;	/* nb row */  
+	int row;	/* nb row */
 	int col;	/* nb col */
 	Line* line;	/* screen */
 	Line* alt;	/* alternate screen */
 	TCursor c;	/* cursor */
-	int top;	/* top	  scroll limit */
+	int top;	/* top    scroll limit */
 	int bot;	/* bottom scroll limit */
 	int mode;	/* terminal mode flags */
 	int esc;	/* escape state flags */
@@ -118,17 +121,18 @@ typedef struct {
 	XIM xim;
 	XIC xic;
 	int scr;
-	int w;	/* window width	 */
+	int w;	/* window width */
 	int h;	/* window height */
 	int bufw; /* pixmap width  */
 	int bufh; /* pixmap height */
 	int ch; /* char height */
 	int cw; /* char width  */
 	char state; /* focus, redraw, visible */
-} XWindow; 
+} XWindow;
 
 typedef struct {
 	KeySym k;
+	unsigned int mask;
 	char s[ESC_BUF_SIZ];
 } Key;
 
@@ -150,15 +154,18 @@ typedef struct {
 	int mode;
 	int bx, by;
 	int ex, ey;
-	struct {int x, y;}  b, e;
+	struct {int x, y;} b, e;
 	char *clip;
 	Atom xtarget;
+	struct timeval tclick1;
+	struct timeval tclick2;
 } Selection;
 
 #include "config.h"
 
 static void die(const char *errstr, ...);
-static void draw(int);
+static void draw();
+static void drawregion(int, int, int, int);
 static void execsh(void);
 static void sigchld(int);
 static void run(void);
@@ -206,7 +213,7 @@ static void xresize(int, int);
 static void expose(XEvent *);
 static void visibility(XEvent *);
 static void unmap(XEvent *);
-static char* kmap(KeySym);
+static char* kmap(KeySym, unsigned int state);
 static void kpress(XEvent *);
 static void resize(XEvent *);
 static void focus(XEvent *);
@@ -219,7 +226,7 @@ static void selrequest(XEvent *);
 static void selinit(void);
 static inline int selected(int, int);
 static void selcopy(void);
-static void selpaste(void);
+static void selpaste();
 
 static int utf8decode(char *, long *);
 static int utf8encode(long *, char *);
@@ -340,7 +347,7 @@ isfullutf8(char *s, int b) {
 	else if((*c1&(B7|B6|B5)) == (B7|B6) && b == 1)
 		return 0;
 	else if((*c1&(B7|B6|B5|B4)) == (B7|B6|B5) &&
-	    ((b == 1) || 
+	    ((b == 1) ||
 	    ((b == 2) && (*c2&(B7|B6)) == B7)))
 		return 0;
 	else if((*c1&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4) &&
@@ -362,12 +369,14 @@ utf8size(char *s) {
 		return 2;
 	else if ((c&(B7|B6|B5|B4)) == (B7|B6|B5))
 		return 3;
-	else 
+	else
 		return 4;
 }
 
 void
 selinit(void) {
+	sel.tclick1.tv_sec = 0;
+	sel.tclick1.tv_usec = 0;
 	sel.mode = 0;
 	sel.bx = -1;
 	sel.clip = NULL;
@@ -376,14 +385,14 @@ selinit(void) {
 		sel.xtarget = XA_STRING;
 }
 
-static inline int 
+static inline int
 selected(int x, int y) {
 	if(sel.ey == y && sel.by == y) {
 		int bx = MIN(sel.bx, sel.ex);
 		int ex = MAX(sel.bx, sel.ex);
 		return BETWEEN(x, bx, ex);
 	}
-	return ((sel.b.y < y&&y < sel.e.y) || (y==sel.e.y && x<=sel.e.x)) 
+	return ((sel.b.y < y&&y < sel.e.y) || (y==sel.e.y && x<=sel.e.x))
 		|| (y==sel.b.y && x>=sel.b.x && (x<=sel.e.x || sel.b.y!=sel.e.y));
 }
 
@@ -511,30 +520,63 @@ xsetsel(char *str) {
 	XFlush(xw.dpy);
 }
 
-/* TODO: doubleclick to select word */
 void
 brelease(XEvent *e) {
 	int b;
 	sel.mode = 0;
 	getbuttoninfo(e, &b, &sel.ex, &sel.ey);
-	if(sel.bx==sel.ex && sel.by==sel.ey) {
+	
+	if(sel.bx == sel.ex && sel.by == sel.ey) {
 		sel.bx = -1;
-		if(b==2)
+		if(b == 2)
 			selpaste();
+
+		else if(b == 1) {
+			/* double click to select word */
+			struct timeval now;
+			gettimeofday(&now, NULL);
+
+			if(TIMEDIFFERENCE(now, sel.tclick1) <= DOUBLECLICK_TIMEOUT) {
+				sel.bx = sel.ex;
+				while(term.line[sel.ey][sel.bx-1].state & GLYPH_SET && 
+					  term.line[sel.ey][sel.bx-1].c[0] != ' ') sel.bx--;
+				sel.b.x = sel.bx;
+				while(term.line[sel.ey][sel.ex+1].state & GLYPH_SET && 
+					  term.line[sel.ey][sel.ex+1].c[0] != ' ') sel.ex++;
+				sel.e.x = sel.ex;
+				sel.b.y = sel.e.y = sel.ey;
+				selcopy();
+			}
+
+			/* triple click on the line */
+			if(TIMEDIFFERENCE(now, sel.tclick2) <= TRIPLECLICK_TIMEOUT) {
+				sel.b.x = sel.bx = 0;
+				sel.e.x = sel.ex = term.col;
+				sel.b.y = sel.e.y = sel.ey;
+				selcopy();
+			}
+		}
 	} else {
-		if(b==1)
+		if(b == 1) 
 			selcopy();
 	}
-	draw(1);
+	memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval));
+	gettimeofday(&sel.tclick1, NULL);
+	draw();
 }
 
 void
 bmotion(XEvent *e) {
-	if (sel.mode) {
+	if(sel.mode) {
+		int oldey = sel.ey, 
+			oldex = sel.ex;
 		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
-		/* XXX: draw() can't keep up, disabled for now.
-		   selection is visible on button release.
-		   draw(1); */
+
+		if(oldey != sel.ey || oldex != sel.ex) {
+			int starty = MIN(oldey, sel.ey);
+			int endy = MAX(oldey, sel.ey);
+			drawregion(0, (starty > 0 ? starty : 0), term.col, (sel.ey < term.row ? endy+1 : term.row));
+		}
 	}
 }
 
@@ -641,6 +683,10 @@ ttyread(void) {
 
 void
 ttywrite(const char *s, size_t n) {
+	{size_t nn;
+		for(nn = 0; nn < n; nn++)
+			dump(s[nn]);
+	}
 	if(write(cmdfd, s, n) == -1)
 		die("write error on tty: %s\n", SERRNO);
 }
@@ -1640,8 +1686,13 @@ xdrawc(int x, int y, Glyph g) {
 	    dc.gc, r.x, r.y+dc.font.ascent, g.c, sl);
 }
 
+void 
+drawregion(int x0, int x1, int y0, int y1) {
+	draw();
+}
+
 void
-draw(int dummy) {
+draw() {
 	int x, y;
 
 	xclear(0, 0, term.col-1, term.row-1);
@@ -1657,8 +1708,13 @@ draw(int dummy) {
 
 #else
 /* optimized drawing routine */
+void 
+draw() {
+	drawregion(0, 0, term.col, term.row);
+}
+
 void
-draw(int redraw_all) {
+drawregion(int x1, int y1, int x2, int y2) {
 	int ic, ib, x, y, ox, sl;
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
@@ -1666,13 +1722,13 @@ draw(int redraw_all) {
 	if(!(xw.state & WIN_VISIBLE))
 		return;
 
-	xclear(0, 0, term.col-1, term.row-1);
-	for(y = 0; y < term.row; y++) {
+	xclear(x1, y1, x2-1, y2-1);
+	for(y = y1; y < y2; y++) {
 		base = term.line[y][0];
 		ic = ib = ox = 0;
-		for(x = 0; x < term.col; x++) {
+		for(x = x1; x < x2; x++) {
 			new = term.line[y][x];
-			if(sel.bx!=-1 && *(new.c) && selected(x, y))
+			if(sel.bx != -1 && *(new.c) && selected(x, y))
 				new.mode ^= ATTR_REVERSE;
 			if(ib > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) ||
 					ib >= DRAW_BUF_SIZ-UTF_SIZ)) {
@@ -1705,7 +1761,7 @@ expose(XEvent *ev) {
 	if(xw.state & WIN_REDRAW) {
 		if(!e->count) {
 			xw.state &= ~WIN_REDRAW;
-			draw(SCREEN_REDRAW);
+			draw();
 		}
 	} else
 		XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, e->x-BORDER, e->y-BORDER,
@@ -1742,14 +1798,14 @@ focus(XEvent *ev) {
 		xseturgency(0);
 	} else
 		xw.state &= ~WIN_FOCUSED;
-	draw(SCREEN_UPDATE);
+	draw();
 }
 
 char*
-kmap(KeySym k) {
+kmap(KeySym k, unsigned int state) {
 	int i;
 	for(i = 0; i < LEN(key); i++)
-		if(key[i].k == k)
+		if(key[i].k == k && (key[i].mask == 0 || key[i].mask & state))
 			return (char*)key[i].s;
 	return NULL;
 }
@@ -1770,7 +1826,7 @@ kpress(XEvent *ev) {
 	len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status);
 	
 	/* 1. custom keys from config.h */
-	if((customkey = kmap(ksym)))
+	if((customkey = kmap(ksym, e->state)))
 		ttywrite(customkey, strlen(customkey));
 	/* 2. hardcoded (overrides X lookup) */
 	else
@@ -1779,7 +1835,7 @@ kpress(XEvent *ev) {
 		case XK_Down:
 		case XK_Left:
 		case XK_Right:
-			sprintf(buf, "\033%c%c", IS_SET(MODE_APPKEYPAD) ? 'O' : '[', "DACB"[ksym - XK_Left]);
+			sprintf(buf, "\033%c%c", IS_SET(MODE_APPKEYPAD) ? 'O' : '[', (shift ? "dacb":"DACB")[ksym - XK_Left]);
 			ttywrite(buf, 3);
 			break;
 		case XK_Insert:
@@ -1817,7 +1873,7 @@ resize(XEvent *e) {
 	if(col == term.col && row == term.row)
 		return;
 	if(tresize(col, row))
-		draw(SCREEN_REDRAW);
+		draw();
 	ttyresize(col, row);
 	xresize(col, row);
 }
@@ -1839,7 +1895,7 @@ run(void) {
 		}
 		if(FD_ISSET(cmdfd, &rfd)) {
 			ttyread();
-			draw(SCREEN_UPDATE); 
+			draw(); 
 		}
 		while(XPending(xw.dpy)) {
 			XNextEvent(xw.dpy, &ev);
diff --git a/st.info b/st.info
index 863c387..6be3eaf 100644
--- a/st.info
+++ b/st.info
@@ -49,6 +49,10 @@ st| simpleterm,
 	kcud1=\E[B,
 	kcuf1=\E[C,
 	kcuu1=\E[A,
+	kLFT=\E[d,
+	kRIT=\E[c,
+	kind=\E[a,
+	kri=\E[b,
 	kdch1=\E[3~,
 	kich1=\E[2~,
 	kend=\E[4~,

From aede91e22a41cbf4b11d64faa42575d1bdbd8446 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Fri, 22 Apr 2011 00:42:58 +0200
Subject: [PATCH 0189/1146] update TODO

---
 TODO | 11 ++++++++---
 st.c |  1 +
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/TODO b/TODO
index 3b2774b..ef68386 100644
--- a/TODO
+++ b/TODO
@@ -9,7 +9,12 @@ code & interface
 ----------------
 
 * clean selection code
-* use the real x11 clipboard
-* clean terminfo entry
-* utf8
+* clean and complete terminfo entry
+* fix shift up/down (shift selection in emacs)
 * ...
+
+misc
+----
+
+    $ grep -nE 'XXX|TODO' st.c
+
diff --git a/st.c b/st.c
index 11ea9fc..e6bb91f 100644
--- a/st.c
+++ b/st.c
@@ -1835,6 +1835,7 @@ kpress(XEvent *ev) {
 		case XK_Down:
 		case XK_Left:
 		case XK_Right:
+			/* XXX: shift up/down doesn't work */
 			sprintf(buf, "\033%c%c", IS_SET(MODE_APPKEYPAD) ? 'O' : '[', (shift ? "dacb":"DACB")[ksym - XK_Left]);
 			ttywrite(buf, 3);
 			break;

From babf4db52b58da74c9e1072d14cb0b9ef5b4dee7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Tue, 26 Apr 2011 20:22:15 +0200
Subject: [PATCH 0190/1146] cleanup.

---
 st.c | 104 ++++++++++++++++-------------------------------------------
 1 file changed, 27 insertions(+), 77 deletions(-)

diff --git a/st.c b/st.c
index e6bb91f..6a6ea75 100644
--- a/st.c
+++ b/st.c
@@ -163,8 +163,8 @@ typedef struct {
 
 #include "config.h"
 
-static void die(const char *errstr, ...);
-static void draw();
+static void die(const char*, ...);
+static void draw(void);
 static void drawregion(int, int, int, int);
 static void execsh(void);
 static void sigchld(int);
@@ -363,11 +363,11 @@ int
 utf8size(char *s) {
 	unsigned char c = *s;
 
-	if (~c&B7)
+	if(~c&B7)
 		return 1;
-	else if ((c&(B7|B6|B5)) == (B7|B6))
+	else if((c&(B7|B6|B5)) == (B7|B6))
 		return 2;
-	else if ((c&(B7|B6|B5|B4)) == (B7|B6|B5))
+	else if((c&(B7|B6|B5|B4)) == (B7|B6|B5))
 		return 3;
 	else
 		return 4;
@@ -523,20 +523,25 @@ xsetsel(char *str) {
 void
 brelease(XEvent *e) {
 	int b;
+
 	sel.mode = 0;
 	getbuttoninfo(e, &b, &sel.ex, &sel.ey);
-	
 	if(sel.bx == sel.ex && sel.by == sel.ey) {
 		sel.bx = -1;
 		if(b == 2)
 			selpaste();
-
 		else if(b == 1) {
-			/* double click to select word */
 			struct timeval now;
 			gettimeofday(&now, NULL);
 
-			if(TIMEDIFFERENCE(now, sel.tclick1) <= DOUBLECLICK_TIMEOUT) {
+			if(TIMEDIFFERENCE(now, sel.tclick2) <= TRIPLECLICK_TIMEOUT) {
+				/* triple click on the line */
+				sel.b.x = sel.bx = 0;
+				sel.e.x = sel.ex = term.col;
+				sel.b.y = sel.e.y = sel.ey;
+				selcopy();
+			} else if(TIMEDIFFERENCE(now, sel.tclick1) <= DOUBLECLICK_TIMEOUT) {
+				/* double click to select word */
 				sel.bx = sel.ex;
 				while(term.line[sel.ey][sel.bx-1].state & GLYPH_SET && 
 					  term.line[sel.ey][sel.bx-1].c[0] != ' ') sel.bx--;
@@ -547,19 +552,9 @@ brelease(XEvent *e) {
 				sel.b.y = sel.e.y = sel.ey;
 				selcopy();
 			}
-
-			/* triple click on the line */
-			if(TIMEDIFFERENCE(now, sel.tclick2) <= TRIPLECLICK_TIMEOUT) {
-				sel.b.x = sel.bx = 0;
-				sel.e.x = sel.ex = term.col;
-				sel.b.y = sel.e.y = sel.ey;
-				selcopy();
-			}
 		}
-	} else {
-		if(b == 1) 
-			selcopy();
-	}
+	} else if(b == 1) 
+		selcopy();
 	memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval));
 	gettimeofday(&sel.tclick1, NULL);
 	draw();
@@ -683,10 +678,6 @@ ttyread(void) {
 
 void
 ttywrite(const char *s, size_t n) {
-	{size_t nn;
-		for(nn = 0; nn < n; nn++)
-			dump(s[nn]);
-	}
 	if(write(cmdfd, s, n) == -1)
 		die("write error on tty: %s\n", SERRNO);
 }
@@ -921,9 +912,9 @@ tsetattr(int *attr, int l) {
 			term.c.attr.mode &= ~ATTR_REVERSE;	 
 			break;
 		case 38:
-			if (i + 2 < l && attr[i + 1] == 5) {
+			if(i + 2 < l && attr[i + 1] == 5) {
 				i += 2;
-				if (BETWEEN(attr[i], 0, 255))
+				if(BETWEEN(attr[i], 0, 255))
 					term.c.attr.fg = attr[i];
 				else
 					fprintf(stderr, "erresc: bad fgcolor %d\n", attr[i]);
@@ -935,9 +926,9 @@ tsetattr(int *attr, int l) {
 			term.c.attr.fg = DefaultFG;
 			break;
 		case 48:
-			if (i + 2 < l && attr[i + 1] == 5) {
+			if(i + 2 < l && attr[i + 1] == 5) {
 				i += 2;
-				if (BETWEEN(attr[i], 0, 255))
+				if(BETWEEN(attr[i], 0, 255))
 					term.c.attr.bg = attr[i];
 				else
 					fprintf(stderr, "erresc: bad bgcolor %d\n", attr[i]);
@@ -1348,7 +1339,6 @@ tputc(char *c) {
 				tmoveto(term.c.x+1, term.c.y);
 			else
 				term.c.state |= CURSOR_WRAPNEXT;
-			break;
 		}
 	}
 }
@@ -1447,7 +1437,7 @@ xloadcols(void) {
 	unsigned long white = WhitePixel(xw.dpy, xw.scr);
 
 	for(i = 0; i < 16; i++) {
-		if (!XAllocNamedColor(xw.dpy, xw.cmap, colorname[i], &color, &color)) {
+		if(!XAllocNamedColor(xw.dpy, xw.cmap, colorname[i], &color, &color)) {
 			dc.col[i] = white;
 			fprintf(stderr, "Could not allocate color '%s'\n", colorname[i]);
 		} else
@@ -1461,7 +1451,7 @@ xloadcols(void) {
 				color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r;
 				color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g;
 				color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b;
-				if (!XAllocColor(xw.dpy, xw.cmap, &color)) {
+				if(!XAllocColor(xw.dpy, xw.cmap, &color)) {
 					dc.col[i] = white;
 					fprintf(stderr, "Could not allocate color %d\n", i);
 				} else
@@ -1488,8 +1478,7 @@ xclear(int x1, int y1, int x2, int y2) {
 }
 
 void
-xhints(void)
-{
+xhints(void) {
 	XClassHint class = {opt_class ? opt_class : TNAME, TNAME};
 	XWMHints wm = {.flags = InputHint, .input = 1};
 	XSizeHints size = {
@@ -1505,8 +1494,7 @@ xhints(void)
 }
 
 XFontSet
-xinitfont(char *fontstr)
-{
+xinitfont(char *fontstr) {
 	XFontSet set;
 	char *def, **missing;
 	int n;
@@ -1522,8 +1510,7 @@ xinitfont(char *fontstr)
 }
 
 void
-xgetfontinfo(XFontSet set, int *ascent, int *descent, short *lbearing, short *rbearing)
-{
+xgetfontinfo(XFontSet set, int *ascent, int *descent, short *lbearing, short *rbearing) {
 	XFontStruct **xfonts;
 	char **font_names;
 	int i, n;
@@ -1540,8 +1527,7 @@ xgetfontinfo(XFontSet set, int *ascent, int *descent, short *lbearing, short *rb
 }
 
 void
-initfonts(char *fontstr, char *bfontstr)
-{
+initfonts(char *fontstr, char *bfontstr) {
 	if((dc.font.set = xinitfont(fontstr)) == NULL ||
 	   (dc.bfont.set = xinitfont(bfontstr)) == NULL)
 		die("Can't load font %s\n", dc.font.set ? BOLDFONT : FONT);
@@ -1674,40 +1660,6 @@ xdrawcursor(void) {
 	}
 }
 
-#ifdef DEBUG
-/* basic drawing routines */
-void
-xdrawc(int x, int y, Glyph g) {
-	int sl = utf8size(g.c);
-	XRectangle r = { x * xw.cw, y * xw.ch, xw.cw, xw.ch };
-	XSetBackground(xw.dpy, dc.gc, dc.col[g.bg]);
-	XSetForeground(xw.dpy, dc.gc, dc.col[g.fg]);
-	XmbDrawImageString(xw.dpy, xw.buf, g.mode&ATTR_BOLD?dc.bfont.fs:dc.font.fs,
-	    dc.gc, r.x, r.y+dc.font.ascent, g.c, sl);
-}
-
-void 
-drawregion(int x0, int x1, int y0, int y1) {
-	draw();
-}
-
-void
-draw() {
-	int x, y;
-
-	xclear(0, 0, term.col-1, term.row-1);
-	for(y = 0; y < term.row; y++)
-		for(x = 0; x < term.col; x++)
-			if(term.line[y][x].state & GLYPH_SET)
-				xdrawc(x, y, term.line[y][x]);
-
-	xdrawcursor();
-	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
-	XFlush(xw.dpy);
-}
-
-#else
-/* optimized drawing routine */
 void 
 draw() {
 	drawregion(0, 0, term.col, term.row);
@@ -1753,8 +1705,6 @@ drawregion(int x1, int y1, int x2, int y2) {
 	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
 }
 
-#endif
-
 void
 expose(XEvent *ev) {
 	XExposeEvent *e = &ev->xexpose;
@@ -1900,7 +1850,7 @@ run(void) {
 		}
 		while(XPending(xw.dpy)) {
 			XNextEvent(xw.dpy, &ev);
-			if (XFilterEvent(&ev, xw.win))
+			if(XFilterEvent(&ev, xw.win))
 				continue;
 			if(handler[ev.type])
 				(handler[ev.type])(&ev);

From 8eaed2cdda375e8e951eb389af3859e18761eddc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Tue, 26 Apr 2011 20:29:28 +0200
Subject: [PATCH 0191/1146] whitespace.

---
 st.c | 66 ++++++++++++++++++++++++++++++------------------------------
 1 file changed, 33 insertions(+), 33 deletions(-)

diff --git a/st.c b/st.c
index 6a6ea75..56c3c6b 100644
--- a/st.c
+++ b/st.c
@@ -398,7 +398,7 @@ selected(int x, int y) {
 
 void
 getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
-	if(b) 
+	if(b)
 		*b = e->xbutton.button;
 
 	*x = (e->xbutton.x - BORDER)/xw.cw;
@@ -543,17 +543,17 @@ brelease(XEvent *e) {
 			} else if(TIMEDIFFERENCE(now, sel.tclick1) <= DOUBLECLICK_TIMEOUT) {
 				/* double click to select word */
 				sel.bx = sel.ex;
-				while(term.line[sel.ey][sel.bx-1].state & GLYPH_SET && 
+				while(term.line[sel.ey][sel.bx-1].state & GLYPH_SET &&
 					  term.line[sel.ey][sel.bx-1].c[0] != ' ') sel.bx--;
 				sel.b.x = sel.bx;
-				while(term.line[sel.ey][sel.ex+1].state & GLYPH_SET && 
+				while(term.line[sel.ey][sel.ex+1].state & GLYPH_SET &&
 					  term.line[sel.ey][sel.ex+1].c[0] != ' ') sel.ex++;
 				sel.e.x = sel.ex;
 				sel.b.y = sel.e.y = sel.ey;
 				selcopy();
 			}
 		}
-	} else if(b == 1) 
+	} else if(b == 1)
 		selcopy();
 	memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval));
 	gettimeofday(&sel.tclick1, NULL);
@@ -563,7 +563,7 @@ brelease(XEvent *e) {
 void
 bmotion(XEvent *e) {
 	if(sel.mode) {
-		int oldey = sel.ey, 
+		int oldey = sel.ey,
 			oldex = sel.ex;
 		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
 
@@ -597,7 +597,7 @@ execsh(void) {
 	exit(EXIT_FAILURE);
 }
 
-void 
+void
 sigchld(int a) {
 	int stat = 0;
 	if(waitpid(pid, &stat, 0) < 0)
@@ -650,7 +650,7 @@ dump(char c) {
 void
 ttyread(void) {
 	static char buf[BUFSIZ];
-	static int buflen = 0; 
+	static int buflen = 0;
 	char *ptr;
 	char s[UTF_SIZ];
 	int charsize; /* size of utf8 char in bytes */
@@ -706,8 +706,8 @@ tcursor(int mode) {
 void
 treset(void) {
 	term.c = (TCursor){{
-		.mode = ATTR_NULL, 
-		.fg = DefaultFG, 
+		.mode = ATTR_NULL,
+		.fg = DefaultFG,
 		.bg = DefaultBG
 	}, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
 	
@@ -762,9 +762,9 @@ tscrollup(int orig, int n) {
 	
 	tclearregion(0, orig, term.col-1, orig+n-1);
 	
-	for(i = orig; i <= term.bot-n; i++) { 
+	for(i = orig; i <= term.bot-n; i++) {
 		 temp = term.line[i];
-		 term.line[i] = term.line[i+n]; 
+		 term.line[i] = term.line[i+n];
 		 term.line[i+n] = temp;
 	}
 }
@@ -894,22 +894,22 @@ tsetattr(int *attr, int l) {
 			term.c.attr.bg = DefaultBG;
 			break;
 		case 1:
-			term.c.attr.mode |= ATTR_BOLD;	 
+			term.c.attr.mode |= ATTR_BOLD;
 			break;
-		case 4: 
+		case 4:
 			term.c.attr.mode |= ATTR_UNDERLINE;
 			break;
-		case 7: 
-			term.c.attr.mode |= ATTR_REVERSE;	
+		case 7:
+			term.c.attr.mode |= ATTR_REVERSE;
 			break;
-		case 22: 
-			term.c.attr.mode &= ~ATTR_BOLD;	 
+		case 22:
+			term.c.attr.mode &= ~ATTR_BOLD;
 			break;
-		case 24: 
+		case 24:
 			term.c.attr.mode &= ~ATTR_UNDERLINE;
 			break;
-		case 27: 
-			term.c.attr.mode &= ~ATTR_REVERSE;	 
+		case 27:
+			term.c.attr.mode &= ~ATTR_REVERSE;
 			break;
 		case 38:
 			if(i + 2 < l && attr[i + 1] == 5) {
@@ -920,7 +920,7 @@ tsetattr(int *attr, int l) {
 					fprintf(stderr, "erresc: bad fgcolor %d\n", attr[i]);
 			}
 			else
-				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]); 
+				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]);
 			break;
 		case 39:
 			term.c.attr.fg = DefaultFG;
@@ -934,7 +934,7 @@ tsetattr(int *attr, int l) {
 					fprintf(stderr, "erresc: bad bgcolor %d\n", attr[i]);
 			}
 			else
-				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]); 
+				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]);
 			break;
 		case 49:
 			term.c.attr.bg = DefaultBG;
@@ -948,7 +948,7 @@ tsetattr(int *attr, int l) {
 				term.c.attr.fg = attr[i] - 90 + 8;
 			else if(BETWEEN(attr[i], 100, 107))
 				term.c.attr.fg = attr[i] - 100 + 8;
-			else 
+			else
 				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]), csidump();
 			
 			break;
@@ -968,7 +968,7 @@ tsetscroll(int t, int b) {
 		b = temp;
 	}
 	term.top = t;
-	term.bot = b;	 
+	term.bot = b;
 }
 
 void
@@ -1193,7 +1193,7 @@ csihandle(void) {
 }
 
 void
-csidump(void) { 
+csidump(void) {
 	int i;
 	printf("ESC [ %s", escseq.priv ? "? " : "");
 	if(escseq.narg)
@@ -1226,7 +1226,7 @@ tputc(char *c) {
 				csiparse(), csihandle();
 			}
 			/* TODO: handle other OSC */
-		} else if(term.esc & ESC_OSC) { 
+		} else if(term.esc & ESC_OSC) {
 			if(ascii == ';') {
 				term.titlelen = 0;
 				term.esc = ESC_START | ESC_TITLE;
@@ -1550,7 +1550,7 @@ xinit(void) {
 	initfonts(FONT, BOLDFONT);
 
 	/* XXX: Assuming same size for bold font */
- 	xw.cw = dc.font.rbearing - dc.font.lbearing;
+	xw.cw = dc.font.rbearing - dc.font.lbearing;
 	xw.ch = dc.font.ascent + dc.font.descent;
 
 	/* colors */
@@ -1582,8 +1582,8 @@ xinit(void) {
 
 	/* input methods */
 	xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
-	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing 
-					   | XIMStatusNothing, XNClientWindow, xw.win, 
+	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
+					   | XIMStatusNothing, XNClientWindow, xw.win,
 					   XNFocusWindow, xw.win, NULL);
 	/* gc */
 	dc.gc = XCreateGC(xw.dpy, xw.win, 0, NULL);
@@ -1591,7 +1591,7 @@ xinit(void) {
 	/* white cursor, black outline */
 	cursor = XCreateFontCursor(xw.dpy, XC_xterm);
 	XDefineCursor(xw.dpy, xw.win, cursor);
-	XRecolorCursor(xw.dpy, cursor, 
+	XRecolorCursor(xw.dpy, cursor,
 		&(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff},
 		&(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
 
@@ -1626,7 +1626,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	}
 
 	XmbDrawImageString(xw.dpy, xw.buf, base.mode & ATTR_BOLD ? dc.bfont.set : dc.font.set,
-	    dc.gc, winx, winy, s, bytelen);
+		dc.gc, winx, winy, s, bytelen);
 	
 	if(base.mode & ATTR_UNDERLINE)
 		XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);
@@ -1660,7 +1660,7 @@ xdrawcursor(void) {
 	}
 }
 
-void 
+void
 draw() {
 	drawregion(0, 0, term.col, term.row);
 }
@@ -1846,7 +1846,7 @@ run(void) {
 		}
 		if(FD_ISSET(cmdfd, &rfd)) {
 			ttyread();
-			draw(); 
+			draw();
 		}
 		while(XPending(xw.dpy)) {
 			XNextEvent(xw.dpy, &ev);

From 80da37203e1699d9143cacfcfaeae7e7645c645d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Tue, 10 May 2011 22:22:44 +0200
Subject: [PATCH 0192/1146] support for x11 xterm mouse reporting

---
 st.c | 37 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 56c3c6b..65c7532 100644
--- a/st.c
+++ b/st.c
@@ -62,7 +62,7 @@ enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT,
 enum { CURSOR_DEFAULT = 0, CURSOR_HIDE = 1, CURSOR_WRAPNEXT = 2 };
 enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
 enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8,
-       MODE_CRLF=16 };
+       MODE_CRLF=16, MODE_MOUSE=32 };
 enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
 enum { WIN_VISIBLE=1, WIN_REDRAW=2, WIN_FOCUSED=4 };
 
@@ -409,8 +409,36 @@ getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
 	sel.e.y = MAX(sel.by, sel.ey);
 }
 
+void
+mousereport(XEvent *e) {
+	int x = (e->xbutton.x - BORDER)/xw.cw;
+	int y = (e->xbutton.y - BORDER)/xw.ch;
+	int button = e->xbutton.button;
+	int state = e->xbutton.state;
+	char buf[] = { '\033', '[', 'M', 0, 32+x+1, 32+y+1 };
+	
+	if(!IS_SET(MODE_MOUSE))
+		return;
+	
+	/* from urxvt */
+	if(e->xbutton.type == ButtonRelease || button == AnyButton)
+		button = 3;
+	else {
+		button -= Button1;
+		if(button >= 3)
+			button += 64 - 3;
+	}
+	
+	buf[3] = 32 + button + (state & ShiftMask ? 4 : 0)
+		+ (state & Mod4Mask    ? 8  : 0)
+		+ (state & ControlMask ? 16 : 0);
+	
+	ttywrite(buf, sizeof(buf));
+}
+
 void
 bpress(XEvent *e) {
+	mousereport(e);
 	sel.mode = 1;
 	sel.ex = sel.bx = (e->xbutton.x - BORDER)/xw.cw;
 	sel.ey = sel.by = (e->xbutton.y - BORDER)/xw.ch;
@@ -526,6 +554,7 @@ brelease(XEvent *e) {
 
 	sel.mode = 0;
 	getbuttoninfo(e, &b, &sel.ex, &sel.ey);
+	mousereport(e);
 	if(sel.bx == sel.ex && sel.by == sel.ey) {
 		sel.bx = -1;
 		if(b == 2)
@@ -1085,6 +1114,9 @@ csihandle(void) {
 			case 25:
 				term.c.state |= CURSOR_HIDE;
 				break;
+			case 1000: /* disable X11 xterm mouse reporting */
+				term.mode &= ~MODE_MOUSE;
+				break;
 			case 1049: /* = 1047 and 1048 */
 			case 1047:
 				if(IS_SET(MODE_ALTSCREEN)) {
@@ -1148,6 +1180,9 @@ csihandle(void) {
 			case 25:
 				term.c.state &= ~CURSOR_HIDE;
 				break;
+			case 1000: /* enable X11 xterm mouse reporting */
+				term.mode |= MODE_MOUSE;
+				break;
 			case 1049: /* = 1047 and 1048 */
 			case 1047:
 				if(IS_SET(MODE_ALTSCREEN))

From 0107293a446725551ceb756affe50b4853046f05 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Tue, 10 May 2011 22:54:30 +0200
Subject: [PATCH 0193/1146] add mouse report escape to terminfo entry.

---
 st.info | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.info b/st.info
index 6be3eaf..ece22fa 100644
--- a/st.info
+++ b/st.info
@@ -70,6 +70,7 @@ st| simpleterm,
 	kf9=\E[20~,
 	khome=\E[1~,
 	knp=\E[6~,
+	kmous=\E[M,
 	kpp=\E[5~,
 	lines#24,
 	mir,

From 5beae6a62ee15dfe36048e377ebf86df09a0cf82 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Tue, 10 May 2011 22:55:35 +0200
Subject: [PATCH 0194/1146] macro cleanup.

---
 st.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index 65c7532..8347dbe 100644
--- a/st.c
+++ b/st.c
@@ -53,7 +53,9 @@
 #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 IS_SET(flag) (term.mode & (flag))
-#define TIMEDIFFERENCE(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
+#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
+#define X2COL(x) (((x) - BORDER)/xw.cw)
+#define Y2ROW(y) (((y) - BORDER)/xw.ch)
 
 /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
 enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 };
@@ -401,8 +403,8 @@ getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
 	if(b)
 		*b = e->xbutton.button;
 
-	*x = (e->xbutton.x - BORDER)/xw.cw;
-	*y = (e->xbutton.y - BORDER)/xw.ch;
+	*x = X2COL(e->xbutton.x);
+	*y = Y2ROW(e->xbutton.y);
 	sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex;
 	sel.b.y = MIN(sel.by, sel.ey);
 	sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx;
@@ -411,8 +413,8 @@ getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
 
 void
 mousereport(XEvent *e) {
-	int x = (e->xbutton.x - BORDER)/xw.cw;
-	int y = (e->xbutton.y - BORDER)/xw.ch;
+	int x = X2COL(e->xbutton.x);
+	int y = Y2ROW(e->xbutton.y);
 	int button = e->xbutton.button;
 	int state = e->xbutton.state;
 	char buf[] = { '\033', '[', 'M', 0, 32+x+1, 32+y+1 };
@@ -440,8 +442,8 @@ void
 bpress(XEvent *e) {
 	mousereport(e);
 	sel.mode = 1;
-	sel.ex = sel.bx = (e->xbutton.x - BORDER)/xw.cw;
-	sel.ey = sel.by = (e->xbutton.y - BORDER)/xw.ch;
+	sel.ex = sel.bx = X2COL(e->xbutton.x);
+	sel.ey = sel.by = Y2ROW(e->xbutton.y);
 }
 
 void
@@ -563,13 +565,13 @@ brelease(XEvent *e) {
 			struct timeval now;
 			gettimeofday(&now, NULL);
 
-			if(TIMEDIFFERENCE(now, sel.tclick2) <= TRIPLECLICK_TIMEOUT) {
+			if(TIMEDIFF(now, sel.tclick2) <= TRIPLECLICK_TIMEOUT) {
 				/* triple click on the line */
 				sel.b.x = sel.bx = 0;
 				sel.e.x = sel.ex = term.col;
 				sel.b.y = sel.e.y = sel.ey;
 				selcopy();
-			} else if(TIMEDIFFERENCE(now, sel.tclick1) <= DOUBLECLICK_TIMEOUT) {
+			} else if(TIMEDIFF(now, sel.tclick1) <= DOUBLECLICK_TIMEOUT) {
 				/* double click to select word */
 				sel.bx = sel.ex;
 				while(term.line[sel.ey][sel.bx-1].state & GLYPH_SET &&

From 7d352f143655ace75dd4e40432199f18f296da5e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sat, 14 May 2011 17:47:37 +0200
Subject: [PATCH 0195/1146] applied parts of Connor Lane Smith's cleanup patch.

---
 st.1 | 26 +++++++++++++-------------
 st.c | 14 +++++++-------
 2 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/st.1 b/st.1
index f1f41a7..69cfe86 100644
--- a/st.1
+++ b/st.1
@@ -1,4 +1,4 @@
-.TH ST 1 st-VERSION
+.TH ST 1 st\-VERSION
 .SH NAME
 st \- simple terminal
 .SH SYNOPSIS
@@ -9,24 +9,24 @@ st \- simple terminal
 .IR title ]
 .RB [ \-v ]
 .RB [ \-e
-.IR cmd ]
+.IR command ...]
 .SH DESCRIPTION
 .B st
 is a simple terminal emulator.
 .SH OPTIONS
 .TP
-.B \-t title
-Overrides the default title (st)
+.BI \-t " title"
+defines the window title (default 'st').
 .TP
-.B \-c class
-Overrides the default class ($TERM)
+.BI \-c " class"
+defines the window class (default $TERM).
 .TP
 .B \-v
-Prints version information to standard output, then exits.
+prints version information to stderr, then exits.
 .TP
-.B \-e cmd [arguments]
-Execute cmd instead of the shell. Type your command as you would on your
-shell. If this option is used, it
-.BI "must be the last"
-on the command-line. This is the same behaviour as xterm/rxvt.
-
+.BI \-e " program " [ " arguments " "... ]"
+st executes
+.I program
+instead of the shell.  If this is used it
+.B must be the last option
+on the command line, as in xterm / rxvt.
diff --git a/st.c b/st.c
index 8347dbe..01ffa21 100644
--- a/st.c
+++ b/st.c
@@ -34,8 +34,8 @@
 #endif
 
 #define USAGE \
-	"st-" VERSION ", (c) 2010 st engineers\n" \
-	"usage: st [-t title] [-c class] [-v] [-e cmd]\n"
+	"st-" VERSION ", (c) 2010-2011 st engineers\n" \
+	"usage: st [-t title] [-c class] [-v] [-e command...]\n"
 
 /* Arbitrary sizes */
 #define ESC_TITLE_SIZ 256
@@ -1907,17 +1907,17 @@ main(int argc, char *argv[]) {
 		case 'c':
 			if(++i < argc) opt_class = argv[i];
 			break;
-		case 'e':
+		case 'e': 
+			/* eat every remaining arguments */
 			if(++i < argc) opt_cmd = &argv[i];
-			break;
+			goto run;
 		case 'v':
 		default:
 			die(USAGE);
 		}
-		/* -e eats every remaining arguments */
-		if(opt_cmd)
-			break;
 	}
+
+ run:
 	setlocale(LC_CTYPE, "");
 	tnew(80, 24);
 	ttynew();

From 6734de9b6e1e74e6c713a6a3e22322e80884828d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 22 May 2011 16:57:27 +0200
Subject: [PATCH 0196/1146] =?UTF-8?q?set=20title=20before=20mapping=20wind?=
 =?UTF-8?q?ow=20(thx=20Kamil=20Cholewi=C5=84ski).?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 01ffa21..1d01925 100644
--- a/st.c
+++ b/st.c
@@ -1632,9 +1632,9 @@ xinit(void) {
 		&(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff},
 		&(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
 
+	XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st");
 	XMapWindow(xw.dpy, xw.win);
 	xhints();
-	XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st");
 	XSync(xw.dpy, 0);
 }
 

From b2db58c2a05168257ee4e4b941f0533c6dde2a10 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 1 Jun 2011 19:57:48 +0200
Subject: [PATCH 0197/1146] add status bar (window title) to terminfo. (thx
 Rafa Gallego)

---
 st.info | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.info b/st.info
index ece22fa..1cc6349 100644
--- a/st.info
+++ b/st.info
@@ -33,8 +33,10 @@ st| simpleterm,
 	ed=\E[J,
 	el=\E[K,
 	el1=\E[1K,
+	fsl=^G,
 	home=\E[H,
 	hpa=\E[%i%p1%dG,
+	hs,
 	ht=^I,
 	hts=\EH,
 	ich=\E[%p1%d@,
@@ -93,6 +95,7 @@ st| simpleterm,
 	smso=\E[7m,
 	smul=\E[4m,
 	tbc=\E[2g,
+	tsl=\E]0;,
 	ul,
 	xenl,
 

From d59f92d6f19a4a914ba99168fdc42d1783eee1ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 8 Jun 2011 12:40:35 +0200
Subject: [PATCH 0198/1146] =?UTF-8?q?reverse=20video=20mode.=20(thx=20Bert?=
 =?UTF-8?q?=20M=C3=BCnnich)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 st.c    | 31 +++++++++++++++++++++++--------
 st.info |  1 +
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/st.c b/st.c
index 1d01925..a4aca51 100644
--- a/st.c
+++ b/st.c
@@ -64,7 +64,7 @@ enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT,
 enum { CURSOR_DEFAULT = 0, CURSOR_HIDE = 1, CURSOR_WRAPNEXT = 2 };
 enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
 enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8,
-       MODE_CRLF=16, MODE_MOUSE=32 };
+       MODE_CRLF=16, MODE_MOUSE=32, MODE_REVERSE=64 };
 enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
 enum { WIN_VISIBLE=1, WIN_REDRAW=2, WIN_FOCUSED=4 };
 
@@ -1103,7 +1103,11 @@ csihandle(void) {
 			case 1:
 				term.mode &= ~MODE_APPKEYPAD;
 				break;
-			case 5: /* TODO: DECSCNM -- Remove reverse video */
+			case 5: /* DECSCNM -- Remove reverse video */
+				if(IS_SET(MODE_REVERSE)) {
+					term.mode &= ~MODE_REVERSE;
+					draw();
+				}
 				break;
 			case 7:
 				term.mode &= ~MODE_WRAP;
@@ -1167,7 +1171,10 @@ csihandle(void) {
 				term.mode |= MODE_APPKEYPAD;
 				break;
 			case 5: /* DECSCNM -- Reverve video */
-				/* TODO: set REVERSE on the whole screen (f) */
+				if(!IS_SET(MODE_REVERSE)) {
+					term.mode |= MODE_REVERSE;
+					draw();
+				}
 				break;
 			case 7:
 				term.mode |= MODE_WRAP;
@@ -1508,7 +1515,7 @@ xloadcols(void) {
 
 void
 xclear(int x1, int y1, int x2, int y2) {
-	XSetForeground(xw.dpy, dc.gc, dc.col[DefaultBG]);
+	XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? DefaultFG : DefaultBG]);
 	XFillRectangle(xw.dpy, xw.buf, dc.gc,
 	               x1 * xw.cw, y1 * xw.ch,
 	               (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
@@ -1640,14 +1647,20 @@ xinit(void) {
 
 void
 xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
-	unsigned long xfg, xbg;
+	unsigned long xfg = dc.col[base.fg], xbg = dc.col[base.bg], temp;
 	int winx = x*xw.cw, winy = y*xw.ch + dc.font.ascent, width = charlen*xw.cw;
 	int i;
+	
+	/* only switch default fg/bg if term is in RV mode */
+	if(IS_SET(MODE_REVERSE)) {
+		if(base.fg == DefaultFG)
+			xfg = dc.col[DefaultBG];
+		if(base.bg == DefaultBG)
+			xbg = dc.col[DefaultFG];
+	}
 
 	if(base.mode & ATTR_REVERSE)
-		xfg = dc.col[base.bg], xbg = dc.col[base.fg];
-	else
-		xfg = dc.col[base.fg], xbg = dc.col[base.bg];
+		temp = xfg, xfg = xbg, xbg = temp;
 
 	XSetBackground(xw.dpy, dc.gc, xbg);
 	XSetForeground(xw.dpy, dc.gc, xfg);
@@ -1692,6 +1705,8 @@ xdrawcursor(void) {
 	/* draw the new one */
 	if(!(term.c.state & CURSOR_HIDE) && (xw.state & WIN_FOCUSED)) {
 		sl = utf8size(g.c);
+		if(IS_SET(MODE_REVERSE))
+			g.mode |= ATTR_REVERSE, g.fg = DefaultCS, g.bg = DefaultFG;
 		xdraws(g.c, g, term.c.x, term.c.y, 1, sl);
 		oldx = term.c.x, oldy = term.c.y;
 	}
diff --git a/st.info b/st.info
index 1cc6349..489908f 100644
--- a/st.info
+++ b/st.info
@@ -33,6 +33,7 @@ st| simpleterm,
 	ed=\E[J,
 	el=\E[K,
 	el1=\E[1K,
+	flash=\E[?5h\E[?5l,
 	fsl=^G,
 	home=\E[H,
 	hpa=\E[%i%p1%dG,

From 9b404c0dfb99a7fd918760984ba4d0c50d3c87b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 8 Jun 2011 19:32:10 +0200
Subject: [PATCH 0199/1146] =?UTF-8?q?disable=20mouse=20highlight=20when=20?=
 =?UTF-8?q?mouse=20report=20enabled.=20(thx=20Bert=20M=C3=BCnnich)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 st.c | 82 +++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 51 insertions(+), 31 deletions(-)

diff --git a/st.c b/st.c
index a4aca51..e705fca 100644
--- a/st.c
+++ b/st.c
@@ -64,7 +64,7 @@ enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT,
 enum { CURSOR_DEFAULT = 0, CURSOR_HIDE = 1, CURSOR_WRAPNEXT = 2 };
 enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
 enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8,
-       MODE_CRLF=16, MODE_MOUSE=32, MODE_REVERSE=64 };
+       MODE_CRLF=16, MODE_MOUSEBTN=32, MODE_MOUSEMOTION=64, MODE_MOUSE=32|64, MODE_REVERSE=128 };
 enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
 enum { WIN_VISIBLE=1, WIN_REDRAW=2, WIN_FOCUSED=4 };
 
@@ -418,17 +418,24 @@ mousereport(XEvent *e) {
 	int button = e->xbutton.button;
 	int state = e->xbutton.state;
 	char buf[] = { '\033', '[', 'M', 0, 32+x+1, 32+y+1 };
-	
-	if(!IS_SET(MODE_MOUSE))
-		return;
+	static int ob, ox, oy;
 	
 	/* from urxvt */
-	if(e->xbutton.type == ButtonRelease || button == AnyButton)
+	if(e->xbutton.type == MotionNotify) {
+		if(!IS_SET(MODE_MOUSEMOTION) || (x == ox && y == oy))
+			return;
+		button = ob + 32;
+		ox = x, oy = y;
+	} else if(e->xbutton.type == ButtonRelease || button == AnyButton) {
 		button = 3;
-	else {
+	} else {
 		button -= Button1;
 		if(button >= 3)
 			button += 64 - 3;
+		if(e->xbutton.type == ButtonPress) {
+			ob = button;
+			ox = x, oy = y;
+		}
 	}
 	
 	buf[3] = 32 + button + (state & ShiftMask ? 4 : 0)
@@ -440,10 +447,13 @@ mousereport(XEvent *e) {
 
 void
 bpress(XEvent *e) {
-	mousereport(e);
-	sel.mode = 1;
-	sel.ex = sel.bx = X2COL(e->xbutton.x);
-	sel.ey = sel.by = Y2ROW(e->xbutton.y);
+	if(IS_SET(MODE_MOUSE))
+		mousereport(e);
+	else if(e->xbutton.button == Button1) {
+		sel.mode = 1;
+		sel.ex = sel.bx = X2COL(e->xbutton.x);
+		sel.ey = sel.by = Y2ROW(e->xbutton.y);
+	}
 }
 
 void
@@ -552,17 +562,18 @@ xsetsel(char *str) {
 
 void
 brelease(XEvent *e) {
-	int b;
-
-	sel.mode = 0;
-	getbuttoninfo(e, &b, &sel.ex, &sel.ey);
-	mousereport(e);
-	if(sel.bx == sel.ex && sel.by == sel.ey) {
-		sel.bx = -1;
-		if(b == 2)
-			selpaste();
-		else if(b == 1) {
+	if(IS_SET(MODE_MOUSE)) {
+		mousereport(e);
+		return;
+	}
+	if(e->xbutton.button == Button2)
+		selpaste();
+	else if(e->xbutton.button == Button1) {
+		sel.mode = 0;
+		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
+		if(sel.bx == sel.ex && sel.by == sel.ey) {
 			struct timeval now;
+			sel.bx = -1;
 			gettimeofday(&now, NULL);
 
 			if(TIMEDIFF(now, sel.tclick2) <= TRIPLECLICK_TIMEOUT) {
@@ -574,18 +585,18 @@ brelease(XEvent *e) {
 			} else if(TIMEDIFF(now, sel.tclick1) <= DOUBLECLICK_TIMEOUT) {
 				/* double click to select word */
 				sel.bx = sel.ex;
-				while(term.line[sel.ey][sel.bx-1].state & GLYPH_SET &&
+				while(sel.bx > 0 && term.line[sel.ey][sel.bx-1].state & GLYPH_SET &&
 					  term.line[sel.ey][sel.bx-1].c[0] != ' ') sel.bx--;
 				sel.b.x = sel.bx;
-				while(term.line[sel.ey][sel.ex+1].state & GLYPH_SET &&
+				while(sel.ex < term.col-1 && term.line[sel.ey][sel.ex+1].state & GLYPH_SET &&
 					  term.line[sel.ey][sel.ex+1].c[0] != ' ') sel.ex++;
 				sel.e.x = sel.ex;
 				sel.b.y = sel.e.y = sel.ey;
 				selcopy();
 			}
-		}
-	} else if(b == 1)
-		selcopy();
+		} else
+			selcopy();
+	}
 	memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval));
 	gettimeofday(&sel.tclick1, NULL);
 	draw();
@@ -593,9 +604,12 @@ brelease(XEvent *e) {
 
 void
 bmotion(XEvent *e) {
+	if(IS_SET(MODE_MOUSE)) {
+		mousereport(e);
+		return;
+	}
 	if(sel.mode) {
-		int oldey = sel.ey,
-			oldex = sel.ex;
+		int oldey = sel.ey, oldex = sel.ex;
 		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
 
 		if(oldey != sel.ey || oldex != sel.ex) {
@@ -1121,7 +1135,10 @@ csihandle(void) {
 				term.c.state |= CURSOR_HIDE;
 				break;
 			case 1000: /* disable X11 xterm mouse reporting */
-				term.mode &= ~MODE_MOUSE;
+				term.mode &= ~MODE_MOUSEBTN;
+				break;
+			case 1002:
+				term.mode &= ~MODE_MOUSEMOTION;
 				break;
 			case 1049: /* = 1047 and 1048 */
 			case 1047:
@@ -1189,8 +1206,11 @@ csihandle(void) {
 			case 25:
 				term.c.state &= ~CURSOR_HIDE;
 				break;
-			case 1000: /* enable X11 xterm mouse reporting */
-				term.mode |= MODE_MOUSE;
+			case 1000: /* 1000,1002: enable xterm mouse report */
+				term.mode |= MODE_MOUSEBTN;
+				break;
+			case 1002:
+				term.mode |= MODE_MOUSEMOTION;
 				break;
 			case 1049: /* = 1047 and 1048 */
 			case 1047:
@@ -1612,7 +1632,7 @@ xinit(void) {
 	attrs.bit_gravity = NorthWestGravity;
 	attrs.event_mask = FocusChangeMask | KeyPressMask
 		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
-		| PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
+		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
 	attrs.colormap = xw.cmap;
 
 	xw.win = XCreateWindow(xw.dpy, XRootWindow(xw.dpy, xw.scr), 0, 0,

From 189a81caa11a278079fde3e610870e07870d8968 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 8 Jun 2011 20:22:38 +0200
Subject: [PATCH 0200/1146] =?UTF-8?q?add=20altscreen=20escseq=20alias=20&?=
 =?UTF-8?q?=20caps=20to=20terminfo=20entry.=20(thx=20Bert=20M=C3=BCnnich)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 st.c    | 6 ++++--
 st.info | 2 ++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index e705fca..bc17df3 100644
--- a/st.c
+++ b/st.c
@@ -1141,12 +1141,13 @@ csihandle(void) {
 				term.mode &= ~MODE_MOUSEMOTION;
 				break;
 			case 1049: /* = 1047 and 1048 */
+			case 47:
 			case 1047:
 				if(IS_SET(MODE_ALTSCREEN)) {
 					tclearregion(0, 0, term.col-1, term.row-1);
 					tswapscreen();
 				}
-				if(escseq.arg[0] == 1047)
+				if(escseq.arg[0] != 1049)
 					break;
 			case 1048:
 				tcursor(CURSOR_LOAD);
@@ -1213,12 +1214,13 @@ csihandle(void) {
 				term.mode |= MODE_MOUSEMOTION;
 				break;
 			case 1049: /* = 1047 and 1048 */
+			case 47:
 			case 1047:
 				if(IS_SET(MODE_ALTSCREEN))
 					tclearregion(0, 0, term.col-1, term.row-1);
 				else
 					tswapscreen();
-				if(escseq.arg[0] == 1047)
+				if(escseq.arg[0] != 1049)
 					break;
 			case 1048:
 				tcursor(CURSOR_SAVE);
diff --git a/st.info b/st.info
index 489908f..37008af 100644
--- a/st.info
+++ b/st.info
@@ -85,6 +85,7 @@ st| simpleterm,
 	rev=\E[7m,
 	ri=\EM,
 	rmacs=\E(B,
+	rmcup=\E[?1049l,
 	rmso=\E[m,
 	rmul=\E[m,
 	sc=\E7,
@@ -93,6 +94,7 @@ st| simpleterm,
 	sgr0=\E[0m,
 	sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
 	smacs=\E(0,
+	smcup=\E[?1049h,
 	smso=\E[7m,
 	smul=\E[4m,
 	tbc=\E[2g,

From 4736edd469d07685f6ceeb4bfe438ba48335bd81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 8 Jun 2011 20:26:00 +0200
Subject: [PATCH 0201/1146] applied parts of "anonymous" cleanup patch.

---
 st.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index bc17df3..6ba5c4c 100644
--- a/st.c
+++ b/st.c
@@ -483,8 +483,7 @@ selcopy(void) {
 
 void
 selnotify(XEvent *e) {
-	unsigned long nitems;
-	unsigned long ofs, rem;
+	unsigned long nitems, ofs, rem;
 	int format;
 	unsigned char *data;
 	Atom type;
@@ -767,7 +766,7 @@ tnew(int col, int row) {
 	term.row = row, term.col = col;
 	term.line = malloc(term.row * sizeof(Line));
 	term.alt  = malloc(term.row * sizeof(Line));
-	for(row = 0 ; row < term.row; row++) {
+	for(row = 0; row < term.row; row++) {
 		term.line[row] = malloc(term.col * sizeof(Glyph));
 		term.alt [row] = malloc(term.col * sizeof(Glyph));
 	}

From 3959a99293785e603270d8798fbe0cb2ba0ae0ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 8 Jun 2011 21:35:58 +0200
Subject: [PATCH 0202/1146] add -w option to embed st. (thx nodus cursorius)

---
 st.1 |  6 ++++++
 st.c | 10 ++++++++--
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/st.1 b/st.1
index 69cfe86..b6c119f 100644
--- a/st.1
+++ b/st.1
@@ -7,6 +7,8 @@ st \- simple terminal
 .IR class ]
 .RB [ \-t 
 .IR title ]
+.RB [ \-w 
+.IR windowid ]
 .RB [ \-v ]
 .RB [ \-e
 .IR command ...]
@@ -21,6 +23,10 @@ defines the window title (default 'st').
 .BI \-c " class"
 defines the window class (default $TERM).
 .TP
+.BI \-w " windowid"
+embeds st within the window identified by 
+.I windowid
+.TP
 .B \-v
 prints version information to stderr, then exits.
 .TP
diff --git a/st.c b/st.c
index 6ba5c4c..b331ead 100644
--- a/st.c
+++ b/st.c
@@ -35,7 +35,7 @@
 
 #define USAGE \
 	"st-" VERSION ", (c) 2010-2011 st engineers\n" \
-	"usage: st [-t title] [-c class] [-v] [-e command...]\n"
+	"usage: st [-t title] [-c class] [-w windowid] [-v] [-e command...]\n"
 
 /* Arbitrary sizes */
 #define ESC_TITLE_SIZ 256
@@ -260,6 +260,7 @@ static pid_t pid;
 static Selection sel;
 static char **opt_cmd  = NULL;
 static char *opt_title = NULL;
+static char *opt_embed = NULL;
 static char *opt_class = NULL;
 
 int
@@ -1606,6 +1607,7 @@ void
 xinit(void) {
 	XSetWindowAttributes attrs;
 	Cursor cursor;
+	Window parent;
 
 	if(!(xw.dpy = XOpenDisplay(NULL)))
 		die("Can't open display\n");
@@ -1636,7 +1638,8 @@ xinit(void) {
 		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
 	attrs.colormap = xw.cmap;
 
-	xw.win = XCreateWindow(xw.dpy, XRootWindow(xw.dpy, xw.scr), 0, 0,
+	parent = opt_embed ? strtol(opt_embed, NULL, 0) : XRootWindow(xw.dpy, xw.scr);
+	xw.win = XCreateWindow(xw.dpy, parent, 0, 0,
 			xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
 			XDefaultVisual(xw.dpy, xw.scr),
 			CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
@@ -1943,6 +1946,9 @@ main(int argc, char *argv[]) {
 		case 'c':
 			if(++i < argc) opt_class = argv[i];
 			break;
+		case 'w':
+			if(++i < argc) opt_embed = argv[i];
+			break;
 		case 'e': 
 			/* eat every remaining arguments */
 			if(++i < argc) opt_cmd = &argv[i];

From cddbd6eee59104a029087c30f9ff5e7e415bc584 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 9 Jun 2011 14:27:07 +0200
Subject: [PATCH 0203/1146] fix segfault with mouse selection. (thx anonymous)

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index b331ead..df8353a 100644
--- a/st.c
+++ b/st.c
@@ -615,7 +615,7 @@ bmotion(XEvent *e) {
 		if(oldey != sel.ey || oldex != sel.ex) {
 			int starty = MIN(oldey, sel.ey);
 			int endy = MAX(oldey, sel.ey);
-			drawregion(0, (starty > 0 ? starty : 0), term.col, (sel.ey < term.row ? endy+1 : term.row));
+			drawregion(0, (starty > 0 ? starty : 0), term.col, (endy < term.row ? endy+1 : term.row));
 		}
 	}
 }

From 8503f954a1cb2d08124fe2c1f0227bd23dffff46 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 9 Jun 2011 18:25:56 +0200
Subject: [PATCH 0204/1146] fix focus state when embed in another window.

---
 st.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index df8353a..f0c2cd2 100644
--- a/st.c
+++ b/st.c
@@ -241,6 +241,8 @@ static void (*handler[LASTEvent])(XEvent *) = {
 	[VisibilityNotify] = visibility,
 	[UnmapNotify] = unmap,
 	[Expose] = expose,
+	[EnterNotify] = focus,
+	[LeaveNotify] = focus,
 	[FocusIn] = focus,
 	[FocusOut] = focus,
 	[MotionNotify] = bmotion,
@@ -1635,7 +1637,8 @@ xinit(void) {
 	attrs.bit_gravity = NorthWestGravity;
 	attrs.event_mask = FocusChangeMask | KeyPressMask
 		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
-		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
+		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask
+		| EnterWindowMask | LeaveWindowMask;
 	attrs.colormap = xw.cmap;
 
 	parent = opt_embed ? strtol(opt_embed, NULL, 0) : XRootWindow(xw.dpy, xw.scr);
@@ -1819,7 +1822,7 @@ xseturgency(int add) {
 
 void
 focus(XEvent *ev) {
-	if(ev->type == FocusIn) {
+	if(ev->type == FocusIn || ev->type == EnterNotify) {
 		xw.state |= WIN_FOCUSED;
 		xseturgency(0);
 	} else

From 6f260ba164ee302b50398e529f71e305e435504a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 14 Aug 2011 17:13:59 +0200
Subject: [PATCH 0205/1146] fix custom key handling.

---
 config.def.h | 52 +++++++++++++++++++++++++++++-----------------------
 st.c         |  9 +++++++--
 2 files changed, 36 insertions(+), 25 deletions(-)

diff --git a/config.def.h b/config.def.h
index c1afd88..37f9620 100644
--- a/config.def.h
+++ b/config.def.h
@@ -25,34 +25,40 @@ static const char *colorname[] = {
 	"white"
 };
 
-/* Default colors (colorname index) */
-/* foreground, background, cursor   */
+/* Default colors (colorname index)
+   foreground, background, cursor   */
 #define DefaultFG 7
 #define DefaultBG 0
 #define DefaultCS 1
 
-/* Special keys (change & recompile st.info accordingly) */
-/*    key,        mask,  output */
+/* Special keys (change & recompile st.info accordingly)
+   Keep in mind that kpress() in st.c hardcodes some keys.
+
+   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)
+   
+      key,        mask,  output */
 static Key key[] = {
-	{ XK_BackSpace, 0, "\177" },
-	{ XK_Insert,    0, "\033[2~" },
-	{ XK_Delete,    0, "\033[3~" },
-	{ XK_Home,      0, "\033[1~" },
-	{ XK_End,       0, "\033[4~" },
-	{ XK_Prior,     0, "\033[5~" },
-	{ XK_Next,      0, "\033[6~" },
-	{ XK_F1,        0, "\033OP"   },
-	{ XK_F2,        0, "\033OQ"   },
-	{ XK_F3,        0, "\033OR"   },
-	{ XK_F4,        0, "\033OS"   },
-	{ XK_F5,        0, "\033[15~" },
-	{ XK_F6,        0, "\033[17~" },
-	{ XK_F7,        0, "\033[18~" },
-	{ XK_F8,        0, "\033[19~" },
-	{ XK_F9,        0, "\033[20~" },
-	{ XK_F10,       0, "\033[21~" },
-	{ XK_F11,       0, "\033[23~" },
-	{ XK_F12,       0, "\033[24~" },
+	{ XK_BackSpace, XK_NO_MOD, "\177" },
+   	{ XK_Insert,    XK_NO_MOD, "\033[2~" },
+	{ XK_Delete,    XK_NO_MOD, "\033[3~" },
+	{ XK_Home,      XK_NO_MOD, "\033[1~" },
+	{ XK_End,       XK_NO_MOD, "\033[4~" },
+	{ XK_Prior,     XK_NO_MOD, "\033[5~" },
+	{ XK_Next,      XK_NO_MOD, "\033[6~" },
+	{ XK_F1,        XK_NO_MOD, "\033OP"   },
+	{ XK_F2,        XK_NO_MOD, "\033OQ"   },
+	{ XK_F3,        XK_NO_MOD, "\033OR"   },
+	{ XK_F4,        XK_NO_MOD, "\033OS"   },
+	{ XK_F5,        XK_NO_MOD, "\033[15~" },
+	{ XK_F6,        XK_NO_MOD, "\033[17~" },
+	{ XK_F7,        XK_NO_MOD, "\033[18~" },
+	{ XK_F8,        XK_NO_MOD, "\033[19~" },
+	{ XK_F9,        XK_NO_MOD, "\033[20~" },
+	{ XK_F10,       XK_NO_MOD, "\033[21~" },
+	{ XK_F11,       XK_NO_MOD, "\033[23~" },
+	{ XK_F12,       XK_NO_MOD, "\033[24~" },
 };
 
 /* Line drawing characters (sometime specific to each font...) */
diff --git a/st.c b/st.c
index f0c2cd2..a60377b 100644
--- a/st.c
+++ b/st.c
@@ -43,6 +43,8 @@
 #define ESC_ARG_SIZ   16
 #define DRAW_BUF_SIZ  1024
 #define UTF_SIZ       4
+#define XK_NO_MOD     UINT_MAX
+#define XK_ANY_MOD    0
 
 #define SERRNO strerror(errno)
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
@@ -1833,9 +1835,12 @@ focus(XEvent *ev) {
 char*
 kmap(KeySym k, unsigned int state) {
 	int i;
-	for(i = 0; i < LEN(key); i++)
-		if(key[i].k == k && (key[i].mask == 0 || key[i].mask & state))
+	state &= ~Mod2Mask;
+	for(i = 0; i < LEN(key); i++) {
+		unsigned int mask = key[i].mask;
+		if(key[i].k == k && ((state & mask) == mask || (mask == XK_NO_MOD && !state)))
 			return (char*)key[i].s;
+	}
 	return NULL;
 }
 

From f78b793d91f954c769e029fe6e1613c22d30f5cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sun, 14 Aug 2011 17:15:19 +0200
Subject: [PATCH 0206/1146] change "op" cap in terminfo entry to xterm/rxvt
 value.

---
 st.info | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.info b/st.info
index 37008af..ea67039 100644
--- a/st.info
+++ b/st.info
@@ -79,7 +79,7 @@ st| simpleterm,
 	mir,
 	msgr,
 	ncv#3,
-	op=\E[37;40m,
+	op=\E[39;49m,
 	pairs#64,
 	rc=\E8,
 	rev=\E[7m,

From d5f3d120eae2377b8a2f80c94fbb5e4bd7a6189d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Fri, 16 Sep 2011 17:57:56 +0200
Subject: [PATCH 0207/1146] remove dup of default window size.

---
 TODO | 1 +
 st.c | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/TODO b/TODO
index ef68386..62a9f42 100644
--- a/TODO
+++ b/TODO
@@ -11,6 +11,7 @@ code & interface
 * clean selection code
 * clean and complete terminfo entry
 * fix shift up/down (shift selection in emacs)
+* fast drawing
 * ...
 
 misc
diff --git a/st.c b/st.c
index f0c2cd2..4649079 100644
--- a/st.c
+++ b/st.c
@@ -1627,8 +1627,8 @@ xinit(void) {
 	xloadcols();
 
 	/* window - default size */
-	xw.bufh = 24 * xw.ch;
-	xw.bufw = 80 * xw.cw;
+	xw.bufh = term.row * xw.ch;
+	xw.bufw = term.col * xw.cw;
 	xw.h = xw.bufh + 2*BORDER;
 	xw.w = xw.bufw + 2*BORDER;
 

From 8d2d8848e8ac7117adffe9e1d168c5125934dfcf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Fri, 16 Sep 2011 18:03:44 +0200
Subject: [PATCH 0208/1146] tweak focus to support XEMBED client message and
 remove focus on EnterNotify. (thx Adrian)

---
 st.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 4649079..6f292ba 100644
--- a/st.c
+++ b/st.c
@@ -37,6 +37,10 @@
 	"st-" VERSION ", (c) 2010-2011 st engineers\n" \
 	"usage: st [-t title] [-c class] [-w windowid] [-v] [-e command...]\n"
 
+/* XEMBED messages */
+#define XEMBED_FOCUS_IN  4
+#define XEMBED_FOCUS_OUT 5
+
 /* Arbitrary sizes */
 #define ESC_TITLE_SIZ 256
 #define ESC_BUF_SIZ   256
@@ -217,6 +221,7 @@ static void visibility(XEvent *);
 static void unmap(XEvent *);
 static char* kmap(KeySym, unsigned int state);
 static void kpress(XEvent *);
+static void cmessage(XEvent *);
 static void resize(XEvent *);
 static void focus(XEvent *);
 static void brelease(XEvent *);
@@ -237,12 +242,11 @@ static int isfullutf8(char *, int);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
+	[ClientMessage] = cmessage,
 	[ConfigureNotify] = resize,
 	[VisibilityNotify] = visibility,
 	[UnmapNotify] = unmap,
 	[Expose] = expose,
-	[EnterNotify] = focus,
-	[LeaveNotify] = focus,
 	[FocusIn] = focus,
 	[FocusOut] = focus,
 	[MotionNotify] = bmotion,
@@ -264,6 +268,7 @@ static char **opt_cmd  = NULL;
 static char *opt_title = NULL;
 static char *opt_embed = NULL;
 static char *opt_class = NULL;
+static Atom xembedatom;
 
 int
 utf8decode(char *s, long *u) {
@@ -1666,6 +1671,8 @@ xinit(void) {
 		&(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff},
 		&(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
 
+	xembedatom = XInternAtom(xw.dpy, "_XEMBED", False);
+
 	XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st");
 	XMapWindow(xw.dpy, xw.win);
 	xhints();
@@ -1822,7 +1829,7 @@ xseturgency(int add) {
 
 void
 focus(XEvent *ev) {
-	if(ev->type == FocusIn || ev->type == EnterNotify) {
+	if(ev->type == FocusIn) {
 		xw.state |= WIN_FOCUSED;
 		xseturgency(0);
 	} else
@@ -1889,6 +1896,19 @@ kpress(XEvent *ev) {
 		}
 }
 
+void
+cmessage(XEvent *e) {
+	if (e->xclient.message_type == xembedatom && e->xclient.format == 32) {
+		if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
+			xw.state |= WIN_FOCUSED;
+			xseturgency(0);
+		} else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
+			xw.state &= ~WIN_FOCUSED;
+		}
+		draw();
+	}
+}
+
 void
 resize(XEvent *e) {
 	int col, row;

From 8e66b5cc16831583a1086f3ba9cd0eaa55f02230 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Fri, 16 Sep 2011 18:21:48 +0200
Subject: [PATCH 0209/1146] move xembedatom in XWindow struct, add link to
 xembed specs.

---
 st.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 6f292ba..7ac02b9 100644
--- a/st.c
+++ b/st.c
@@ -124,6 +124,7 @@ typedef struct {
 	Colormap cmap;
 	Window win;
 	Pixmap buf;
+	Atom xembed;
 	XIM xim;
 	XIC xic;
 	int scr;
@@ -268,7 +269,6 @@ static char **opt_cmd  = NULL;
 static char *opt_title = NULL;
 static char *opt_embed = NULL;
 static char *opt_class = NULL;
-static Atom xembedatom;
 
 int
 utf8decode(char *s, long *u) {
@@ -1671,7 +1671,7 @@ xinit(void) {
 		&(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff},
 		&(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
 
-	xembedatom = XInternAtom(xw.dpy, "_XEMBED", False);
+	xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
 
 	XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st");
 	XMapWindow(xw.dpy, xw.win);
@@ -1898,7 +1898,9 @@ kpress(XEvent *ev) {
 
 void
 cmessage(XEvent *e) {
-	if (e->xclient.message_type == xembedatom && e->xclient.format == 32) {
+	/* 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) {
 			xw.state |= WIN_FOCUSED;
 			xseturgency(0);

From 4bd087766f16bd541a1aebd0b0348ecc5fe9b94c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Fri, 16 Sep 2011 18:48:16 +0200
Subject: [PATCH 0210/1146] selection is removed or scrolled properly. (thx
 Rafa Garcia Gallego)

---
 st.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/st.c b/st.c
index c295de6..89fbee9 100644
--- a/st.c
+++ b/st.c
@@ -237,6 +237,7 @@ static void selinit(void);
 static inline int selected(int, int);
 static void selcopy(void);
 static void selpaste();
+static void selscroll(int, int);
 
 static int utf8decode(char *, long *);
 static int utf8encode(long *, char *);
@@ -806,6 +807,8 @@ tscrolldown(int orig, int n) {
 		term.line[i] = term.line[i-n];
 		term.line[i-n] = temp;
 	}
+
+	selscroll(orig, n);
 }
 
 void
@@ -821,6 +824,31 @@ tscrollup(int orig, int n) {
 		 term.line[i] = term.line[i+n];
 		 term.line[i+n] = temp;
 	}
+
+	selscroll(orig, -n);
+}
+
+void
+selscroll(int orig, int n) {
+	if(sel.bx == -1)
+		return;
+	
+	if(BETWEEN(sel.by, orig, term.bot) || BETWEEN(sel.ey, orig, term.bot)) {
+		if((sel.by += n) > term.bot || (sel.ey += n) < term.top) {
+			sel.bx = -1;
+			return;
+		}
+		if(sel.by < term.top) {
+			sel.by = term.top;
+			sel.bx = 0;
+		}
+		if(sel.ey > term.bot) {
+			sel.ey = term.bot;
+			sel.ex = term.col;
+		}
+		sel.b.y = sel.by, sel.b.x = sel.bx;
+		sel.e.y = sel.ey, sel.e.x = sel.ex;
+	}
 }
 
 void
@@ -1077,6 +1105,7 @@ csihandle(void) {
 		break;
 	/* XXX: (CSI n I) CHT -- Cursor Forward Tabulation <n> tab stops */
 	case 'J': /* ED -- Clear screen */
+		sel.bx = -1;
 		switch(escseq.arg[0]) {
 		case 0: /* below */
 			tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
@@ -1382,6 +1411,7 @@ tputc(char *c) {
 			}
 		}
 	} else {
+		if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey)) sel.bx = -1;
 		switch(ascii) {
 		case '\t':
 			tputtab();

From 9d613092d6698ef41cb7492cdb3214ee9a5ab4d7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 22 Sep 2011 10:04:58 +0200
Subject: [PATCH 0211/1146] simplify version format.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 89fbee9..6594aa3 100644
--- a/st.c
+++ b/st.c
@@ -34,7 +34,7 @@
 #endif
 
 #define USAGE \
-	"st-" VERSION ", (c) 2010-2011 st engineers\n" \
+	"st " VERSION " (c) 2010-2011 st engineers\n" \
 	"usage: st [-t title] [-c class] [-w windowid] [-v] [-e command...]\n"
 
 /* XEMBED messages */

From 907cb8bfa69926616639f9a19127117b37326029 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 6 Oct 2011 21:32:34 +0200
Subject: [PATCH 0212/1146] no palette limit (thx Nick)

---
 config.def.h | 2 +-
 st.c         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/config.def.h b/config.def.h
index 37f9620..35f36cb 100644
--- a/config.def.h
+++ b/config.def.h
@@ -5,7 +5,7 @@
 #define BORDER 2
 #define SHELL "/bin/sh"
 
-/* Terminal colors */
+/* Terminal colors (16 first used in escape sequence) */
 static const char *colorname[] = {
 	"black",
 	"red3",
diff --git a/st.c b/st.c
index 6594aa3..72e57c8 100644
--- a/st.c
+++ b/st.c
@@ -1541,7 +1541,7 @@ xloadcols(void) {
 	XColor color;
 	unsigned long white = WhitePixel(xw.dpy, xw.scr);
 
-	for(i = 0; i < 16; i++) {
+	for(i = 0; i < LEN(colorname); i++) {
 		if(!XAllocNamedColor(xw.dpy, xw.cmap, colorname[i], &color, &color)) {
 			dc.col[i] = white;
 			fprintf(stderr, "Could not allocate color '%s'\n", colorname[i]);

From 0dbf9c8c12a5de35d1cef22349ab80e8f0a8f10e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 20 Oct 2011 23:20:59 +0200
Subject: [PATCH 0213/1146] add dirty flag for lines

---
 st.c | 43 +++++++++++++++++++++++++++++++++++++++----
 1 file changed, 39 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 72e57c8..ad6db0d 100644
--- a/st.c
+++ b/st.c
@@ -111,6 +111,7 @@ typedef struct {
 	int col;	/* nb col */
 	Line* line;	/* screen */
 	Line* alt;	/* alternate screen */
+	char* dirty; /* dirtyness of lines */
 	TCursor c;	/* cursor */
 	int top;	/* top    scroll limit */
 	int bot;	/* bottom scroll limit */
@@ -203,6 +204,7 @@ static void tsetattr(int*, int);
 static void tsetchar(char*);
 static void tsetscroll(int, int);
 static void tswapscreen(void);
+static void tfulldirt(void);
 
 static void ttynew(void);
 static void ttyread(void);
@@ -748,6 +750,14 @@ ttyresize(int x, int y) {
 		fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
 }
 
+void
+tfulldirt(void)
+{
+	int i;
+	for(i = 0; i < term.row; i++)
+		term.dirty[i] = 1;
+}
+
 void
 tcursor(int mode) {
 	static TCursor c;
@@ -777,9 +787,12 @@ tnew(int col, int row) {
 	term.row = row, term.col = col;
 	term.line = malloc(term.row * sizeof(Line));
 	term.alt  = malloc(term.row * sizeof(Line));
+	term.dirty = malloc(term.row * sizeof(*term.dirty));
+
 	for(row = 0; row < term.row; row++) {
 		term.line[row] = malloc(term.col * sizeof(Glyph));
 		term.alt [row] = malloc(term.col * sizeof(Glyph));
+		term.dirty[row] = 0;
 	}
 	/* setup screen */
 	treset();
@@ -791,6 +804,7 @@ tswapscreen(void) {
 	term.line = term.alt;
 	term.alt = tmp;
 	term.mode ^= MODE_ALTSCREEN;
+	tfulldirt();
 }
 
 void
@@ -806,6 +820,9 @@ tscrolldown(int orig, int n) {
 		temp = term.line[i];
 		term.line[i] = term.line[i-n];
 		term.line[i-n] = temp;
+
+		term.dirty[i] = 1;
+		term.dirty[i-n] = 1;
 	}
 
 	selscroll(orig, n);
@@ -823,6 +840,9 @@ tscrollup(int orig, int n) {
 		 temp = term.line[i];
 		 term.line[i] = term.line[i+n];
 		 term.line[i+n] = temp;
+
+		 term.dirty[i] = 1;
+		 term.dirty[i+n] = 1;
 	}
 
 	selscroll(orig, -n);
@@ -896,6 +916,7 @@ tmoveto(int x, int y) {
 
 void
 tsetchar(char *c) {
+	term.dirty[term.c.y] = 1;
 	term.line[term.c.y][term.c.x] = term.c.attr;
 	memcpy(term.line[term.c.y][term.c.x].c, c, UTF_SIZ);
 	term.line[term.c.y][term.c.x].state |= GLYPH_SET;
@@ -915,9 +936,11 @@ tclearregion(int x1, int y1, int x2, int y2) {
 	LIMIT(y1, 0, term.row-1);
 	LIMIT(y2, 0, term.row-1);
 
-	for(y = y1; y <= y2; y++)
+	for(y = y1; y <= y2; y++) {
+		term.dirty[y] = 1;
 		for(x = x1; x <= x2; x++)
 			term.line[y][x].state = 0;
+	}
 }
 
 void
@@ -925,6 +948,8 @@ tdeletechar(int n) {
 	int src = term.c.x + n;
 	int dst = term.c.x;
 	int size = term.col - src;
+	
+	term.dirty[term.c.y] = 1;
 
 	if(src >= term.col) {
 		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
@@ -940,6 +965,8 @@ tinsertblank(int n) {
 	int dst = src + n;
 	int size = term.col - dst;
 
+	term.dirty[term.c.y] = 1;
+
 	if(dst >= term.col) {
 		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
 		return;
@@ -1411,7 +1438,8 @@ tputc(char *c) {
 			}
 		}
 	} else {
-		if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey)) sel.bx = -1;
+		if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey))
+			sel.bx = -1;
 		switch(ascii) {
 		case '\t':
 			tputtab();
@@ -1479,9 +1507,11 @@ tresize(int col, int row) {
 	/* resize to new height */
 	term.line = realloc(term.line, row * sizeof(Line));
 	term.alt  = realloc(term.alt,  row * sizeof(Line));
+	term.dirty = realloc(term.dirty, row * sizeof(*term.dirty));
 
 	/* resize each row to new width, zero-pad if needed */
 	for(i = 0; i < minrow; i++) {
+		term.dirty[i] = 1;
 		term.line[i] = realloc(term.line[i], col * sizeof(Glyph));
 		term.alt[i]  = realloc(term.alt[i],  col * sizeof(Glyph));
 		for(x = mincol; x < col; x++) {
@@ -1492,6 +1522,7 @@ tresize(int col, int row) {
 
 	/* allocate any new rows */
 	for(/* i == minrow */; i < row; i++) {
+		term.dirty[i] = 1;
 		term.line[i] = calloc(col, sizeof(Glyph));
 		term.alt [i] = calloc(col, sizeof(Glyph));
 	}
@@ -1502,6 +1533,7 @@ tresize(int col, int row) {
 	tmoveto(term.c.x, term.c.y);
 	/* reset scrolling region */
 	tsetscroll(0, row-1);
+
 	return (slide > 0);
 }
 
@@ -1792,8 +1824,11 @@ drawregion(int x1, int y1, int x2, int y2) {
 	if(!(xw.state & WIN_VISIBLE))
 		return;
 
-	xclear(x1, y1, x2-1, y2-1);
 	for(y = y1; y < y2; y++) {
+		if(!term.dirty[y])
+			continue;
+		xclear(0, y, term.col, y);
+		term.dirty[y] = 0;
 		base = term.line[y][0];
 		ic = ib = ox = 0;
 		for(x = x1; x < x2; x++) {
@@ -1801,7 +1836,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 			if(sel.bx != -1 && *(new.c) && selected(x, y))
 				new.mode ^= ATTR_REVERSE;
 			if(ib > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) ||
-					ib >= DRAW_BUF_SIZ-UTF_SIZ)) {
+						  ib >= DRAW_BUF_SIZ-UTF_SIZ)) {
 				xdraws(buf, base, ox, y, ic, ib);
 				ic = ib = 0;
 			}

From 23bb97d9f3b01da5bc4ad5c01616606adee4f1da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 20 Oct 2011 23:26:58 +0200
Subject: [PATCH 0214/1146] drawregion() only copies region on screen.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index ad6db0d..46f6d5b 100644
--- a/st.c
+++ b/st.c
@@ -1855,7 +1855,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 			xdraws(buf, base, ox, y, ic, ib);
 	}
 	xdrawcursor();
-	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER);
+	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, x1*xw.cw, y1*xw.ch, (x2-1)*xw.cw, (y2-1)*xw.ch, BORDER, BORDER);
 }
 
 void

From a20125a3d1fd9fec2af7886a474691a1839f8537 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Tue, 1 Nov 2011 16:33:43 +0100
Subject: [PATCH 0215/1146] fix selection. (thx Tarmo Heiskanen)

---
 st.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index ad6db0d..98bb051 100644
--- a/st.c
+++ b/st.c
@@ -463,6 +463,9 @@ bpress(XEvent *e) {
 	if(IS_SET(MODE_MOUSE))
 		mousereport(e);
 	else if(e->xbutton.button == Button1) {
+		if(sel.bx != -1)
+			for(int i=sel.b.y; i<=sel.e.y; i++)
+				term.dirty[i] = 1;
 		sel.mode = 1;
 		sel.ex = sel.bx = X2COL(e->xbutton.x);
 		sel.ey = sel.by = Y2ROW(e->xbutton.y);
@@ -583,6 +586,7 @@ brelease(XEvent *e) {
 	else if(e->xbutton.button == Button1) {
 		sel.mode = 0;
 		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
+		term.dirty[sel.ey] = 1;
 		if(sel.bx == sel.ex && sel.by == sel.ey) {
 			struct timeval now;
 			sel.bx = -1;
@@ -627,7 +631,9 @@ bmotion(XEvent *e) {
 		if(oldey != sel.ey || oldex != sel.ex) {
 			int starty = MIN(oldey, sel.ey);
 			int endy = MAX(oldey, sel.ey);
-			drawregion(0, (starty > 0 ? starty : 0), term.col, (endy < term.row ? endy+1 : term.row));
+			for(int i=starty; i<=endy; i++)
+				term.dirty[i] = 1;
+			draw();
 		}
 	}
 }

From 13a8eeb810ccfdaefd58c52328dd0ec867e3ae8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Tue, 10 Jan 2012 22:21:03 +0100
Subject: [PATCH 0216/1146] =?UTF-8?q?fix=20segfault=20in=20selection.=20(t?=
 =?UTF-8?q?hx=20Martti=20K=C3=BChne)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index e193443..c3d0888 100644
--- a/st.c
+++ b/st.c
@@ -547,7 +547,7 @@ selrequest(XEvent *e) {
 				XA_ATOM, 32, PropModeReplace,
 				(unsigned char *) &string, 1);
 		xev.property = xsre->property;
-	} else if(xsre->target == sel.xtarget) {
+	} else if(xsre->target == sel.xtarget && sel.clip != NULL) {
 		XChangeProperty(xsre->display, xsre->requestor, xsre->property,
 				xsre->target, 8, PropModeReplace,
 				(unsigned char *) sel.clip, strlen(sel.clip));

From 896310e5928b6daab5f594acd9648ffe8233022e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sat, 21 Jan 2012 23:14:41 +0100
Subject: [PATCH 0217/1146] copy dirty lines to screen, add select() timeout &
 min time between draw() calls.

* add a timeout value (SELECT_TIMEOUT) of 20ms in the select() call
* wait at least 20ms (DRAW_TIMEOUT) between draw() calls
* only copy dirty lines from the buffer to the screen

what draw() does:
* clears dirty lines in the buffer
* draws the longest same-attributes string of each
  dirty line to the buffer with multiple xdraws() call
* copies the current dirty line from buffer to the screen with a single
  xcopy() call

this changeset makes st run ~10x faster.
---
 st.c | 53 ++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 44 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index c3d0888..c543bb1 100644
--- a/st.c
+++ b/st.c
@@ -13,8 +13,10 @@
 #include <sys/ioctl.h>
 #include <sys/select.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <time.h>
 #include <unistd.h>
 #include <X11/Xatom.h>
 #include <X11/Xlib.h>
@@ -22,9 +24,6 @@
 #include <X11/cursorfont.h>
 #include <X11/keysym.h>
 
-#include <sys/time.h>
-#include <time.h>
-
 #if   defined(__linux)
  #include <pty.h>
 #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
@@ -50,6 +49,9 @@
 #define XK_NO_MOD     UINT_MAX
 #define XK_ANY_MOD    0
 
+#define SELECT_TIMEOUT (20*1000) /* 20 ms */
+#define DRAW_TIMEOUT  (20*1000) /* 20 ms */
+
 #define SERRNO strerror(errno)
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
 #define MAX(a, b)  ((a) < (b) ? (b) : (a))
@@ -138,6 +140,7 @@ typedef struct {
 	int ch; /* char height */
 	int cw; /* char width  */
 	char state; /* focus, redraw, visible */
+	struct timeval lastdraw;
 } XWindow;
 
 typedef struct {
@@ -179,6 +182,7 @@ static void drawregion(int, int, int, int);
 static void execsh(void);
 static void sigchld(int);
 static void run(void);
+static int last_draw_too_old(void);
 
 static void csidump(void);
 static void csihandle(void);
@@ -214,6 +218,7 @@ static void ttywrite(const char *, size_t);
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
 static void xclear(int, int, int, int);
+static void xcopy(int, int, int, int);
 static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
@@ -224,7 +229,7 @@ static void xresize(int, int);
 static void expose(XEvent *);
 static void visibility(XEvent *);
 static void unmap(XEvent *);
-static char* kmap(KeySym, unsigned int state);
+static char* kmap(KeySym, unsigned int);
 static void kpress(XEvent *);
 static void cmessage(XEvent *);
 static void resize(XEvent *);
@@ -1786,6 +1791,14 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);
 }
 
+/* copy buffer pixmap to screen pixmap */
+void
+xcopy(int x, int y, int cols, int rows) {
+	int src_x = x*xw.cw, src_y = y*xw.ch, src_w = cols*xw.cw, src_h = rows*xw.ch;
+	int dst_x = BORDER+src_x, dst_y = BORDER+src_y;
+	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, src_x, src_y, src_w, src_h, dst_x, dst_y);
+}
+
 void
 xdrawcursor(void) {
 	static int oldx = 0;
@@ -1805,7 +1818,9 @@ xdrawcursor(void) {
 		xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, 1, sl);
 	} else
 		xclear(oldx, oldy, oldx, oldy);
-	
+
+	xcopy(oldx, oldy, 1, 1);
+
 	/* draw the new one */
 	if(!(term.c.state & CURSOR_HIDE) && (xw.state & WIN_FOCUSED)) {
 		sl = utf8size(g.c);
@@ -1814,11 +1829,14 @@ xdrawcursor(void) {
 		xdraws(g.c, g, term.c.x, term.c.y, 1, sl);
 		oldx = term.c.x, oldy = term.c.y;
 	}
+
+	xcopy(term.c.x, term.c.y, 1, 1);
 }
 
 void
 draw() {
 	drawregion(0, 0, term.col, term.row);
+	gettimeofday(&xw.lastdraw, NULL);
 }
 
 void
@@ -1859,9 +1877,9 @@ drawregion(int x1, int y1, int x2, int y2) {
 		}
 		if(ib > 0)
 			xdraws(buf, base, ox, y, ic, ib);
+		xcopy(0, y, term.col, 1);
 	}
 	xdrawcursor();
-	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, x1*xw.cw, y1*xw.ch, x2*xw.cw, y2*xw.ch, BORDER, BORDER);
 }
 
 void
@@ -2006,25 +2024,42 @@ resize(XEvent *e) {
 	xresize(col, row);
 }
 
+int
+last_draw_too_old(void) {
+	struct timeval now;
+	gettimeofday(&now, NULL);
+	return TIMEDIFF(now, xw.lastdraw) >= PRINT_TIMEOUT/1000;
+}
+
 void
 run(void) {
 	XEvent ev;
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dpy);
-
+	struct timeval timeout = {0};
+	int stuff_to_print = 0;
+	
 	for(;;) {
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);
-		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL) < 0) {
+		timeout.tv_sec  = 0;
+		timeout.tv_usec = SELECT_TIMEOUT;
+		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, &timeout) < 0) {
 			if(errno == EINTR)
 				continue;
 			die("select failed: %s\n", SERRNO);
 		}
 		if(FD_ISSET(cmdfd, &rfd)) {
 			ttyread();
+			stuff_to_print = 1;
+		}
+
+		if(stuff_to_print && last_draw_too_old()) {
+			stuff_to_print = 0;
 			draw();
 		}
+
 		while(XPending(xw.dpy)) {
 			XNextEvent(xw.dpy, &ev);
 			if(XFilterEvent(&ev, xw.win))
@@ -2050,7 +2085,7 @@ main(int argc, char *argv[]) {
 		case 'w':
 			if(++i < argc) opt_embed = argv[i];
 			break;
-		case 'e': 
+		case 'e':
 			/* eat every remaining arguments */
 			if(++i < argc) opt_cmd = &argv[i];
 			goto run;

From df54ab040509829b4baec1673e4b158038ff983d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sat, 21 Jan 2012 23:26:53 +0100
Subject: [PATCH 0218/1146] fix PRINT/DRAW _TIMEOUT and fix redrawing bug.

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index c543bb1..f56667b 100644
--- a/st.c
+++ b/st.c
@@ -1888,7 +1888,7 @@ expose(XEvent *ev) {
 	if(xw.state & WIN_REDRAW) {
 		if(!e->count) {
 			xw.state &= ~WIN_REDRAW;
-			draw();
+			xcopy(0, 0, term.col, term.row);
 		}
 	} else
 		XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, e->x-BORDER, e->y-BORDER,
@@ -2028,7 +2028,7 @@ int
 last_draw_too_old(void) {
 	struct timeval now;
 	gettimeofday(&now, NULL);
-	return TIMEDIFF(now, xw.lastdraw) >= PRINT_TIMEOUT/1000;
+	return TIMEDIFF(now, xw.lastdraw) >= DRAW_TIMEOUT/1000;
 }
 
 void

From bcb7ec68c2780a65d0d362bafd3690b2a8f5473e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Sat, 21 Jan 2012 23:43:03 +0100
Subject: [PATCH 0219/1146] cosmetic, whitespace, etc.

---
 st.c | 79 ++++++++++++++++++++++++++++++++----------------------------
 1 file changed, 42 insertions(+), 37 deletions(-)

diff --git a/st.c b/st.c
index f56667b..b1db093 100644
--- a/st.c
+++ b/st.c
@@ -6,6 +6,7 @@
 #include <limits.h>
 #include <locale.h>
 #include <stdarg.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -79,6 +80,10 @@ enum { WIN_VISIBLE=1, WIN_REDRAW=2, WIN_FOCUSED=4 };
 #undef B0
 enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 };
 
+typedef unsigned char uchar;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
 typedef struct {
 	char c[UTF_SIZ];     /* character code */
 	char mode;  /* attribute flags */
@@ -113,7 +118,7 @@ typedef struct {
 	int col;	/* nb col */
 	Line* line;	/* screen */
 	Line* alt;	/* alternate screen */
-	char* dirty; /* dirtyness of lines */
+	bool* dirty; /* dirtyness of lines */
 	TCursor c;	/* cursor */
 	int top;	/* top    scroll limit */
 	int bot;	/* bottom scroll limit */
@@ -145,13 +150,13 @@ typedef struct {
 
 typedef struct {
 	KeySym k;
-	unsigned int mask;
+	uint mask;
 	char s[ESC_BUF_SIZ];
 } Key;
 
 /* Drawing Context */
 typedef struct {
-	unsigned long col[256];
+	ulong col[256];
 	GC gc;
 	struct {
 		int ascent;
@@ -182,7 +187,7 @@ static void drawregion(int, int, int, int);
 static void execsh(void);
 static void sigchld(int);
 static void run(void);
-static int last_draw_too_old(void);
+static bool last_draw_too_old(void);
 
 static void csidump(void);
 static void csihandle(void);
@@ -229,7 +234,7 @@ static void xresize(int, int);
 static void expose(XEvent *);
 static void visibility(XEvent *);
 static void unmap(XEvent *);
-static char* kmap(KeySym, unsigned int);
+static char* kmap(KeySym, uint);
 static void kpress(XEvent *);
 static void cmessage(XEvent *);
 static void resize(XEvent *);
@@ -241,7 +246,7 @@ static void selnotify(XEvent *);
 static void selrequest(XEvent *);
 
 static void selinit(void);
-static inline int selected(int, int);
+static inline bool selected(int, int);
 static void selcopy(void);
 static void selpaste();
 static void selscroll(int, int);
@@ -282,31 +287,31 @@ static char *opt_class = NULL;
 
 int
 utf8decode(char *s, long *u) {
-	unsigned char c;
+	uchar c;
 	int i, n, rtn;
 
 	rtn = 1;
 	c = *s;
-	if(~c&B7) { /* 0xxxxxxx */
+	if(~c & B7) { /* 0xxxxxxx */
 		*u = c;
 		return rtn;
-	} else if((c&(B7|B6|B5)) == (B7|B6)) { /* 110xxxxx */
+	} else if((c & (B7|B6|B5)) == (B7|B6)) { /* 110xxxxx */
 		*u = c&(B4|B3|B2|B1|B0);
 		n = 1;
-	} else if((c&(B7|B6|B5|B4)) == (B7|B6|B5)) { /* 1110xxxx */
+	} else if((c & (B7|B6|B5|B4)) == (B7|B6|B5)) { /* 1110xxxx */
 		*u = c&(B3|B2|B1|B0);
 		n = 2;
-	} else if((c&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4)) { /* 11110xxx */
-		*u = c&(B2|B1|B0);
+	} else if((c & (B7|B6|B5|B4|B3)) == (B7|B6|B5|B4)) { /* 11110xxx */
+		*u = c & (B2|B1|B0);
 		n = 3;
 	} else
 		goto invalid;
-	for(i=n,++s; i>0; --i,++rtn,++s) {
+	for(i = n, ++s; i > 0; --i, ++rtn, ++s) {
 		c = *s;
-		if((c&(B7|B6)) != B7) /* 10xxxxxx */
+		if((c & (B7|B6)) != B7) /* 10xxxxxx */
 			goto invalid;
 		*u <<= 6;
-		*u |= c&(B5|B4|B3|B2|B1|B0);
+		*u |= c & (B5|B4|B3|B2|B1|B0);
 	}
 	if((n == 1 && *u < 0x80) ||
 	   (n == 2 && *u < 0x800) ||
@@ -321,11 +326,11 @@ invalid:
 
 int
 utf8encode(long *u, char *s) {
-	unsigned char *sp;
-	unsigned long uc;
+	uchar *sp;
+	ulong uc;
 	int i, n;
 
-	sp = (unsigned char*) s;
+	sp = (uchar*) s;
 	uc = *u;
 	if(uc < 0x80) {
 		*sp = uc; /* 0xxxxxxx */
@@ -357,11 +362,11 @@ invalid:
    UTF-8 otherwise return 0 */
 int
 isfullutf8(char *s, int b) {
-	unsigned char *c1, *c2, *c3;
+	uchar *c1, *c2, *c3;
 
-	c1 = (unsigned char *) s;
-	c2 = (unsigned char *) ++s;
-	c3 = (unsigned char *) ++s;
+	c1 = (uchar *) s;
+	c2 = (uchar *) ++s;
+	c3 = (uchar *) ++s;
 	if(b < 1)
 		return 0;
 	else if((*c1&(B7|B6|B5)) == (B7|B6) && b == 1)
@@ -381,7 +386,7 @@ isfullutf8(char *s, int b) {
 
 int
 utf8size(char *s) {
-	unsigned char c = *s;
+	uchar c = *s;
 
 	if(~c&B7)
 		return 1;
@@ -405,7 +410,7 @@ selinit(void) {
 		sel.xtarget = XA_STRING;
 }
 
-static inline int
+static inline bool
 selected(int x, int y) {
 	if(sel.ey == y && sel.by == y) {
 		int bx = MIN(sel.bx, sel.ex);
@@ -504,9 +509,9 @@ selcopy(void) {
 
 void
 selnotify(XEvent *e) {
-	unsigned long nitems, ofs, rem;
+	ulong nitems, ofs, rem;
 	int format;
-	unsigned char *data;
+	uchar *data;
 	Atom type;
 
 	ofs = 0;
@@ -550,12 +555,12 @@ selrequest(XEvent *e) {
 		Atom string = sel.xtarget;
 		XChangeProperty(xsre->display, xsre->requestor, xsre->property,
 				XA_ATOM, 32, PropModeReplace,
-				(unsigned char *) &string, 1);
+				(uchar *) &string, 1);
 		xev.property = xsre->property;
 	} else if(xsre->target == sel.xtarget && sel.clip != NULL) {
 		XChangeProperty(xsre->display, xsre->requestor, xsre->property,
 				xsre->target, 8, PropModeReplace,
-				(unsigned char *) sel.clip, strlen(sel.clip));
+				(uchar *) sel.clip, strlen(sel.clip));
 		xev.property = xsre->property;
 	}
 
@@ -636,7 +641,7 @@ bmotion(XEvent *e) {
 		if(oldey != sel.ey || oldex != sel.ex) {
 			int starty = MIN(oldey, sel.ey);
 			int endy = MAX(oldey, sel.ey);
-			for(int i=starty; i<=endy; i++)
+			for(int i = starty; i <= endy; i++)
 				term.dirty[i] = 1;
 			draw();
 		}
@@ -1444,7 +1449,7 @@ tputc(char *c) {
 				break;
 			default:
 				fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
-				    (unsigned char) ascii, isprint(ascii)?ascii:'.');
+				    (uchar) ascii, isprint(ascii)?ascii:'.');
 				term.esc = 0;
 			}
 		}
@@ -1582,7 +1587,7 @@ void
 xloadcols(void) {
 	int i, r, g, b;
 	XColor color;
-	unsigned long white = WhitePixel(xw.dpy, xw.scr);
+	ulong white = WhitePixel(xw.dpy, xw.scr);
 
 	for(i = 0; i < LEN(colorname); i++) {
 		if(!XAllocNamedColor(xw.dpy, xw.cmap, colorname[i], &color, &color)) {
@@ -1756,7 +1761,7 @@ xinit(void) {
 
 void
 xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
-	unsigned long xfg = dc.col[base.fg], xbg = dc.col[base.bg], temp;
+	ulong xfg = dc.col[base.fg], xbg = dc.col[base.bg], temp;
 	int winx = x*xw.cw, winy = y*xw.ch + dc.font.ascent, width = charlen*xw.cw;
 	int i;
 	
@@ -1776,7 +1781,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 	if(base.mode & ATTR_GFX) {
 		for(i = 0; i < bytelen; i++) {
-			char c = gfx[(unsigned int)s[i] % 256];
+			char c = gfx[(uint)s[i] % 256];
 			if(c)
 				s[i] = c;
 			else if(s[i] > 0x5f)
@@ -1929,11 +1934,11 @@ focus(XEvent *ev) {
 }
 
 char*
-kmap(KeySym k, unsigned int state) {
+kmap(KeySym k, uint state) {
 	int i;
 	state &= ~Mod2Mask;
 	for(i = 0; i < LEN(key); i++) {
-		unsigned int mask = key[i].mask;
+		uint mask = key[i].mask;
 		if(key[i].k == k && ((state & mask) == mask || (mask == XK_NO_MOD && !state)))
 			return (char*)key[i].s;
 	}
@@ -2024,7 +2029,7 @@ resize(XEvent *e) {
 	xresize(col, row);
 }
 
-int
+bool
 last_draw_too_old(void) {
 	struct timeval now;
 	gettimeofday(&now, NULL);
@@ -2037,7 +2042,7 @@ run(void) {
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dpy);
 	struct timeval timeout = {0};
-	int stuff_to_print = 0;
+	bool stuff_to_print = 0;
 	
 	for(;;) {
 		FD_ZERO(&rfd);

From b6b90253b88f6787804c5ced60d48e37394512f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Tue, 7 Feb 2012 23:53:45 +0100
Subject: [PATCH 0220/1146] Added tag 0.2 for changeset 3c2f9f2ab5e4

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 4959fd3..a57f1d5 100644
--- a/.hgtags
+++ b/.hgtags
@@ -1,2 +1,3 @@
 cbc18c988236c63a58ed24031805e8d36a3ad01a 0.1
 f245ac2efd8ac2f1ac6bffae876c2663e794f79d 0.1.1
+3c2f9f2ab5e433db1401047760ec31d66939b74b 0.2

From cee6ccc6ee21fb6a4e4e04c2727aec26b7d47e07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 8 Feb 2012 16:45:52 +0100
Subject: [PATCH 0221/1146] reduce size of each glyph for faster copy.

---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index b1db093..98cd78a 100644
--- a/st.c
+++ b/st.c
@@ -86,10 +86,10 @@ typedef unsigned long ulong;
 
 typedef struct {
 	char c[UTF_SIZ];     /* character code */
-	char mode;  /* attribute flags */
-	int fg;     /* foreground      */
-	int bg;     /* background      */
-	char state; /* state flags     */
+	uchar mode;  /* attribute flags */
+	uchar fg;     /* foreground      */
+	uchar bg;     /* background      */
+	uchar state; /* state flags     */
 } Glyph;
 
 typedef Glyph* Line;

From b11e22df7d965fb5dff0954623e55093b50d3a62 Mon Sep 17 00:00:00 2001
From: "anselm@garbe.us" <unknown>
Date: Sat, 11 Feb 2012 10:48:18 +0100
Subject: [PATCH 0222/1146] some minor fixes

---
 LICENSE   | 2 +-
 config.mk | 2 +-
 st.c      | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/LICENSE b/LICENSE
index ee32d28..a8336d7 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2009, Aurélien APTEL <aurelien dot aptel at gmail dot com>
+Copyright (c) 2009-2012, Aurélien APTEL <aurelien dot aptel at gmail dot com>
 Copyright (c) 2009, Anselm R Garbe <garbeam at gmail dot com>
 
 Redistribution and use in source and binary forms, with or without
diff --git a/config.mk b/config.mk
index ea5b5ef..5729e59 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.1.1
+VERSION = 0.2-tip
 
 # Customize below to fit your system
 
diff --git a/st.c b/st.c
index b1db093..abaa7bf 100644
--- a/st.c
+++ b/st.c
@@ -34,7 +34,7 @@
 #endif
 
 #define USAGE \
-	"st " VERSION " (c) 2010-2011 st engineers\n" \
+	"st " VERSION " (c) 2010-2012 st engineers\n" \
 	"usage: st [-t title] [-c class] [-w windowid] [-v] [-e command...]\n"
 
 /* XEMBED messages */

From 33558ca042357ee7387b7c0ba9574af1106c4037 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 15 Feb 2012 19:10:31 +0100
Subject: [PATCH 0223/1146] handle dim/bright colors.

---
 st.c | 35 +++++++++++++++++------------------
 1 file changed, 17 insertions(+), 18 deletions(-)

diff --git a/st.c b/st.c
index fca97ce..627e566 100644
--- a/st.c
+++ b/st.c
@@ -1341,14 +1341,8 @@ csihandle(void) {
 
 void
 csidump(void) {
-	int i;
-	printf("ESC [ %s", escseq.priv ? "? " : "");
-	if(escseq.narg)
-		for(i = 0; i < escseq.narg; i++)
-			printf("%d ", escseq.arg[i]);
-	if(escseq.mode)
-		putchar(escseq.mode);
-	putchar('\n');
+	fwrite("\033[", 1, 2, stdout);
+	fwrite(escseq.buf, 1, escseq.len, stdout);
 }
 
 void
@@ -1761,23 +1755,29 @@ xinit(void) {
 
 void
 xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
-	ulong xfg = dc.col[base.fg], xbg = dc.col[base.bg], temp;
+	int fg = base.fg, bg = base.bg, temp;
 	int winx = x*xw.cw, winy = y*xw.ch + dc.font.ascent, width = charlen*xw.cw;
+	XFontSet fontset = dc.font.set;
 	int i;
 	
 	/* only switch default fg/bg if term is in RV mode */
 	if(IS_SET(MODE_REVERSE)) {
-		if(base.fg == DefaultFG)
-			xfg = dc.col[DefaultBG];
-		if(base.bg == DefaultBG)
-			xbg = dc.col[DefaultFG];
+		if(fg == DefaultFG)
+			fg = DefaultBG;
+		if(bg == DefaultBG)
+			bg = DefaultFG;
 	}
 
 	if(base.mode & ATTR_REVERSE)
-		temp = xfg, xfg = xbg, xbg = temp;
+		temp = fg, fg = bg, bg = temp;
 
-	XSetBackground(xw.dpy, dc.gc, xbg);
-	XSetForeground(xw.dpy, dc.gc, xfg);
+	if(base.mode & ATTR_BOLD) {
+		fg += 8;
+		fontset = dc.bfont.set;
+	}
+
+	XSetBackground(xw.dpy, dc.gc, dc.col[bg]);
+	XSetForeground(xw.dpy, dc.gc, dc.col[fg]);
 
 	if(base.mode & ATTR_GFX) {
 		for(i = 0; i < bytelen; i++) {
@@ -1789,8 +1789,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		}
 	}
 
-	XmbDrawImageString(xw.dpy, xw.buf, base.mode & ATTR_BOLD ? dc.bfont.set : dc.font.set,
-		dc.gc, winx, winy, s, bytelen);
+	XmbDrawImageString(xw.dpy, xw.buf, fontset, dc.gc, winx, winy, s, bytelen);
 	
 	if(base.mode & ATTR_UNDERLINE)
 		XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);

From d8e11bdb0ecbccbaab7d944a577b9557ccff5d52 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 15 Feb 2012 19:11:07 +0100
Subject: [PATCH 0224/1146] document possible configuration.

---
 config.def.h | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index 35f36cb..f1bd91e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,12 +1,16 @@
-#define TAB 8
-#define TNAME "st-256color"
+
 #define FONT "-*-*-medium-r-*-*-*-120-75-75-*-60-*-*"
 #define BOLDFONT "-*-*-bold-r-*-*-*-120-75-75-*-60-*-*"
+
+/* Space in pixels around the terminal buffer */
 #define BORDER 2
+
+/* Default shell to use if SHELL is not set in the env */
 #define SHELL "/bin/sh"
 
 /* Terminal colors (16 first used in escape sequence) */
 static const char *colorname[] = {
+	/* 8 normal colors */
 	"black",
 	"red3",
 	"green3",
@@ -15,6 +19,8 @@ static const char *colorname[] = {
 	"magenta3",
 	"cyan3",
 	"gray90",
+
+	/* 8 bright colors */
 	"gray50",
 	"red",
 	"green",
@@ -22,14 +28,17 @@ static const char *colorname[] = {
 	"#5c5cff",
 	"magenta",
 	"cyan",
-	"white"
+	"white",
+	
+	/* more colors can be added to use with DefaultXX */
+	"#cccccc",
 };
 
 /* Default colors (colorname index)
    foreground, background, cursor   */
 #define DefaultFG 7
 #define DefaultBG 0
-#define DefaultCS 1
+#define DefaultCS 16
 
 /* Special keys (change & recompile st.info accordingly)
    Keep in mind that kpress() in st.c hardcodes some keys.
@@ -61,6 +70,9 @@ static Key key[] = {
 	{ XK_F12,       XK_NO_MOD, "\033[24~" },
 };
 
+/* Set TERM to this */
+#define TNAME "st-256color"
+
 /* Line drawing characters (sometime specific to each font...) */
 static char gfx[] = {
 	['f'] = 'o',
@@ -72,3 +84,5 @@ static char gfx[] = {
 /* double-click timeout (in milliseconds) between clicks for selection */
 #define DOUBLECLICK_TIMEOUT 300
 #define TRIPLECLICK_TIMEOUT (2*DOUBLECLICK_TIMEOUT)
+
+#define TAB 8

From be2877cd042eaf5d0f7dda102f526357aa577232 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 15 Feb 2012 19:33:48 +0100
Subject: [PATCH 0225/1146] show dark cursor when unfocused.

---
 TODO         |  7 ++++++-
 config.def.h | 10 ++++++----
 st.c         |  8 ++++++--
 3 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/TODO b/TODO
index 62a9f42..311d9ca 100644
--- a/TODO
+++ b/TODO
@@ -10,10 +10,15 @@ code & interface
 
 * clean selection code
 * clean and complete terminfo entry
-* fix shift up/down (shift selection in emacs)
 * fast drawing
 * ...
 
+bugs
+----
+
+* handle XOpenMI() errors
+* fix shift up/down (shift selection in emacs)
+
 misc
 ----
 
diff --git a/config.def.h b/config.def.h
index f1bd91e..169bcdd 100644
--- a/config.def.h
+++ b/config.def.h
@@ -32,13 +32,15 @@ static const char *colorname[] = {
 	
 	/* more colors can be added to use with DefaultXX */
 	"#cccccc",
+	"#333333",
 };
 
 /* Default colors (colorname index)
-   foreground, background, cursor   */
-#define DefaultFG 7
-#define DefaultBG 0
-#define DefaultCS 16
+   foreground, background, cursor, unfocused cursor */
+#define DefaultFG  7
+#define DefaultBG  0
+#define DefaultCS  16
+#define DefaultUCS 17
 
 /* Special keys (change & recompile st.info accordingly)
    Keep in mind that kpress() in st.c hardcodes some keys.
diff --git a/st.c b/st.c
index 627e566..a86e0f9 100644
--- a/st.c
+++ b/st.c
@@ -1826,10 +1826,14 @@ xdrawcursor(void) {
 	xcopy(oldx, oldy, 1, 1);
 
 	/* draw the new one */
-	if(!(term.c.state & CURSOR_HIDE) && (xw.state & WIN_FOCUSED)) {
-		sl = utf8size(g.c);
+	if(!(term.c.state & CURSOR_HIDE)) {
+		if(!(xw.state & WIN_FOCUSED))
+			g.bg = DefaultUCS;
+
 		if(IS_SET(MODE_REVERSE))
 			g.mode |= ATTR_REVERSE, g.fg = DefaultCS, g.bg = DefaultFG;
+
+		sl = utf8size(g.c);
 		xdraws(g.c, g, term.c.x, term.c.y, 1, sl);
 		oldx = term.c.x, oldy = term.c.y;
 	}

From 751fb765e4f26ce1500b4e8ee9f4cd5b6039b495 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 16 Feb 2012 00:10:32 +0100
Subject: [PATCH 0226/1146] fix default color overwriten bug.

---
 config.def.h |  8 +++++---
 st.c         | 41 +++++++++++++++++++++++------------------
 2 files changed, 28 insertions(+), 21 deletions(-)

diff --git a/config.def.h b/config.def.h
index 169bcdd..047b5d1 100644
--- a/config.def.h
+++ b/config.def.h
@@ -30,7 +30,9 @@ static const char *colorname[] = {
 	"cyan",
 	"white",
 	
-	/* more colors can be added to use with DefaultXX */
+	[255] = 0,
+	
+	/* more colors can be added after 255 to use with DefaultXX */
 	"#cccccc",
 	"#333333",
 };
@@ -39,8 +41,8 @@ static const char *colorname[] = {
    foreground, background, cursor, unfocused cursor */
 #define DefaultFG  7
 #define DefaultBG  0
-#define DefaultCS  16
-#define DefaultUCS 17
+#define DefaultCS  256
+#define DefaultUCS 257
 
 /* Special keys (change & recompile st.info accordingly)
    Keep in mind that kpress() in st.c hardcodes some keys.
diff --git a/st.c b/st.c
index a86e0f9..e6a5e4e 100644
--- a/st.c
+++ b/st.c
@@ -83,13 +83,14 @@ enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 };
 typedef unsigned char uchar;
 typedef unsigned int uint;
 typedef unsigned long ulong;
+typedef unsigned short ushort;
 
 typedef struct {
 	char c[UTF_SIZ];     /* character code */
 	uchar mode;  /* attribute flags */
-	uchar fg;     /* foreground      */
-	uchar bg;     /* background      */
-	uchar state; /* state flags     */
+	ushort fg;   /* foreground  */
+	ushort bg;   /* background  */
+	uchar state; /* state flags    */
 } Glyph;
 
 typedef Glyph* Line;
@@ -154,18 +155,6 @@ typedef struct {
 	char s[ESC_BUF_SIZ];
 } Key;
 
-/* Drawing Context */
-typedef struct {
-	ulong col[256];
-	GC gc;
-	struct {
-		int ascent;
-		int descent;
-		short lbearing;
-		short rbearing;
-		XFontSet set;
-	} font, bfont;
-} DC;
 
 /* TODO: use better name for vars... */
 typedef struct {
@@ -181,6 +170,19 @@ typedef struct {
 
 #include "config.h"
 
+/* Drawing Context */
+typedef struct {
+	ulong col[LEN(colorname) < 256 ? 256 : LEN(colorname)];
+	GC gc;
+	struct {
+		int ascent;
+		int descent;
+		short lbearing;
+		short rbearing;
+		XFontSet set;
+	} font, bfont;
+} DC;
+
 static void die(const char*, ...);
 static void draw(void);
 static void drawregion(int, int, int, int);
@@ -1583,16 +1585,19 @@ xloadcols(void) {
 	XColor color;
 	ulong white = WhitePixel(xw.dpy, xw.scr);
 
+	/* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */
 	for(i = 0; i < LEN(colorname); i++) {
+		if(!colorname[i])
+			continue;
 		if(!XAllocNamedColor(xw.dpy, xw.cmap, colorname[i], &color, &color)) {
 			dc.col[i] = white;
 			fprintf(stderr, "Could not allocate color '%s'\n", colorname[i]);
 		} else
 			dc.col[i] = color.pixel;
 	}
-
-	/* same colors as xterm */
-	for(r = 0; r < 6; r++)
+	
+	/* load colors [16-255] ; same colors as xterm */
+	for(i = 16, r = 0; r < 6; r++)
 		for(g = 0; g < 6; g++)
 			for(b = 0; b < 6; b++) {
 				color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r;

From 53ac69e90d95e52dedf99129e39a993d45c812ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 16 Feb 2012 00:33:11 +0100
Subject: [PATCH 0227/1146] clean and name enum definitions.

---
 st.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 54 insertions(+), 10 deletions(-)

diff --git a/st.c b/st.c
index e6a5e4e..89d123c 100644
--- a/st.c
+++ b/st.c
@@ -66,17 +66,61 @@
 #define X2COL(x) (((x) - BORDER)/xw.cw)
 #define Y2ROW(y) (((y) - BORDER)/xw.ch)
 
-/* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
-enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 };
-enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT,
-       CURSOR_SAVE, CURSOR_LOAD };
-enum { CURSOR_DEFAULT = 0, CURSOR_HIDE = 1, CURSOR_WRAPNEXT = 2 };
-enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
-enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8,
-       MODE_CRLF=16, MODE_MOUSEBTN=32, MODE_MOUSEMOTION=64, MODE_MOUSE=32|64, MODE_REVERSE=128 };
-enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
-enum { WIN_VISIBLE=1, WIN_REDRAW=2, WIN_FOCUSED=4 };
+enum glyph_attribute {
+	ATTR_NULL      = 0,
+	ATTR_REVERSE   = 1,
+	ATTR_UNDERLINE = 2,
+	ATTR_BOLD      = 4,
+	ATTR_GFX       = 8,
+};
 
+enum cursor_movement {
+	CURSOR_UP,
+	CURSOR_DOWN,
+	CURSOR_LEFT,
+	CURSOR_RIGHT,
+	CURSOR_SAVE,
+	CURSOR_LOAD
+};
+
+enum cursor_state {
+	CURSOR_DEFAULT  = 0,
+	CURSOR_HIDE     = 1,
+	CURSOR_WRAPNEXT = 2
+};
+
+enum glyph_state {
+	GLYPH_SET   = 1,
+	GLYPH_DIRTY = 2
+};
+
+enum term_mode {
+	MODE_WRAP        = 1,
+	MODE_INSERT      = 2,
+	MODE_APPKEYPAD   = 4,
+	MODE_ALTSCREEN   = 8,
+	MODE_CRLF        = 16,
+	MODE_MOUSEBTN    = 32,
+	MODE_MOUSEMOTION = 64,
+	MODE_MOUSE       = 32|64,
+	MODE_REVERSE     = 128
+};
+
+enum escape_state {
+	ESC_START      = 1,
+	ESC_CSI        = 2,
+	ESC_OSC        = 4,
+	ESC_TITLE      = 8,
+	ESC_ALTCHARSET = 16
+};
+
+enum window_state {
+	WIN_VISIBLE = 1,
+	WIN_REDRAW  = 2,
+	WIN_FOCUSED = 4
+};
+
+/* bit macro */
 #undef B0
 enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 };
 

From cb2e0e9c31a510cd6cdbbd3b0da231157a975d95 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 16 Feb 2012 00:58:16 +0100
Subject: [PATCH 0228/1146] rewrite csidump().

---
 st.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 89d123c..3b7eb78 100644
--- a/st.c
+++ b/st.c
@@ -1387,8 +1387,17 @@ csihandle(void) {
 
 void
 csidump(void) {
-	fwrite("\033[", 1, 2, stdout);
-	fwrite(escseq.buf, 1, escseq.len, stdout);
+	int i;
+	fwrite("ESC[", 1, 4, stdout);
+	for(i = 0; i < escseq.len; i++) {
+		uint c = escseq.buf[i] & 0xff;
+		if(isprint(c)) putchar(c);
+		else if(c == '\n') printf("(\\n)");
+		else if(c == '\r') printf("(\\r)");
+		else if(c == 0x1b) printf("(\\e)");
+		else printf("(%02x)", c);
+	}
+	putchar('\n');
 }
 
 void

From ff5edcfd7055102c46098f18adf1b469eec7caef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 16 Feb 2012 00:59:26 +0100
Subject: [PATCH 0229/1146] replace fwrite by printf.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 3b7eb78..baea2bc 100644
--- a/st.c
+++ b/st.c
@@ -1388,7 +1388,7 @@ csihandle(void) {
 void
 csidump(void) {
 	int i;
-	fwrite("ESC[", 1, 4, stdout);
+	printf("ESC[");
 	for(i = 0; i < escseq.len; i++) {
 		uint c = escseq.buf[i] & 0xff;
 		if(isprint(c)) putchar(c);

From 970d44a60db7b64279e1c14d8750253580feecaa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 16 Feb 2012 01:05:14 +0100
Subject: [PATCH 0230/1146] bump version.

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 5729e59..6b5dba0 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.2-tip
+VERSION = 0.2.1
 
 # Customize below to fit your system
 

From 83b06565889ff7bae8f335effec80d7da53b2214 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 16 Feb 2012 01:05:26 +0100
Subject: [PATCH 0231/1146] Added tag 0.2.1 for changeset 108926a0fe61

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index a57f1d5..977dd47 100644
--- a/.hgtags
+++ b/.hgtags
@@ -1,3 +1,4 @@
 cbc18c988236c63a58ed24031805e8d36a3ad01a 0.1
 f245ac2efd8ac2f1ac6bffae876c2663e794f79d 0.1.1
 3c2f9f2ab5e433db1401047760ec31d66939b74b 0.2
+108926a0fe610b92c0296148721c3225932f39aa 0.2.1

From 7823aeb1f9eb5b7a77b42506f5f60a5743f7f71f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 16 Feb 2012 01:06:45 +0100
Subject: [PATCH 0232/1146] revert to "tip" in VERSION.

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 6b5dba0..082a295 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.2.1
+VERSION = 0.2.1-tip
 
 # Customize below to fit your system
 

From 6c0a1eff2fb2419b9bbfb545d0cf21a2e524efb2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Thu, 16 Feb 2012 19:24:46 +0100
Subject: [PATCH 0233/1146] use SHELL as default shell.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index baea2bc..741e680 100644
--- a/st.c
+++ b/st.c
@@ -709,7 +709,7 @@ execsh(void) {
 	char **args;
 	char *envshell = getenv("SHELL");
 
-	DEFAULT(envshell, "sh");
+	DEFAULT(envshell, SHELL);
 	putenv("TERM="TNAME);
 	args = opt_cmd ? opt_cmd : (char*[]){envshell, "-i", NULL};
 	execvp(args[0], args);

From cfea72c7b48261006079a327a9ce1adbe2bdc3e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Mon, 27 Feb 2012 12:44:02 +0100
Subject: [PATCH 0234/1146] cleanup. refactored dirt-related function.

---
 st.c | 50 +++++++++++++++++++++++++++++++++-----------------
 1 file changed, 33 insertions(+), 17 deletions(-)

diff --git a/st.c b/st.c
index 741e680..4dc1c5a 100644
--- a/st.c
+++ b/st.c
@@ -259,6 +259,7 @@ static void tsetattr(int*, int);
 static void tsetchar(char*);
 static void tsetscroll(int, int);
 static void tswapscreen(void);
+static void tsetdirt(int, int);
 static void tfulldirt(void);
 
 static void ttynew(void);
@@ -446,8 +447,8 @@ utf8size(char *s) {
 
 void
 selinit(void) {
-	sel.tclick1.tv_sec = 0;
-	sel.tclick1.tv_usec = 0;
+	memset(&sel.tclick1, 0, sizeof(sel.tclick1));
+	memset(&sel.tclick2, 0, sizeof(sel.tclick2));
 	sel.mode = 0;
 	sel.bx = -1;
 	sel.clip = NULL;
@@ -520,8 +521,7 @@ bpress(XEvent *e) {
 		mousereport(e);
 	else if(e->xbutton.button == Button1) {
 		if(sel.bx != -1)
-			for(int i=sel.b.y; i<=sel.e.y; i++)
-				term.dirty[i] = 1;
+			tsetdirt(sel.b.y, sel.e.y);
 		sel.mode = 1;
 		sel.ex = sel.bx = X2COL(e->xbutton.x);
 		sel.ey = sel.by = Y2ROW(e->xbutton.y);
@@ -531,21 +531,28 @@ bpress(XEvent *e) {
 void
 selcopy(void) {
 	char *str, *ptr;
-	int x, y, sz, sl, ls = 0;
+	int x, y, bufsize, is_selected = 0;
 
 	if(sel.bx == -1)
 		str = NULL;
+
 	else {
-		sz = (term.col+1) * (sel.e.y-sel.b.y+1) * UTF_SIZ;
-		ptr = str = malloc(sz);
+		bufsize = (term.col+1) * (sel.e.y-sel.b.y+1) * UTF_SIZ;
+		ptr = str = malloc(bufsize);
+
+		/* append every set & selected glyph to the selection */
 		for(y = 0; y < term.row; y++) {
-			for(x = 0; x < term.col; x++)
-				if(term.line[y][x].state & GLYPH_SET && (ls = selected(x, y))) {
-					sl = utf8size(term.line[y][x].c);
-					memcpy(ptr, term.line[y][x].c, sl);
-					ptr += sl;
+			for(x = 0; x < term.col; x++) {
+				is_selected = selected(x, y);
+				if((term.line[y][x].state & GLYPH_SET) && is_selected) {
+					int size = utf8size(term.line[y][x].c);
+					memcpy(ptr, term.line[y][x].c, size);
+					ptr += size;
 				}
-			if(ls && y < sel.e.y)
+			}
+
+			/* \n at the end of every selected line except for the last one */
+			if(is_selected && y < sel.e.y)
 				*ptr++ = '\n';
 		}
 		*ptr = 0;
@@ -687,8 +694,7 @@ bmotion(XEvent *e) {
 		if(oldey != sel.ey || oldex != sel.ex) {
 			int starty = MIN(oldey, sel.ey);
 			int endy = MAX(oldey, sel.ey);
-			for(int i = starty; i <= endy; i++)
-				term.dirty[i] = 1;
+			tsetdirt(starty, endy);
 			draw();
 		}
 	}
@@ -813,13 +819,23 @@ ttyresize(int x, int y) {
 }
 
 void
-tfulldirt(void)
+tsetdirt(int top, int bot)
 {
 	int i;
-	for(i = 0; i < term.row; i++)
+
+	LIMIT(top, 0, term.row-1);
+	LIMIT(bot, 0, term.row-1);
+
+	for(i = top; i <= bot; i++)
 		term.dirty[i] = 1;
 }
 
+void
+tfulldirt(void)
+{
+	tsetdirt(0, term.row-1);
+}
+
 void
 tcursor(int mode) {
 	static TCursor c;

From 8fdba7494fe33d3be1f6f96b8e900ef1bca01d47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Mon, 27 Feb 2012 12:48:13 +0100
Subject: [PATCH 0235/1146] update TODO.

---
 TODO | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/TODO b/TODO
index 311d9ca..ea37a96 100644
--- a/TODO
+++ b/TODO
@@ -18,6 +18,8 @@ bugs
 
 * handle XOpenMI() errors
 * fix shift up/down (shift selection in emacs)
+* fix selection click
+* fix selection paste for xatom STRING
 
 misc
 ----

From 94771d05886fbdd2422e66b7c0256ab27fa375cb Mon Sep 17 00:00:00 2001
From: Brandon Invergo <brandon@invergo.net>
Date: Sat, 28 Jul 2012 14:27:26 +0200
Subject: [PATCH 0236/1146] Implement Xdbe-based double-buffering

---
 config.mk |  2 +-
 st.c      | 50 ++++++++++++--------------------------------------
 2 files changed, 13 insertions(+), 39 deletions(-)

diff --git a/config.mk b/config.mk
index 082a295..4f273cd 100644
--- a/config.mk
+++ b/config.mk
@@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib
 
 # includes and libs
 INCS = -I. -I/usr/include -I${X11INC}
-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil
+LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext
 
 # flags
 CPPFLAGS = -DVERSION=\"${VERSION}\"
diff --git a/st.c b/st.c
index 4dc1c5a..0e82eaf 100644
--- a/st.c
+++ b/st.c
@@ -24,6 +24,7 @@
 #include <X11/Xutil.h>
 #include <X11/cursorfont.h>
 #include <X11/keysym.h>
+#include <X11/extensions/Xdbe.h>
 
 #if   defined(__linux)
  #include <pty.h>
@@ -178,7 +179,7 @@ typedef struct {
 	Display* dpy;
 	Colormap cmap;
 	Window win;
-	Pixmap buf;
+	XdbeBackBuffer buf;
 	Atom xembed;
 	XIM xim;
 	XIC xic;
@@ -270,7 +271,7 @@ static void ttywrite(const char *, size_t);
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
 static void xclear(int, int, int, int);
-static void xcopy(int, int, int, int);
+static void xcopy();
 static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
@@ -1620,32 +1621,8 @@ tresize(int col, int row) {
 
 void
 xresize(int col, int row) {
-	Pixmap newbuf;
-	int oldw, oldh;
-
-	oldw = xw.bufw;
-	oldh = xw.bufh;
 	xw.bufw = MAX(1, col * xw.cw);
 	xw.bufh = MAX(1, row * xw.ch);
-	newbuf = XCreatePixmap(xw.dpy, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dpy, xw.scr));
-	XCopyArea(xw.dpy, xw.buf, newbuf, dc.gc, 0, 0, xw.bufw, xw.bufh, 0, 0);
-	XFreePixmap(xw.dpy, xw.buf);
-	XSetForeground(xw.dpy, dc.gc, dc.col[DefaultBG]);
-	if(xw.bufw > oldw)
-		XFillRectangle(xw.dpy, newbuf, dc.gc, oldw, 0,
-				xw.bufw-oldw, MIN(xw.bufh, oldh));
-	else if(xw.bufw < oldw && (BORDER > 0 || xw.w > xw.bufw))
-		XClearArea(xw.dpy, xw.win, BORDER+xw.bufw, BORDER,
-				xw.w-xw.bufh-BORDER, BORDER+MIN(xw.bufh, oldh),
-				False);
-	if(xw.bufh > oldh)
-		XFillRectangle(xw.dpy, newbuf, dc.gc, 0, oldh,
-				xw.bufw, xw.bufh-oldh);
-	else if(xw.bufh < oldh && (BORDER > 0 || xw.h > xw.bufh))
-		XClearArea(xw.dpy, xw.win, BORDER, BORDER+xw.bufh,
-				xw.w-2*BORDER, xw.h-xw.bufh-BORDER,
-				False);
-	xw.buf = newbuf;
 }
 
 void
@@ -1801,7 +1778,7 @@ xinit(void) {
 			CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
 			| CWColormap,
 			&attrs);
-	xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dpy, xw.scr));
+	xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeCopied);
 
 
 	/* input methods */
@@ -1871,10 +1848,10 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 /* copy buffer pixmap to screen pixmap */
 void
-xcopy(int x, int y, int cols, int rows) {
-	int src_x = x*xw.cw, src_y = y*xw.ch, src_w = cols*xw.cw, src_h = rows*xw.ch;
-	int dst_x = BORDER+src_x, dst_y = BORDER+src_y;
-	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, src_x, src_y, src_w, src_h, dst_x, dst_y);
+xcopy() {
+        XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
+        XdbeSwapBuffers(xw.dpy, swpinfo, 1);
+
 }
 
 void
@@ -1918,6 +1895,7 @@ xdrawcursor(void) {
 void
 draw() {
 	drawregion(0, 0, term.col, term.row);
+	xcopy();
 	gettimeofday(&xw.lastdraw, NULL);
 }
 
@@ -1959,7 +1937,6 @@ drawregion(int x1, int y1, int x2, int y2) {
 		}
 		if(ib > 0)
 			xdraws(buf, base, ox, y, ic, ib);
-		xcopy(0, y, term.col, 1);
 	}
 	xdrawcursor();
 }
@@ -1968,13 +1945,10 @@ void
 expose(XEvent *ev) {
 	XExposeEvent *e = &ev->xexpose;
 	if(xw.state & WIN_REDRAW) {
-		if(!e->count) {
+		if(!e->count)
 			xw.state &= ~WIN_REDRAW;
-			xcopy(0, 0, term.col, term.row);
-		}
-	} else
-		XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, e->x-BORDER, e->y-BORDER,
-				e->width, e->height, e->x, e->y);
+        }
+        xcopy();
 }
 
 void

From c6853fe18564437fe0a4cb06565a0a7d63d40b5a Mon Sep 17 00:00:00 2001
From: Brandon Invergo <brandon@invergo.net>
Date: Fri, 3 Aug 2012 14:46:40 +0200
Subject: [PATCH 0237/1146] apply post-XDBE patch BORDER fix

---
 st.c | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/st.c b/st.c
index 0e82eaf..4fc4d3d 100644
--- a/st.c
+++ b/st.c
@@ -186,8 +186,6 @@ typedef struct {
 	int scr;
 	int w;	/* window width */
 	int h;	/* window height */
-	int bufw; /* pixmap width  */
-	int bufh; /* pixmap height */
 	int ch; /* char height */
 	int cw; /* char width  */
 	char state; /* focus, redraw, visible */
@@ -1621,8 +1619,8 @@ tresize(int col, int row) {
 
 void
 xresize(int col, int row) {
-	xw.bufw = MAX(1, col * xw.cw);
-	xw.bufh = MAX(1, row * xw.ch);
+	xw.w = MAX(1, 2*BORDER + col * xw.cw);
+	xw.h = MAX(1, 2*BORDER + row * xw.ch);
 }
 
 void
@@ -1671,7 +1669,7 @@ void
 xclear(int x1, int y1, int x2, int y2) {
 	XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? DefaultFG : DefaultBG]);
 	XFillRectangle(xw.dpy, xw.buf, dc.gc,
-	               x1 * xw.cw, y1 * xw.ch,
+	               BORDER + x1 * xw.cw, BORDER + y1 * xw.ch,
 	               (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
 }
 
@@ -1757,10 +1755,8 @@ xinit(void) {
 	xloadcols();
 
 	/* window - default size */
-	xw.bufh = term.row * xw.ch;
-	xw.bufw = term.col * xw.cw;
-	xw.h = xw.bufh + 2*BORDER;
-	xw.w = xw.bufw + 2*BORDER;
+	xw.h = 2*BORDER + term.row * xw.ch;
+	xw.w = 2*BORDER + term.col * xw.cw;
 
 	attrs.background_pixel = dc.col[DefaultBG];
 	attrs.border_pixel = dc.col[DefaultBG];
@@ -1807,7 +1803,7 @@ xinit(void) {
 void
 xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	int fg = base.fg, bg = base.bg, temp;
-	int winx = x*xw.cw, winy = y*xw.ch + dc.font.ascent, width = charlen*xw.cw;
+	int winx = BORDER+x*xw.cw, winy = BORDER+y*xw.ch + dc.font.ascent, width = charlen*xw.cw;
 	XFontSet fontset = dc.font.set;
 	int i;
 	

From ee7fd748ac7bfabda2ac37251d230b45adb3e138 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 29 Aug 2012 19:59:37 +0200
Subject: [PATCH 0238/1146] Add tabs field into Term struct

Tabs stop are simulated in st using a fixed size of 8, always, without be
worried about sequences changing the tab stops. A user can put a tab stop in
each horizontal position of the screen, so we need at least one flag for
each column of the screen. In the same way as dirty flags is used for the
rows, it is used a bool dinamic array.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c |   22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)
---
 st.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 4fc4d3d..d169ddf 100644
--- a/st.c
+++ b/st.c
@@ -164,7 +164,7 @@ typedef struct {
 	int col;	/* nb col */
 	Line* line;	/* screen */
 	Line* alt;	/* alternate screen */
-	bool* dirty; /* dirtyness of lines */
+	bool* dirty;	/* dirtyness of lines */
 	TCursor c;	/* cursor */
 	int top;	/* top    scroll limit */
 	int bot;	/* bottom scroll limit */
@@ -172,6 +172,7 @@ typedef struct {
 	int esc;	/* escape state flags */
 	char title[ESC_TITLE_SIZ];
 	int titlelen;
+	bool *tabs;
 } Term;
 
 /* Purely graphic info */
@@ -847,12 +848,16 @@ tcursor(int mode) {
 
 void
 treset(void) {
+	unsigned 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 = TAB; i < term.col; i += TAB)
+		term.tabs[i] = 1;
 	term.top = 0, term.bot = term.row - 1;
 	term.mode = MODE_WRAP;
 	tclearregion(0, 0, term.col-1, term.row-1);
@@ -865,12 +870,14 @@ tnew(int col, int row) {
 	term.line = malloc(term.row * sizeof(Line));
 	term.alt  = malloc(term.row * sizeof(Line));
 	term.dirty = malloc(term.row * sizeof(*term.dirty));
+	term.tabs = malloc(term.col * sizeof(*term.tabs));
 
 	for(row = 0; row < term.row; row++) {
 		term.line[row] = malloc(term.col * sizeof(Glyph));
 		term.alt [row] = malloc(term.col * sizeof(Glyph));
 		term.dirty[row] = 0;
 	}
+	memset(term.tabs, 0, term.col * sizeof(*term.tabs));
 	/* setup screen */
 	treset();
 }
@@ -1588,6 +1595,7 @@ tresize(int col, int row) {
 	term.line = realloc(term.line, row * sizeof(Line));
 	term.alt  = realloc(term.alt,  row * sizeof(Line));
 	term.dirty = realloc(term.dirty, row * sizeof(*term.dirty));
+	term.tabs = realloc(term.tabs, col * sizeof(*term.tabs));
 
 	/* resize each row to new width, zero-pad if needed */
 	for(i = 0; i < minrow; i++) {
@@ -1606,7 +1614,15 @@ tresize(int col, int row) {
 		term.line[i] = calloc(col, sizeof(Glyph));
 		term.alt [i] = calloc(col, sizeof(Glyph));
 	}
-	
+	if (col > term.col) {
+		bool *bp = term.tabs + term.col;
+
+		memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
+		while (--bp > term.tabs && !*bp)
+			/* nothing */ ;
+		for (bp += TAB; bp < term.tabs + col; bp += TAB)
+			*bp = 1;
+	}
 	/* update terminal size */
 	term.col = col, term.row = row;
 	/* make use of the LIMIT in tmoveto */

From 93901ca4fee8a1ab71cb8b918f3d65404460f9ce Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 29 Aug 2012 19:59:43 +0200
Subject: [PATCH 0239/1146] Add HTS sequence

This sequence adds a new tab stop in the current horizontal position. This
means that tputtab must be look for the next tab stop in the tabs array
instead of using a hard coded value offset. Also, CHT sequence XXX message
is removed because it is not a vt10x sequence (as far as I know it is a
vt50x sequence), and it is not implemented by linux virtual terminal neither
by xterm.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c |   12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
---
 st.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index d169ddf..4b7e4eb 100644
--- a/st.c
+++ b/st.c
@@ -1214,7 +1214,6 @@ csihandle(void) {
 		DEFAULT(escseq.arg[1], 1);
 		tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
 		break;
-	/* XXX: (CSI n I) CHT -- Cursor Forward Tabulation <n> tab stops */
 	case 'J': /* ED -- Clear screen */
 		sel.bx = -1;
 		switch(escseq.arg[0]) {
@@ -1429,8 +1428,11 @@ csireset(void) {
 
 void
 tputtab(void) {
-	int space = TAB - term.c.x % TAB;
-	tmoveto(term.c.x + space, term.c.y);
+	unsigned x;
+
+	for (x = term.c.x + 1; x < term.col && !term.tabs[x]; ++x)
+		/* nothing */ ;
+	tmoveto(x, term.c.y);
 }
 
 void
@@ -1491,6 +1493,10 @@ tputc(char *c) {
 				tnewline(1); /* always go to first col */
 				term.esc = 0;
 				break;
+			case 'H': /* HTS -- Horizontal tab stop */
+				term.tabs[term.c.x] = 1;
+				term.esc = 0;
+				break;
 			case 'M': /* RI -- Reverse index */
 				if(term.c.y == term.top)
 					tscrolldown(term.top, 1);

From c084c06b402de4fe995734a2c89cae26ff7c9064 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 29 Aug 2012 19:59:47 +0200
Subject: [PATCH 0240/1146] Add TBC sequence

This sequence clears tab stops in the terminal. If the argument is not present
or is zero, then removes the tab stop of the current horizontal position. If
the argument is 3 then removes all the tab stops of the terminal. It was
necessary modify the terminfo entry tbc, because it has \E[2g instead of the
correct \E[3g.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c    |   12 ++++++++++++
 st.info |    2 +-
 2 files changed, 13 insertions(+), 1 deletion(-)
---
 st.c    | 12 ++++++++++++
 st.info |  2 +-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 4b7e4eb..b7dfd55 100644
--- a/st.c
+++ b/st.c
@@ -1203,6 +1203,18 @@ csihandle(void) {
 		DEFAULT(escseq.arg[0], 1);
 		tmoveto(0, term.c.y-escseq.arg[0]);
 		break;
+	case 'g': /* TBC -- Tabulation clear */
+		switch (escseq.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 '`': /* XXX: HPA -- same? */
 		DEFAULT(escseq.arg[0], 1);
diff --git a/st.info b/st.info
index ea67039..d8e3d0d 100644
--- a/st.info
+++ b/st.info
@@ -97,7 +97,7 @@ st| simpleterm,
 	smcup=\E[?1049h,
 	smso=\E[7m,
 	smul=\E[4m,
-	tbc=\E[2g,
+	tbc=\E[3g,
 	tsl=\E]0;,
 	ul,
 	xenl,

From 12de47a93393e098d5d48333290a5710a543c3d6 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 29 Aug 2012 20:01:34 +0200
Subject: [PATCH 0241/1146] Applying the patches of k0ga and changing the
 LICENSE file in the appropriate

way.
---
 LICENSE | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/LICENSE b/LICENSE
index a8336d7..1b91f2a 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,6 @@
 Copyright (c) 2009-2012, Aurélien APTEL <aurelien dot aptel at gmail dot com>
+Copyright (c) 2012, Roberto E. Vargas Caballero <k0ga at shike2 dot com>
+Copyright (c) 2012, Christoph Lohmann <20h at r-36 dot net>
 Copyright (c) 2009, Anselm R Garbe <garbeam at gmail dot com>
 
 Redistribution and use in source and binary forms, with or without

From aaef13aaaaddbbf1e793b9df0e9cfc4d6d28d1b9 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 29 Aug 2012 20:05:25 +0200
Subject: [PATCH 0242/1146] Add CHT sequence

This sequence performs "Cursor Forward Tabulation <n> tab stops", which
although is not present in vt100 or vt102, xterm accepts it.
---
 st.c |    5 +++++
 1 file changed, 5 insertions(+)
---
 st.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/st.c b/st.c
index b7dfd55..b9bab29 100644
--- a/st.c
+++ b/st.c
@@ -1226,6 +1226,11 @@ csihandle(void) {
 		DEFAULT(escseq.arg[1], 1);
 		tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
 		break;
+	case 'I': /* CHT -- Cursor Forward Tabulation <n> tab stops */
+		DEFAULT(escseq.arg[0], 1);
+		while (escseq.arg[0]--)
+			tputtab();
+		break;
 	case 'J': /* ED -- Clear screen */
 		sel.bx = -1;
 		switch(escseq.arg[0]) {

From ff040e9894f62fe28bf100488211d0a407740668 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 29 Aug 2012 21:13:47 +0200
Subject: [PATCH 0243/1146] Adding setb and setf and a comment about terminfo
 installation.

---
 Makefile | 2 ++
 st.info  | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/Makefile b/Makefile
index 041eadb..8fc9674 100644
--- a/Makefile
+++ b/Makefile
@@ -48,6 +48,8 @@ install: all
 	@mkdir -p ${DESTDIR}${MANPREFIX}/man1
 	@sed "s/VERSION/${VERSION}/g" < st.1 > ${DESTDIR}${MANPREFIX}/man1/st.1
 	@chmod 644 ${DESTDIR}${MANPREFIX}/man1/st.1
+	@echo If things do not seem to work, be sure that there is no \
+		floating st terminfo in the .terminfo directory in your home dir.
 	@tic -s st.info
 
 uninstall:
diff --git a/st.info b/st.info
index d8e3d0d..08630d3 100644
--- a/st.info
+++ b/st.info
@@ -91,6 +91,8 @@ st| simpleterm,
 	sc=\E7,
 	setab=\E[4%p1%dm,
 	setaf=\E[3%p1%dm,
+	setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
+	setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
 	sgr0=\E[0m,
 	sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
 	smacs=\E(0,

From 6696ef8563a58ee07e4de5b3a74b52b91934f6a9 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 29 Aug 2012 23:14:20 +0200
Subject: [PATCH 0244/1146] Add OSC, DSC, PM, APC and settitle.

---
 TODO |   1 +
 st.c | 279 ++++++++++++++++++++++++++++++++++++++++-------------------
 2 files changed, 191 insertions(+), 89 deletions(-)

diff --git a/TODO b/TODO
index ea37a96..3ddeeb4 100644
--- a/TODO
+++ b/TODO
@@ -20,6 +20,7 @@ bugs
 * fix shift up/down (shift selection in emacs)
 * fix selection click
 * fix selection paste for xatom STRING
+* fix umlaut handling in settitle
 
 misc
 ----
diff --git a/st.c b/st.c
index b9bab29..d8acce4 100644
--- a/st.c
+++ b/st.c
@@ -43,9 +43,10 @@
 #define XEMBED_FOCUS_OUT 5
 
 /* Arbitrary sizes */
-#define ESC_TITLE_SIZ 256
 #define ESC_BUF_SIZ   256
 #define ESC_ARG_SIZ   16
+#define STR_BUF_SIZ   256
+#define STR_ARG_SIZ   16
 #define DRAW_BUF_SIZ  1024
 #define UTF_SIZ       4
 #define XK_NO_MOD     UINT_MAX
@@ -110,9 +111,9 @@ enum term_mode {
 enum escape_state {
 	ESC_START      = 1,
 	ESC_CSI        = 2,
-	ESC_OSC        = 4,
-	ESC_TITLE      = 8,
-	ESC_ALTCHARSET = 16
+	ESC_STR        = 4, /* DSC, OSC, PM, APC */
+	ESC_ALTCHARSET = 8,
+	ESC_STR_END    = 16, /* a final string was encountered */
 };
 
 enum window_state {
@@ -158,6 +159,16 @@ typedef struct {
 	char mode;
 } CSIEscape;
 
+/* STR Escape sequence structs */
+/* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
+typedef struct {
+	char type;             /* ESC type ... */
+	char buf[STR_BUF_SIZ]; /* raw string */
+	int len;               /* raw string length */
+	char *args[STR_ARG_SIZ];
+	int narg;              /* nb of args */
+} STREscape;
+
 /* Internal representation of the screen */
 typedef struct {
 	int row;	/* nb row */
@@ -170,8 +181,6 @@ typedef struct {
 	int bot;	/* bottom scroll limit */
 	int mode;	/* terminal mode flags */
 	int esc;	/* escape state flags */
-	char title[ESC_TITLE_SIZ];
-	int titlelen;
 	bool *tabs;
 } Term;
 
@@ -239,6 +248,10 @@ static void csidump(void);
 static void csihandle(void);
 static void csiparse(void);
 static void csireset(void);
+static void strdump(void);
+static void strhandle(void);
+static void strparse(void);
+static void strreset(void);
 
 static void tclearregion(int, int, int, int);
 static void tcursor(int);
@@ -323,7 +336,8 @@ static void (*handler[LASTEvent])(XEvent *) = {
 static DC dc;
 static XWindow xw;
 static Term term;
-static CSIEscape escseq;
+static CSIEscape csiescseq;
+static STREscape strescseq;
 static int cmdfd;
 static pid_t pid;
 static Selection sel;
@@ -968,22 +982,22 @@ tnewline(int first_col) {
 void
 csiparse(void) {
 	/* int noarg = 1; */
-	char *p = escseq.buf;
+	char *p = csiescseq.buf;
 
-	escseq.narg = 0;
+	csiescseq.narg = 0;
 	if(*p == '?')
-		escseq.priv = 1, p++;
+		csiescseq.priv = 1, p++;
 	
-	while(p < escseq.buf+escseq.len) {
+	while(p < csiescseq.buf+csiescseq.len) {
 		while(isdigit(*p)) {
-			escseq.arg[escseq.narg] *= 10;
-			escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */;
+			csiescseq.arg[csiescseq.narg] *= 10;
+			csiescseq.arg[csiescseq.narg] += *p++ - '0'/*, noarg = 0 */;
 		}
-		if(*p == ';' && escseq.narg+1 < ESC_ARG_SIZ)
-			escseq.narg++, p++;
+		if(*p == ';' && csiescseq.narg+1 < ESC_ARG_SIZ)
+			csiescseq.narg++, p++;
 		else {
-			escseq.mode = *p;
-			escseq.narg++;
+			csiescseq.mode = *p;
+			csiescseq.narg++;
 			return;
 		}
 	}
@@ -1166,7 +1180,7 @@ tsetscroll(int t, int b) {
 
 void
 csihandle(void) {
-	switch(escseq.mode) {
+	switch(csiescseq.mode) {
 	default:
 	unknown:
 		fprintf(stderr, "erresc: unknown csi ");
@@ -1174,37 +1188,37 @@ csihandle(void) {
 		/* die(""); */
 		break;
 	case '@': /* ICH -- Insert <n> blank char */
-		DEFAULT(escseq.arg[0], 1);
-		tinsertblank(escseq.arg[0]);
+		DEFAULT(csiescseq.arg[0], 1);
+		tinsertblank(csiescseq.arg[0]);
 		break;
 	case 'A': /* CUU -- Cursor <n> Up */
 	case 'e':
-		DEFAULT(escseq.arg[0], 1);
-		tmoveto(term.c.x, term.c.y-escseq.arg[0]);
+		DEFAULT(csiescseq.arg[0], 1);
+		tmoveto(term.c.x, term.c.y-csiescseq.arg[0]);
 		break;
 	case 'B': /* CUD -- Cursor <n> Down */
-		DEFAULT(escseq.arg[0], 1);
-		tmoveto(term.c.x, term.c.y+escseq.arg[0]);
+		DEFAULT(csiescseq.arg[0], 1);
+		tmoveto(term.c.x, term.c.y+csiescseq.arg[0]);
 		break;
 	case 'C': /* CUF -- Cursor <n> Forward */
 	case 'a':
-		DEFAULT(escseq.arg[0], 1);
-		tmoveto(term.c.x+escseq.arg[0], term.c.y);
+		DEFAULT(csiescseq.arg[0], 1);
+		tmoveto(term.c.x+csiescseq.arg[0], term.c.y);
 		break;
 	case 'D': /* CUB -- Cursor <n> Backward */
-		DEFAULT(escseq.arg[0], 1);
-		tmoveto(term.c.x-escseq.arg[0], term.c.y);
+		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(escseq.arg[0], 1);
-		tmoveto(0, term.c.y+escseq.arg[0]);
+		DEFAULT(csiescseq.arg[0], 1);
+		tmoveto(0, term.c.y+csiescseq.arg[0]);
 		break;
 	case 'F': /* CPL -- Cursor <n> Up and first col */
-		DEFAULT(escseq.arg[0], 1);
-		tmoveto(0, term.c.y-escseq.arg[0]);
+		DEFAULT(csiescseq.arg[0], 1);
+		tmoveto(0, term.c.y-csiescseq.arg[0]);
 		break;
 	case 'g': /* TBC -- Tabulation clear */
-		switch (escseq.arg[0]) {
+		switch (csiescseq.arg[0]) {
 		case 0: /* clear current tab stop */
 			term.tabs[term.c.x] = 0;
 			break;
@@ -1217,23 +1231,23 @@ csihandle(void) {
 		break;
 	case 'G': /* CHA -- Move to <col> */
 	case '`': /* XXX: HPA -- same? */
-		DEFAULT(escseq.arg[0], 1);
-		tmoveto(escseq.arg[0]-1, term.c.y);
+		DEFAULT(csiescseq.arg[0], 1);
+		tmoveto(csiescseq.arg[0]-1, term.c.y);
 		break;
 	case 'H': /* CUP -- Move to <row> <col> */
 	case 'f': /* XXX: HVP -- same? */
-		DEFAULT(escseq.arg[0], 1);
-		DEFAULT(escseq.arg[1], 1);
-		tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
+		DEFAULT(csiescseq.arg[0], 1);
+		DEFAULT(csiescseq.arg[1], 1);
+		tmoveto(csiescseq.arg[1]-1, csiescseq.arg[0]-1);
 		break;
 	case 'I': /* CHT -- Cursor Forward Tabulation <n> tab stops */
-		DEFAULT(escseq.arg[0], 1);
-		while (escseq.arg[0]--)
+		DEFAULT(csiescseq.arg[0], 1);
+		while (csiescseq.arg[0]--)
 			tputtab();
 		break;
 	case 'J': /* ED -- Clear screen */
 		sel.bx = -1;
-		switch(escseq.arg[0]) {
+		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)
@@ -1252,7 +1266,7 @@ csihandle(void) {
 		}
 		break;
 	case 'K': /* EL -- Clear line */
-		switch(escseq.arg[0]) {
+		switch(csiescseq.arg[0]) {
 		case 0: /* right */
 			tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
 			break;
@@ -1265,20 +1279,20 @@ csihandle(void) {
 		}
 		break;
 	case 'S': /* SU -- Scroll <n> line up */
-		DEFAULT(escseq.arg[0], 1);
-		tscrollup(term.top, escseq.arg[0]);
+		DEFAULT(csiescseq.arg[0], 1);
+		tscrollup(term.top, csiescseq.arg[0]);
 		break;
 	case 'T': /* SD -- Scroll <n> line down */
-		DEFAULT(escseq.arg[0], 1);
-		tscrolldown(term.top, escseq.arg[0]);
+		DEFAULT(csiescseq.arg[0], 1);
+		tscrolldown(term.top, csiescseq.arg[0]);
 		break;
 	case 'L': /* IL -- Insert <n> blank lines */
-		DEFAULT(escseq.arg[0], 1);
-		tinsertblankline(escseq.arg[0]);
+		DEFAULT(csiescseq.arg[0], 1);
+		tinsertblankline(csiescseq.arg[0]);
 		break;
 	case 'l': /* RM -- Reset Mode */
-		if(escseq.priv) {
-			switch(escseq.arg[0]) {
+		if(csiescseq.priv) {
+			switch(csiescseq.arg[0]) {
 			case 1:
 				term.mode &= ~MODE_APPKEYPAD;
 				break;
@@ -1312,7 +1326,7 @@ csihandle(void) {
 					tclearregion(0, 0, term.col-1, term.row-1);
 					tswapscreen();
 				}
-				if(escseq.arg[0] != 1049)
+				if(csiescseq.arg[0] != 1049)
 					break;
 			case 1048:
 				tcursor(CURSOR_LOAD);
@@ -1321,7 +1335,7 @@ csihandle(void) {
 				goto unknown;
 			}
 		} else {
-			switch(escseq.arg[0]) {
+			switch(csiescseq.arg[0]) {
 			case 4:
 				term.mode &= ~MODE_INSERT;
 				break;
@@ -1331,25 +1345,25 @@ csihandle(void) {
 		}
 		break;
 	case 'M': /* DL -- Delete <n> lines */
-		DEFAULT(escseq.arg[0], 1);
-		tdeleteline(escseq.arg[0]);
+		DEFAULT(csiescseq.arg[0], 1);
+		tdeleteline(csiescseq.arg[0]);
 		break;
 	case 'X': /* ECH -- Erase <n> char */
-		DEFAULT(escseq.arg[0], 1);
-		tclearregion(term.c.x, term.c.y, term.c.x + escseq.arg[0], term.c.y);
+		DEFAULT(csiescseq.arg[0], 1);
+		tclearregion(term.c.x, term.c.y, term.c.x + csiescseq.arg[0], term.c.y);
 		break;
 	case 'P': /* DCH -- Delete <n> char */
-		DEFAULT(escseq.arg[0], 1);
-		tdeletechar(escseq.arg[0]);
+		DEFAULT(csiescseq.arg[0], 1);
+		tdeletechar(csiescseq.arg[0]);
 		break;
 	/* XXX: (CSI n Z) CBT -- Cursor Backward Tabulation <n> tab stops */
 	case 'd': /* VPA -- Move to <row> */
-		DEFAULT(escseq.arg[0], 1);
-		tmoveto(term.c.x, escseq.arg[0]-1);
+		DEFAULT(csiescseq.arg[0], 1);
+		tmoveto(term.c.x, csiescseq.arg[0]-1);
 		break;
 	case 'h': /* SM -- Set terminal mode */
-		if(escseq.priv) {
-			switch(escseq.arg[0]) {
+		if(csiescseq.priv) {
+			switch(csiescseq.arg[0]) {
 			case 1:
 				term.mode |= MODE_APPKEYPAD;
 				break;
@@ -1367,7 +1381,7 @@ csihandle(void) {
 				break;
 			case 12: /* att610 -- Start blinking cursor (IGNORED) */
 				 /* fallthrough for xterm cvvis = CSI [ ? 12 ; 25 h */
-				if(escseq.narg > 1 && escseq.arg[1] != 25)
+				if(csiescseq.narg > 1 && csiescseq.arg[1] != 25)
 					break;
 			case 25:
 				term.c.state &= ~CURSOR_HIDE;
@@ -1385,7 +1399,7 @@ csihandle(void) {
 					tclearregion(0, 0, term.col-1, term.row-1);
 				else
 					tswapscreen();
-				if(escseq.arg[0] != 1049)
+				if(csiescseq.arg[0] != 1049)
 					break;
 			case 1048:
 				tcursor(CURSOR_SAVE);
@@ -1393,7 +1407,7 @@ csihandle(void) {
 			default: goto unknown;
 			}
 		} else {
-			switch(escseq.arg[0]) {
+			switch(csiescseq.arg[0]) {
 			case 4:
 				term.mode |= MODE_INSERT;
 				break;
@@ -1402,15 +1416,15 @@ csihandle(void) {
 		};
 		break;
 	case 'm': /* SGR -- Terminal attribute (color) */
-		tsetattr(escseq.arg, escseq.narg);
+		tsetattr(csiescseq.arg, csiescseq.narg);
 		break;
 	case 'r': /* DECSTBM -- Set Scrolling Region */
-		if(escseq.priv)
+		if(csiescseq.priv)
 			goto unknown;
 		else {
-			DEFAULT(escseq.arg[0], 1);
-			DEFAULT(escseq.arg[1], term.row);
-			tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
+			DEFAULT(csiescseq.arg[0], 1);
+			DEFAULT(csiescseq.arg[1], term.row);
+			tsetscroll(csiescseq.arg[0]-1, csiescseq.arg[1]-1);
 			tmoveto(0, 0);
 		}
 		break;
@@ -1427,8 +1441,8 @@ void
 csidump(void) {
 	int i;
 	printf("ESC[");
-	for(i = 0; i < escseq.len; i++) {
-		uint c = escseq.buf[i] & 0xff;
+	for(i = 0; i < csiescseq.len; i++) {
+		uint c = csiescseq.buf[i] & 0xff;
 		if(isprint(c)) putchar(c);
 		else if(c == '\n') printf("(\\n)");
 		else if(c == '\r') printf("(\\r)");
@@ -1440,7 +1454,80 @@ csidump(void) {
 
 void
 csireset(void) {
-	memset(&escseq, 0, sizeof(escseq));
+	memset(&csiescseq, 0, sizeof(csiescseq));
+}
+
+void
+strhandle(void) {
+	char *p;
+
+	p = strescseq.buf; 
+
+	switch(strescseq.type) {
+	case ']': /* OSC -- Operating System Command */
+		switch(p[0]) {
+		case '0':
+		case '2':
+			/*
+			 * TODO: Handle special chars in string, like umlauts.
+			 */
+			if(p[1] == ';') {
+				if(!strncmp(strescseq.buf, "settitle ", 9)) {
+					XStoreName(xw.dpy, xw.win, strescseq.buf+11);	
+				} else {
+					XStoreName(xw.dpy, xw.win, strescseq.buf+2);
+				}
+			}
+			break;
+		case ';':
+			XStoreName(xw.dpy, xw.win, strescseq.buf+1);
+			break;
+		case '4': /* TODO: Set color (arg0) to "rgb:%hexr/$hexg/$hexb" (arg1) */
+			break;
+		default:
+			fprintf(stderr, "erresc: unknown str ");
+			strdump();
+			break;
+		}
+		break;
+	case 'P': /* DSC -- Device Control String */
+	case '_': /* APC -- Application Program Command */
+	case '^': /* PM -- Privacy Message */
+	default:
+		fprintf(stderr, "erresc: unknown str ");
+		strdump();
+		/* die(""); */
+		break;
+	}
+}
+
+void
+strparse(void) {
+	/*
+	 * TODO: Implement parsing like for CSI when required.
+	 * Format: ESC type cmd ';' arg0 [';' argn] ESC \
+	 */
+	return;
+}
+
+void
+strdump(void) {
+	int i;
+	printf("ESC%c", strescseq.type);
+	for(i = 0; i < strescseq.len; i++) {
+		uint c = strescseq.buf[i] & 0xff;
+		if(isprint(c)) putchar(c);
+		else if(c == '\n') printf("(\\n)");
+		else if(c == '\r') printf("(\\r)");
+		else if(c == 0x1b) printf("(\\e)");
+		else printf("(%02x)", c);
+	}
+	printf("ESC\\\n");
+}
+
+void
+strreset(void) {
+	memset(&strescseq, 0, sizeof(strescseq));
 }
 
 void
@@ -1457,25 +1544,31 @@ tputc(char *c) {
 	char ascii = *c;
 	if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {
-			escseq.buf[escseq.len++] = ascii;
-			if(BETWEEN(ascii, 0x40, 0x7E) || escseq.len >= ESC_BUF_SIZ) {
+			csiescseq.buf[csiescseq.len++] = ascii;
+			if(BETWEEN(ascii, 0x40, 0x7E) || csiescseq.len >= ESC_BUF_SIZ) {
 				term.esc = 0;
 				csiparse(), csihandle();
 			}
-			/* TODO: handle other OSC */
-		} else if(term.esc & ESC_OSC) {
-			if(ascii == ';') {
-				term.titlelen = 0;
-				term.esc = ESC_START | ESC_TITLE;
-			}
-		} else if(term.esc & ESC_TITLE) {
-			if(ascii == '\a' || term.titlelen+1 >= ESC_TITLE_SIZ) {
+		} else if(term.esc & ESC_STR) {
+			switch(ascii) {
+			case '\033':
+				term.esc = ESC_START | ESC_STR_END;
+				break;
+			case '\a': /* backwards compatibility to xterm */
 				term.esc = 0;
-				term.title[term.titlelen] = '\0';
-				XStoreName(xw.dpy, xw.win, term.title);
-			} else {
-				term.title[term.titlelen++] = ascii;
+				strhandle();
+				break;
+			default:
+				strescseq.buf[strescseq.len++] = ascii;
+				if (strescseq.len+1 >= STR_BUF_SIZ) {
+					term.esc = 0;
+					strhandle();
+				}
 			}
+		} else if(term.esc & ESC_STR_END) {
+			term.esc = 0;
+			if(ascii == '\\')
+				strhandle();
 		} else if(term.esc & ESC_ALTCHARSET) {
 			switch(ascii) {
 			case '0': /* Line drawing crap */
@@ -1493,8 +1586,13 @@ tputc(char *c) {
 			case '[':
 				term.esc |= ESC_CSI;
 				break;
-			case ']':
-				term.esc |= ESC_OSC;
+			case 'P': /* DCS -- Device Control String */
+			case '_': /* APC -- Application Program Command */
+			case '^': /* PM -- Privacy Message */
+			case ']': /* OSC -- Operating System Command */
+				strreset();
+				strescseq.type = ascii;
+				term.esc |= ESC_STR;
 				break;
 			case '(':
 				term.esc |= ESC_ALTCHARSET;
@@ -1541,6 +1639,9 @@ tputc(char *c) {
 				tcursor(CURSOR_LOAD);
 				term.esc = 0;
 				break;
+			case '\\': /* ST -- Stop */
+				term.esc = 0;
+				break;
 			default:
 				fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
 				    (uchar) ascii, isprint(ascii)?ascii:'.');

From 91fa81dbac4f09de234921cdf5afacb8c8295919 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 30 Aug 2012 07:38:47 +0200
Subject: [PATCH 0245/1146] Never trust terminfo fata morganas. And adding
 other xterm compatibility.

---
 st.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index d8acce4..5b98c6f 100644
--- a/st.c
+++ b/st.c
@@ -1467,16 +1467,13 @@ strhandle(void) {
 	case ']': /* OSC -- Operating System Command */
 		switch(p[0]) {
 		case '0':
+		case '1':
 		case '2':
 			/*
 			 * TODO: Handle special chars in string, like umlauts.
 			 */
 			if(p[1] == ';') {
-				if(!strncmp(strescseq.buf, "settitle ", 9)) {
-					XStoreName(xw.dpy, xw.win, strescseq.buf+11);	
-				} else {
-					XStoreName(xw.dpy, xw.win, strescseq.buf+2);
-				}
+				XStoreName(xw.dpy, xw.win, strescseq.buf+2);
 			}
 			break;
 		case ';':

From c58950f2efd8f203e72add7b22e7f5b973c09a7d Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 30 Aug 2012 21:17:54 +0200
Subject: [PATCH 0246/1146] Applying the CBT patch of Roberto Vargas. Thanks.

---
 st.c | 59 ++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 36 insertions(+), 23 deletions(-)

diff --git a/st.c b/st.c
index 5b98c6f..8cc0e1d 100644
--- a/st.c
+++ b/st.c
@@ -97,11 +97,11 @@ enum glyph_state {
 };
 
 enum term_mode {
-	MODE_WRAP        = 1,
+	MODE_WRAP	= 1,
 	MODE_INSERT      = 2,
 	MODE_APPKEYPAD   = 4,
 	MODE_ALTSCREEN   = 8,
-	MODE_CRLF        = 16,
+	MODE_CRLF	= 16,
 	MODE_MOUSEBTN    = 32,
 	MODE_MOUSEMOTION = 64,
 	MODE_MOUSE       = 32|64,
@@ -110,8 +110,8 @@ enum term_mode {
 
 enum escape_state {
 	ESC_START      = 1,
-	ESC_CSI        = 2,
-	ESC_STR        = 4, /* DSC, OSC, PM, APC */
+	ESC_CSI	= 2,
+	ESC_STR	= 4, /* DSC, OSC, PM, APC */
 	ESC_ALTCHARSET = 8,
 	ESC_STR_END    = 16, /* a final string was encountered */
 };
@@ -152,21 +152,21 @@ typedef struct {
 /* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
 typedef struct {
 	char buf[ESC_BUF_SIZ]; /* raw string */
-	int len;               /* raw string length */
+	int len;	       /* raw string length */
 	char priv;
 	int arg[ESC_ARG_SIZ];
-	int narg;              /* nb of args */
+	int narg;	      /* nb of args */
 	char mode;
 } CSIEscape;
 
 /* STR Escape sequence structs */
 /* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
 typedef struct {
-	char type;             /* ESC type ... */
+	char type;	     /* ESC type ... */
 	char buf[STR_BUF_SIZ]; /* raw string */
-	int len;               /* raw string length */
+	int len;	       /* raw string length */
 	char *args[STR_ARG_SIZ];
-	int narg;              /* nb of args */
+	int narg;	      /* nb of args */
 } STREscape;
 
 /* Internal representation of the screen */
@@ -262,7 +262,7 @@ static void tinsertblankline(int);
 static void tmoveto(int, int);
 static void tnew(int, int);
 static void tnewline(int);
-static void tputtab(void);
+static void tputtab(bool);
 static void tputc(char*);
 static void treset(void);
 static int tresize(int, int);
@@ -1243,7 +1243,7 @@ csihandle(void) {
 	case 'I': /* CHT -- Cursor Forward Tabulation <n> tab stops */
 		DEFAULT(csiescseq.arg[0], 1);
 		while (csiescseq.arg[0]--)
-			tputtab();
+			tputtab(1);
 		break;
 	case 'J': /* ED -- Clear screen */
 		sel.bx = -1;
@@ -1356,7 +1356,11 @@ csihandle(void) {
 		DEFAULT(csiescseq.arg[0], 1);
 		tdeletechar(csiescseq.arg[0]);
 		break;
-	/* XXX: (CSI n Z) CBT -- Cursor Backward Tabulation <n> tab stops */
+	case 'Z': /* CBT -- Cursor Backward Tabulation <n> tab stops */
+		DEFAULT(csiescseq.arg[0], 1);
+		while (csiescseq.arg[0]--)
+			tputtab(0);
+		break;
 	case 'd': /* VPA -- Move to <row> */
 		DEFAULT(csiescseq.arg[0], 1);
 		tmoveto(term.c.x, csiescseq.arg[0]-1);
@@ -1528,11 +1532,20 @@ strreset(void) {
 }
 
 void
-tputtab(void) {
-	unsigned x;
+tputtab(bool forward) {
+	unsigned x = term.c.x;
 
-	for (x = term.c.x + 1; x < term.col && !term.tabs[x]; ++x)
-		/* nothing */ ;
+	if (forward) {
+		if (x == term.col)
+			return;
+		for (++x; x < term.col && !term.tabs[x]; ++x)
+			/* nothing */ ;
+	} else {
+		if (x == 0)
+			return;
+		for (--x; x > 0 && !term.tabs[x]; --x)
+			/* nothing */ ;
+	}
 	tmoveto(x, term.c.y);
 }
 
@@ -1650,7 +1663,7 @@ tputc(char *c) {
 			sel.bx = -1;
 		switch(ascii) {
 		case '\t':
-			tputtab();
+			tputtab(1);
 			break;
 		case '\b':
 			tmoveto(term.c.x-1, term.c.y);
@@ -1806,8 +1819,8 @@ void
 xclear(int x1, int y1, int x2, int y2) {
 	XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? DefaultFG : DefaultBG]);
 	XFillRectangle(xw.dpy, xw.buf, dc.gc,
-	               BORDER + x1 * xw.cw, BORDER + y1 * xw.ch,
-	               (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
+		       BORDER + x1 * xw.cw, BORDER + y1 * xw.ch,
+		       (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
 }
 
 void
@@ -1982,8 +1995,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 /* copy buffer pixmap to screen pixmap */
 void
 xcopy() {
-        XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
-        XdbeSwapBuffers(xw.dpy, swpinfo, 1);
+	XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
+	XdbeSwapBuffers(xw.dpy, swpinfo, 1);
 
 }
 
@@ -2080,8 +2093,8 @@ expose(XEvent *ev) {
 	if(xw.state & WIN_REDRAW) {
 		if(!e->count)
 			xw.state &= ~WIN_REDRAW;
-        }
-        xcopy();
+	}
+	xcopy();
 }
 
 void

From 81c678e53e21d496a18a1cde539101da77237e24 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 30 Aug 2012 21:19:53 +0200
Subject: [PATCH 0247/1146] Silencing the compiler but keeping strparse.

This will really be needed when there is a full 256 color support.
---
 st.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/st.c b/st.c
index 8cc0e1d..123d29e 100644
--- a/st.c
+++ b/st.c
@@ -1465,6 +1465,11 @@ void
 strhandle(void) {
 	char *p;
 
+	/*
+	 * TODO: make this being useful in case of color palette change.
+	 */
+	strparse();
+
 	p = strescseq.buf; 
 
 	switch(strescseq.type) {

From 4cdcc395397f7b7db48265f5ce0949effaf99c1f Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 2 Sep 2012 19:08:52 +0200
Subject: [PATCH 0248/1146] Add vpa terminfo capability

---
 st.info |    2 ++
 1 file changed, 2 insertions(+)
---
 st.info | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.info b/st.info
index 08630d3..902c05a 100644
--- a/st.info
+++ b/st.info
@@ -103,6 +103,8 @@ st| simpleterm,
 	tsl=\E]0;,
 	ul,
 	xenl,
+	vpa=\E[%i%p1%dd,
+
 
 st-256color| simpleterm with 256 colors,
 	use=st,

From c79df9f78d0defed1c7420201416c10768c46076 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 2 Sep 2012 19:09:35 +0200
Subject: [PATCH 0249/1146] Enable multiple arguments in SM and RM

SM and RM can receive multiple parameters, but the code only was accepting
only one. This patch join the code of set and reset modes (SM and RM) in a
common function and uses a loop which deals with all the arguments of the
sequence. This patch improves xterm and vt100 compability.
---
 st.c |  180 ++++++++++++++++++++++++++++--------------------------------------
 1 file changed, 76 insertions(+), 104 deletions(-)
---
 st.c | 180 +++++++++++++++++++++++++----------------------------------
 1 file changed, 76 insertions(+), 104 deletions(-)

diff --git a/st.c b/st.c
index 123d29e..f3f7f28 100644
--- a/st.c
+++ b/st.c
@@ -273,6 +273,7 @@ static void tsetchar(char*);
 static void tsetscroll(int, int);
 static void tswapscreen(void);
 static void tsetdirt(int, int);
+static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 
 static void ttynew(void);
@@ -1178,6 +1179,79 @@ tsetscroll(int t, int b) {
 	term.bot = b;
 }
 
+#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
+
+void
+tsetmode(bool priv, bool set, int *args, int narg) {
+	int *lim, mode;
+
+	for (lim = args + narg; args < lim; ++args) {
+		if(priv) {
+			switch(*args) {
+			case 1:
+				MODBIT(term.mode, set, MODE_APPKEYPAD);
+				break;
+			case 5: /* DECSCNM -- Reverve video */
+				mode = term.mode;
+				MODBIT(term.mode,set, MODE_REVERSE);
+				if (mode != term.mode)
+					draw();
+				break;
+			case 7:
+				MODBIT(term.mode, set, MODE_WRAP);
+				break;
+			case 20:
+				MODBIT(term.mode, set, MODE_CRLF);
+				break;
+			case 12: /* att610 -- Start blinking cursor (IGNORED) */
+				break;
+			case 25:
+				MODBIT(term.c.state, !set, CURSOR_HIDE);
+				break;
+			case 1000: /* 1000,1002: enable xterm mouse report */
+				MODBIT(term.mode, set, MODE_MOUSEBTN);
+				break;
+			case 1002:
+				MODBIT(term.mode, set, MODE_MOUSEMOTION);
+				break;
+			case 1049: /* = 1047 and 1048 */
+			case 47:
+			case 1047:
+				if(IS_SET(MODE_ALTSCREEN))
+					tclearregion(0, 0, term.col-1, term.row-1);
+				if ((set && !IS_SET(MODE_ALTSCREEN)) ||
+				    (!set && IS_SET(MODE_ALTSCREEN))) {
+					    tswapscreen();
+				}
+				if (*args != 1049)
+					break;
+				/* pass through */
+			case 1048:
+				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
+				break;
+			default:
+				fprintf(stderr,
+					"erresc: unknown private set/reset mode %d\n",
+					*args);
+				break;
+			}
+		} else {
+			switch(*args) {
+			case 4:
+				MODBIT(term.mode, set, MODE_INSERT);
+				break;
+			default:
+				fprintf(stderr,
+					"erresc: unknown set/reset mode %d\n",
+					*args);
+				break;
+			}
+		}
+	}
+}
+#undef MODBIT
+
+
 void
 csihandle(void) {
 	switch(csiescseq.mode) {
@@ -1291,58 +1365,7 @@ csihandle(void) {
 		tinsertblankline(csiescseq.arg[0]);
 		break;
 	case 'l': /* RM -- Reset Mode */
-		if(csiescseq.priv) {
-			switch(csiescseq.arg[0]) {
-			case 1:
-				term.mode &= ~MODE_APPKEYPAD;
-				break;
-			case 5: /* DECSCNM -- Remove reverse video */
-				if(IS_SET(MODE_REVERSE)) {
-					term.mode &= ~MODE_REVERSE;
-					draw();
-				}
-				break;
-			case 7:
-				term.mode &= ~MODE_WRAP;
-				break;
-			case 12: /* att610 -- Stop blinking cursor (IGNORED) */
-				break;
-			case 20:
-				term.mode &= ~MODE_CRLF;
-				break;
-			case 25:
-				term.c.state |= CURSOR_HIDE;
-				break;
-			case 1000: /* disable X11 xterm mouse reporting */
-				term.mode &= ~MODE_MOUSEBTN;
-				break;
-			case 1002:
-				term.mode &= ~MODE_MOUSEMOTION;
-				break;
-			case 1049: /* = 1047 and 1048 */
-			case 47:
-			case 1047:
-				if(IS_SET(MODE_ALTSCREEN)) {
-					tclearregion(0, 0, term.col-1, term.row-1);
-					tswapscreen();
-				}
-				if(csiescseq.arg[0] != 1049)
-					break;
-			case 1048:
-				tcursor(CURSOR_LOAD);
-				break;
-			default:
-				goto unknown;
-			}
-		} else {
-			switch(csiescseq.arg[0]) {
-			case 4:
-				term.mode &= ~MODE_INSERT;
-				break;
-			default:
-				goto unknown;
-			}
-		}
+		tsetmode(csiescseq.priv, 0, csiescseq.arg, csiescseq.narg);
 		break;
 	case 'M': /* DL -- Delete <n> lines */
 		DEFAULT(csiescseq.arg[0], 1);
@@ -1366,58 +1389,7 @@ csihandle(void) {
 		tmoveto(term.c.x, csiescseq.arg[0]-1);
 		break;
 	case 'h': /* SM -- Set terminal mode */
-		if(csiescseq.priv) {
-			switch(csiescseq.arg[0]) {
-			case 1:
-				term.mode |= MODE_APPKEYPAD;
-				break;
-			case 5: /* DECSCNM -- Reverve video */
-				if(!IS_SET(MODE_REVERSE)) {
-					term.mode |= MODE_REVERSE;
-					draw();
-				}
-				break;
-			case 7:
-				term.mode |= MODE_WRAP;
-				break;
-			case 20:
-				term.mode |= MODE_CRLF;
-				break;
-			case 12: /* att610 -- Start blinking cursor (IGNORED) */
-				 /* fallthrough for xterm cvvis = CSI [ ? 12 ; 25 h */
-				if(csiescseq.narg > 1 && csiescseq.arg[1] != 25)
-					break;
-			case 25:
-				term.c.state &= ~CURSOR_HIDE;
-				break;
-			case 1000: /* 1000,1002: enable xterm mouse report */
-				term.mode |= MODE_MOUSEBTN;
-				break;
-			case 1002:
-				term.mode |= MODE_MOUSEMOTION;
-				break;
-			case 1049: /* = 1047 and 1048 */
-			case 47:
-			case 1047:
-				if(IS_SET(MODE_ALTSCREEN))
-					tclearregion(0, 0, term.col-1, term.row-1);
-				else
-					tswapscreen();
-				if(csiescseq.arg[0] != 1049)
-					break;
-			case 1048:
-				tcursor(CURSOR_SAVE);
-				break;
-			default: goto unknown;
-			}
-		} else {
-			switch(csiescseq.arg[0]) {
-			case 4:
-				term.mode |= MODE_INSERT;
-				break;
-			default: goto unknown;
-			}
-		};
+		tsetmode(csiescseq.priv, 1, csiescseq.arg, csiescseq.narg);
 		break;
 	case 'm': /* SGR -- Terminal attribute (color) */
 		tsetattr(csiescseq.arg, csiescseq.narg);

From 588ba51a539d18de5f9497a38ab7875e7b3e1429 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 2 Sep 2012 19:42:00 +0200
Subject: [PATCH 0250/1146] Make it more obvious where the wrong attribute is
 used.

---
 st.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index f3f7f28..9ad4f89 100644
--- a/st.c
+++ b/st.c
@@ -1128,7 +1128,7 @@ tsetattr(int *attr, int l) {
 					fprintf(stderr, "erresc: bad fgcolor %d\n", attr[i]);
 			}
 			else
-				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]);
+				fprintf(stderr, "erresc(38): gfx attr %d unknown\n", attr[i]);
 			break;
 		case 39:
 			term.c.attr.fg = DefaultFG;
@@ -1142,7 +1142,7 @@ tsetattr(int *attr, int l) {
 					fprintf(stderr, "erresc: bad bgcolor %d\n", attr[i]);
 			}
 			else
-				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]);
+				fprintf(stderr, "erresc(48): gfx attr %d unknown\n", attr[i]);
 			break;
 		case 49:
 			term.c.attr.bg = DefaultBG;
@@ -1157,8 +1157,7 @@ tsetattr(int *attr, int l) {
 			else if(BETWEEN(attr[i], 100, 107))
 				term.c.attr.fg = attr[i] - 100 + 8;
 			else
-				fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]), csidump();
-			
+				fprintf(stderr, "erresc(default): gfx attr %d unknown\n", attr[i]), csidump();
 			break;
 		}
 	}

From 7f17a70834961cd1ff748b2621c6fc87c069be22 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 2 Sep 2012 19:43:29 +0200
Subject: [PATCH 0251/1146] Cleaning up lonely tabs.

---
 st.c | 46 +++++++++++++++++++++++-----------------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/st.c b/st.c
index 9ad4f89..8e1afe2 100644
--- a/st.c
+++ b/st.c
@@ -504,7 +504,7 @@ mousereport(XEvent *e) {
 	int state = e->xbutton.state;
 	char buf[] = { '\033', '[', 'M', 0, 32+x+1, 32+y+1 };
 	static int ob, ox, oy;
-	
+
 	/* from urxvt */
 	if(e->xbutton.type == MotionNotify) {
 		if(!IS_SET(MODE_MOUSEMOTION) || (x == ox && y == oy))
@@ -522,11 +522,11 @@ mousereport(XEvent *e) {
 			ox = x, oy = y;
 		}
 	}
-	
+
 	buf[3] = 32 + button + (state & ShiftMask ? 4 : 0)
 		+ (state & Mod4Mask    ? 8  : 0)
 		+ (state & ControlMask ? 16 : 0);
-	
+
 	ttywrite(buf, sizeof(buf));
 }
 
@@ -751,7 +751,7 @@ sigchld(int a) {
 void
 ttynew(void) {
 	int m, s;
-	
+
 	/* seems to work fine on linux, openbsd and freebsd */
 	struct winsize w = {term.row, term.col, 0, 0};
 	if(openpty(&m, &s, NULL, NULL, &w) < 0)
@@ -910,11 +910,11 @@ void
 tscrolldown(int orig, int n) {
 	int i;
 	Line temp;
-	
+
 	LIMIT(n, 0, term.bot-orig+1);
 
 	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];
@@ -932,9 +932,9 @@ 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);
-	
+
 	for(i = orig; i <= term.bot-n; i++) {
 		 temp = term.line[i];
 		 term.line[i] = term.line[i+n];
@@ -951,7 +951,7 @@ void
 selscroll(int orig, int n) {
 	if(sel.bx == -1)
 		return;
-	
+
 	if(BETWEEN(sel.by, orig, term.bot) || BETWEEN(sel.ey, orig, term.bot)) {
 		if((sel.by += n) > term.bot || (sel.ey += n) < term.top) {
 			sel.bx = -1;
@@ -988,7 +988,7 @@ csiparse(void) {
 	csiescseq.narg = 0;
 	if(*p == '?')
 		csiescseq.priv = 1, p++;
-	
+
 	while(p < csiescseq.buf+csiescseq.len) {
 		while(isdigit(*p)) {
 			csiescseq.arg[csiescseq.narg] *= 10;
@@ -1047,7 +1047,7 @@ tdeletechar(int n) {
 	int src = term.c.x + n;
 	int dst = term.c.x;
 	int size = term.col - src;
-	
+
 	term.dirty[term.c.y] = 1;
 
 	if(src >= term.col) {
@@ -1765,7 +1765,7 @@ xloadcols(void) {
 		} else
 			dc.col[i] = color.pixel;
 	}
-	
+
 	/* load colors [16-255] ; same colors as xterm */
 	for(i = 16, r = 0; r < 6; r++)
 		for(g = 0; g < 6; g++)
@@ -1868,7 +1868,7 @@ xinit(void) {
 	if(!(xw.dpy = XOpenDisplay(NULL)))
 		die("Can't open display\n");
 	xw.scr = XDefaultScreen(xw.dpy);
-	
+
 	/* font */
 	initfonts(FONT, BOLDFONT);
 
@@ -1910,7 +1910,7 @@ xinit(void) {
 					   XNFocusWindow, xw.win, NULL);
 	/* gc */
 	dc.gc = XCreateGC(xw.dpy, xw.win, 0, NULL);
-	
+
 	/* white cursor, black outline */
 	cursor = XCreateFontCursor(xw.dpy, XC_xterm);
 	XDefineCursor(xw.dpy, xw.win, cursor);
@@ -1932,7 +1932,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	int winx = BORDER+x*xw.cw, winy = BORDER+y*xw.ch + dc.font.ascent, width = charlen*xw.cw;
 	XFontSet fontset = dc.font.set;
 	int i;
-	
+
 	/* only switch default fg/bg if term is in RV mode */
 	if(IS_SET(MODE_REVERSE)) {
 		if(fg == DefaultFG)
@@ -1963,7 +1963,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	}
 
 	XmbDrawImageString(xw.dpy, xw.buf, fontset, dc.gc, winx, winy, s, bytelen);
-	
+
 	if(base.mode & ATTR_UNDERLINE)
 		XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);
 }
@@ -1982,10 +1982,10 @@ xdrawcursor(void) {
 	static int oldy = 0;
 	int sl;
 	Glyph g = {{' '}, ATTR_NULL, DefaultBG, DefaultCS, 0};
-	
+
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
-	
+
 	if(term.line[term.c.y][term.c.x].state & GLYPH_SET)
 		memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
 
@@ -2132,7 +2132,7 @@ kpress(XEvent *ev) {
 	meta = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
 	len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status);
-	
+
 	/* 1. custom keys from config.h */
 	if((customkey = kmap(ksym, e->state)))
 		ttywrite(customkey, strlen(customkey));
@@ -2186,10 +2186,10 @@ cmessage(XEvent *e) {
 void
 resize(XEvent *e) {
 	int col, row;
-	
+
 	if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
 		return;
-	
+
 	xw.w = e->xconfigure.width;
 	xw.h = e->xconfigure.height;
 	col = (xw.w - 2*BORDER) / xw.cw;
@@ -2216,7 +2216,7 @@ run(void) {
 	int xfd = XConnectionNumber(xw.dpy);
 	struct timeval timeout = {0};
 	bool stuff_to_print = 0;
-	
+
 	for(;;) {
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
@@ -2251,7 +2251,7 @@ run(void) {
 int
 main(int argc, char *argv[]) {
 	int i;
-	
+
 	for(i = 1; i < argc; i++) {
 		switch(argv[i][0] != '-' || argv[i][2] ? -1 : argv[i][1]) {
 		case 't':

From b11d85c9bef5a49c071553410c3f73c3181c6ece Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 2 Sep 2012 19:53:50 +0200
Subject: [PATCH 0252/1146] Add standout mode.

---
 st.c    | 8 +++++++-
 st.info | 4 ++--
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 8e1afe2..bd230a3 100644
--- a/st.c
+++ b/st.c
@@ -1104,6 +1104,9 @@ tsetattr(int *attr, int l) {
 		case 1:
 			term.c.attr.mode |= ATTR_BOLD;
 			break;
+		case 3: /* enter standout (highlight) mode TODO: make it italic */
+			term.c.attr.mode |= ATTR_REVERSE;
+			break;
 		case 4:
 			term.c.attr.mode |= ATTR_UNDERLINE;
 			break;
@@ -1113,6 +1116,9 @@ tsetattr(int *attr, int l) {
 		case 22:
 			term.c.attr.mode &= ~ATTR_BOLD;
 			break;
+		case 23: /* leave standout (highlight) mode TODO: make it italic */
+			term.c.attr.mode &= ~ATTR_REVERSE;
+			break;
 		case 24:
 			term.c.attr.mode &= ~ATTR_UNDERLINE;
 			break;
@@ -1441,7 +1447,7 @@ strhandle(void) {
 	 */
 	strparse();
 
-	p = strescseq.buf; 
+	p = strescseq.buf;
 
 	switch(strescseq.type) {
 	case ']': /* OSC -- Operating System Command */
diff --git a/st.info b/st.info
index 902c05a..e883319 100644
--- a/st.info
+++ b/st.info
@@ -86,7 +86,7 @@ st| simpleterm,
 	ri=\EM,
 	rmacs=\E(B,
 	rmcup=\E[?1049l,
-	rmso=\E[m,
+	rmso=\E[23m,
 	rmul=\E[m,
 	sc=\E7,
 	setab=\E[4%p1%dm,
@@ -97,7 +97,7 @@ st| simpleterm,
 	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,
 	smacs=\E(0,
 	smcup=\E[?1049h,
-	smso=\E[7m,
+	smso=\E[3m,
 	smul=\E[4m,
 	tbc=\E[3g,
 	tsl=\E]0;,

From cfefa054e80afa22d6948bf997a6818e778801f6 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 3 Sep 2012 21:50:22 +0200
Subject: [PATCH 0253/1146] =?UTF-8?q?Patch=20from=20Roberto=20Vargas.=20?=
 =?UTF-8?q?=C2=BBAdd=20initialization=20strings=20in=20terminfo=C2=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Taken from the description:

When tput init is executed the list of task performed are (taken from
terminfo(5)):

              run the program
                     iprog

              output is1 is2

              set the margins using
                     mgc, smgl and smgr

              set tabs using
                     tbc and hts

              print the file
                     if

              and finally
                     output is3.

When reset is executed, a more stronger initialization process is performed,
so the terminal can return from an unknown state. rs1, rs2 and rs3 are used
in this case instead of
using is1, is2 and is3.

This patch makes is2 = rs2, resets insert mode and set normal keypad
mode. For rs1 it performs a full initilization using ^[c.
---
 st.info | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.info b/st.info
index e883319..6c9b098 100644
--- a/st.info
+++ b/st.info
@@ -46,6 +46,7 @@ st| simpleterm,
 	ind=^J,
 	indn=\E[%p1%dS,
 	invis=\E[8m,
+	in2=\E[4l\E>,
 	it#8,
 	kbs=\177,
 	kcub1=\E[D,
@@ -82,6 +83,8 @@ st| simpleterm,
 	op=\E[39;49m,
 	pairs#64,
 	rc=\E8,
+	rs1=\Ec,
+	rs2=\E[4l\E>,
 	rev=\E[7m,
 	ri=\EM,
 	rmacs=\E(B,

From a984ffc4cb755c6dcdbc153b2591dca0ae6a8ead Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 3 Sep 2012 21:52:21 +0200
Subject: [PATCH 0254/1146] Add write I/O to file

This is a theorical feature listed in http://st.suckless.org/goals. All the
input/output of the terminal will be written to a file, which can be very
useful for debugging, and also allow interconnect st to other process
through named pipes.
---
 st.1 |    6 ++++++
 st.c |   14 +++++++++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)
---
 st.1 |  6 ++++++
 st.c | 14 +++++++++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/st.1 b/st.1
index b6c119f..931b481 100644
--- a/st.1
+++ b/st.1
@@ -10,6 +10,8 @@ st \- simple terminal
 .RB [ \-w 
 .IR windowid ]
 .RB [ \-v ]
+.RB [ \-f
+.IR file ]
 .RB [ \-e
 .IR command ...]
 .SH DESCRIPTION
@@ -30,6 +32,10 @@ embeds st within the window identified by
 .B \-v
 prints version information to stderr, then exits.
 .TP
+.BI \-f " file"
+writes all the I/O to
+.I file
+.TP
 .BI \-e " program " [ " arguments " "... ]"
 st executes
 .I program
diff --git a/st.c b/st.c
index bd230a3..fde0493 100644
--- a/st.c
+++ b/st.c
@@ -36,7 +36,7 @@
 
 #define USAGE \
 	"st " VERSION " (c) 2010-2012 st engineers\n" \
-	"usage: st [-t title] [-c class] [-w windowid] [-v] [-e command...]\n"
+	"usage: st [-t title] [-c class] [-w windowid] [-v] [-f file] [-e command...]\n"
 
 /* XEMBED messages */
 #define XEMBED_FOCUS_IN  4
@@ -342,7 +342,9 @@ static STREscape strescseq;
 static int cmdfd;
 static pid_t pid;
 static Selection sel;
+static FILE *fileio;
 static char **opt_cmd  = NULL;
+static char *opt_io    = NULL;
 static char *opt_title = NULL;
 static char *opt_embed = NULL;
 static char *opt_class = NULL;
@@ -776,6 +778,10 @@ ttynew(void) {
 		close(s);
 		cmdfd = m;
 		signal(SIGCHLD, sigchld);
+		if (opt_io && !(fileio = fopen(opt_io, "w"))) {
+			fprintf(stderr, "Error opening %s:%s",
+				opt_io, strerror(errno));
+		}
 	}
 }
 
@@ -1534,6 +1540,9 @@ tputtab(bool forward) {
 void
 tputc(char *c) {
 	char ascii = *c;
+
+	if (fileio)
+		putc(ascii, fileio);
 	if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {
 			csiescseq.buf[csiescseq.len++] = ascii;
@@ -2269,6 +2278,9 @@ main(int argc, char *argv[]) {
 		case 'w':
 			if(++i < argc) opt_embed = argv[i];
 			break;
+		case 'f':
+			if (++i < argc) opt_io = argv[i];
+			break;
 		case 'e':
 			/* eat every remaining arguments */
 			if(++i < argc) opt_cmd = &argv[i];

From 930b2c4a7f222e15e6493d5bbb8fd90e681d2626 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 3 Sep 2012 21:52:34 +0200
Subject: [PATCH 0255/1146] Force redisplay of all lines in DECSCNM

When it is called DECSCNM all lines become dirty, because it is necessary
redraw all lines for getting the new colors. It is easy see the problem
running 'echo ^[[?5h'.

In order to get a correct flash when running tput flash is necessary wait
after DECSCNM, until the changes are displayed, because in other case the
switch between reverse on/reverse off will be too much fast and nothing will
happen.
---
 st.c |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
---
 st.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index fde0493..193db5e 100644
--- a/st.c
+++ b/st.c
@@ -54,6 +54,7 @@
 
 #define SELECT_TIMEOUT (20*1000) /* 20 ms */
 #define DRAW_TIMEOUT  (20*1000) /* 20 ms */
+#define REDRAW_TIMEOUT (80*1000) /* 80 ms */
 
 #define SERRNO strerror(errno)
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
@@ -238,6 +239,7 @@ typedef struct {
 
 static void die(const char*, ...);
 static void draw(void);
+static void redraw(void);
 static void drawregion(int, int, int, int);
 static void execsh(void);
 static void sigchld(int);
@@ -1206,7 +1208,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				mode = term.mode;
 				MODBIT(term.mode,set, MODE_REVERSE);
 				if (mode != term.mode)
-					draw();
+					redraw();
 				break;
 			case 7:
 				MODBIT(term.mode, set, MODE_WRAP);
@@ -2029,6 +2031,14 @@ xdrawcursor(void) {
 	xcopy(term.c.x, term.c.y, 1, 1);
 }
 
+void
+redraw(void) {
+	struct timespec tv = {0, REDRAW_TIMEOUT * 1000};
+	tfulldirt();
+	draw();
+	nanosleep(&tv, NULL);
+}
+
 void
 draw() {
 	drawregion(0, 0, term.col, term.row);

From 466decd53552059bfba9551a924354ae989cb46a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 3 Sep 2012 21:54:40 +0200
Subject: [PATCH 0256/1146] Fixing a type in in2 in the st.info.

---
 st.info | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.info b/st.info
index 6c9b098..bd9c158 100644
--- a/st.info
+++ b/st.info
@@ -46,7 +46,7 @@ st| simpleterm,
 	ind=^J,
 	indn=\E[%p1%dS,
 	invis=\E[8m,
-	in2=\E[4l\E>,
+	is2=\E[4l\E>,
 	it#8,
 	kbs=\177,
 	kcub1=\E[D,

From 579f12d47b38e23abb1073b8e70d67c0c203c42c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 3 Sep 2012 23:02:29 +0200
Subject: [PATCH 0257/1146] Add -g geometry to st and the manpage.

---
 st.1 |  4 +++
 st.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 72 insertions(+), 18 deletions(-)

diff --git a/st.1 b/st.1
index 931b481..8269b38 100644
--- a/st.1
+++ b/st.1
@@ -5,6 +5,8 @@ st \- simple terminal
 .B st
 .RB [ \-c
 .IR class ]
+.RB [ \-g
+.IR geometry ]
 .RB [ \-t 
 .IR title ]
 .RB [ \-w 
@@ -29,6 +31,8 @@ defines the window class (default $TERM).
 embeds st within the window identified by 
 .I windowid
 .TP
+.B \-g " geometry"
+defines the X11 geometry string, which will fixate the height and width of st. 
 .B \-v
 prints version information to stderr, then exits.
 .TP
diff --git a/st.c b/st.c
index 193db5e..8b30d4c 100644
--- a/st.c
+++ b/st.c
@@ -36,7 +36,8 @@
 
 #define USAGE \
 	"st " VERSION " (c) 2010-2012 st engineers\n" \
-	"usage: st [-t title] [-c class] [-w windowid] [-v] [-f file] [-e command...]\n"
+	"usage: st [-t title] [-c class] [-g geometry]" \
+	" [-w windowid] [-v] [-f file] [-e command...]\n"
 
 /* XEMBED messages */
 #define XEMBED_FOCUS_IN  4
@@ -195,6 +196,8 @@ typedef struct {
 	XIM xim;
 	XIC xic;
 	int scr;
+	Bool isfixed; /* is fixed geometry? */
+	int fx, fy, fw, fh; /* fixed geometry */
 	int w;	/* window width */
 	int h;	/* window height */
 	int ch; /* char height */
@@ -1820,16 +1823,25 @@ void
 xhints(void) {
 	XClassHint class = {opt_class ? opt_class : TNAME, TNAME};
 	XWMHints wm = {.flags = InputHint, .input = 1};
-	XSizeHints size = {
-		.flags = PSize | PResizeInc | PBaseSize,
-		.height = xw.h,
-		.width = xw.w,
-		.height_inc = xw.ch,
-		.width_inc = xw.cw,
-		.base_height = 2*BORDER,
-		.base_width = 2*BORDER,
-	};
-	XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, &size, &wm, &class);
+	XSizeHints *sizeh = NULL;
+
+	sizeh = XAllocSizeHints();
+	if(xw.isfixed == False) {
+		sizeh->flags = PSize | PResizeInc | PBaseSize;
+		sizeh->height = xw.h;
+		sizeh->width = xw.w;
+		sizeh->height_inc = xw.ch;
+		sizeh->width_inc = xw.cw;
+		sizeh->base_height = 2*BORDER;
+		sizeh->base_width = 2*BORDER;
+	} else {
+		sizeh->flags = PMaxSize | PMinSize;
+		sizeh->min_width = sizeh->max_width = xw.fw;
+		sizeh->min_height = sizeh->max_height = xw.fh;
+	}
+
+	XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, &class);
+	XFree(sizeh);
 }
 
 XFontSet
@@ -1881,11 +1893,28 @@ xinit(void) {
 	XSetWindowAttributes attrs;
 	Cursor cursor;
 	Window parent;
+	int sw, sh;
 
 	if(!(xw.dpy = XOpenDisplay(NULL)))
 		die("Can't open display\n");
 	xw.scr = XDefaultScreen(xw.dpy);
 
+	/* adjust fixed window geometry */
+	if(xw.isfixed) {
+		sw = DisplayWidth(xw.dpy, xw.scr);
+		sh = DisplayWidth(xw.dpy, xw.scr);
+		if(xw.fx < 0)
+			xw.fx = sw + xw.fx - xw.fw;
+		if(xw.fy < 0)
+			xw.fy = sh + xw.fy - xw.fh;
+	} else {
+		/* window - default size */
+		xw.h = 2*BORDER + term.row * xw.ch;
+		xw.w = 2*BORDER + term.col * xw.cw;
+		xw.fw = xw.w;
+		xw.fh = xw.h;
+	}
+
 	/* font */
 	initfonts(FONT, BOLDFONT);
 
@@ -1897,10 +1926,6 @@ xinit(void) {
 	xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
 	xloadcols();
 
-	/* window - default size */
-	xw.h = 2*BORDER + term.row * xw.ch;
-	xw.w = 2*BORDER + term.col * xw.cw;
-
 	attrs.background_pixel = dc.col[DefaultBG];
 	attrs.border_pixel = dc.col[DefaultBG];
 	attrs.bit_gravity = NorthWestGravity;
@@ -1911,8 +1936,8 @@ xinit(void) {
 	attrs.colormap = xw.cmap;
 
 	parent = opt_embed ? strtol(opt_embed, NULL, 0) : XRootWindow(xw.dpy, xw.scr);
-	xw.win = XCreateWindow(xw.dpy, parent, 0, 0,
-			xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
+	xw.win = XCreateWindow(xw.dpy, parent, xw.fx, xw.fy,
+			xw.fw, xw.fh, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
 			XDefaultVisual(xw.dpy, xw.scr),
 			CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
 			| CWColormap,
@@ -2275,7 +2300,10 @@ run(void) {
 
 int
 main(int argc, char *argv[]) {
-	int i;
+	int i, bitm, xr, yr;
+	unsigned int wr, hr;
+
+	xw.fw = xw.fh = xw.fx = xw.fy = 0;
 
 	for(i = 1; i < argc; i++) {
 		switch(argv[i][0] != '-' || argv[i][2] ? -1 : argv[i][1]) {
@@ -2295,6 +2323,27 @@ main(int argc, char *argv[]) {
 			/* eat every remaining arguments */
 			if(++i < argc) opt_cmd = &argv[i];
 			goto run;
+		case 'g':
+			if(++i >= argc)
+				break;
+
+			bitm = XParseGeometry(argv[i], &xr, &yr, &wr, &hr);
+			if(bitm & XValue)
+				xw.fx = xr;
+			if(bitm & YValue)
+				xw.fy = yr;
+			if(bitm & WidthValue)
+				xw.fw = (int)wr;
+			if(bitm & HeightValue)
+				xw.fh = (int)hr;
+			if(bitm & XNegative && xw.fx == 0)
+				xw.fx = -1;
+			if(bitm & XNegative && xw.fy == 0)
+				xw.fy = -1;
+
+			if(xw.fh != 0 && xw.fw != 0)
+				xw.isfixed = True;
+			break;
 		case 'v':
 		default:
 			die(USAGE);
@@ -2310,3 +2359,4 @@ main(int argc, char *argv[]) {
 	run();
 	return 0;
 }
+

From 1d6702024b8930587f719288b86ba5b931ad557c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 3 Sep 2012 23:09:34 +0200
Subject: [PATCH 0258/1146] Fixing the border pixel when there is a negative
 position.

---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 8b30d4c..09b0262 100644
--- a/st.c
+++ b/st.c
@@ -1902,11 +1902,11 @@ xinit(void) {
 	/* adjust fixed window geometry */
 	if(xw.isfixed) {
 		sw = DisplayWidth(xw.dpy, xw.scr);
-		sh = DisplayWidth(xw.dpy, xw.scr);
+		sh = DisplayHeight(xw.dpy, xw.scr);
 		if(xw.fx < 0)
-			xw.fx = sw + xw.fx - xw.fw;
+			xw.fx = sw + xw.fx - xw.fw - 1;
 		if(xw.fy < 0)
-			xw.fy = sh + xw.fy - xw.fh;
+			xw.fy = sh + xw.fy - xw.fh - 1;
 	} else {
 		/* window - default size */
 		xw.h = 2*BORDER + term.row * xw.ch;

From 66669a558560c0ba3b5da4cd2009de81d68a2263 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 4 Sep 2012 20:31:21 +0200
Subject: [PATCH 0259/1146] Add newline to stderr message

---
 st.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 09b0262..586d124 100644
--- a/st.c
+++ b/st.c
@@ -784,7 +784,7 @@ ttynew(void) {
 		cmdfd = m;
 		signal(SIGCHLD, sigchld);
 		if (opt_io && !(fileio = fopen(opt_io, "w"))) {
-			fprintf(stderr, "Error opening %s:%s",
+			fprintf(stderr, "Error opening %s:%s\n",
 				opt_io, strerror(errno));
 		}
 	}

From 98b6f84bfcb63cff54f8aee87191432fa769346c Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 4 Sep 2012 20:33:01 +0200
Subject: [PATCH 0260/1146] Check alternative screen before drawing box
 selection

Some programs use the alternative screen (vi, less, ...), whose
content is different of the main screen. If you select text in one of
the screen, you don't wait the box selection is painted in the other
screen, so it is necessary check if the selection was done in the same
screen we are going to paint. Before to this commit, you could do
something like:

	$ LESS="" ls | less
	(select some code)
	q

and selection box remains drawing in the main screen, but the content
of selection keeps text of the alternate screen.
---
 st.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
---
 st.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 586d124..b143582 100644
--- a/st.c
+++ b/st.c
@@ -221,6 +221,7 @@ typedef struct {
 	struct {int x, y;} b, e;
 	char *clip;
 	Atom xtarget;
+	bool alt;
 	struct timeval tclick1;
 	struct timeval tclick2;
 } Selection;
@@ -579,6 +580,7 @@ selcopy(void) {
 		}
 		*ptr = 0;
 	}
+	sel.alt = IS_SET(MODE_ALTSCREEN);
 	xsetsel(str);
 }
 
@@ -2076,7 +2078,10 @@ drawregion(int x1, int y1, int x2, int y2) {
 	int ic, ib, x, y, ox, sl;
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
+	bool ena_sel = sel.bx != -1, alt = IS_SET(MODE_ALTSCREEN);
 
+	if((sel.alt && !alt) || (!sel.alt && alt))
+		ena_sel = 0;
 	if(!(xw.state & WIN_VISIBLE))
 		return;
 
@@ -2089,7 +2094,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 		ic = ib = ox = 0;
 		for(x = x1; x < x2; x++) {
 			new = term.line[y][x];
-			if(sel.bx != -1 && *(new.c) && selected(x, y))
+			if(ena_sel && *(new.c) && selected(x, y))
 				new.mode ^= ATTR_REVERSE;
 			if(ib > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) ||
 						  ib >= DRAW_BUF_SIZ-UTF_SIZ)) {

From 59fe59d3d1f922ec3a99c758e54ab88cfdf939be Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 4 Sep 2012 20:34:43 +0200
Subject: [PATCH 0261/1146] Unifying the old style.

---
 st.c | 47 ++++++++++++++++++++++++-----------------------
 1 file changed, 24 insertions(+), 23 deletions(-)

diff --git a/st.c b/st.c
index b143582..d483d85 100644
--- a/st.c
+++ b/st.c
@@ -785,7 +785,7 @@ ttynew(void) {
 		close(s);
 		cmdfd = m;
 		signal(SIGCHLD, sigchld);
-		if (opt_io && !(fileio = fopen(opt_io, "w"))) {
+		if(opt_io && !(fileio = fopen(opt_io, "w"))) {
 			fprintf(stderr, "Error opening %s:%s\n",
 				opt_io, strerror(errno));
 		}
@@ -884,7 +884,7 @@ treset(void) {
 	}, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
 
 	memset(term.tabs, 0, term.col * sizeof(*term.tabs));
-	for (i = TAB; i < term.col; i += TAB)
+	for(i = TAB; i < term.col; i += TAB)
 		term.tabs[i] = 1;
 	term.top = 0, term.bot = term.row - 1;
 	term.mode = MODE_WRAP;
@@ -1203,7 +1203,7 @@ void
 tsetmode(bool priv, bool set, int *args, int narg) {
 	int *lim, mode;
 
-	for (lim = args + narg; args < lim; ++args) {
+	for(lim = args + narg; args < lim; ++args) {
 		if(priv) {
 			switch(*args) {
 			case 1:
@@ -1212,7 +1212,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 5: /* DECSCNM -- Reverve video */
 				mode = term.mode;
 				MODBIT(term.mode,set, MODE_REVERSE);
-				if (mode != term.mode)
+				if(mode != term.mode)
 					redraw();
 				break;
 			case 7:
@@ -1237,11 +1237,11 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 1047:
 				if(IS_SET(MODE_ALTSCREEN))
 					tclearregion(0, 0, term.col-1, term.row-1);
-				if ((set && !IS_SET(MODE_ALTSCREEN)) ||
+				if((set && !IS_SET(MODE_ALTSCREEN)) ||
 				    (!set && IS_SET(MODE_ALTSCREEN))) {
 					    tswapscreen();
 				}
-				if (*args != 1049)
+				if(*args != 1049)
 					break;
 				/* pass through */
 			case 1048:
@@ -1334,7 +1334,7 @@ csihandle(void) {
 		break;
 	case 'I': /* CHT -- Cursor Forward Tabulation <n> tab stops */
 		DEFAULT(csiescseq.arg[0], 1);
-		while (csiescseq.arg[0]--)
+		while(csiescseq.arg[0]--)
 			tputtab(1);
 		break;
 	case 'J': /* ED -- Clear screen */
@@ -1399,7 +1399,7 @@ csihandle(void) {
 		break;
 	case 'Z': /* CBT -- Cursor Backward Tabulation <n> tab stops */
 		DEFAULT(csiescseq.arg[0], 1);
-		while (csiescseq.arg[0]--)
+		while(csiescseq.arg[0]--)
 			tputtab(0);
 		break;
 	case 'd': /* VPA -- Move to <row> */
@@ -1530,15 +1530,15 @@ void
 tputtab(bool forward) {
 	unsigned x = term.c.x;
 
-	if (forward) {
-		if (x == term.col)
+	if(forward) {
+		if(x == term.col)
 			return;
-		for (++x; x < term.col && !term.tabs[x]; ++x)
+		for(++x; x < term.col && !term.tabs[x]; ++x)
 			/* nothing */ ;
 	} else {
-		if (x == 0)
+		if(x == 0)
 			return;
-		for (--x; x > 0 && !term.tabs[x]; --x)
+		for(--x; x > 0 && !term.tabs[x]; --x)
 			/* nothing */ ;
 	}
 	tmoveto(x, term.c.y);
@@ -1548,8 +1548,9 @@ void
 tputc(char *c) {
 	char ascii = *c;
 
-	if (fileio)
+	if(fileio)
 		putc(ascii, fileio);
+
 	if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {
 			csiescseq.buf[csiescseq.len++] = ascii;
@@ -1568,7 +1569,7 @@ tputc(char *c) {
 				break;
 			default:
 				strescseq.buf[strescseq.len++] = ascii;
-				if (strescseq.len+1 >= STR_BUF_SIZ) {
+				if(strescseq.len+1 >= STR_BUF_SIZ) {
 					term.esc = 0;
 					strhandle();
 				}
@@ -1746,13 +1747,13 @@ tresize(int col, int row) {
 		term.line[i] = calloc(col, sizeof(Glyph));
 		term.alt [i] = calloc(col, sizeof(Glyph));
 	}
-	if (col > term.col) {
+	if(col > term.col) {
 		bool *bp = term.tabs + term.col;
 
 		memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
-		while (--bp > term.tabs && !*bp)
+		while(--bp > term.tabs && !*bp)
 			/* nothing */ ;
-		for (bp += TAB; bp < term.tabs + col; bp += TAB)
+		for(bp += TAB; bp < term.tabs + col; bp += TAB)
 			*bp = 1;
 	}
 	/* update terminal size */
@@ -1805,7 +1806,7 @@ xloadcols(void) {
 
 	for(r = 0; r < 24; r++, i++) {
 		color.red = color.green = color.blue = 0x0808 + 0x0a0a * r;
-		if (!XAllocColor(xw.dpy, xw.cmap, &color)) {
+		if(!XAllocColor(xw.dpy, xw.cmap, &color)) {
 			dc.col[i] = white;
 			fprintf(stderr, "Could not allocate color %d\n", i);
 		} else
@@ -2227,11 +2228,11 @@ 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) {
+	if(e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
+		if(e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
 			xw.state |= WIN_FOCUSED;
 			xseturgency(0);
-		} else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
+		} else if(e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
 			xw.state &= ~WIN_FOCUSED;
 		}
 		draw();
@@ -2322,7 +2323,7 @@ main(int argc, char *argv[]) {
 			if(++i < argc) opt_embed = argv[i];
 			break;
 		case 'f':
-			if (++i < argc) opt_io = argv[i];
+			if(++i < argc) opt_io = argv[i];
 			break;
 		case 'e':
 			/* eat every remaining arguments */

From 6e88c7f60206275a5378521ef5d3dd96b0b09f36 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 4 Sep 2012 21:56:55 +0200
Subject: [PATCH 0262/1146] CUP == HVP; CHA == HPA;

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index d483d85..11867b7 100644
--- a/st.c
+++ b/st.c
@@ -1322,12 +1322,12 @@ csihandle(void) {
 		}
 		break;
 	case 'G': /* CHA -- Move to <col> */
-	case '`': /* XXX: HPA -- same? */
+	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': /* XXX: HVP -- same? */
+	case 'f': /* HVP */
 		DEFAULT(csiescseq.arg[0], 1);
 		DEFAULT(csiescseq.arg[1], 1);
 		tmoveto(csiescseq.arg[1]-1, csiescseq.arg[0]-1);

From 052a617828e446c8ee17dfefceba447fcf1f50e2 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 4 Sep 2012 22:05:24 +0200
Subject: [PATCH 0263/1146] Updating the TODO and enabling BCE.

---
 TODO    | 9 ++++-----
 st.info | 2 +-
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/TODO b/TODO
index 3ddeeb4..c498734 100644
--- a/TODO
+++ b/TODO
@@ -1,17 +1,15 @@
 vt emulation
 ------------
 
-* screen erased with background color ## capname:bce
-* back tab                            ## capname:cbt ## seq:CSI Z
-* ...
+* color definition in CSI
+	* implement CSI parsing
+* implement real italic
 
 code & interface
 ----------------
 
 * clean selection code
 * clean and complete terminfo entry
-* fast drawing
-* ...
 
 bugs
 ----
@@ -21,6 +19,7 @@ bugs
 * fix selection click
 * fix selection paste for xatom STRING
 * fix umlaut handling in settitle
+* fix the scrolling issues in less 
 
 misc
 ----
diff --git a/st.info b/st.info
index bd9c158..ccd31f2 100644
--- a/st.info
+++ b/st.info
@@ -3,7 +3,7 @@
 st| simpleterm,
 	acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
 	am,
-#	bce,
+	bce,
 	bel=^G,
 #	blink=\E[5m,
 	bold=\E[1m,

From e02d72441ab6c1fba649ca65824b2d5dbb9db0f4 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 4 Sep 2012 22:06:54 +0200
Subject: [PATCH 0264/1146] =?UTF-8?q?Another=20thing=20for=20TODO=20?=
 =?UTF-8?q?=E2=80=93=20resize.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 TODO | 1 +
 1 file changed, 1 insertion(+)

diff --git a/TODO b/TODO
index c498734..1541d13 100644
--- a/TODO
+++ b/TODO
@@ -4,6 +4,7 @@ vt emulation
 * color definition in CSI
 	* implement CSI parsing
 * implement real italic
+* tell ncurses applications about resize
 
 code & interface
 ----------------

From b1d383a0a344e35dad1064e129f70d52bddfd7b2 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 4 Sep 2012 22:44:33 +0200
Subject: [PATCH 0265/1146] Cleaning up the fixed window size and the resizing
 of clients.

---
 st.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 11867b7..63c3f85 100644
--- a/st.c
+++ b/st.c
@@ -841,6 +841,8 @@ ttyresize(int x, int y) {
 
 	w.ws_row = term.row;
 	w.ws_col = term.col;
+	w.ws_xpixel = xw.w;
+	w.ws_ypixel = xw.h;
 	w.ws_xpixel = w.ws_ypixel = 0;
 	if(ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
 		fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
@@ -1910,12 +1912,15 @@ xinit(void) {
 			xw.fx = sw + xw.fx - xw.fw - 1;
 		if(xw.fy < 0)
 			xw.fy = sh + xw.fy - xw.fh - 1;
+
+		xw.h = xw.fh;
+		xw.w = xw.fw;
 	} else {
 		/* window - default size */
 		xw.h = 2*BORDER + term.row * xw.ch;
 		xw.w = 2*BORDER + term.col * xw.cw;
-		xw.fw = xw.w;
-		xw.fh = xw.h;
+		xw.fx = 0;
+		xw.fy = 0;
 	}
 
 	/* font */
@@ -1940,7 +1945,7 @@ xinit(void) {
 
 	parent = opt_embed ? strtol(opt_embed, NULL, 0) : XRootWindow(xw.dpy, xw.scr);
 	xw.win = XCreateWindow(xw.dpy, parent, xw.fx, xw.fy,
-			xw.fw, xw.fh, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
+			xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
 			XDefaultVisual(xw.dpy, xw.scr),
 			CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
 			| CWColormap,
@@ -2254,8 +2259,8 @@ resize(XEvent *e) {
 		return;
 	if(tresize(col, row))
 		draw();
-	ttyresize(col, row);
 	xresize(col, row);
+	ttyresize(col, row);
 }
 
 bool
@@ -2310,6 +2315,7 @@ main(int argc, char *argv[]) {
 	unsigned int wr, hr;
 
 	xw.fw = xw.fh = xw.fx = xw.fy = 0;
+	xw.isfixed = False;
 
 	for(i = 1; i < argc; i++) {
 		switch(argv[i][0] != '-' || argv[i][2] ? -1 : argv[i][1]) {

From e09709d92d89c8593f7390f12dc22fdc563eb57f Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 4 Sep 2012 22:51:29 +0200
Subject: [PATCH 0266/1146] Forgot one line. It's late.

---
 st.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.c b/st.c
index 63c3f85..a2564f8 100644
--- a/st.c
+++ b/st.c
@@ -843,7 +843,6 @@ ttyresize(int x, int y) {
 	w.ws_col = term.col;
 	w.ws_xpixel = xw.w;
 	w.ws_ypixel = xw.h;
-	w.ws_xpixel = w.ws_ypixel = 0;
 	if(ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
 		fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
 }

From 67c1a23053666dbac6b1ff9b17698f59b6b27887 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 5 Sep 2012 00:08:13 +0200
Subject: [PATCH 0267/1146] Fixing the resizing behaviour.

---
 st.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/st.c b/st.c
index a2564f8..cf329fd 100644
--- a/st.c
+++ b/st.c
@@ -739,6 +739,10 @@ execsh(void) {
 	char **args;
 	char *envshell = getenv("SHELL");
 
+	unsetenv("COLUMNS");
+	unsetenv("LINES");
+	unsetenv("TERMCAP");
+
 	DEFAULT(envshell, SHELL);
 	putenv("TERM="TNAME);
 	args = opt_cmd ? opt_cmd : (char*[]){envshell, "-i", NULL};

From 98dc91eb82843da4683a16a98050a23746e2fa68 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 5 Sep 2012 00:09:13 +0200
Subject: [PATCH 0268/1146] Removing the resize issue from the TODO file.

---
 TODO | 1 -
 1 file changed, 1 deletion(-)

diff --git a/TODO b/TODO
index 1541d13..c498734 100644
--- a/TODO
+++ b/TODO
@@ -4,7 +4,6 @@ vt emulation
 * color definition in CSI
 	* implement CSI parsing
 * implement real italic
-* tell ncurses applications about resize
 
 code & interface
 ----------------

From da4a77edbebbb75fcb549c5ecac326d5e59aeef5 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 5 Sep 2012 00:58:17 +0200
Subject: [PATCH 0269/1146] Disable BCE again.

---
 TODO    | 1 +
 st.info | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/TODO b/TODO
index c498734..9ee59e3 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,7 @@
 vt emulation
 ------------
 
+* implement BCE right
 * color definition in CSI
 	* implement CSI parsing
 * implement real italic
diff --git a/st.info b/st.info
index ccd31f2..bd9c158 100644
--- a/st.info
+++ b/st.info
@@ -3,7 +3,7 @@
 st| simpleterm,
 	acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
 	am,
-	bce,
+#	bce,
 	bel=^G,
 #	blink=\E[5m,
 	bold=\E[1m,

From a61b9ea82ef65cd00f1d4908113fb9e3f7c7cc66 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 5 Sep 2012 01:25:37 +0200
Subject: [PATCH 0270/1146] Enable keypad set and unset commands.

---
 st.info | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.info b/st.info
index bd9c158..aaae099 100644
--- a/st.info
+++ b/st.info
@@ -89,6 +89,7 @@ st| simpleterm,
 	ri=\EM,
 	rmacs=\E(B,
 	rmcup=\E[?1049l,
+	rmkx=\E>,
 	rmso=\E[23m,
 	rmul=\E[m,
 	sc=\E7,
@@ -100,6 +101,7 @@ st| simpleterm,
 	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,
 	smacs=\E(0,
 	smcup=\E[?1049h,
+	smkx=\E=,
 	smso=\E[3m,
 	smul=\E[4m,
 	tbc=\E[3g,

From 56c551e4f4b5678ba770106bf8a679c044bcf57e Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 5 Sep 2012 01:32:42 +0200
Subject: [PATCH 0271/1146] Add to TODO to make function keys work.

---
 TODO | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/TODO b/TODO
index 9ee59e3..84025ae 100644
--- a/TODO
+++ b/TODO
@@ -5,6 +5,11 @@ vt emulation
 * color definition in CSI
 	* implement CSI parsing
 * implement real italic
+* make the keypad keys really work
+	* kf0 .. kf44
+	* kend, kel, kent, kfnd, ked, kext
+	* kNXT, kPRV
+	* ka1, ka3, kb2
 
 code & interface
 ----------------

From 462a966ee2c0f49f432bedaf8e6ebdff995262a9 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 5 Sep 2012 21:48:26 +0200
Subject: [PATCH 0272/1146] Implement italic font support.

---
 TODO         |  1 -
 config.def.h | 10 ++++++----
 st.c         | 30 ++++++++++++++++++++----------
 st.info      | 10 ++++++----
 4 files changed, 32 insertions(+), 19 deletions(-)

diff --git a/TODO b/TODO
index 84025ae..c77c105 100644
--- a/TODO
+++ b/TODO
@@ -4,7 +4,6 @@ vt emulation
 * implement BCE right
 * color definition in CSI
 	* implement CSI parsing
-* implement real italic
 * make the keypad keys really work
 	* kf0 .. kf44
 	* kend, kel, kent, kfnd, ked, kext
diff --git a/config.def.h b/config.def.h
index 047b5d1..0aef8be 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,6 +1,8 @@
 
 #define FONT "-*-*-medium-r-*-*-*-120-75-75-*-60-*-*"
 #define BOLDFONT "-*-*-bold-r-*-*-*-120-75-75-*-60-*-*"
+/* If italic is not availbel, fall back to bold. */
+#define ITALICFONT "-*-*-medium-o-*-*-*-120-75-75-*-60-*-*," BOLDFONT
 
 /* Space in pixels around the terminal buffer */
 #define BORDER 2
@@ -29,9 +31,9 @@ static const char *colorname[] = {
 	"magenta",
 	"cyan",
 	"white",
-	
+
 	[255] = 0,
-	
+
 	/* more colors can be added after 255 to use with DefaultXX */
 	"#cccccc",
 	"#333333",
@@ -50,11 +52,11 @@ static const char *colorname[] = {
    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)
-   
+
       key,        mask,  output */
 static Key key[] = {
 	{ XK_BackSpace, XK_NO_MOD, "\177" },
-   	{ XK_Insert,    XK_NO_MOD, "\033[2~" },
+	{ XK_Insert,    XK_NO_MOD, "\033[2~" },
 	{ XK_Delete,    XK_NO_MOD, "\033[3~" },
 	{ XK_Home,      XK_NO_MOD, "\033[1~" },
 	{ XK_End,       XK_NO_MOD, "\033[4~" },
diff --git a/st.c b/st.c
index cf329fd..655d5a3 100644
--- a/st.c
+++ b/st.c
@@ -76,6 +76,7 @@ enum glyph_attribute {
 	ATTR_UNDERLINE = 2,
 	ATTR_BOLD      = 4,
 	ATTR_GFX       = 8,
+	ATTR_ITALIC    = 16,
 };
 
 enum cursor_movement {
@@ -238,7 +239,7 @@ typedef struct {
 		short lbearing;
 		short rbearing;
 		XFontSet set;
-	} font, bfont;
+	} font, bfont, ifont;
 } DC;
 
 static void die(const char*, ...);
@@ -1122,8 +1123,8 @@ tsetattr(int *attr, int l) {
 		case 1:
 			term.c.attr.mode |= ATTR_BOLD;
 			break;
-		case 3: /* enter standout (highlight) mode TODO: make it italic */
-			term.c.attr.mode |= ATTR_REVERSE;
+		case 3: /* enter standout (highlight) */
+			term.c.attr.mode |= ATTR_ITALIC;
 			break;
 		case 4:
 			term.c.attr.mode |= ATTR_UNDERLINE;
@@ -1134,8 +1135,8 @@ tsetattr(int *attr, int l) {
 		case 22:
 			term.c.attr.mode &= ~ATTR_BOLD;
 			break;
-		case 23: /* leave standout (highlight) mode TODO: make it italic */
-			term.c.attr.mode &= ~ATTR_REVERSE;
+		case 23: /* leave standout (highlight) mode */
+			term.c.attr.mode &= ~ATTR_ITALIC;
 			break;
 		case 24:
 			term.c.attr.mode &= ~ATTR_UNDERLINE;
@@ -1886,14 +1887,20 @@ xgetfontinfo(XFontSet set, int *ascent, int *descent, short *lbearing, short *rb
 }
 
 void
-initfonts(char *fontstr, char *bfontstr) {
-	if((dc.font.set = xinitfont(fontstr)) == NULL ||
-	   (dc.bfont.set = xinitfont(bfontstr)) == NULL)
-		die("Can't load font %s\n", dc.font.set ? BOLDFONT : FONT);
+initfonts(char *fontstr, char *bfontstr, char *ifontstr) {
+	if((dc.font.set = xinitfont(fontstr)) == NULL)
+		die("Can't load font %s\n", fontstr);
+	if((dc.bfont.set = xinitfont(bfontstr)) == NULL)
+		die("Can't load bfont %s\n", bfontstr);
+	if((dc.ifont.set = xinitfont(ifontstr)) == NULL)
+		die("Can't load ifont %s\n", ifontstr);
+
 	xgetfontinfo(dc.font.set, &dc.font.ascent, &dc.font.descent,
 	    &dc.font.lbearing, &dc.font.rbearing);
 	xgetfontinfo(dc.bfont.set, &dc.bfont.ascent, &dc.bfont.descent,
 	    &dc.bfont.lbearing, &dc.bfont.rbearing);
+	xgetfontinfo(dc.ifont.set, &dc.ifont.ascent, &dc.ifont.descent,
+	    &dc.ifont.lbearing, &dc.ifont.rbearing);
 }
 
 void
@@ -1927,7 +1934,7 @@ xinit(void) {
 	}
 
 	/* font */
-	initfonts(FONT, BOLDFONT);
+	initfonts(FONT, BOLDFONT, ITALICFONT);
 
 	/* XXX: Assuming same size for bold font */
 	xw.cw = dc.font.rbearing - dc.font.lbearing;
@@ -2002,6 +2009,9 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		fontset = dc.bfont.set;
 	}
 
+	if(base.mode & ATTR_ITALIC)
+		fontset = dc.ifont.set;
+
 	XSetBackground(xw.dpy, dc.gc, dc.col[bg]);
 	XSetForeground(xw.dpy, dc.gc, dc.col[fg]);
 
diff --git a/st.info b/st.info
index aaae099..38012d8 100644
--- a/st.info
+++ b/st.info
@@ -83,15 +83,16 @@ st| simpleterm,
 	op=\E[39;49m,
 	pairs#64,
 	rc=\E8,
-	rs1=\Ec,
-	rs2=\E[4l\E>,
 	rev=\E[7m,
 	ri=\EM,
+	ritm=\E[23m,
 	rmacs=\E(B,
 	rmcup=\E[?1049l,
-	rmkx=\E>,
+#	rmkx=\E>,
 	rmso=\E[23m,
 	rmul=\E[m,
+	rs1=\Ec,
+	rs2=\E[4l\E>,
 	sc=\E7,
 	setab=\E[4%p1%dm,
 	setaf=\E[3%p1%dm,
@@ -99,9 +100,10 @@ st| simpleterm,
 	setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
 	sgr0=\E[0m,
 	sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
+	sitm=\E[3m,
 	smacs=\E(0,
 	smcup=\E[?1049h,
-	smkx=\E=,
+#	smkx=\E=,
 	smso=\E[3m,
 	smul=\E[4m,
 	tbc=\E[3g,

From 42505c5215c84db192287337922581ba43dec89d Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 5 Sep 2012 21:52:01 +0200
Subject: [PATCH 0273/1146] Removing unneeded arguments to copy(). Thanks to
 Andrew Hills.

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 655d5a3..4e208d4 100644
--- a/st.c
+++ b/st.c
@@ -2059,7 +2059,7 @@ xdrawcursor(void) {
 	} else
 		xclear(oldx, oldy, oldx, oldy);
 
-	xcopy(oldx, oldy, 1, 1);
+	xcopy();
 
 	/* draw the new one */
 	if(!(term.c.state & CURSOR_HIDE)) {
@@ -2074,7 +2074,7 @@ xdrawcursor(void) {
 		oldx = term.c.x, oldy = term.c.y;
 	}
 
-	xcopy(term.c.x, term.c.y, 1, 1);
+	xcopy();
 }
 
 void

From 017af76f5c89fa1acf9b54ceaad2101dcfd880a0 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 5 Sep 2012 21:54:52 +0200
Subject: [PATCH 0274/1146] Forcing the parameter limit to xcopy() and
 selpaste(). Thanks to Rob Pilling.

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 4e208d4..8e31a73 100644
--- a/st.c
+++ b/st.c
@@ -291,7 +291,7 @@ static void ttywrite(const char *, size_t);
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
 static void xclear(int, int, int, int);
-static void xcopy();
+static void xcopy(void);
 static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
@@ -316,7 +316,7 @@ static void selrequest(XEvent *);
 static void selinit(void);
 static inline bool selected(int, int);
 static void selcopy(void);
-static void selpaste();
+static void selpaste(void);
 static void selscroll(int, int);
 
 static int utf8decode(char *, long *);

From f471a32d29ad9e5e06cf5e5d5efc8422483f535e Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 5 Sep 2012 21:55:45 +0200
Subject: [PATCH 0275/1146] Unhighlight selection when selection is owner by
 other window

st marks the active selection using reverse colors in the box selection, but
once that another window becomes owner of the selection, it is very
confusing that st keeps highlight the old selection. Usually terminal
emulators remove the highlight when it is not valid anymore.

X sends a SelectionClear event in this situation, so we only have to add a
callback which unhighlight the selectin box.
---
 st.c |    9 +++++++++
 1 file changed, 9 insertions(+)
---
 st.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/st.c b/st.c
index 8e31a73..bf3993a 100644
--- a/st.c
+++ b/st.c
@@ -311,6 +311,7 @@ static void brelease(XEvent *);
 static void bpress(XEvent *);
 static void bmotion(XEvent *);
 static void selnotify(XEvent *);
+static void selclear(XEvent *);
 static void selrequest(XEvent *);
 
 static void selinit(void);
@@ -336,6 +337,7 @@ static void (*handler[LASTEvent])(XEvent *) = {
 	[MotionNotify] = bmotion,
 	[ButtonPress] = bpress,
 	[ButtonRelease] = brelease,
+	[SelectionClear] = selclear,
 	[SelectionNotify] = selnotify,
 	[SelectionRequest] = selrequest,
 };
@@ -612,6 +614,13 @@ selpaste() {
 	XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY, xw.win, CurrentTime);
 }
 
+void selclear(XEvent *e) {
+	if(sel.bx == -1)
+		return;
+	sel.bx = -1;
+	tsetdirt(sel.b.y, sel.e.y);
+}
+
 void
 selrequest(XEvent *e) {
 	XSelectionRequestEvent *xsre;

From dd0b7a077f5184c0eac99955aeb91f3c6a0d9c11 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 5 Sep 2012 22:17:42 +0200
Subject: [PATCH 0276/1146] If the selection is cleared, draw() and do it on
 button press too.

---
 st.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.c b/st.c
index bf3993a..a2f4f46 100644
--- a/st.c
+++ b/st.c
@@ -551,6 +551,7 @@ bpress(XEvent *e) {
 		sel.mode = 1;
 		sel.ex = sel.bx = X2COL(e->xbutton.x);
 		sel.ey = sel.by = Y2ROW(e->xbutton.y);
+		draw();
 	}
 }
 
@@ -619,6 +620,7 @@ void selclear(XEvent *e) {
 		return;
 	sel.bx = -1;
 	tsetdirt(sel.b.y, sel.e.y);
+	draw();
 }
 
 void

From 4a4ae19158a6d18d63b8e9fce92e6e5e45543746 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 5 Sep 2012 22:39:09 +0200
Subject: [PATCH 0277/1146] Removing masks for unhandled enter and leaving
 events.

---
 st.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/st.c b/st.c
index a2f4f46..165d930 100644
--- a/st.c
+++ b/st.c
@@ -1960,8 +1960,7 @@ xinit(void) {
 	attrs.bit_gravity = NorthWestGravity;
 	attrs.event_mask = FocusChangeMask | KeyPressMask
 		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
-		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask
-		| EnterWindowMask | LeaveWindowMask;
+		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
 	attrs.colormap = xw.cmap;
 
 	parent = opt_embed ? strtol(opt_embed, NULL, 0) : XRootWindow(xw.dpy, xw.scr);
@@ -2047,7 +2046,6 @@ void
 xcopy() {
 	XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
 	XdbeSwapBuffers(xw.dpy, swpinfo, 1);
-
 }
 
 void

From 86cf8e3073aa5c51f7ea8ea9a9ca5f13dde829c3 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 5 Sep 2012 23:06:59 +0200
Subject: [PATCH 0278/1146] Adding the removal of the timeouts to the TODO.

---
 TODO | 1 +
 1 file changed, 1 insertion(+)

diff --git a/TODO b/TODO
index c77c105..1996137 100644
--- a/TODO
+++ b/TODO
@@ -15,6 +15,7 @@ code & interface
 
 * clean selection code
 * clean and complete terminfo entry
+* remove the timeouts in the main loop
 
 bugs
 ----

From f2da43a0b66f76532ebef5ed2b2c9135aca771a5 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 5 Sep 2012 23:38:57 +0200
Subject: [PATCH 0279/1146] Adding instantenous debug output and fixing italic
 with a reset.

---
 st.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 165d930..fd5e0fd 100644
--- a/st.c
+++ b/st.c
@@ -1127,7 +1127,8 @@ tsetattr(int *attr, int l) {
 	for(i = 0; i < l; i++) {
 		switch(attr[i]) {
 		case 0:
-			term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE | ATTR_BOLD);
+			term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE | ATTR_BOLD \
+					| ATTR_ITALIC);
 			term.c.attr.fg = DefaultFG;
 			term.c.attr.bg = DefaultBG;
 			break;
@@ -1565,8 +1566,10 @@ void
 tputc(char *c) {
 	char ascii = *c;
 
-	if(fileio)
+	if(fileio) {
 		putc(ascii, fileio);
+		fflush(fileio);
+	}
 
 	if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {

From a1cd28f8099eac3938461f9e63ff6b74d4d824ef Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 6 Sep 2012 00:00:50 +0200
Subject: [PATCH 0280/1146] Allow simpler stdout -f handling.

---
 st.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index fd5e0fd..7852de0 100644
--- a/st.c
+++ b/st.c
@@ -801,9 +801,15 @@ ttynew(void) {
 		close(s);
 		cmdfd = m;
 		signal(SIGCHLD, sigchld);
-		if(opt_io && !(fileio = fopen(opt_io, "w"))) {
-			fprintf(stderr, "Error opening %s:%s\n",
-				opt_io, strerror(errno));
+		if(opt_io) {
+			if(!strcmp(opt_io, "-")) {
+				fileio = stdout;
+			} else {
+				if(!(fileio = fopen(opt_io, "w"))) {
+					fprintf(stderr, "Error opening %s:%s\n",
+						opt_io, strerror(errno));
+				}
+			}
 		}
 	}
 }

From 122ed577027ccbb85b2fe6a0f9449035fe074a9e Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 6 Sep 2012 08:02:56 +0200
Subject: [PATCH 0281/1146] Making the selection work again.

---
 st.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.c b/st.c
index 7852de0..a4575f4 100644
--- a/st.c
+++ b/st.c
@@ -551,7 +551,6 @@ bpress(XEvent *e) {
 		sel.mode = 1;
 		sel.ex = sel.bx = X2COL(e->xbutton.x);
 		sel.ey = sel.by = Y2ROW(e->xbutton.y);
-		draw();
 	}
 }
 

From af29fb2a5015918a8bb32075ab82b4e59d85910a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 10 Sep 2012 13:39:41 +0200
Subject: [PATCH 0282/1146] Fixing the too small window in non-tiling window
 managers.

---
 st.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/st.c b/st.c
index a4575f4..15d22ac 100644
--- a/st.c
+++ b/st.c
@@ -1933,6 +1933,17 @@ xinit(void) {
 		die("Can't open display\n");
 	xw.scr = XDefaultScreen(xw.dpy);
 
+	/* font */
+	initfonts(FONT, BOLDFONT, ITALICFONT);
+
+	/* XXX: Assuming same size for bold font */
+	xw.cw = dc.font.rbearing - dc.font.lbearing;
+	xw.ch = dc.font.ascent + dc.font.descent;
+
+	/* colors */
+	xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
+	xloadcols();
+
 	/* adjust fixed window geometry */
 	if(xw.isfixed) {
 		sw = DisplayWidth(xw.dpy, xw.scr);
@@ -1952,17 +1963,6 @@ xinit(void) {
 		xw.fy = 0;
 	}
 
-	/* font */
-	initfonts(FONT, BOLDFONT, ITALICFONT);
-
-	/* XXX: Assuming same size for bold font */
-	xw.cw = dc.font.rbearing - dc.font.lbearing;
-	xw.ch = dc.font.ascent + dc.font.descent;
-
-	/* colors */
-	xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
-	xloadcols();
-
 	attrs.background_pixel = dc.col[DefaultBG];
 	attrs.border_pixel = dc.col[DefaultBG];
 	attrs.bit_gravity = NorthWestGravity;

From c092bce366ce7469e92f59c889b31fa9037976b2 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 12 Sep 2012 13:00:39 +0200
Subject: [PATCH 0283/1146] Add another obscure way to set a window title.

---
 st.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/st.c b/st.c
index 15d22ac..f3b0b08 100644
--- a/st.c
+++ b/st.c
@@ -1509,6 +1509,9 @@ strhandle(void) {
 			break;
 		}
 		break;
+	case 'k': /* old title set compatibility */
+		XStoreName(xw.dpy, xw.win, strescseq.buf);
+		break;
 	case 'P': /* DSC -- Device Control String */
 	case '_': /* APC -- Application Program Command */
 	case '^': /* PM -- Privacy Message */
@@ -1624,6 +1627,7 @@ tputc(char *c) {
 			case '_': /* APC -- Application Program Command */
 			case '^': /* PM -- Privacy Message */
 			case ']': /* OSC -- Operating System Command */
+			case 'k': /* old title set compatibility */
 				strreset();
 				strescseq.type = ascii;
 				term.esc |= ESC_STR;

From 121d9109e8202aaa8df836f2d23922008bdf2c72 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 12 Sep 2012 13:08:26 +0200
Subject: [PATCH 0284/1146] Add preliminary blink stubs. Real implementation is
 still missing.

---
 st.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index f3b0b08..5e8cf02 100644
--- a/st.c
+++ b/st.c
@@ -77,6 +77,7 @@ enum glyph_attribute {
 	ATTR_BOLD      = 4,
 	ATTR_GFX       = 8,
 	ATTR_ITALIC    = 16,
+	ATTR_BLINK     = 32,
 };
 
 enum cursor_movement {
@@ -1133,7 +1134,7 @@ tsetattr(int *attr, int l) {
 		switch(attr[i]) {
 		case 0:
 			term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE | ATTR_BOLD \
-					| ATTR_ITALIC);
+					| ATTR_ITALIC | ATTR_BLINK);
 			term.c.attr.fg = DefaultFG;
 			term.c.attr.bg = DefaultBG;
 			break;
@@ -1146,6 +1147,9 @@ tsetattr(int *attr, int l) {
 		case 4:
 			term.c.attr.mode |= ATTR_UNDERLINE;
 			break;
+		case 5:
+			term.c.attr.mode |= ATTR_BLINK;
+			break;
 		case 7:
 			term.c.attr.mode |= ATTR_REVERSE;
 			break;
@@ -1158,6 +1162,9 @@ tsetattr(int *attr, int l) {
 		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;

From 8f1144edee8f4c9ac54faae2ad522544e9e217fa Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 12 Sep 2012 13:20:10 +0200
Subject: [PATCH 0285/1146] Make nyancat(1) work. Important release feature!

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 5e8cf02..75c6cea 100644
--- a/st.c
+++ b/st.c
@@ -1204,7 +1204,7 @@ tsetattr(int *attr, int l) {
 			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.fg = attr[i] - 100 + 8;
+				term.c.attr.bg = attr[i] - 100 + 8;
 			else
 				fprintf(stderr, "erresc(default): gfx attr %d unknown\n", attr[i]), csidump();
 			break;

From b9d5fec4f277b688b3bb4741134abf152e801e90 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 12 Sep 2012 21:25:35 +0200
Subject: [PATCH 0286/1146] Add xmalloc and xrealloc wrappers

If malloc  or realloc fail they return NULL. Theorically this condition
should be tested in the code, but it's a strange condition today (basically
if this is hapenning thenyou have a big problem), and even Linux never returns
NULL in the default configuration (only if the process don't have room in
the space address, something a bit impossible in the case of st). But stis
enough small for being executed in low resources computers where this can be
a real problem. So the easy way is creating a wrappers function for them and
call to die in case of error.
---
 st.c |   44 +++++++++++++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 13 deletions(-)
---
 st.c | 44 +++++++++++++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 13 deletions(-)

diff --git a/st.c b/st.c
index 75c6cea..8741145 100644
--- a/st.c
+++ b/st.c
@@ -326,6 +326,9 @@ static int utf8encode(long *, char *);
 static int utf8size(char *);
 static int isfullutf8(char *, int);
 
+static void *xmalloc(size_t);
+static void *xrealloc(void *, size_t);
+
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
 	[ClientMessage] = cmessage,
@@ -359,6 +362,21 @@ static char *opt_title = NULL;
 static char *opt_embed = NULL;
 static char *opt_class = NULL;
 
+void *
+xmalloc(size_t len) {
+	void *p = malloc(len);
+	if(!p)
+		die("Out of memory");
+	return p;
+}
+
+void *
+xrealloc(void *p, size_t len) {
+	if((p = realloc(p, len)) == NULL)
+		die("Out of memory");
+	return p;
+}
+
 int
 utf8decode(char *s, long *u) {
 	uchar c;
@@ -565,7 +583,7 @@ selcopy(void) {
 
 	else {
 		bufsize = (term.col+1) * (sel.e.y-sel.b.y+1) * UTF_SIZ;
-		ptr = str = malloc(bufsize);
+		ptr = str = xmalloc(bufsize);
 
 		/* append every set & selected glyph to the selection */
 		for(y = 0; y < term.row; y++) {
@@ -918,14 +936,14 @@ void
 tnew(int col, int row) {
 	/* set screen size */
 	term.row = row, term.col = col;
-	term.line = malloc(term.row * sizeof(Line));
-	term.alt  = malloc(term.row * sizeof(Line));
-	term.dirty = malloc(term.row * sizeof(*term.dirty));
-	term.tabs = malloc(term.col * sizeof(*term.tabs));
+	term.line = xmalloc(term.row * sizeof(Line));
+	term.alt  = xmalloc(term.row * sizeof(Line));
+	term.dirty = xmalloc(term.row * sizeof(*term.dirty));
+	term.tabs = xmalloc(term.col * sizeof(*term.tabs));
 
 	for(row = 0; row < term.row; row++) {
-		term.line[row] = malloc(term.col * sizeof(Glyph));
-		term.alt [row] = malloc(term.col * sizeof(Glyph));
+		term.line[row] = xmalloc(term.col * sizeof(Glyph));
+		term.alt [row] = xmalloc(term.col * sizeof(Glyph));
 		term.dirty[row] = 0;
 	}
 	memset(term.tabs, 0, term.col * sizeof(*term.tabs));
@@ -1761,16 +1779,16 @@ tresize(int col, int row) {
 	}
 
 	/* resize to new height */
-	term.line = realloc(term.line, row * sizeof(Line));
-	term.alt  = realloc(term.alt,  row * sizeof(Line));
-	term.dirty = realloc(term.dirty, row * sizeof(*term.dirty));
-	term.tabs = realloc(term.tabs, col * sizeof(*term.tabs));
+	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.dirty[i] = 1;
-		term.line[i] = realloc(term.line[i], col * sizeof(Glyph));
-		term.alt[i]  = realloc(term.alt[i],  col * sizeof(Glyph));
+		term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
+		term.alt[i]  = xrealloc(term.alt[i],  col * sizeof(Glyph));
 		for(x = mincol; x < col; x++) {
 			term.line[i][x].state = 0;
 			term.alt[i][x].state = 0;

From 720cb816dcff55f8b75bdc2a8ffa265f460f5d55 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 12 Sep 2012 21:51:55 +0200
Subject: [PATCH 0287/1146] Remove buffering to fileio instead of calling
 fflush

By default text files are line buffered, and this means that -f option will
not write the line until a \n is printed. This is not very useful for
debugging, so a call to fflush was added. This patch substitute this call
(which will be done by each character painted) by the full remove of the
buffering in the file.
---
 st.c |   12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)
---
 st.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index 8741145..19d0a86 100644
--- a/st.c
+++ b/st.c
@@ -355,7 +355,7 @@ static STREscape strescseq;
 static int cmdfd;
 static pid_t pid;
 static Selection sel;
-static FILE *fileio;
+static int iofd = -1;
 static char **opt_cmd  = NULL;
 static char *opt_io    = NULL;
 static char *opt_title = NULL;
@@ -821,9 +821,9 @@ ttynew(void) {
 		signal(SIGCHLD, sigchld);
 		if(opt_io) {
 			if(!strcmp(opt_io, "-")) {
-				fileio = stdout;
+				iofd = STDOUT_FILENO;
 			} else {
-				if(!(fileio = fopen(opt_io, "w"))) {
+				if((iofd = open(opt_io, O_WRONLY | O_CREAT, 0666)) < 0) {
 					fprintf(stderr, "Error opening %s:%s\n",
 						opt_io, strerror(errno));
 				}
@@ -1599,10 +1599,8 @@ void
 tputc(char *c) {
 	char ascii = *c;
 
-	if(fileio) {
-		putc(ascii, fileio);
-		fflush(fileio);
-	}
+	if(iofd != -1)
+		write(iofd, c, 1);
 
 	if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {

From d018c9c8efc3e1781d84d7b7d24e9531bb841b34 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 13 Sep 2012 07:04:34 +0200
Subject: [PATCH 0288/1146] Adding another bold off sequence.

---
 st.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index 19d0a86..0db81f4 100644
--- a/st.c
+++ b/st.c
@@ -1171,6 +1171,7 @@ tsetattr(int *attr, int l) {
 		case 7:
 			term.c.attr.mode |= ATTR_REVERSE;
 			break;
+		case 21:
 		case 22:
 			term.c.attr.mode &= ~ATTR_BOLD;
 			break;

From 977c5d908903c4c300b02811382a9ab53ec73803 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 13 Sep 2012 07:04:59 +0200
Subject: [PATCH 0289/1146] Adding a statemant on legacy support.

---
 LEGACY | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 LEGACY

diff --git a/LEGACY b/LEGACY
new file mode 100644
index 0000000..6aca893
--- /dev/null
+++ b/LEGACY
@@ -0,0 +1,17 @@
+A STATEMENT ON LEGACY SUPPORT
+
+In the terminal world there is much cruft that comes from old and unsup‐
+ported terminals that inherit incompatible modes  and  escape  sequences
+which noone is able to know, except when he/she comes from that time and
+developed a graphical vt100 emulator at that time.
+
+One  goal  of  st is to only support what is really needed. When you en‐
+counter a sequence which you really need, implement it.  But  while  you
+are  add 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
+

From fe2ba95b3d81127b98a5dc6fa0341a90beabd1a0 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 13 Sep 2012 07:16:38 +0200
Subject: [PATCH 0290/1146] Reset window title on terminal reset too.

---
 st.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 0db81f4..fe2b922 100644
--- a/st.c
+++ b/st.c
@@ -296,6 +296,7 @@ static void xcopy(void);
 static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
+static void xresettitle(void);
 static void xseturgency(int);
 static void xsetsel(char*);
 static void xresize(int, int);
@@ -1684,6 +1685,7 @@ tputc(char *c) {
 			case 'c': /* RIS -- Reset to inital state */
 				treset();
 				term.esc = 0;
+				xresettitle();
 				break;
 			case '=': /* DECPAM -- Application keypad */
 				term.mode |= MODE_APPKEYPAD;
@@ -2026,7 +2028,7 @@ xinit(void) {
 
 	xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
 
-	XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st");
+	xresettitle();
 	XMapWindow(xw.dpy, xw.win);
 	xhints();
 	XSync(xw.dpy, 0);
@@ -2122,6 +2124,11 @@ xdrawcursor(void) {
 	xcopy();
 }
 
+void
+xresettitle(void) {
+	XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st");
+}
+
 void
 redraw(void) {
 	struct timespec tv = {0, REDRAW_TIMEOUT * 1000};

From 776a022e39a3c8f7c81b35d6b4307ffaa0ae3df8 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 13 Sep 2012 23:19:57 +0200
Subject: [PATCH 0291/1146] Importing the patch of Roberto Vargas to inherit
 signal handlers.

---
 st.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/st.c b/st.c
index fe2b922..c2ee3e2 100644
--- a/st.c
+++ b/st.c
@@ -774,6 +774,13 @@ execsh(void) {
 	unsetenv("LINES");
 	unsetenv("TERMCAP");
 
+	signal(SIGCHLD, SIG_DFL);
+	signal(SIGHUP, SIG_DFL);
+	signal(SIGINT, SIG_DFL);
+	signal(SIGQUIT, SIG_DFL);
+	signal(SIGTERM, SIG_DFL);
+	signal(SIGALRM, SIG_DFL);
+
 	DEFAULT(envshell, SHELL);
 	putenv("TERM="TNAME);
 	args = opt_cmd ? opt_cmd : (char*[]){envshell, "-i", NULL};

From b1563526561a913dc2a69ee78eb5aaa09cc98978 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 13 Sep 2012 23:21:40 +0200
Subject: [PATCH 0292/1146] Ignore NUL character as a padding character. Telnet
 may use this. Patch of

Roberto Vargas.
---
 st.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.c b/st.c
index c2ee3e2..da895c6 100644
--- a/st.c
+++ b/st.c
@@ -1723,6 +1723,8 @@ tputc(char *c) {
 		if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey))
 			sel.bx = -1;
 		switch(ascii) {
+		case '\0': /* padding character, do nothing */
+			break;
 		case '\t':
 			tputtab(1);
 			break;

From a62789788c87425fd90209bad15b324f8dee84da Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 14 Sep 2012 19:46:07 +0200
Subject: [PATCH 0293/1146] Implementing italic-bold. This will require an
 increase of the avgWdth.

---
 config.def.h |  7 ++++---
 st.c         | 12 +++++++++---
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/config.def.h b/config.def.h
index 0aef8be..f0e5556 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,8 +1,9 @@
 
-#define FONT "-*-*-medium-r-*-*-*-120-75-75-*-60-*-*"
-#define BOLDFONT "-*-*-bold-r-*-*-*-120-75-75-*-60-*-*"
+#define FONT "-*-*-medium-r-*-*-*-120-75-75-*-70-*-*"
+#define BOLDFONT "-*-*-bold-r-*-*-*-120-75-75-*-70-*-*"
 /* If italic is not availbel, fall back to bold. */
-#define ITALICFONT "-*-*-medium-o-*-*-*-120-75-75-*-60-*-*," BOLDFONT
+#define ITALICFONT "-*-*-medium-o-*-*-*-120-75-75-*-70-*-*," BOLDFONT
+#define ITALICBOLDFONT "-*-*-bold-o-*-*-*-120-75-75-*-70-*-*," BOLDFONT
 
 /* Space in pixels around the terminal buffer */
 #define BORDER 2
diff --git a/st.c b/st.c
index da895c6..2e1ac67 100644
--- a/st.c
+++ b/st.c
@@ -240,7 +240,7 @@ typedef struct {
 		short lbearing;
 		short rbearing;
 		XFontSet set;
-	} font, bfont, ifont;
+	} font, bfont, ifont, ibfont;
 } DC;
 
 static void die(const char*, ...);
@@ -1945,13 +1945,15 @@ xgetfontinfo(XFontSet set, int *ascent, int *descent, short *lbearing, short *rb
 }
 
 void
-initfonts(char *fontstr, char *bfontstr, char *ifontstr) {
+initfonts(char *fontstr, char *bfontstr, char *ifontstr, char *ibfontstr) {
 	if((dc.font.set = xinitfont(fontstr)) == NULL)
 		die("Can't load font %s\n", fontstr);
 	if((dc.bfont.set = xinitfont(bfontstr)) == NULL)
 		die("Can't load bfont %s\n", bfontstr);
 	if((dc.ifont.set = xinitfont(ifontstr)) == NULL)
 		die("Can't load ifont %s\n", ifontstr);
+	if((dc.ibfont.set = xinitfont(ibfontstr)) == NULL)
+		die("Can't load ibfont %s\n", ibfontstr);
 
 	xgetfontinfo(dc.font.set, &dc.font.ascent, &dc.font.descent,
 	    &dc.font.lbearing, &dc.font.rbearing);
@@ -1959,6 +1961,8 @@ initfonts(char *fontstr, char *bfontstr, char *ifontstr) {
 	    &dc.bfont.lbearing, &dc.bfont.rbearing);
 	xgetfontinfo(dc.ifont.set, &dc.ifont.ascent, &dc.ifont.descent,
 	    &dc.ifont.lbearing, &dc.ifont.rbearing);
+	xgetfontinfo(dc.ibfont.set, &dc.ibfont.ascent, &dc.ibfont.descent,
+	    &dc.ibfont.lbearing, &dc.ibfont.rbearing);
 }
 
 void
@@ -1973,7 +1977,7 @@ xinit(void) {
 	xw.scr = XDefaultScreen(xw.dpy);
 
 	/* font */
-	initfonts(FONT, BOLDFONT, ITALICFONT);
+	initfonts(FONT, BOLDFONT, ITALICFONT, ITALICBOLDFONT);
 
 	/* XXX: Assuming same size for bold font */
 	xw.cw = dc.font.rbearing - dc.font.lbearing;
@@ -2068,6 +2072,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 	if(base.mode & ATTR_ITALIC)
 		fontset = dc.ifont.set;
+	if(base.mode & (ATTR_ITALIC|ATTR_ITALIC))
+		fontset = dc.ibfont.set;
 
 	XSetBackground(xw.dpy, dc.gc, dc.col[bg]);
 	XSetForeground(xw.dpy, dc.gc, dc.col[fg]);

From ba1e9daeef0d7e6e52a9889d8f7eb61d74480cf0 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 16 Sep 2012 10:45:36 +0200
Subject: [PATCH 0294/1146] Call XdbeQueryExtension before of calling any Xdbe
 function

XdbeQueryExtension() tells to the caller if the Xdbe extension is present in
the X server, so it should be called for sanity. But like is said in
XdbeQueryExtension(3):

	No other Xdbe functions may be called before this function.  If a
	client violates this rule, the effects of all subsequent Xdbe calls
	that it makes are undefined.

it is mandatory call this function.
---
 st.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
---
 st.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 2e1ac67..b013bca 100644
--- a/st.c
+++ b/st.c
@@ -1970,7 +1970,7 @@ xinit(void) {
 	XSetWindowAttributes attrs;
 	Cursor cursor;
 	Window parent;
-	int sw, sh;
+	int sw, sh, major, minor;
 
 	if(!(xw.dpy = XOpenDisplay(NULL)))
 		die("Can't open display\n");
@@ -2021,9 +2021,10 @@ xinit(void) {
 			CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
 			| CWColormap,
 			&attrs);
+	if(!XdbeQueryExtension(xw.dpy, &major, &minor))
+		die("Xdbe extension is not present\n");
 	xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeCopied);
 
-
 	/* input methods */
 	xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
 	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing

From 15cc8754c2e272ebac6e86845859816e881da000 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 16 Sep 2012 10:46:08 +0200
Subject: [PATCH 0295/1146] Call XSync in redraw

It is necessary call to XSync if you want a good tput flash, because in
other way you can not be sure that white screen will be shown.
---
 st.c |    1 +
 1 file changed, 1 insertion(+)
---
 st.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index b013bca..f4ad23d 100644
--- a/st.c
+++ b/st.c
@@ -2150,6 +2150,7 @@ redraw(void) {
 	struct timespec tv = {0, REDRAW_TIMEOUT * 1000};
 	tfulldirt();
 	draw();
+	XSync(xw.dpy, False); /* necessary for a good tput flash */
 	nanosleep(&tv, NULL);
 }
 

From 85849ce72aa4e9cee307a031b97777e9eba2d453 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 16 Sep 2012 10:47:21 +0200
Subject: [PATCH 0296/1146] Remove timeout in the main loop

The main loop waits until there is some data to read in file descriptors of
the X server or the pseudo tty. But it uses a timeout in select(), which
causes that st awake each 20 ms, even it doesn't have something to do. This
patch removes this problem removing the timeout, which is not needed.
---
 TODO |    1 -
 st.c |   27 +++------------------------
 2 files changed, 3 insertions(+), 25 deletions(-)
---
 TODO |  1 -
 st.c | 27 +++------------------------
 2 files changed, 3 insertions(+), 25 deletions(-)

diff --git a/TODO b/TODO
index 1996137..c77c105 100644
--- a/TODO
+++ b/TODO
@@ -15,7 +15,6 @@ code & interface
 
 * clean selection code
 * clean and complete terminfo entry
-* remove the timeouts in the main loop
 
 bugs
 ----
diff --git a/st.c b/st.c
index f4ad23d..d7ca875 100644
--- a/st.c
+++ b/st.c
@@ -53,8 +53,6 @@
 #define XK_NO_MOD     UINT_MAX
 #define XK_ANY_MOD    0
 
-#define SELECT_TIMEOUT (20*1000) /* 20 ms */
-#define DRAW_TIMEOUT  (20*1000) /* 20 ms */
 #define REDRAW_TIMEOUT (80*1000) /* 80 ms */
 
 #define SERRNO strerror(errno)
@@ -205,7 +203,6 @@ typedef struct {
 	int ch; /* char height */
 	int cw; /* char width  */
 	char state; /* focus, redraw, visible */
-	struct timeval lastdraw;
 } XWindow;
 
 typedef struct {
@@ -250,7 +247,6 @@ static void drawregion(int, int, int, int);
 static void execsh(void);
 static void sigchld(int);
 static void run(void);
-static bool last_draw_too_old(void);
 
 static void csidump(void);
 static void csihandle(void);
@@ -2158,7 +2154,6 @@ void
 draw() {
 	drawregion(0, 0, term.col, term.row);
 	xcopy();
-	gettimeofday(&xw.lastdraw, NULL);
 }
 
 void
@@ -2345,41 +2340,25 @@ resize(XEvent *e) {
 	ttyresize(col, row);
 }
 
-bool
-last_draw_too_old(void) {
-	struct timeval now;
-	gettimeofday(&now, NULL);
-	return TIMEDIFF(now, xw.lastdraw) >= DRAW_TIMEOUT/1000;
-}
-
 void
 run(void) {
 	XEvent ev;
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dpy);
-	struct timeval timeout = {0};
-	bool stuff_to_print = 0;
 
 	for(;;) {
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);
-		timeout.tv_sec  = 0;
-		timeout.tv_usec = SELECT_TIMEOUT;
-		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, &timeout) < 0) {
+		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL) < 0) {
 			if(errno == EINTR)
 				continue;
 			die("select failed: %s\n", SERRNO);
 		}
-		if(FD_ISSET(cmdfd, &rfd)) {
+		if(FD_ISSET(cmdfd, &rfd))
 			ttyread();
-			stuff_to_print = 1;
-		}
 
-		if(stuff_to_print && last_draw_too_old()) {
-			stuff_to_print = 0;
-			draw();
-		}
+		draw();
 
 		while(XPending(xw.dpy)) {
 			XNextEvent(xw.dpy, &ev);

From c5a9b799d44be9c0fa4264dc34d9dd61321be795 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 16 Sep 2012 10:48:38 +0200
Subject: [PATCH 0297/1146] Render only once in each main loop iteration

draw() runs over all lines of the screen and renders only the dirty lines,
this avoids render lines which are not modified since last draw() call. In
this moment the main loop is something like:

     - Wait something to read from file descriptors
     - Read from pseudo tty
     - Call draw() for rending
     - Read X events

This cause the problem that all the X events that have to update the screen
have to call draw() (because draw() is called before of X events handling),
so you can have multiples renderings in only one iteration, that will waste
a lot of resources.

This patch change the main loop to:

     - Wait something to read from file descriptors
     - Read from pseudo tty
     - Read X events
     - Call draw() for rending

So X events don't have to worry about rendering, because draw() is called
after them.

The only place where draw is called outside of the main loop is in redraw(),
but it is necessary for getting a good tput flash.
---
 st.c |   29 ++++++-----------------------
 1 file changed, 6 insertions(+), 23 deletions(-)
---
 st.c | 29 ++++++-----------------------
 1 file changed, 6 insertions(+), 23 deletions(-)

diff --git a/st.c b/st.c
index d7ca875..397f6a6 100644
--- a/st.c
+++ b/st.c
@@ -288,7 +288,6 @@ static void ttywrite(const char *, size_t);
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
 static void xclear(int, int, int, int);
-static void xcopy(void);
 static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
@@ -635,7 +634,6 @@ void selclear(XEvent *e) {
 		return;
 	sel.bx = -1;
 	tsetdirt(sel.b.y, sel.e.y);
-	draw();
 }
 
 void
@@ -685,8 +683,6 @@ xsetsel(char *str) {
 
 	clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
 	XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
-
-	XFlush(xw.dpy);
 }
 
 void
@@ -729,7 +725,6 @@ brelease(XEvent *e) {
 	}
 	memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval));
 	gettimeofday(&sel.tclick1, NULL);
-	draw();
 }
 
 void
@@ -746,7 +741,6 @@ bmotion(XEvent *e) {
 			int starty = MIN(oldey, sel.ey);
 			int endy = MAX(oldey, sel.ey);
 			tsetdirt(starty, endy);
-			draw();
 		}
 	}
 }
@@ -2091,13 +2085,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);
 }
 
-/* copy buffer pixmap to screen pixmap */
-void
-xcopy() {
-	XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
-	XdbeSwapBuffers(xw.dpy, swpinfo, 1);
-}
-
 void
 xdrawcursor(void) {
 	static int oldx = 0;
@@ -2118,8 +2105,6 @@ xdrawcursor(void) {
 	} else
 		xclear(oldx, oldy, oldx, oldy);
 
-	xcopy();
-
 	/* draw the new one */
 	if(!(term.c.state & CURSOR_HIDE)) {
 		if(!(xw.state & WIN_FOCUSED))
@@ -2132,8 +2117,6 @@ xdrawcursor(void) {
 		xdraws(g.c, g, term.c.x, term.c.y, 1, sl);
 		oldx = term.c.x, oldy = term.c.y;
 	}
-
-	xcopy();
 }
 
 void
@@ -2152,8 +2135,10 @@ redraw(void) {
 
 void
 draw() {
+	XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
+
 	drawregion(0, 0, term.col, term.row);
-	xcopy();
+	XdbeSwapBuffers(xw.dpy, swpinfo, 1);
 }
 
 void
@@ -2208,7 +2193,6 @@ expose(XEvent *ev) {
 		if(!e->count)
 			xw.state &= ~WIN_REDRAW;
 	}
-	xcopy();
 }
 
 void
@@ -2241,7 +2225,6 @@ focus(XEvent *ev) {
 		xseturgency(0);
 	} else
 		xw.state &= ~WIN_FOCUSED;
-	draw();
 }
 
 char*
@@ -2317,7 +2300,6 @@ cmessage(XEvent *e) {
 		} else if(e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
 			xw.state &= ~WIN_FOCUSED;
 		}
-		draw();
 	}
 }
 
@@ -2358,8 +2340,6 @@ run(void) {
 		if(FD_ISSET(cmdfd, &rfd))
 			ttyread();
 
-		draw();
-
 		while(XPending(xw.dpy)) {
 			XNextEvent(xw.dpy, &ev);
 			if(XFilterEvent(&ev, xw.win))
@@ -2367,6 +2347,9 @@ run(void) {
 			if(handler[ev.type])
 				(handler[ev.type])(&ev);
 		}
+
+		draw();
+		XFlush(xw.dpy);
 	}
 }
 

From d81250e5f96e96dd430a3fc61b5b47ffc04f98d8 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 16 Sep 2012 10:49:12 +0200
Subject: [PATCH 0298/1146] Fix selection bug

After the commit named "Remove timeout in the main loop", selection is not
working in the proper way. After selecting something, press mouse button in
a line outside of selection causes an incorrect highlight. This patch fix
the problem forcing a draw after the press event, but this is only a fast
hack. Real solution means rewriting selection code.
---
 st.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
---
 st.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 397f6a6..12d6665 100644
--- a/st.c
+++ b/st.c
@@ -561,8 +561,11 @@ bpress(XEvent *e) {
 	if(IS_SET(MODE_MOUSE))
 		mousereport(e);
 	else if(e->xbutton.button == Button1) {
-		if(sel.bx != -1)
+		if(sel.bx != -1) {
+			sel.bx = -1;
 			tsetdirt(sel.b.y, sel.e.y);
+			draw();
+		}
 		sel.mode = 1;
 		sel.ex = sel.bx = X2COL(e->xbutton.x);
 		sel.ey = sel.by = Y2ROW(e->xbutton.y);

From 9fbafe55c996324a73a0be3af80edcd39e5a393b Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 16 Sep 2012 13:22:23 +0200
Subject: [PATCH 0299/1146] Preliminary solution to the stuttering problem.

---
 st.c | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 12d6665..da6f17e 100644
--- a/st.c
+++ b/st.c
@@ -48,7 +48,7 @@
 #define ESC_ARG_SIZ   16
 #define STR_BUF_SIZ   256
 #define STR_ARG_SIZ   16
-#define DRAW_BUF_SIZ  1024
+#define DRAW_BUF_SIZ  20*1024
 #define UTF_SIZ       4
 #define XK_NO_MOD     UINT_MAX
 #define XK_ANY_MOD    0
@@ -2329,7 +2329,8 @@ void
 run(void) {
 	XEvent ev;
 	fd_set rfd;
-	int xfd = XConnectionNumber(xw.dpy);
+	int xfd = XConnectionNumber(xw.dpy), i;
+	struct timeval drawtimeout;
 
 	for(;;) {
 		FD_ZERO(&rfd);
@@ -2340,9 +2341,29 @@ run(void) {
 				continue;
 			die("select failed: %s\n", SERRNO);
 		}
-		if(FD_ISSET(cmdfd, &rfd))
+
+		/*
+		 * Stop after a certain number of reads so the user does not
+		 * feel like the system is stuttering.
+		 */
+		for(i = 0; i < 1000 && FD_ISSET(cmdfd, &rfd); i++) {
 			ttyread();
 
+			FD_ZERO(&rfd);
+			FD_SET(cmdfd, &rfd);
+			/*
+			 * Just wait a bit so it isn't disturbing the
+			 * user and the system is able to write something.
+			 */
+			drawtimeout.tv_sec = 0;
+			drawtimeout.tv_usec = 5;
+			if(select(cmdfd+1, &rfd, NULL, NULL, &drawtimeout) < 0) {
+				if(errno == EINTR)
+					continue;
+				die("select failed: %s\n", SERRNO);
+			}
+		}
+
 		while(XPending(xw.dpy)) {
 			XNextEvent(xw.dpy, &ev);
 			if(XFilterEvent(&ev, xw.win))

From b93741e34df3ebe05f7ccc14f1fd4b0da01bf1fa Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 16 Sep 2012 13:50:07 +0200
Subject: [PATCH 0300/1146] Remove some solved issues and add some new.

---
 TODO | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/TODO b/TODO
index c77c105..144bb2c 100644
--- a/TODO
+++ b/TODO
@@ -9,22 +9,26 @@ vt emulation
 	* kend, kel, kent, kfnd, ked, kext
 	* kNXT, kPRV
 	* ka1, ka3, kb2
+* add arrow keys handling
 
 code & interface
 ----------------
 
 * clean selection code
 * clean and complete terminfo entry
+* add border around cursor, when it could be hard to read
+	* white border when not selected would suffice
+	* + definition in config.h
 
 bugs
 ----
 
 * handle XOpenMI() errors
 * fix shift up/down (shift selection in emacs)
-* fix selection click
 * fix selection paste for xatom STRING
 * fix umlaut handling in settitle
-* fix the scrolling issues in less 
+* fix rows and column definition in fixed geometry
+* clear the borders of the st window, if something has drawn on it
 
 misc
 ----

From 2257932261375d663aa5b99ce4592499470ab06a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 16 Sep 2012 13:59:10 +0200
Subject: [PATCH 0301/1146] Adding some more fields to the manpage, like
 authors, license etc.

---
 st.1 | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/st.1 b/st.1
index 8269b38..8ec0008 100644
--- a/st.1
+++ b/st.1
@@ -38,7 +38,8 @@ prints version information to stderr, then exits.
 .TP
 .BI \-f " file"
 writes all the I/O to
-.I file
+.I file.
+This feature is useful when recording st sessions.
 .TP
 .BI \-e " program " [ " arguments " "... ]"
 st executes
@@ -46,3 +47,16 @@ st executes
 instead of the shell.  If this is used it
 .B must be the last option
 on the command line, as in xterm / rxvt.
+.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)
+.SH BUGS
+See the TODO file in the distribution.
+

From 58a57a23051deba7c77901c9971d839a0db05db0 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 16 Sep 2012 14:02:35 +0200
Subject: [PATCH 0302/1146] Remove call to draw in resize

In previous commits draw was removed from all the X events, but I forgot do
it in resize.
---
 st.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index da6f17e..6371167 100644
--- a/st.c
+++ b/st.c
@@ -2319,8 +2319,7 @@ resize(XEvent *e) {
 	row = (xw.h - 2*BORDER) / xw.ch;
 	if(col == term.col && row == term.row)
 		return;
-	if(tresize(col, row))
-		draw();
+	tresize(col, row);
 	xresize(col, row);
 	ttyresize(col, row);
 }

From 426887ccec8577ee33d1fb44f258d6a70a2eddf1 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 16 Sep 2012 20:43:51 +0200
Subject: [PATCH 0303/1146] Applying a shortening proposal for the run loop of
 k0ga.

---
 st.c | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/st.c b/st.c
index 6371167..d5ecf61 100644
--- a/st.c
+++ b/st.c
@@ -2329,13 +2329,13 @@ run(void) {
 	XEvent ev;
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dpy), i;
-	struct timeval drawtimeout;
+	struct timeval drawtimeout, *tv = NULL;
 
-	for(;;) {
+	for(i = 0;; i++) {
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);
-		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL) < 0) {
+		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv) < 0) {
 			if(errno == EINTR)
 				continue;
 			die("select failed: %s\n", SERRNO);
@@ -2345,23 +2345,20 @@ run(void) {
 		 * Stop after a certain number of reads so the user does not
 		 * feel like the system is stuttering.
 		 */
-		for(i = 0; i < 1000 && FD_ISSET(cmdfd, &rfd); i++) {
+		if(i < 1000 && FD_ISSET(cmdfd, &rfd)) {
 			ttyread();
 
-			FD_ZERO(&rfd);
-			FD_SET(cmdfd, &rfd);
 			/*
 			 * Just wait a bit so it isn't disturbing the
 			 * user and the system is able to write something.
 			 */
 			drawtimeout.tv_sec = 0;
 			drawtimeout.tv_usec = 5;
-			if(select(cmdfd+1, &rfd, NULL, NULL, &drawtimeout) < 0) {
-				if(errno == EINTR)
-					continue;
-				die("select failed: %s\n", SERRNO);
-			}
+			tv = &drawtimeout;
+			continue;
 		}
+		i = 0;
+		tv = NULL;
 
 		while(XPending(xw.dpy)) {
 			XNextEvent(xw.dpy, &ev);

From e3671006dba1c21316c570e11d6688f5513fb44e Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 17 Sep 2012 22:11:20 +0200
Subject: [PATCH 0304/1146] Add xcalloc wrapper

malloc and realloc are called through xmalloc and xrealloc, so calloc should
be called through xcalloc.
---
 st.c |   13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)
---
 st.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index d5ecf61..df7f8d8 100644
--- a/st.c
+++ b/st.c
@@ -324,6 +324,7 @@ static int isfullutf8(char *, int);
 
 static void *xmalloc(size_t);
 static void *xrealloc(void *, size_t);
+static void *xcalloc(size_t nmemb, size_t size);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
@@ -373,6 +374,14 @@ xrealloc(void *p, size_t len) {
 	return p;
 }
 
+void *
+xcalloc(size_t nmemb, size_t size) {
+	void *p = calloc(nmemb, size);
+	if(!p)
+		die("Out of memory\n");
+	return p;
+}
+
 int
 utf8decode(char *s, long *u) {
 	uchar c;
@@ -1801,8 +1810,8 @@ tresize(int col, int row) {
 	/* allocate any new rows */
 	for(/* i == minrow */; i < row; i++) {
 		term.dirty[i] = 1;
-		term.line[i] = calloc(col, sizeof(Glyph));
-		term.alt [i] = calloc(col, sizeof(Glyph));
+		term.line[i] = xcalloc(col, sizeof(Glyph));
+		term.alt [i] = xcalloc(col, sizeof(Glyph));
 	}
 	if(col > term.col) {
 		bool *bp = term.tabs + term.col;

From 111199cf226b33f12e6ee3e66e50fbe5c3566e33 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 17 Sep 2012 22:11:28 +0200
Subject: [PATCH 0305/1146] Add newline in error messages

---
 st.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index df7f8d8..c408ca9 100644
--- a/st.c
+++ b/st.c
@@ -363,14 +363,14 @@ void *
 xmalloc(size_t len) {
 	void *p = malloc(len);
 	if(!p)
-		die("Out of memory");
+		die("Out of memory\n");
 	return p;
 }
 
 void *
 xrealloc(void *p, size_t len) {
 	if((p = realloc(p, len)) == NULL)
-		die("Out of memory");
+		die("Out of memory\n");
 	return p;
 }
 

From 88a8f85a8a6de56d23510cf6e7810d90478085a5 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 17 Sep 2012 22:13:09 +0200
Subject: [PATCH 0306/1146] Copy non set positions as spaces

st selection don't insert in the selection position whose value is not
set. This is correct for the positions in the end of the line, but cause
some problems in the beginning. For example echo -e 'a\tb' will print in the
screen:

a	b

but after selecting and copying in some place you get:

ab

because positions from 1 to 7 don't have any value. This patch deals all
positions without value as blank (even at the end of the line).
---
 st.c |   17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)
---
 st.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index c408ca9..b2e5e22 100644
--- a/st.c
+++ b/st.c
@@ -596,14 +596,17 @@ selcopy(void) {
 		/* append every set & selected glyph to the selection */
 		for(y = 0; y < term.row; y++) {
 			for(x = 0; x < term.col; x++) {
-				is_selected = selected(x, y);
-				if((term.line[y][x].state & GLYPH_SET) && is_selected) {
-					int size = utf8size(term.line[y][x].c);
-					memcpy(ptr, term.line[y][x].c, size);
-					ptr += size;
-				}
-			}
+				int size;
+				char *p;
+				Glyph *gp = &term.line[y][x];
 
+				if(!(is_selected = selected(x, y)))
+					continue;
+				p = (gp->state & GLYPH_SET) ? gp->c : " ";
+				size = utf8size(p);
+				memcpy(ptr, p, size);
+				ptr += size;
+			}
 			/* \n at the end of every selected line except for the last one */
 			if(is_selected && y < sel.e.y)
 				*ptr++ = '\n';

From 4876d6e05b6c1b17b0c366f15ae72ae48f045068 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 17 Sep 2012 22:13:17 +0200
Subject: [PATCH 0307/1146] Clean windows display after resizing

Some times the size after a resizing is not an exact multiply of a number of
characters, so redrawn the screen using the lines and columns of the neww
size can cause that some old graphics keep in the screen. Solution is clean
all the windows with the background color.
---
 st.c |    3 +++
 1 file changed, 3 insertions(+)
---
 st.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.c b/st.c
index b2e5e22..20e4512 100644
--- a/st.c
+++ b/st.c
@@ -1839,6 +1839,9 @@ void
 xresize(int col, int row) {
 	xw.w = MAX(1, 2*BORDER + col * xw.cw);
 	xw.h = MAX(1, 2*BORDER + row * xw.ch);
+	XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0,
+		       DisplayWidth(xw.dpy, xw.scr),
+		       DisplayHeight(xw.dpy, xw.scr));
 }
 
 void

From e4bf2679c1bbbd4d4a8bfdf9c1a143b59ce5888c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 17 Sep 2012 22:44:27 +0200
Subject: [PATCH 0308/1146] Fixing the redrawing patch of k0ga, so it's using
 xclear() in redraw() too.

---
 st.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index 20e4512..89c59b4 100644
--- a/st.c
+++ b/st.c
@@ -198,6 +198,7 @@ typedef struct {
 	int scr;
 	Bool isfixed; /* is fixed geometry? */
 	int fx, fy, fw, fh; /* fixed geometry */
+	int tw, th; /* tty width and height */
 	int w;	/* window width */
 	int h;	/* window height */
 	int ch; /* char height */
@@ -894,8 +895,8 @@ ttyresize(int x, int y) {
 
 	w.ws_row = term.row;
 	w.ws_col = term.col;
-	w.ws_xpixel = xw.w;
-	w.ws_ypixel = xw.h;
+	w.ws_xpixel = xw.tw;
+	w.ws_ypixel = xw.th;
 	if(ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
 		fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
 }
@@ -1837,11 +1838,8 @@ tresize(int col, int row) {
 
 void
 xresize(int col, int row) {
-	xw.w = MAX(1, 2*BORDER + col * xw.cw);
-	xw.h = MAX(1, 2*BORDER + row * xw.ch);
-	XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0,
-		       DisplayWidth(xw.dpy, xw.scr),
-		       DisplayHeight(xw.dpy, xw.scr));
+	xw.tw = MAX(1, 2*BORDER + col * xw.cw);
+	xw.th = MAX(1, 2*BORDER + row * xw.ch);
 }
 
 void
@@ -2145,6 +2143,8 @@ xresettitle(void) {
 void
 redraw(void) {
 	struct timespec tv = {0, REDRAW_TIMEOUT * 1000};
+
+	xclear(0, 0, xw.w, xw.h);
 	tfulldirt();
 	draw();
 	XSync(xw.dpy, False); /* necessary for a good tput flash */
@@ -2334,6 +2334,8 @@ resize(XEvent *e) {
 	row = (xw.h - 2*BORDER) / xw.ch;
 	if(col == term.col && row == term.row)
 		return;
+
+	xclear(0, 0, xw.w, xw.h);
 	tresize(col, row);
 	xresize(col, row);
 	ttyresize(col, row);

From 0eaed8f085d9b0c4763ca3a42338f40e2401e335 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 17 Sep 2012 23:14:40 +0200
Subject: [PATCH 0309/1146] Redrawing is fixed.

---
 TODO | 1 -
 1 file changed, 1 deletion(-)

diff --git a/TODO b/TODO
index 144bb2c..45eaf7f 100644
--- a/TODO
+++ b/TODO
@@ -28,7 +28,6 @@ bugs
 * fix selection paste for xatom STRING
 * fix umlaut handling in settitle
 * fix rows and column definition in fixed geometry
-* clear the borders of the st window, if something has drawn on it
 
 misc
 ----

From 50a619cee3093ad00a5672075b1f8914467d37e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Tue, 18 Sep 2012 19:08:03 +0200
Subject: [PATCH 0310/1146] LEGACY: typo.

---
 LEGACY | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LEGACY b/LEGACY
index 6aca893..bf28b1e 100644
--- a/LEGACY
+++ b/LEGACY
@@ -7,7 +7,7 @@ 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  add it, do not add the other cruft you might encounter while sneek‐
+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.
 

From 1ba5f4172f0bf8b5001ffcfc69118b62bf0fb78a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Tue, 18 Sep 2012 19:13:19 +0200
Subject: [PATCH 0311/1146] config.def.h: typo in comment.

---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index f0e5556..7746eaf 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,7 +1,7 @@
 
 #define FONT "-*-*-medium-r-*-*-*-120-75-75-*-70-*-*"
 #define BOLDFONT "-*-*-bold-r-*-*-*-120-75-75-*-70-*-*"
-/* If italic is not availbel, fall back to bold. */
+/* If italic is not available, fall back to bold. */
 #define ITALICFONT "-*-*-medium-o-*-*-*-120-75-75-*-70-*-*," BOLDFONT
 #define ITALICBOLDFONT "-*-*-bold-o-*-*-*-120-75-75-*-70-*-*," BOLDFONT
 

From 816a70c01ba6bf5e5d2d5e91830f75ef8e4b595d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Aptel?= <aurelien.aptel@gmail.com>
Date: Wed, 19 Sep 2012 16:03:16 +0200
Subject: [PATCH 0312/1146] use typedef'd unsigned type and regular bool type.

---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 89c59b4..35f6f16 100644
--- a/st.c
+++ b/st.c
@@ -196,7 +196,7 @@ typedef struct {
 	XIM xim;
 	XIC xic;
 	int scr;
-	Bool isfixed; /* is fixed geometry? */
+	bool isfixed; /* is fixed geometry? */
 	int fx, fy, fw, fh; /* fixed geometry */
 	int tw, th; /* tty width and height */
 	int w;	/* window width */
@@ -931,7 +931,7 @@ tcursor(int mode) {
 
 void
 treset(void) {
-	unsigned i;
+	uint i;
 	term.c = (TCursor){{
 		.mode = ATTR_NULL,
 		.fg = DefaultFG,
@@ -1594,7 +1594,7 @@ strreset(void) {
 
 void
 tputtab(bool forward) {
-	unsigned x = term.c.x;
+	uint x = term.c.x;
 
 	if(forward) {
 		if(x == term.col)
@@ -2393,7 +2393,7 @@ run(void) {
 int
 main(int argc, char *argv[]) {
 	int i, bitm, xr, yr;
-	unsigned int wr, hr;
+	uint wr, hr;
 
 	xw.fw = xw.fh = xw.fx = xw.fy = 0;
 	xw.isfixed = False;

From 2b3c1219c863d9faa30ae58e5bf56d58ada0247d Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 24 Sep 2012 10:20:45 +0200
Subject: [PATCH 0313/1146] Initial Xft support for st. More to follow.

---
 config.def.h |   9 ++--
 config.mk    |   4 +-
 st.c         | 130 +++++++++++++++++++++++----------------------------
 3 files changed, 65 insertions(+), 78 deletions(-)

diff --git a/config.def.h b/config.def.h
index 7746eaf..5cb1fd2 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,9 +1,8 @@
 
-#define FONT "-*-*-medium-r-*-*-*-120-75-75-*-70-*-*"
-#define BOLDFONT "-*-*-bold-r-*-*-*-120-75-75-*-70-*-*"
-/* If italic is not available, fall back to bold. */
-#define ITALICFONT "-*-*-medium-o-*-*-*-120-75-75-*-70-*-*," BOLDFONT
-#define ITALICBOLDFONT "-*-*-bold-o-*-*-*-120-75-75-*-70-*-*," BOLDFONT
+#define FONT "Bitstream Vera Sans Mono:pixelsize=12:antialias=false:autohint=true"
+#define BOLDFONT FONT ":weight=bold"
+#define ITALICFONT FONT ":slant=italic,oblique"
+#define ITALICBOLDFONT BOLDFONT ":slant=italic,oblique"
 
 /* Space in pixels around the terminal buffer */
 #define BORDER 2
diff --git a/config.mk b/config.mk
index 4f273cd..f57afa2 100644
--- a/config.mk
+++ b/config.mk
@@ -11,8 +11,8 @@ X11INC = /usr/X11R6/include
 X11LIB = /usr/X11R6/lib
 
 # includes and libs
-INCS = -I. -I/usr/include -I${X11INC}
-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext
+INCS = -I. -I/usr/include -I${X11INC} -I/usr/include/freetype2
+LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext -lXft
 
 # flags
 CPPFLAGS = -DVERSION=\"${VERSION}\"
diff --git a/st.c b/st.c
index 89c59b4..f7fecf8 100644
--- a/st.c
+++ b/st.c
@@ -25,6 +25,9 @@
 #include <X11/cursorfont.h>
 #include <X11/keysym.h>
 #include <X11/extensions/Xdbe.h>
+#include <X11/Xft/Xft.h>
+#define Glyph Glyph_
+#define Font Font_
 
 #if   defined(__linux)
  #include <pty.h>
@@ -195,6 +198,8 @@ typedef struct {
 	Atom xembed;
 	XIM xim;
 	XIC xic;
+	XftDraw *xft_draw;
+	Visual *vis;
 	int scr;
 	Bool isfixed; /* is fixed geometry? */
 	int fx, fy, fw, fh; /* fixed geometry */
@@ -212,7 +217,6 @@ typedef struct {
 	char s[ESC_BUF_SIZ];
 } Key;
 
-
 /* TODO: use better name for vars... */
 typedef struct {
 	int mode;
@@ -228,17 +232,22 @@ typedef struct {
 
 #include "config.h"
 
+/* Font structure */
+typedef struct {
+	int ascent;
+	int descent;
+	short lbearing;
+	short rbearing;
+	XFontSet set;
+	XftFont* xft_set;
+} Font;
+
 /* Drawing Context */
 typedef struct {
 	ulong col[LEN(colorname) < 256 ? 256 : LEN(colorname)];
+	XftColor xft_col[LEN(colorname) < 256 ? 256 : LEN(colorname)];
 	GC gc;
-	struct {
-		int ascent;
-		int descent;
-		short lbearing;
-		short rbearing;
-		XFontSet set;
-	} font, bfont, ifont, ibfont;
+	Font font, bfont, ifont, ibfont;
 } DC;
 
 static void die(const char*, ...);
@@ -1840,47 +1849,49 @@ void
 xresize(int col, int row) {
 	xw.tw = MAX(1, 2*BORDER + col * xw.cw);
 	xw.th = MAX(1, 2*BORDER + row * xw.ch);
+
+	XftDrawChange(xw.xft_draw, xw.buf);
 }
 
 void
 xloadcols(void) {
 	int i, r, g, b;
-	XColor color;
+	XRenderColor xft_color = { .alpha = 0 };
 	ulong white = WhitePixel(xw.dpy, xw.scr);
 
 	/* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */
 	for(i = 0; i < LEN(colorname); i++) {
 		if(!colorname[i])
 			continue;
-		if(!XAllocNamedColor(xw.dpy, xw.cmap, colorname[i], &color, &color)) {
+		if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[i], &dc.xft_col[i])) {
 			dc.col[i] = white;
 			fprintf(stderr, "Could not allocate color '%s'\n", colorname[i]);
 		} else
-			dc.col[i] = color.pixel;
+			dc.col[i] = dc.xft_col[i].pixel;
 	}
 
 	/* load colors [16-255] ; same colors as xterm */
 	for(i = 16, r = 0; r < 6; r++)
 		for(g = 0; g < 6; g++)
 			for(b = 0; b < 6; b++) {
-				color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r;
-				color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g;
-				color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b;
-				if(!XAllocColor(xw.dpy, xw.cmap, &color)) {
+				xft_color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r;
+				xft_color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g;
+				xft_color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b;
+				if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color, &dc.xft_col[i])) {
 					dc.col[i] = white;
 					fprintf(stderr, "Could not allocate color %d\n", i);
 				} else
-					dc.col[i] = color.pixel;
+					dc.col[i] = dc.xft_col[i].pixel;
 				i++;
 			}
 
 	for(r = 0; r < 24; r++, i++) {
-		color.red = color.green = color.blue = 0x0808 + 0x0a0a * r;
-		if(!XAllocColor(xw.dpy, xw.cmap, &color)) {
+		xft_color.red = xft_color.green = xft_color.blue = 0x0808 + 0x0a0a * r;
+		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color, &dc.xft_col[i])) {
 			dc.col[i] = white;
 			fprintf(stderr, "Could not allocate color %d\n", i);
 		} else
-			dc.col[i] = color.pixel;
+			dc.col[i] = dc.xft_col[i].pixel;
 	}
 }
 
@@ -1917,58 +1928,25 @@ xhints(void) {
 	XFree(sizeh);
 }
 
-XFontSet
-xinitfont(char *fontstr) {
-	XFontSet set;
-	char *def, **missing;
-	int n;
-
-	missing = NULL;
-	set = XCreateFontSet(xw.dpy, fontstr, &missing, &n, &def);
-	if(missing) {
-		while(n--)
-			fprintf(stderr, "st: missing fontset: %s\n", missing[n]);
-		XFreeStringList(missing);
-	}
-	return set;
-}
-
 void
-xgetfontinfo(XFontSet set, int *ascent, int *descent, short *lbearing, short *rbearing) {
-	XFontStruct **xfonts;
-	char **font_names;
-	int i, n;
+xinitfont(Font *f, char *fontstr) {
+	f->xft_set = XftFontOpenName(xw.dpy, xw.scr, fontstr);
 
-	*ascent = *descent = *lbearing = *rbearing = 0;
-	n = XFontsOfFontSet(set, &xfonts, &font_names);
-	for(i = 0; i < n; i++) {
-		*ascent = MAX(*ascent, (*xfonts)->ascent);
-		*descent = MAX(*descent, (*xfonts)->descent);
-		*lbearing = MAX(*lbearing, (*xfonts)->min_bounds.lbearing);
-		*rbearing = MAX(*rbearing, (*xfonts)->max_bounds.rbearing);
-		xfonts++;
-	}
+	if(!f->xft_set)
+		die("st: can't open font %s.\n", fontstr);
+
+	f->ascent = f->xft_set->ascent;
+	f->descent = f->xft_set->descent;
+	f->lbearing = 0;
+	f->rbearing = f->xft_set->max_advance_width;
 }
 
 void
 initfonts(char *fontstr, char *bfontstr, char *ifontstr, char *ibfontstr) {
-	if((dc.font.set = xinitfont(fontstr)) == NULL)
-		die("Can't load font %s\n", fontstr);
-	if((dc.bfont.set = xinitfont(bfontstr)) == NULL)
-		die("Can't load bfont %s\n", bfontstr);
-	if((dc.ifont.set = xinitfont(ifontstr)) == NULL)
-		die("Can't load ifont %s\n", ifontstr);
-	if((dc.ibfont.set = xinitfont(ibfontstr)) == NULL)
-		die("Can't load ibfont %s\n", ibfontstr);
-
-	xgetfontinfo(dc.font.set, &dc.font.ascent, &dc.font.descent,
-	    &dc.font.lbearing, &dc.font.rbearing);
-	xgetfontinfo(dc.bfont.set, &dc.bfont.ascent, &dc.bfont.descent,
-	    &dc.bfont.lbearing, &dc.bfont.rbearing);
-	xgetfontinfo(dc.ifont.set, &dc.ifont.ascent, &dc.ifont.descent,
-	    &dc.ifont.lbearing, &dc.ifont.rbearing);
-	xgetfontinfo(dc.ibfont.set, &dc.ibfont.ascent, &dc.ibfont.descent,
-	    &dc.ibfont.lbearing, &dc.ibfont.rbearing);
+	xinitfont(&dc.font, fontstr);
+	xinitfont(&dc.bfont, bfontstr);
+	xinitfont(&dc.ifont, ifontstr);
+	xinitfont(&dc.ibfont, ibfontstr);
 }
 
 void
@@ -1981,6 +1959,7 @@ xinit(void) {
 	if(!(xw.dpy = XOpenDisplay(NULL)))
 		die("Can't open display\n");
 	xw.scr = XDefaultScreen(xw.dpy);
+	xw.vis = XDefaultVisual(xw.dpy, xw.scr);
 
 	/* font */
 	initfonts(FONT, BOLDFONT, ITALICFONT, ITALICBOLDFONT);
@@ -2023,14 +2002,19 @@ xinit(void) {
 	parent = opt_embed ? strtol(opt_embed, NULL, 0) : XRootWindow(xw.dpy, xw.scr);
 	xw.win = XCreateWindow(xw.dpy, parent, xw.fx, xw.fy,
 			xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
-			XDefaultVisual(xw.dpy, xw.scr),
+			xw.vis,
 			CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
 			| CWColormap,
 			&attrs);
+
+	/* double buffering */
 	if(!XdbeQueryExtension(xw.dpy, &major, &minor))
 		die("Xdbe extension is not present\n");
 	xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeCopied);
 
+	/* Xft rendering context */
+	xw.xft_draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
+
 	/* input methods */
 	xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
 	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
@@ -2058,7 +2042,8 @@ void
 xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	int fg = base.fg, bg = base.bg, temp;
 	int winx = BORDER+x*xw.cw, winy = BORDER+y*xw.ch + dc.font.ascent, width = charlen*xw.cw;
-	XFontSet fontset = dc.font.set;
+	Font *font = &dc.font;
+	XGlyphInfo extents;
 	int i;
 
 	/* only switch default fg/bg if term is in RV mode */
@@ -2074,13 +2059,13 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 	if(base.mode & ATTR_BOLD) {
 		fg += 8;
-		fontset = dc.bfont.set;
+		font = &dc.bfont;
 	}
 
 	if(base.mode & ATTR_ITALIC)
-		fontset = dc.ifont.set;
+		font = &dc.ifont;
 	if(base.mode & (ATTR_ITALIC|ATTR_ITALIC))
-		fontset = dc.ibfont.set;
+		font = &dc.ibfont;
 
 	XSetBackground(xw.dpy, dc.gc, dc.col[bg]);
 	XSetForeground(xw.dpy, dc.gc, dc.col[fg]);
@@ -2095,7 +2080,10 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		}
 	}
 
-	XmbDrawImageString(xw.dpy, xw.buf, fontset, dc.gc, winx, winy, s, bytelen);
+	XftTextExtentsUtf8(xw.dpy, font->xft_set, (FcChar8 *)s, bytelen, &extents);
+	width = extents.xOff;
+	XftDrawRect(xw.xft_draw, &dc.xft_col[bg], winx, winy - font->ascent, width, xw.ch);
+	XftDrawStringUtf8(xw.xft_draw, &dc.xft_col[fg], font->xft_set, winx, winy, (FcChar8 *)s, bytelen);
 
 	if(base.mode & ATTR_UNDERLINE)
 		XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);

From b6cfff16254bb9014f27ff4c5c9e49953ee91735 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 24 Sep 2012 10:26:50 +0200
Subject: [PATCH 0314/1146] Clear X window in tsetreset()

tsetreset() is called when it is necessary a full initialization of the
terminal, so it also should clean the full X window and not only the
terminal content. It is necessary change the order of the
initialization in main(), and put xinit before of tnew(), because tnew()
calls to tsetreset(), and  this can cause a call to xreset() with
incorrect values.
---
 st.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 3c158c0..4c8d67f 100644
--- a/st.c
+++ b/st.c
@@ -952,6 +952,7 @@ treset(void) {
 		term.tabs[i] = 1;
 	term.top = 0, term.bot = term.row - 1;
 	term.mode = MODE_WRAP;
+	xclear(0, 0, xw.w, xw.h);
 	tclearregion(0, 0, term.col-1, term.row-1);
 }
 
@@ -2433,9 +2434,9 @@ main(int argc, char *argv[]) {
 
  run:
 	setlocale(LC_CTYPE, "");
+	xinit();
 	tnew(80, 24);
 	ttynew();
-	xinit();
 	selinit();
 	run();
 	return 0;

From 11bec67875936ffd954c7c28faf98b3cc25cb47f Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 24 Sep 2012 10:27:22 +0200
Subject: [PATCH 0315/1146] Remove unused parameters in ttyresize

---
 st.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 4c8d67f..83edbb8 100644
--- a/st.c
+++ b/st.c
@@ -292,7 +292,7 @@ static void tfulldirt(void);
 
 static void ttynew(void);
 static void ttyread(void);
-static void ttyresize(int, int);
+static void ttyresize(void);
 static void ttywrite(const char *, size_t);
 
 static void xdraws(char *, Glyph, int, int, int, int);
@@ -899,7 +899,7 @@ ttywrite(const char *s, size_t n) {
 }
 
 void
-ttyresize(int x, int y) {
+ttyresize(void) {
 	struct winsize w;
 
 	w.ws_row = term.row;
@@ -2327,7 +2327,7 @@ resize(XEvent *e) {
 	xclear(0, 0, xw.w, xw.h);
 	tresize(col, row);
 	xresize(col, row);
-	ttyresize(col, row);
+	ttyresize();
 }
 
 void

From 2f215654a4b27eb573fb6551d28bdf760e95ef58 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 24 Sep 2012 10:28:05 +0200
Subject: [PATCH 0316/1146] Add KAM sequence

This sequence lock/unlock the keyboard ignoring all the key pressing events
from X server.
---
 st.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
---
 st.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 83edbb8..538ed9a 100644
--- a/st.c
+++ b/st.c
@@ -110,7 +110,8 @@ enum term_mode {
 	MODE_MOUSEBTN    = 32,
 	MODE_MOUSEMOTION = 64,
 	MODE_MOUSE       = 32|64,
-	MODE_REVERSE     = 128
+	MODE_REVERSE     = 128,
+	MODE_KBDLOCK     = 256
 };
 
 enum escape_state {
@@ -1328,6 +1329,9 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			}
 		} else {
 			switch(*args) {
+			case 2:
+				MODBIT(term.mode, set, MODE_KBDLOCK);
+				break;
 			case 4:
 				MODBIT(term.mode, set, MODE_INSERT);
 				break;
@@ -2257,6 +2261,8 @@ kpress(XEvent *ev) {
 	int shift;
 	Status status;
 
+	if (IS_SET(MODE_KBDLOCK))
+		return;
 	meta = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
 	len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status);

From c3b6345595c6b5ec5925544a2f462458f16cbf6a Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 24 Sep 2012 10:28:35 +0200
Subject: [PATCH 0317/1146] Fix LNM sequence

LNM sequence is a standard ANSI mode, not a DEC private mode.
---
 st.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 538ed9a..d432ee7 100644
--- a/st.c
+++ b/st.c
@@ -1292,9 +1292,6 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 7:
 				MODBIT(term.mode, set, MODE_WRAP);
 				break;
-			case 20:
-				MODBIT(term.mode, set, MODE_CRLF);
-				break;
 			case 12: /* att610 -- Start blinking cursor (IGNORED) */
 				break;
 			case 25:
@@ -1335,6 +1332,9 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 4:
 				MODBIT(term.mode, set, MODE_INSERT);
 				break;
+			case 20:
+				MODBIT(term.mode, set, MODE_CRLF);
+				break;
 			default:
 				fprintf(stderr,
 					"erresc: unknown set/reset mode %d\n",

From 74d6abfee5a1455c7c126d6b78760efd65d9d7c3 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 24 Sep 2012 10:29:37 +0200
Subject: [PATCH 0318/1146] Add some documentetion to tsetmode

The names of the terminal modes supported by vt102 are (taken from the VT220
programmer reference manual):

Table 4-7 ANSI-Standardized Modes
Name  Mnemonic		    Parameter (Ps)
Error (ignored)		    -         0 (3/0)
Keyboard action		    KAM	      2 (3/2)
Insert/replace		    IRM	      4 (3/4)
Send/receive		    SRM	      12 (3/1 3/2)
Line feed/new line	    LNM       20 (3/2 3/0)

Table 4-8 ANSI-Compatible DEC Private Modes
Name  Mnemonic		  Parameter (Ps)
Error (ignored)		  -	    0 (3/0)
Cursor key		  DECCKM    1 (3/1)
ANSI/VT52		  DECANM    2 (3/2)
Column			  DECCOLM   3 (3/3)
Scroll			  DECSCLM   4 (3/4)
Screen			  DECSCNM   5 (3/5)
Origin			  DECOM	    6 (3/6)
Auto wrap		  DECAWM    7 (3/7)
Auto repeat		  DECARM    8 (3/8)
Printer form feed	  DECPFF    18 (3/1 3/8)
Printer extent		  DECPEX    19 (3/1 3/9)
Text cursor enable	  DECTCEM   25 (3/2 3/5)
National replacement character sets DECNRCM 42 (3/4 3/2)

This patch adds a comment for each one of these sequences.
---
 st.c |   26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)
---
 st.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index d432ee7..9760b6c 100644
--- a/st.c
+++ b/st.c
@@ -1280,7 +1280,8 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 	for(lim = args + narg; args < lim; ++args) {
 		if(priv) {
 			switch(*args) {
-			case 1:
+				break;
+			case 1: /* DECCKM -- Cursor key */
 				MODBIT(term.mode, set, MODE_APPKEYPAD);
 				break;
 			case 5: /* DECSCNM -- Reverve video */
@@ -1289,9 +1290,14 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				if(mode != term.mode)
 					redraw();
 				break;
-			case 7:
+			case 6: /* XXX: DECOM -- Origin */
+				break;
+			case 7: /* DECAWM -- Auto wrap */
 				MODBIT(term.mode, set, MODE_WRAP);
 				break;
+			case 8: /* XXX: DECARM -- Auto repeat */
+				break;
+			case 0:  /* Error (IGNORED) */
 			case 12: /* att610 -- Start blinking cursor (IGNORED) */
 				break;
 			case 25:
@@ -1319,6 +1325,12 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
 				break;
 			default:
+			/* case 2:  DECANM -- ANSI/VT52 (NOT SUPPOURTED) */
+			/* case 3:  DECCOLM -- Column  (NOT SUPPORTED) */
+			/* case 4:  DECSCLM -- Scroll (NOT SUPPORTED) */
+			/* case 18: DECPFF -- Printer feed (NOT SUPPORTED) */
+			/* case 19: DECPEX -- Printer extent (NOT SUPPORTED) */
+			/* case 42: DECNRCM -- National characters (NOT SUPPORTED) */
 				fprintf(stderr,
 					"erresc: unknown private set/reset mode %d\n",
 					*args);
@@ -1326,13 +1338,17 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			}
 		} else {
 			switch(*args) {
-			case 2:
+			case 0:  /* Error (IGNORED) */
+				break;
+			case 2:  /* KAM -- keyboard action */
 				MODBIT(term.mode, set, MODE_KBDLOCK);
 				break;
-			case 4:
+			case 4:  /* IRM -- Insertion-replacement */
 				MODBIT(term.mode, set, MODE_INSERT);
 				break;
-			case 20:
+			case 12: /* XXX: SRM -- Send/Receive */
+				break;
+			case 20: /* LNM -- Linefeed/new line */
 				MODBIT(term.mode, set, MODE_CRLF);
 				break;
 			default:

From e9c677816c0161a6702dabb244bd2fd918dcb0af Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 24 Sep 2012 10:31:35 +0200
Subject: [PATCH 0319/1146] Adding a TODO for xft fallback.

---
 TODO | 1 +
 1 file changed, 1 insertion(+)

diff --git a/TODO b/TODO
index 45eaf7f..201a1a3 100644
--- a/TODO
+++ b/TODO
@@ -19,6 +19,7 @@ code & interface
 * add border around cursor, when it could be hard to read
 	* white border when not selected would suffice
 	* + definition in config.h
+* add fallback fonts for the restricted xft code
 
 bugs
 ----

From 055a4f6d2cc727cc58509a39e130bdd8dbfa452b Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 24 Sep 2012 11:04:26 +0200
Subject: [PATCH 0320/1146] The xinit() call needs to be behind all the tty
 init, otherwise all the

allocated structures are wrong. The xclear() is now done on purpose. Please
keep X11 calls out of the way of pure tty-related calls.
---
 st.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 9760b6c..2d080e5 100644
--- a/st.c
+++ b/st.c
@@ -953,7 +953,7 @@ treset(void) {
 		term.tabs[i] = 1;
 	term.top = 0, term.bot = term.row - 1;
 	term.mode = MODE_WRAP;
-	xclear(0, 0, xw.w, xw.h);
+
 	tclearregion(0, 0, term.col-1, term.row-1);
 }
 
@@ -1728,6 +1728,7 @@ tputc(char *c) {
 			case 'c': /* RIS -- Reset to inital state */
 				treset();
 				term.esc = 0;
+				xclear(0, 0, xw.w, xw.h);
 				xresettitle();
 				break;
 			case '=': /* DECPAM -- Application keypad */
@@ -2456,9 +2457,9 @@ main(int argc, char *argv[]) {
 
  run:
 	setlocale(LC_CTYPE, "");
-	xinit();
 	tnew(80, 24);
 	ttynew();
+	xinit();
 	selinit();
 	run();
 	return 0;

From 246d704ba0c1d83b3eed2388483300687276b797 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 24 Sep 2012 14:01:59 +0200
Subject: [PATCH 0321/1146] Changing the default font to DejaVu Sans Mono,
 which is more appealing and

activating antialiasing.
---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 5cb1fd2..1f0291e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,5 +1,5 @@
 
-#define FONT "Bitstream Vera Sans Mono:pixelsize=12:antialias=false:autohint=true"
+#define FONT "DejaVu Sans Mono:pixelsize=12:antialias=true:autohint=true"
 #define BOLDFONT FONT ":weight=bold"
 #define ITALICFONT FONT ":slant=italic,oblique"
 #define ITALICBOLDFONT BOLDFONT ":slant=italic,oblique"

From eb360e5fd151107ca8088a9c1aad33aa373c4fb0 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 25 Sep 2012 21:04:35 +0200
Subject: [PATCH 0322/1146] Fix bug in tputc writing to io file

If -f options is enabled then tputc() writes all the data to a file. Actual
code assumes that all the strings in 'c' parameters have always 1 byte
length, but this is not always true, because due to utf-8 encoding some
characters can have a diferent length. So it is necessary pass string length
to tputc in order it can call to write() correctly.
---
 st.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 2d080e5..a0bd69f 100644
--- a/st.c
+++ b/st.c
@@ -278,7 +278,7 @@ static void tmoveto(int, int);
 static void tnew(int, int);
 static void tnewline(int);
 static void tputtab(bool);
-static void tputc(char*);
+static void tputc(char*, int);
 static void treset(void);
 static int tresize(int, int);
 static void tscrollup(int, int);
@@ -884,7 +884,7 @@ ttyread(void) {
 	while(buflen >= UTF_SIZ || isfullutf8(ptr,buflen)) {
 		charsize = utf8decode(ptr, &utf8c);
 		utf8encode(&utf8c, s);
-		tputc(s);
+		tputc(s, charsize);
 		ptr    += charsize;
 		buflen -= charsize;
 	}
@@ -1641,11 +1641,11 @@ tputtab(bool forward) {
 }
 
 void
-tputc(char *c) {
+tputc(char *c, int len) {
 	char ascii = *c;
 
 	if(iofd != -1)
-		write(iofd, c, 1);
+		write(iofd, c, len);
 
 	if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {

From 980c5956ed4eb0c1e748f1e5c550fabdaaf4ef14 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 25 Sep 2012 21:17:43 +0200
Subject: [PATCH 0323/1146] Enabling enacs and adding compatibility to xterm
 and urxvt for alternative

charsets.
---
 st.c    | 1 +
 st.info | 1 +
 2 files changed, 2 insertions(+)

diff --git a/st.c b/st.c
index a0bd69f..efe309f 100644
--- a/st.c
+++ b/st.c
@@ -1700,6 +1700,7 @@ tputc(char *c, int len) {
 				strescseq.type = ascii;
 				term.esc |= ESC_STR;
 				break;
+			case ')':
 			case '(':
 				term.esc |= ESC_ALTCHARSET;
 				break;
diff --git a/st.info b/st.info
index 38012d8..58e2139 100644
--- a/st.info
+++ b/st.info
@@ -33,6 +33,7 @@ st| simpleterm,
 	ed=\E[J,
 	el=\E[K,
 	el1=\E[1K,
+	enacs=\E)0,
 	flash=\E[?5h\E[?5l,
 	fsl=^G,
 	home=\E[H,

From c3b0e2202b908834d3c08e3eaf70e0ac282cf319 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 25 Sep 2012 21:39:25 +0200
Subject: [PATCH 0324/1146] A reset should reset the line drawing too.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index efe309f..009ccb4 100644
--- a/st.c
+++ b/st.c
@@ -1177,7 +1177,7 @@ tsetattr(int *attr, int l) {
 		switch(attr[i]) {
 		case 0:
 			term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE | ATTR_BOLD \
-					| ATTR_ITALIC | ATTR_BLINK);
+					| ATTR_ITALIC | ATTR_BLINK | ATTR_GFX);
 			term.c.attr.fg = DefaultFG;
 			term.c.attr.bg = DefaultBG;
 			break;

From 3a095984b053ebb159956368eb3258f51f50e352 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 26 Sep 2012 20:21:08 +0200
Subject: [PATCH 0325/1146] Implementing line drawing right.

---
 config.def.h |  8 --------
 st.c         | 52 ++++++++++++++++++++++++++++++++++++----------------
 2 files changed, 36 insertions(+), 24 deletions(-)

diff --git a/config.def.h b/config.def.h
index 1f0291e..5a49b9d 100644
--- a/config.def.h
+++ b/config.def.h
@@ -79,14 +79,6 @@ static Key key[] = {
 /* Set TERM to this */
 #define TNAME "st-256color"
 
-/* Line drawing characters (sometime specific to each font...) */
-static char gfx[] = {
-	['f'] = 'o',
-	['g'] = '+',
-	['i'] = '#',
-	[255] = 0,
-};
-
 /* double-click timeout (in milliseconds) between clicks for selection */
 #define DOUBLECLICK_TIMEOUT 300
 #define TRIPLECLICK_TIMEOUT (2*DOUBLECLICK_TIMEOUT)
diff --git a/st.c b/st.c
index 009ccb4..a64b84d 100644
--- a/st.c
+++ b/st.c
@@ -1094,6 +1094,27 @@ tmoveto(int x, int y) {
 
 void
 tsetchar(char *c) {
+	/*
+	 * The table is proudly stolen from rxvt.
+	 */
+	if(term.c.attr.mode & ATTR_GFX) {
+		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 - ~ */
+		};
+
+		if(c[0] >= 0x41 && c[0] <= 0x7e
+				&& vt100_0[c[0] - 0x41]) {
+			c = vt100_0[c[0] - 0x41];
+		}
+	}
+
 	term.dirty[term.c.y] = 1;
 	term.line[term.c.y][term.c.x] = term.c.attr;
 	memcpy(term.line[term.c.y][term.c.x].c, c, UTF_SIZ);
@@ -1177,7 +1198,7 @@ tsetattr(int *attr, int l) {
 		switch(attr[i]) {
 		case 0:
 			term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE | ATTR_BOLD \
-					| ATTR_ITALIC | ATTR_BLINK | ATTR_GFX);
+					| ATTR_ITALIC | ATTR_BLINK);
 			term.c.attr.fg = DefaultFG;
 			term.c.attr.bg = DefaultBG;
 			break;
@@ -1676,12 +1697,18 @@ tputc(char *c, int len) {
 				strhandle();
 		} else if(term.esc & ESC_ALTCHARSET) {
 			switch(ascii) {
-			case '0': /* Line drawing crap */
+			case '0': /* Line drawing set */
 				term.c.attr.mode |= ATTR_GFX;
 				break;
-			case 'B': /* Back to regular text */
+			case 'B': /* USASCII */
 				term.c.attr.mode &= ~ATTR_GFX;
 				break;
+			case 'A': /* UK (IGNORED) */
+			case '<': /* multinational charset (IGNORED) */
+			case '5': /* Finnish (IGNORED) */
+			case 'C': /* Finnish (IGNORED) */
+			case 'K': /* German (IGNORED) */
+				break;
 			default:
 				fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
 			}
@@ -1700,10 +1727,14 @@ tputc(char *c, int len) {
 				strescseq.type = ascii;
 				term.esc |= ESC_STR;
 				break;
-			case ')':
-			case '(':
+			case '(': /* set primary charset G0 */
 				term.esc |= ESC_ALTCHARSET;
 				break;
+			case ')': /* set secondary charset G1 (IGNORED) */
+			case '*': /* set tertiary charset G2 (IGNORED) */
+			case '+': /* set quaternary charset G3 (IGNORED) */
+				term.esc = 0;
+				break;
 			case 'D': /* IND -- Linefeed */
 				if(term.c.y == term.bot)
 					tscrollup(term.top, 1);
@@ -2067,7 +2098,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	int winx = BORDER+x*xw.cw, winy = BORDER+y*xw.ch + dc.font.ascent, width = charlen*xw.cw;
 	Font *font = &dc.font;
 	XGlyphInfo extents;
-	int i;
 
 	/* only switch default fg/bg if term is in RV mode */
 	if(IS_SET(MODE_REVERSE)) {
@@ -2093,16 +2123,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	XSetBackground(xw.dpy, dc.gc, dc.col[bg]);
 	XSetForeground(xw.dpy, dc.gc, dc.col[fg]);
 
-	if(base.mode & ATTR_GFX) {
-		for(i = 0; i < bytelen; i++) {
-			char c = gfx[(uint)s[i] % 256];
-			if(c)
-				s[i] = c;
-			else if(s[i] > 0x5f)
-				s[i] -= 0x5f;
-		}
-	}
-
 	XftTextExtentsUtf8(xw.dpy, font->xft_set, (FcChar8 *)s, bytelen, &extents);
 	width = extents.xOff;
 	XftDrawRect(xw.xft_draw, &dc.xft_col[bg], winx, winy - font->ascent, width, xw.ch);

From 375b6e5b175ce0a01d47288e94e9c4a8acc3939a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 26 Sep 2012 20:21:59 +0200
Subject: [PATCH 0326/1146] Switching to Liberation Mono as default solely
 because of line drawing. A next

patch to fix the font symbols in all fonts should make it easier to choose a
better font.
---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 5a49b9d..de29427 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,5 +1,5 @@
 
-#define FONT "DejaVu Sans Mono:pixelsize=12:antialias=true:autohint=true"
+#define FONT "Liberation Mono:pixelsize=12:antialias=true:autohint=true"
 #define BOLDFONT FONT ":weight=bold"
 #define ITALICFONT FONT ":slant=italic,oblique"
 #define ITALICBOLDFONT BOLDFONT ":slant=italic,oblique"

From a7d7e29300acade90f2025f0b85fa5eae06edb24 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 26 Sep 2012 20:53:46 +0200
Subject: [PATCH 0327/1146] Ignore all control characters not handled

Taken from vt100 programmer manual:

	Control characters have values of \000 - \037, and \177. The control
	characters recognized by the VT100 are shown in Table 3-10. All
	other control codes cause no action to be taken.

We have to take attention when we are using alternate charset, because in
this cases they are not used as control characters.
---
 st.c |   20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)
---
 st.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/st.c b/st.c
index a64b84d..515dfb1 100644
--- a/st.c
+++ b/st.c
@@ -1663,7 +1663,7 @@ tputtab(bool forward) {
 
 void
 tputc(char *c, int len) {
-	char ascii = *c;
+	uchar ascii = *c;
 
 	if(iofd != -1)
 		write(iofd, c, len);
@@ -1792,8 +1792,6 @@ tputc(char *c, int len) {
 		if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey))
 			sel.bx = -1;
 		switch(ascii) {
-		case '\0': /* padding character, do nothing */
-			break;
 		case '\t':
 			tputtab(1);
 			break;
@@ -1818,13 +1816,15 @@ tputc(char *c, int len) {
 			term.esc = ESC_START;
 			break;
 		default:
-			if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
-				tnewline(1); /* always go to first col */
-			tsetchar(c);
-			if(term.c.x+1 < term.col)
-				tmoveto(term.c.x+1, term.c.y);
-			else
-				term.c.state |= CURSOR_WRAPNEXT;
+			if(ascii >= '\020' || term.c.attr.mode & ATTR_GFX) {
+				if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
+					tnewline(1); /* always go to first col */
+				tsetchar(c);
+				if(term.c.x+1 < term.col)
+					tmoveto(term.c.x+1, term.c.y);
+				else
+					term.c.state |= CURSOR_WRAPNEXT;
+			}
 		}
 	}
 }

From 3af49e34f666554fcd52a52a7ca15f3e7eafa197 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 26 Sep 2012 20:55:18 +0200
Subject: [PATCH 0328/1146] Allow control characters inside escape sequences

Taken from vt100 manual programmer:

	Control characters (codes \0 to \37 inclusive) are specifically
	excluded from the control sequence syntax, but may be embedded
	within a control sequence. Embedded control characters are executed
	as soon as they are encountered by the VT100. The processing of the
	control sequence then continues with the next character received.
---
 st.c |   68 +++++++++++++++++++++++++++++++++---------------------------------
 1 file changed, 34 insertions(+), 34 deletions(-)
---
 st.c | 68 ++++++++++++++++++++++++++++++------------------------------
 1 file changed, 34 insertions(+), 34 deletions(-)

diff --git a/st.c b/st.c
index 515dfb1..2767d54 100644
--- a/st.c
+++ b/st.c
@@ -1668,6 +1668,32 @@ tputc(char *c, int len) {
 	if(iofd != -1)
 		write(iofd, c, len);
 
+	switch(ascii) {
+	case '\t':
+		tputtab(1);
+		return;
+	case '\b':
+		tmoveto(term.c.x-1, term.c.y);
+		return;
+	case '\r':
+		tmoveto(0, term.c.y);
+		return;
+	case '\f':
+	case '\v':
+	case '\n':
+		/* go to first col if the mode is set */
+		tnewline(IS_SET(MODE_CRLF));
+		return;
+	case '\a':
+		if(!(xw.state & WIN_FOCUSED))
+			xseturgency(1);
+		return;
+	case '\033':
+		csireset();
+		term.esc = ESC_START;
+		return;
+	}
+
 	if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {
 			csiescseq.buf[csiescseq.len++] = ascii;
@@ -1791,40 +1817,14 @@ tputc(char *c, int len) {
 	} else {
 		if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey))
 			sel.bx = -1;
-		switch(ascii) {
-		case '\t':
-			tputtab(1);
-			break;
-		case '\b':
-			tmoveto(term.c.x-1, term.c.y);
-			break;
-		case '\r':
-			tmoveto(0, term.c.y);
-			break;
-		case '\f':
-		case '\v':
-		case '\n':
-			/* go to first col if the mode is set */
-			tnewline(IS_SET(MODE_CRLF));
-			break;
-		case '\a':
-			if(!(xw.state & WIN_FOCUSED))
-				xseturgency(1);
-			break;
-		case '\033':
-			csireset();
-			term.esc = ESC_START;
-			break;
-		default:
-			if(ascii >= '\020' || term.c.attr.mode & ATTR_GFX) {
-				if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
-					tnewline(1); /* always go to first col */
-				tsetchar(c);
-				if(term.c.x+1 < term.col)
-					tmoveto(term.c.x+1, term.c.y);
-				else
-					term.c.state |= CURSOR_WRAPNEXT;
-			}
+		if(ascii >= '\020' || term.c.attr.mode & ATTR_GFX) {
+			if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
+				tnewline(1); /* always go to first col */
+			tsetchar(c);
+			if(term.c.x+1 < term.col)
+				tmoveto(term.c.x+1, term.c.y);
+			else
+				term.c.state |= CURSOR_WRAPNEXT;
 		}
 	}
 }

From 29b209f5f55c80e457a5a913a463bd24f8e307e9 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 27 Sep 2012 19:28:44 +0200
Subject: [PATCH 0329/1146] Vt escape sequences allow escape sequences in
 escape sequences and escape
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

sequences, so we have to support escape sequences in escape sequences that
escape sequences in escape sequences – setting a title won't notify you
anymore.
---
 st.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.c b/st.c
index 2767d54..bb80321 100644
--- a/st.c
+++ b/st.c
@@ -1685,6 +1685,9 @@ tputc(char *c, int len) {
 		tnewline(IS_SET(MODE_CRLF));
 		return;
 	case '\a':
+		if(term.esc & ESC_STR)
+			break;
+
 		if(!(xw.state & WIN_FOCUSED))
 			xseturgency(1);
 		return;

From d7b1e31eec9a87c666334006de25a7f8102c55a9 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 29 Sep 2012 11:17:16 +0200
Subject: [PATCH 0330/1146] All xcolors are not Xft colors and the clearing of
 the borders has been

optimized. There is a speedup when resizing windows.
---
 st.c | 83 ++++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 30 deletions(-)

diff --git a/st.c b/st.c
index bb80321..ab8540c 100644
--- a/st.c
+++ b/st.c
@@ -239,13 +239,11 @@ typedef struct {
 	int descent;
 	short lbearing;
 	short rbearing;
-	XFontSet set;
 	XftFont* xft_set;
 } Font;
 
 /* Drawing Context */
 typedef struct {
-	ulong col[LEN(colorname) < 256 ? 256 : LEN(colorname)];
 	XftColor xft_col[LEN(colorname) < 256 ? 256 : LEN(colorname)];
 	GC gc;
 	Font font, bfont, ifont, ibfont;
@@ -299,12 +297,14 @@ static void ttywrite(const char *, size_t);
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
 static void xclear(int, int, int, int);
+static void xclearborders(void);
 static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
 static void xresettitle(void);
 static void xseturgency(int);
 static void xsetsel(char*);
+static void xtermclear(int, int, int, int);
 static void xresize(int, int);
 
 static void expose(XEvent *);
@@ -1307,7 +1307,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				break;
 			case 5: /* DECSCNM -- Reverve video */
 				mode = term.mode;
-				MODBIT(term.mode,set, MODE_REVERSE);
+				MODBIT(term.mode, set, MODE_REVERSE);
 				if(mode != term.mode)
 					redraw();
 				break;
@@ -1789,7 +1789,7 @@ tputc(char *c, int len) {
 			case 'c': /* RIS -- Reset to inital state */
 				treset();
 				term.esc = 0;
-				xclear(0, 0, xw.w, xw.h);
+				xclearborders();
 				xresettitle();
 				break;
 			case '=': /* DECPAM -- Application keypad */
@@ -1914,17 +1914,19 @@ void
 xloadcols(void) {
 	int i, r, g, b;
 	XRenderColor xft_color = { .alpha = 0 };
-	ulong white = WhitePixel(xw.dpy, xw.scr);
+
+	/* load default white color */
+	if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[256], &dc.xft_col[256]))
+		die("Could not allocate color '%s'\n", colorname[256]);
 
 	/* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */
 	for(i = 0; i < LEN(colorname); i++) {
 		if(!colorname[i])
 			continue;
 		if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[i], &dc.xft_col[i])) {
-			dc.col[i] = white;
+			dc.xft_col[i] = dc.xft_col[256];
 			fprintf(stderr, "Could not allocate color '%s'\n", colorname[i]);
-		} else
-			dc.col[i] = dc.xft_col[i].pixel;
+		}
 	}
 
 	/* load colors [16-255] ; same colors as xterm */
@@ -1935,29 +1937,51 @@ xloadcols(void) {
 				xft_color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g;
 				xft_color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b;
 				if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color, &dc.xft_col[i])) {
-					dc.col[i] = white;
+					dc.xft_col[i] = dc.xft_col[256];
 					fprintf(stderr, "Could not allocate color %d\n", i);
-				} else
-					dc.col[i] = dc.xft_col[i].pixel;
+				}
 				i++;
 			}
 
 	for(r = 0; r < 24; r++, i++) {
 		xft_color.red = xft_color.green = xft_color.blue = 0x0808 + 0x0a0a * r;
 		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color, &dc.xft_col[i])) {
-			dc.col[i] = white;
+			dc.xft_col[i] = dc.xft_col[256];
 			fprintf(stderr, "Could not allocate color %d\n", i);
-		} else
-			dc.col[i] = dc.xft_col[i].pixel;
+		}
 	}
 }
 
+void
+xtermclear(int col1, int row1, int col2, int row2) {
+	XftDrawRect(xw.xft_draw,
+			&dc.xft_col[IS_SET(MODE_REVERSE) ? DefaultFG : DefaultBG],
+			BORDER + col1 * xw.cw,
+			BORDER + row1 * xw.ch,
+			(col2-col1+1) * xw.cw,
+			(row2-row1+1) * xw.ch);
+}
+
+/*
+ * Absolute coordinates.
+ */
 void
 xclear(int x1, int y1, int x2, int y2) {
-	XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? DefaultFG : DefaultBG]);
-	XFillRectangle(xw.dpy, xw.buf, dc.gc,
-		       BORDER + x1 * xw.cw, BORDER + y1 * xw.ch,
-		       (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
+	XftDrawRect(xw.xft_draw,
+			&dc.xft_col[IS_SET(MODE_REVERSE) ? DefaultFG : DefaultBG],
+			x1, y1, x2-x1, y2-y1);
+}
+
+void
+xclearborders(void) {
+	/* top and left border */
+	xclear(0, 0, BORDER, xw.h);
+	xclear(0, 0, xw.w, BORDER);
+
+	/* lower and right border */
+	xclear(BORDER, xw.th - 1, xw.w, xw.h);
+	/* Will just draw what hasn't been drawn by the previous call. */
+	xclear(xw.tw - 1, BORDER, xw.w, xw.h - xw.th - 2);
 }
 
 void
@@ -2048,8 +2072,8 @@ xinit(void) {
 		xw.fy = 0;
 	}
 
-	attrs.background_pixel = dc.col[DefaultBG];
-	attrs.border_pixel = dc.col[DefaultBG];
+	attrs.background_pixel = dc.xft_col[DefaultBG].pixel;
+	attrs.border_pixel = dc.xft_col[DefaultBG].pixel;
 	attrs.bit_gravity = NorthWestGravity;
 	attrs.event_mask = FocusChangeMask | KeyPressMask
 		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
@@ -2123,16 +2147,15 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	if(base.mode & (ATTR_ITALIC|ATTR_ITALIC))
 		font = &dc.ibfont;
 
-	XSetBackground(xw.dpy, dc.gc, dc.col[bg]);
-	XSetForeground(xw.dpy, dc.gc, dc.col[fg]);
-
 	XftTextExtentsUtf8(xw.dpy, font->xft_set, (FcChar8 *)s, bytelen, &extents);
 	width = extents.xOff;
 	XftDrawRect(xw.xft_draw, &dc.xft_col[bg], winx, winy - font->ascent, width, xw.ch);
 	XftDrawStringUtf8(xw.xft_draw, &dc.xft_col[fg], font->xft_set, winx, winy, (FcChar8 *)s, bytelen);
 
-	if(base.mode & ATTR_UNDERLINE)
-		XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);
+	if(base.mode & ATTR_UNDERLINE) {
+		XftDrawRect(xw.xft_draw, &dc.xft_col[fg], winx, winy+1,
+				width, 1);
+	}
 }
 
 void
@@ -2153,7 +2176,7 @@ xdrawcursor(void) {
 		sl = utf8size(term.line[oldy][oldx].c);
 		xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, 1, sl);
 	} else
-		xclear(oldx, oldy, oldx, oldy);
+		xtermclear(oldx, oldy, oldx, oldy);
 
 	/* draw the new one */
 	if(!(term.c.state & CURSOR_HIDE)) {
@@ -2178,7 +2201,7 @@ void
 redraw(void) {
 	struct timespec tv = {0, REDRAW_TIMEOUT * 1000};
 
-	xclear(0, 0, xw.w, xw.h);
+	xclearborders();
 	tfulldirt();
 	draw();
 	XSync(xw.dpy, False); /* necessary for a good tput flash */
@@ -2186,7 +2209,7 @@ redraw(void) {
 }
 
 void
-draw() {
+draw(void) {
 	XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
 
 	drawregion(0, 0, term.col, term.row);
@@ -2208,7 +2231,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 	for(y = y1; y < y2; y++) {
 		if(!term.dirty[y])
 			continue;
-		xclear(0, y, term.col, y);
+		xtermclear(0, y, term.col, y);
 		term.dirty[y] = 0;
 		base = term.line[y][0];
 		ic = ib = ox = 0;
@@ -2371,9 +2394,9 @@ resize(XEvent *e) {
 	if(col == term.col && row == term.row)
 		return;
 
-	xclear(0, 0, xw.w, xw.h);
 	tresize(col, row);
 	xresize(col, row);
+	xclearborders();
 	ttyresize();
 }
 

From ed5b8700a6e6c14b814dcc2e54a90eb1868070b5 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 29 Sep 2012 11:23:34 +0200
Subject: [PATCH 0331/1146] We need all the colors to be available, so die() on
 some not available.

This is a new opportunity to see if X11 somewhen handled colors in a strange
way.
---
 st.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/st.c b/st.c
index ab8540c..5ed3753 100644
--- a/st.c
+++ b/st.c
@@ -1915,17 +1915,12 @@ xloadcols(void) {
 	int i, r, g, b;
 	XRenderColor xft_color = { .alpha = 0 };
 
-	/* load default white color */
-	if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[256], &dc.xft_col[256]))
-		die("Could not allocate color '%s'\n", colorname[256]);
-
 	/* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */
 	for(i = 0; i < LEN(colorname); i++) {
 		if(!colorname[i])
 			continue;
 		if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[i], &dc.xft_col[i])) {
-			dc.xft_col[i] = dc.xft_col[256];
-			fprintf(stderr, "Could not allocate color '%s'\n", colorname[i]);
+			die("Could not allocate color '%s'\n", colorname[i]);
 		}
 	}
 
@@ -1937,8 +1932,7 @@ xloadcols(void) {
 				xft_color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g;
 				xft_color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b;
 				if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color, &dc.xft_col[i])) {
-					dc.xft_col[i] = dc.xft_col[256];
-					fprintf(stderr, "Could not allocate color %d\n", i);
+					die("Could not allocate color %d\n", i);
 				}
 				i++;
 			}

From 9cae1eb0ded2e1ca604753893e2307531ef73afc Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 30 Sep 2012 20:10:58 +0200
Subject: [PATCH 0332/1146] Remove the cruft of the user to have to define the
 different font styles.

---
 st.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 5ed3753..710cf34 100644
--- a/st.c
+++ b/st.c
@@ -336,6 +336,7 @@ static int isfullutf8(char *, int);
 static void *xmalloc(size_t);
 static void *xrealloc(void *, size_t);
 static void *xcalloc(size_t nmemb, size_t size);
+static char *smstrcat(char *, ...);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
@@ -393,6 +394,44 @@ xcalloc(size_t nmemb, size_t size) {
 	return p;
 }
 
+char *
+smstrcat(char *src, ...)
+{
+	va_list fmtargs;
+	char *ret, *p, *v;
+	int len, slen, flen;
+
+	len = slen = strlen(src);
+
+	va_start(fmtargs, src);
+	for(;;) {
+		v = va_arg(fmtargs, char *);
+		if(v == NULL)
+			break;
+		len += strlen(v);
+	}
+	va_end(fmtargs);
+
+	p = ret = xmalloc(len+1);
+	memmove(p, src, slen);
+	p += slen;
+
+	va_start(fmtargs, src);
+	for(;;) {
+		v = va_arg(fmtargs, char *);
+		if(v == NULL)
+			break;
+		flen = strlen(v);
+		memmove(p, v, flen);
+		p += flen;
+	}
+	va_end(fmtargs);
+
+	ret[len] = '\0';
+
+	return ret;
+}
+
 int
 utf8decode(char *s, long *u) {
 	uchar c;
@@ -2017,11 +2056,22 @@ xinitfont(Font *f, char *fontstr) {
 }
 
 void
-initfonts(char *fontstr, char *bfontstr, char *ifontstr, char *ibfontstr) {
+initfonts(char *fontstr) {
+	char *fstr;
+
 	xinitfont(&dc.font, fontstr);
-	xinitfont(&dc.bfont, bfontstr);
-	xinitfont(&dc.ifont, ifontstr);
-	xinitfont(&dc.ibfont, ibfontstr);
+
+	fstr = smstrcat(fontstr, ":weight=bold", NULL);
+	xinitfont(&dc.bfont, fstr);
+	free(fstr);
+
+	fstr = smstrcat(fontstr, ":slant=italic,oblique", NULL);
+	xinitfont(&dc.ifont, fstr);
+	free(fstr);
+
+	fstr = smstrcat(fontstr, ":weight=bold:slant=italic,oblique", NULL);
+	xinitfont(&dc.ibfont, fstr);
+	free(fstr);
 }
 
 void
@@ -2037,7 +2087,7 @@ xinit(void) {
 	xw.vis = XDefaultVisual(xw.dpy, xw.scr);
 
 	/* font */
-	initfonts(FONT, BOLDFONT, ITALICFONT, ITALICBOLDFONT);
+	initfonts(FONT);
 
 	/* XXX: Assuming same size for bold font */
 	xw.cw = dc.font.rbearing - dc.font.lbearing;

From 5dfd5df4fe566beb17069e6390236854f6ace58f Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 30 Sep 2012 20:23:10 +0200
Subject: [PATCH 0333/1146] This changes -f to be the parameter for the font.
 Now -f is -o.

The parameters were reordered according to the alphabet too.
---
 st.1 | 33 +++++++++++++++++++++------------
 st.c | 42 ++++++++++++++++++++++++++----------------
 2 files changed, 47 insertions(+), 28 deletions(-)

diff --git a/st.1 b/st.1
index 8ec0008..1c100c0 100644
--- a/st.1
+++ b/st.1
@@ -5,15 +5,17 @@ st \- simple terminal
 .B st
 .RB [ \-c
 .IR class ]
+.RB [ \-f
+.IR font ]
 .RB [ \-g
 .IR geometry ]
+.RB [ \-o
+.IR file ]
 .RB [ \-t 
 .IR title ]
 .RB [ \-w 
 .IR windowid ]
 .RB [ \-v ]
-.RB [ \-f
-.IR file ]
 .RB [ \-e
 .IR command ...]
 .SH DESCRIPTION
@@ -21,26 +23,33 @@ st \- simple terminal
 is a simple terminal emulator.
 .SH OPTIONS
 .TP
-.BI \-t " title"
-defines the window title (default 'st').
-.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, which will fixate the height and width of st. 
+.TP
+.BI \-o " file"
+writes all the I/O to
+.I file.
+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 \-w " windowid"
 embeds st within the window identified by 
 .I windowid
 .TP
-.B \-g " geometry"
-defines the X11 geometry string, which will fixate the height and width of st. 
 .B \-v
 prints version information to stderr, then exits.
 .TP
-.BI \-f " file"
-writes all the I/O to
-.I file.
-This feature is useful when recording st sessions.
-.TP
 .BI \-e " program " [ " arguments " "... ]"
 st executes
 .I program
diff --git a/st.c b/st.c
index 710cf34..59fb06c 100644
--- a/st.c
+++ b/st.c
@@ -39,8 +39,8 @@
 
 #define USAGE \
 	"st " VERSION " (c) 2010-2012 st engineers\n" \
-	"usage: st [-t title] [-c class] [-g geometry]" \
-	" [-w windowid] [-v] [-f file] [-e command...]\n"
+	"usage: st [-v] [-c class] [-f font] [-g geometry] [-o file]" \
+	" [-t title] [-w windowid] [-e command ...]\n"
 
 /* XEMBED messages */
 #define XEMBED_FOCUS_IN  4
@@ -365,11 +365,12 @@ static int cmdfd;
 static pid_t pid;
 static Selection sel;
 static int iofd = -1;
-static char **opt_cmd  = NULL;
-static char *opt_io    = NULL;
+static char **opt_cmd = NULL;
+static char *opt_io = NULL;
 static char *opt_title = NULL;
 static char *opt_embed = NULL;
 static char *opt_class = NULL;
+static char *opt_font = NULL;
 
 void *
 xmalloc(size_t len) {
@@ -2087,7 +2088,7 @@ xinit(void) {
 	xw.vis = XDefaultVisual(xw.dpy, xw.scr);
 
 	/* font */
-	initfonts(FONT);
+	initfonts((opt_font != NULL)? opt_font : FONT);
 
 	/* XXX: Assuming same size for bold font */
 	xw.cw = dc.font.rbearing - dc.font.lbearing;
@@ -2503,22 +2504,19 @@ main(int argc, char *argv[]) {
 
 	for(i = 1; i < argc; i++) {
 		switch(argv[i][0] != '-' || argv[i][2] ? -1 : argv[i][1]) {
-		case 't':
-			if(++i < argc) opt_title = argv[i];
-			break;
 		case 'c':
-			if(++i < argc) opt_class = argv[i];
-			break;
-		case 'w':
-			if(++i < argc) opt_embed = argv[i];
-			break;
-		case 'f':
-			if(++i < argc) opt_io = argv[i];
+			if(++i < argc)
+				opt_class = argv[i];
 			break;
 		case 'e':
 			/* eat every remaining arguments */
-			if(++i < argc) opt_cmd = &argv[i];
+			if(++i < argc)
+				opt_cmd = &argv[i];
 			goto run;
+		case 'f':
+			if(++i < argc)
+				opt_font = argv[i];
+			break;
 		case 'g':
 			if(++i >= argc)
 				break;
@@ -2540,9 +2538,21 @@ main(int argc, char *argv[]) {
 			if(xw.fh != 0 && xw.fw != 0)
 				xw.isfixed = True;
 			break;
+		case 'o':
+			if(++i < argc)
+				opt_io = argv[i];
+			break;
+		case 't':
+			if(++i < argc)
+				opt_title = argv[i];
+			break;
 		case 'v':
 		default:
 			die(USAGE);
+		case 'w':
+			if(++i < argc)
+				opt_embed = argv[i];
+			break;
 		}
 	}
 

From af9e248f976e8396c5aa7fd021ff95ccab78cb72 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 30 Sep 2012 20:23:45 +0200
Subject: [PATCH 0334/1146] Removing the now obsolete definitions from the
 config.def.h file.

---
 config.def.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/config.def.h b/config.def.h
index de29427..3e6667a 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,8 +1,5 @@
 
 #define FONT "Liberation Mono:pixelsize=12:antialias=true:autohint=true"
-#define BOLDFONT FONT ":weight=bold"
-#define ITALICFONT FONT ":slant=italic,oblique"
-#define ITALICBOLDFONT BOLDFONT ":slant=italic,oblique"
 
 /* Space in pixels around the terminal buffer */
 #define BORDER 2

From 0d88f1ef75c2fe9403a72c80d6fa8ed199ec474f Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 2 Oct 2012 12:48:55 +0200
Subject: [PATCH 0335/1146] Thanks to c00kiemon5ter. Not changing bold to
 bright colors seems to be the

right choice.
---
 st.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 59fb06c..4fbe05c 100644
--- a/st.c
+++ b/st.c
@@ -2182,10 +2182,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	if(base.mode & ATTR_REVERSE)
 		temp = fg, fg = bg, bg = temp;
 
-	if(base.mode & ATTR_BOLD) {
-		fg += 8;
+	if(base.mode & ATTR_BOLD)
 		font = &dc.bfont;
-	}
 
 	if(base.mode & ATTR_ITALIC)
 		font = &dc.ifont;

From 2752018e27420947a034d50f1ce165bbb76ae1a8 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 4 Oct 2012 22:59:45 +0200
Subject: [PATCH 0336/1146] This adds the fontcache dependency to try something
 out. Additionally the

invert mode now works as expected. In the config.def.h autohint is set to
false, so the fonts are drawn correctly, without any overlapping.
---
 config.def.h |  2 +-
 config.mk    |  2 +-
 st.c         | 94 ++++++++++++++++++++++++++++++++++++----------------
 3 files changed, 68 insertions(+), 30 deletions(-)

diff --git a/config.def.h b/config.def.h
index 3e6667a..9c64948 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,5 +1,5 @@
 
-#define FONT "Liberation Mono:pixelsize=12:antialias=true:autohint=true"
+#define FONT "Liberation Mono:pixelsize=12:antialias=true:autohint=false"
 
 /* Space in pixels around the terminal buffer */
 #define BORDER 2
diff --git a/config.mk b/config.mk
index f57afa2..3cd714f 100644
--- a/config.mk
+++ b/config.mk
@@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib
 
 # includes and libs
 INCS = -I. -I/usr/include -I${X11INC} -I/usr/include/freetype2
-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext -lXft
+LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext -lXft -lfontconfig
 
 # flags
 CPPFLAGS = -DVERSION=\"${VERSION}\"
diff --git a/st.c b/st.c
index 4fbe05c..b4dc591 100644
--- a/st.c
+++ b/st.c
@@ -26,6 +26,7 @@
 #include <X11/keysym.h>
 #include <X11/extensions/Xdbe.h>
 #include <X11/Xft/Xft.h>
+#include <fontconfig/fontconfig.h>
 #define Glyph Glyph_
 #define Font Font_
 
@@ -235,6 +236,8 @@ typedef struct {
 
 /* Font structure */
 typedef struct {
+	int height;
+	int width;
 	int ascent;
 	int descent;
 	short lbearing;
@@ -1345,7 +1348,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 1: /* DECCKM -- Cursor key */
 				MODBIT(term.mode, set, MODE_APPKEYPAD);
 				break;
-			case 5: /* DECSCNM -- Reverve video */
+			case 5: /* DECSCNM -- Reverse video */
 				mode = term.mode;
 				MODBIT(term.mode, set, MODE_REVERSE);
 				if(mode != term.mode)
@@ -1965,8 +1968,8 @@ xloadcols(void) {
 	}
 
 	/* load colors [16-255] ; same colors as xterm */
-	for(i = 16, r = 0; r < 6; r++)
-		for(g = 0; g < 6; g++)
+	for(i = 16, r = 0; r < 6; r++) {
+		for(g = 0; g < 6; g++) {
 			for(b = 0; b < 6; b++) {
 				xft_color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r;
 				xft_color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g;
@@ -1976,12 +1979,13 @@ xloadcols(void) {
 				}
 				i++;
 			}
+		}
+	}
 
 	for(r = 0; r < 24; r++, i++) {
 		xft_color.red = xft_color.green = xft_color.blue = 0x0808 + 0x0a0a * r;
 		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color, &dc.xft_col[i])) {
-			dc.xft_col[i] = dc.xft_col[256];
-			fprintf(stderr, "Could not allocate color %d\n", i);
+			die("Could not allocate color %d\n", i);
 		}
 	}
 }
@@ -2045,15 +2049,29 @@ xhints(void) {
 
 void
 xinitfont(Font *f, char *fontstr) {
-	f->xft_set = XftFontOpenName(xw.dpy, xw.scr, fontstr);
+	FcPattern *pattern, *match;
+	FcResult result;
 
-	if(!f->xft_set)
+	pattern = FcNameParse((FcChar8 *)fontstr);
+	if(!pattern)
+		die("st: can't open font %s\n", fontstr);
+
+	match = XftFontMatch(xw.dpy, xw.scr, pattern, &result);
+	FcPatternDestroy(pattern);
+	if(!match)
+		die("st: can't open font %s\n", fontstr);
+	if(!(f->xft_set = XftFontOpenPattern(xw.dpy, match))) {
+		FcPatternDestroy(match);
 		die("st: can't open font %s.\n", fontstr);
+	}
 
 	f->ascent = f->xft_set->ascent;
 	f->descent = f->xft_set->descent;
 	f->lbearing = 0;
 	f->rbearing = f->xft_set->max_advance_width;
+
+	f->height = f->xft_set->height;
+	f->width = f->lbearing + f->rbearing;
 }
 
 void
@@ -2061,6 +2079,8 @@ initfonts(char *fontstr) {
 	char *fstr;
 
 	xinitfont(&dc.font, fontstr);
+	xw.cw = dc.font.width;
+	xw.ch = dc.font.height;
 
 	fstr = smstrcat(fontstr, ":weight=bold", NULL);
 	xinitfont(&dc.bfont, fstr);
@@ -2090,10 +2110,6 @@ xinit(void) {
 	/* font */
 	initfonts((opt_font != NULL)? opt_font : FONT);
 
-	/* XXX: Assuming same size for bold font */
-	xw.cw = dc.font.rbearing - dc.font.lbearing;
-	xw.ch = dc.font.ascent + dc.font.descent;
-
 	/* colors */
 	xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
 	xloadcols();
@@ -2166,37 +2182,59 @@ xinit(void) {
 
 void
 xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
-	int fg = base.fg, bg = base.bg, temp;
-	int winx = BORDER+x*xw.cw, winy = BORDER+y*xw.ch + dc.font.ascent, width = charlen*xw.cw;
+	int winx = BORDER+x*xw.cw, winy = BORDER+y*xw.ch,
+	    width = charlen*xw.cw;
 	Font *font = &dc.font;
 	XGlyphInfo extents;
-
-	/* only switch default fg/bg if term is in RV mode */
-	if(IS_SET(MODE_REVERSE)) {
-		if(fg == DefaultFG)
-			fg = DefaultBG;
-		if(bg == DefaultBG)
-			bg = DefaultFG;
-	}
+	XftColor *fg = &dc.xft_col[base.fg], *bg = &dc.xft_col[base.bg],
+		 *temp, revfg, revbg;
+	XRenderColor colfg, colbg;
 
 	if(base.mode & ATTR_REVERSE)
 		temp = fg, fg = bg, bg = temp;
-
-	if(base.mode & ATTR_BOLD)
+	if(base.mode & ATTR_BOLD) {
+		fg = &dc.xft_col[base.fg + 8];
 		font = &dc.bfont;
-
+	}
 	if(base.mode & ATTR_ITALIC)
 		font = &dc.ifont;
 	if(base.mode & (ATTR_ITALIC|ATTR_ITALIC))
 		font = &dc.ibfont;
 
-	XftTextExtentsUtf8(xw.dpy, font->xft_set, (FcChar8 *)s, bytelen, &extents);
+	if(IS_SET(MODE_REVERSE)) {
+		if(fg == &dc.xft_col[DefaultFG]) {
+			fg = &dc.xft_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.xft_col[DefaultBG]) {
+			bg = &dc.xft_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;
+		}
+	}
+
+	XftTextExtentsUtf8(xw.dpy, font->xft_set, (FcChar8 *)s, bytelen,
+			&extents);
 	width = extents.xOff;
-	XftDrawRect(xw.xft_draw, &dc.xft_col[bg], winx, winy - font->ascent, width, xw.ch);
-	XftDrawStringUtf8(xw.xft_draw, &dc.xft_col[fg], font->xft_set, winx, winy, (FcChar8 *)s, bytelen);
+
+	XftDrawRect(xw.xft_draw, bg, winx, winy, width, xw.ch);
+	XftDrawStringUtf8(xw.xft_draw, fg, font->xft_set, winx,
+			winy + font->ascent, (FcChar8 *)s, bytelen);
 
 	if(base.mode & ATTR_UNDERLINE) {
-		XftDrawRect(xw.xft_draw, &dc.xft_col[fg], winx, winy+1,
+		XftDrawRect(xw.xft_draw, fg, winx, winy+1,
 				width, 1);
 	}
 }

From 0b489c4a6a3da54fd6ce99e19520262a0e6a3cd1 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 5 Oct 2012 09:38:10 +0200
Subject: [PATCH 0337/1146] When the drawing behaviour was changed underline
 was not corrected.

Thanks to Peter A. Shevtsov!
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index b4dc591..df166b7 100644
--- a/st.c
+++ b/st.c
@@ -2234,7 +2234,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			winy + font->ascent, (FcChar8 *)s, bytelen);
 
 	if(base.mode & ATTR_UNDERLINE) {
-		XftDrawRect(xw.xft_draw, fg, winx, winy+1,
+		XftDrawRect(xw.xft_draw, fg, winx, winy + font->ascent + 1,
 				width, 1);
 	}
 }

From 5caa46cf575a48e6421aaf8757e066f6d32263d9 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 5 Oct 2012 11:07:55 +0200
Subject: [PATCH 0338/1146] Turning on antialias by default really makes it
 more unreadable. Maybe if once

the majority has bigger screens, this can be turned on by default again.
Thanks pancake, for the hint.
---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 9c64948..5c4c518 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,5 +1,5 @@
 
-#define FONT "Liberation Mono:pixelsize=12:antialias=true:autohint=false"
+#define FONT "Liberation Mono:pixelsize=12:antialias=false:autohint=false"
 
 /* Space in pixels around the terminal buffer */
 #define BORDER 2

From bf6cf05ba5211b35d7b10169624679428c5f4974 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 5 Oct 2012 22:51:08 +0200
Subject: [PATCH 0339/1146] Fixing the brightening on bold. For the 256 colors
 and greyscale I assumed a

reasonable solution.
---
 st.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index df166b7..7ae9d8c 100644
--- a/st.c
+++ b/st.c
@@ -2192,10 +2192,27 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 	if(base.mode & ATTR_REVERSE)
 		temp = fg, fg = bg, bg = temp;
+
 	if(base.mode & ATTR_BOLD) {
-		fg = &dc.xft_col[base.fg + 8];
+		if(BETWEEN(base.fg, 0, 7)) {
+			/* basic system colors */
+			fg = &dc.xft_col[base.fg + 8];
+		} else if(BETWEEN(base.fg, 16, 195)) {
+			/* 256 colors */
+			fg = &dc.xft_col[base.fg + 36];
+		} else if(BETWEEN(base.fg, 232, 251)) {
+			/* greyscale */
+			fg = &dc.xft_col[base.fg + 4];
+		}
+		/*
+		 * Those ranges will not be brightened:
+		 *	8 - 15 – bright system colors
+		 *	196 - 231 – highest 256 color cube
+		 *	252 - 255 – brightest colors in grescale
+		 */
 		font = &dc.bfont;
 	}
+
 	if(base.mode & ATTR_ITALIC)
 		font = &dc.ifont;
 	if(base.mode & (ATTR_ITALIC|ATTR_ITALIC))

From 7efa4514d104d51793c4dd01ddedd4976080be07 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 5 Oct 2012 22:59:08 +0200
Subject: [PATCH 0340/1146] =?UTF-8?q?Adding=20the=20patch=20of=20David=20D?=
 =?UTF-8?q?ufberg=20T=C3=B6ttrup=20to=20implement=20WM=5FDELETE=5FWINDOW.?=
 =?UTF-8?q?=20Thank=20you!?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 st.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 7ae9d8c..1ac7fde 100644
--- a/st.c
+++ b/st.c
@@ -197,7 +197,7 @@ typedef struct {
 	Colormap cmap;
 	Window win;
 	XdbeBackBuffer buf;
-	Atom xembed;
+	Atom xembed, wmdeletewin;
 	XIM xim;
 	XIC xic;
 	XftDraw *xft_draw;
@@ -850,12 +850,15 @@ execsh(void) {
 void
 sigchld(int a) {
 	int stat = 0;
+
 	if(waitpid(pid, &stat, 0) < 0)
 		die("Waiting for pid %hd failed: %s\n",	pid, SERRNO);
-	if(WIFEXITED(stat))
+
+	if(WIFEXITED(stat)) {
 		exit(WEXITSTATUS(stat));
-	else
+	} else {
 		exit(EXIT_FAILURE);
+	}
 }
 
 void
@@ -2173,6 +2176,8 @@ xinit(void) {
 		&(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
 
 	xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
+	xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
+	XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
 
 	xresettitle();
 	XMapWindow(xw.dpy, xw.win);
@@ -2475,6 +2480,10 @@ cmessage(XEvent *e) {
 		} else if(e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
 			xw.state &= ~WIN_FOCUSED;
 		}
+	} else if(e->xclient.data.l[0] == xw.wmdeletewin) {
+		/* Send SIGHUP to shell */
+		kill(pid, SIGHUP);
+		exit(EXIT_SUCCESS);
 	}
 }
 

From 4eddf19fdc2f3845c927291b99d3faefe73f98f3 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 6 Oct 2012 09:58:45 +0200
Subject: [PATCH 0341/1146] The style inquisition was here. Yes, making it a
 unified style. The last

infidels will be squashed too!
---
 st.c | 365 +++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 230 insertions(+), 135 deletions(-)

diff --git a/st.c b/st.c
index 1ac7fde..f6c9f18 100644
--- a/st.c
+++ b/st.c
@@ -180,9 +180,9 @@ typedef struct {
 typedef struct {
 	int row;	/* nb row */
 	int col;	/* nb col */
-	Line* line;	/* screen */
-	Line* alt;	/* alternate screen */
-	bool* dirty;	/* dirtyness of lines */
+	Line *line;	/* screen */
+	Line *alt;	/* alternate screen */
+	bool *dirty;	/* dirtyness of lines */
 	TCursor c;	/* cursor */
 	int top;	/* top    scroll limit */
 	int bot;	/* bottom scroll limit */
@@ -242,7 +242,7 @@ typedef struct {
 	int descent;
 	short lbearing;
 	short rbearing;
-	XftFont* xft_set;
+	XftFont *xft_set;
 } Font;
 
 /* Drawing Context */
@@ -252,7 +252,7 @@ typedef struct {
 	Font font, bfont, ifont, ibfont;
 } DC;
 
-static void die(const char*, ...);
+static void die(const char *, ...);
 static void draw(void);
 static void redraw(void);
 static void drawregion(int, int, int, int);
@@ -279,7 +279,7 @@ static void tmoveto(int, int);
 static void tnew(int, int);
 static void tnewline(int);
 static void tputtab(bool);
-static void tputc(char*, int);
+static void tputc(char *, int);
 static void treset(void);
 static int tresize(int, int);
 static void tscrollup(int, int);
@@ -313,7 +313,7 @@ static void xresize(int, int);
 static void expose(XEvent *);
 static void visibility(XEvent *);
 static void unmap(XEvent *);
-static char* kmap(KeySym, uint);
+static char *kmap(KeySym, uint);
 static void kpress(XEvent *);
 static void cmessage(XEvent *);
 static void resize(XEvent *);
@@ -378,8 +378,10 @@ static char *opt_font = NULL;
 void *
 xmalloc(size_t len) {
 	void *p = malloc(len);
+
 	if(!p)
 		die("Out of memory\n");
+
 	return p;
 }
 
@@ -387,14 +389,17 @@ void *
 xrealloc(void *p, size_t len) {
 	if((p = realloc(p, len)) == NULL)
 		die("Out of memory\n");
+
 	return p;
 }
 
 void *
 xcalloc(size_t nmemb, size_t size) {
 	void *p = calloc(nmemb, size);
+
 	if(!p)
 		die("Out of memory\n");
+
 	return p;
 }
 
@@ -455,8 +460,10 @@ utf8decode(char *s, long *u) {
 	} else if((c & (B7|B6|B5|B4|B3)) == (B7|B6|B5|B4)) { /* 11110xxx */
 		*u = c & (B2|B1|B0);
 		n = 3;
-	} else
+	} else {
 		goto invalid;
+	}
+
 	for(i = n, ++s; i > 0; --i, ++rtn, ++s) {
 		c = *s;
 		if((c & (B7|B6)) != B7) /* 10xxxxxx */
@@ -464,14 +471,18 @@ utf8decode(char *s, long *u) {
 		*u <<= 6;
 		*u |= c & (B5|B4|B3|B2|B1|B0);
 	}
+
 	if((n == 1 && *u < 0x80) ||
 	   (n == 2 && *u < 0x800) ||
 	   (n == 3 && *u < 0x10000) ||
-	   (*u >= 0xD800 && *u <= 0xDFFF))
+	   (*u >= 0xD800 && *u <= 0xDFFF)) {
 		goto invalid;
+	}
+
 	return rtn;
 invalid:
 	*u = 0xFFFD;
+
 	return rtn;
 }
 
@@ -481,7 +492,7 @@ utf8encode(long *u, char *s) {
 	ulong uc;
 	int i, n;
 
-	sp = (uchar*) s;
+	sp = (uchar *)s;
 	uc = *u;
 	if(uc < 0x80) {
 		*sp = uc; /* 0xxxxxxx */
@@ -498,14 +509,17 @@ utf8encode(long *u, char *s) {
 	} else {
 		goto invalid;
 	}
+
 	for(i=n,++sp; i>0; --i,++sp)
 		*sp = ((uc >> 6*(i-1)) & (B5|B4|B3|B2|B1|B0)) | B7; /* 10xxxxxx */
+
 	return n+1;
 invalid:
 	/* U+FFFD */
 	*s++ = '\xEF';
 	*s++ = '\xBF';
 	*s = '\xBD';
+
 	return 3;
 }
 
@@ -515,38 +529,40 @@ int
 isfullutf8(char *s, int b) {
 	uchar *c1, *c2, *c3;
 
-	c1 = (uchar *) s;
-	c2 = (uchar *) ++s;
-	c3 = (uchar *) ++s;
-	if(b < 1)
+	c1 = (uchar *)s;
+	c2 = (uchar *)++s;
+	c3 = (uchar *)++s;
+	if(b < 1) {
 		return 0;
-	else if((*c1&(B7|B6|B5)) == (B7|B6) && b == 1)
+	} else if((*c1&(B7|B6|B5)) == (B7|B6) && b == 1) {
 		return 0;
-	else if((*c1&(B7|B6|B5|B4)) == (B7|B6|B5) &&
+	} else if((*c1&(B7|B6|B5|B4)) == (B7|B6|B5) &&
 	    ((b == 1) ||
-	    ((b == 2) && (*c2&(B7|B6)) == B7)))
+	    ((b == 2) && (*c2&(B7|B6)) == B7))) {
 		return 0;
-	else if((*c1&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4) &&
+	} else if((*c1&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4) &&
 	    ((b == 1) ||
 	    ((b == 2) && (*c2&(B7|B6)) == B7) ||
-	    ((b == 3) && (*c2&(B7|B6)) == B7 && (*c3&(B7|B6)) == B7)))
+	    ((b == 3) && (*c2&(B7|B6)) == B7 && (*c3&(B7|B6)) == B7))) {
 		return 0;
-	else
+	} else {
 		return 1;
+	}
 }
 
 int
 utf8size(char *s) {
 	uchar c = *s;
 
-	if(~c&B7)
+	if(~c&B7) {
 		return 1;
-	else if((c&(B7|B6|B5)) == (B7|B6))
+	} else if((c&(B7|B6|B5)) == (B7|B6)) {
 		return 2;
-	else if((c&(B7|B6|B5|B4)) == (B7|B6|B5))
+	} else if((c&(B7|B6|B5|B4)) == (B7|B6|B5)) {
 		return 3;
-	else
+	} else {
 		return 4;
+	}
 }
 
 void
@@ -563,13 +579,18 @@ selinit(void) {
 
 static inline bool
 selected(int x, int y) {
+	int bx, ex;
+
 	if(sel.ey == y && sel.by == y) {
-		int bx = MIN(sel.bx, sel.ex);
-		int ex = MAX(sel.bx, sel.ex);
+		bx = MIN(sel.bx, sel.ex);
+		ex = MAX(sel.bx, sel.ex);
 		return BETWEEN(x, bx, ex);
 	}
-	return ((sel.b.y < y&&y < sel.e.y) || (y==sel.e.y && x<=sel.e.x))
-		|| (y==sel.b.y && x>=sel.b.x && (x<=sel.e.x || sel.b.y!=sel.e.y));
+
+	return ((sel.b.y < y&&y < sel.e.y)
+			|| (y==sel.e.y && x<=sel.e.x))
+			|| (y==sel.b.y && x>=sel.b.x
+					&& (x<=sel.e.x || sel.b.y!=sel.e.y));
 }
 
 void
@@ -621,9 +642,9 @@ mousereport(XEvent *e) {
 
 void
 bpress(XEvent *e) {
-	if(IS_SET(MODE_MOUSE))
+	if(IS_SET(MODE_MOUSE)) {
 		mousereport(e);
-	else if(e->xbutton.button == Button1) {
+	} else if(e->xbutton.button == Button1) {
 		if(sel.bx != -1) {
 			sel.bx = -1;
 			tsetdirt(sel.b.y, sel.e.y);
@@ -637,22 +658,20 @@ bpress(XEvent *e) {
 
 void
 selcopy(void) {
-	char *str, *ptr;
-	int x, y, bufsize, is_selected = 0;
+	char *str, *ptr, *p;
+	int x, y, bufsize, is_selected = 0, size;
+	Glyph *gp;
 
-	if(sel.bx == -1)
+	if(sel.bx == -1) {
 		str = NULL;
-
-	else {
+	} else {
 		bufsize = (term.col+1) * (sel.e.y-sel.b.y+1) * UTF_SIZ;
 		ptr = str = xmalloc(bufsize);
 
 		/* append every set & selected glyph to the selection */
 		for(y = 0; y < term.row; y++) {
 			for(x = 0; x < term.col; x++) {
-				int size;
-				char *p;
-				Glyph *gp = &term.line[y][x];
+				gp = &term.line[y][x];
 
 				if(!(is_selected = selected(x, y)))
 					continue;
@@ -694,8 +713,9 @@ selnotify(XEvent *e) {
 }
 
 void
-selpaste() {
-	XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY, xw.win, CurrentTime);
+selpaste(void) {
+	XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY,
+			xw.win, CurrentTime);
 }
 
 void selclear(XEvent *e) {
@@ -709,7 +729,7 @@ void
 selrequest(XEvent *e) {
 	XSelectionRequestEvent *xsre;
 	XSelectionEvent xev;
-	Atom xa_targets;
+	Atom xa_targets, string;
 
 	xsre = (XSelectionRequestEvent *) e;
 	xev.type = SelectionNotify;
@@ -723,7 +743,7 @@ selrequest(XEvent *e) {
 	xa_targets = XInternAtom(xw.dpy, "TARGETS", 0);
 	if(xsre->target == xa_targets) {
 		/* respond with the supported type */
-		Atom string = sel.xtarget;
+		string = sel.xtarget;
 		XChangeProperty(xsre->display, xsre->requestor, xsre->property,
 				XA_ATOM, 32, PropModeReplace,
 				(uchar *) &string, 1);
@@ -756,18 +776,20 @@ xsetsel(char *str) {
 
 void
 brelease(XEvent *e) {
+	struct timeval now;
+
 	if(IS_SET(MODE_MOUSE)) {
 		mousereport(e);
 		return;
 	}
-	if(e->xbutton.button == Button2)
+
+	if(e->xbutton.button == Button2) {
 		selpaste();
-	else if(e->xbutton.button == Button1) {
+	} else if(e->xbutton.button == Button1) {
 		sel.mode = 0;
 		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
 		term.dirty[sel.ey] = 1;
 		if(sel.bx == sel.ex && sel.by == sel.ey) {
-			struct timeval now;
 			sel.bx = -1;
 			gettimeofday(&now, NULL);
 
@@ -781,34 +803,44 @@ brelease(XEvent *e) {
 				/* double click to select word */
 				sel.bx = sel.ex;
 				while(sel.bx > 0 && term.line[sel.ey][sel.bx-1].state & GLYPH_SET &&
-					  term.line[sel.ey][sel.bx-1].c[0] != ' ') sel.bx--;
+					  term.line[sel.ey][sel.bx-1].c[0] != ' ') {
+					sel.bx--;
+				}
 				sel.b.x = sel.bx;
 				while(sel.ex < term.col-1 && term.line[sel.ey][sel.ex+1].state & GLYPH_SET &&
-					  term.line[sel.ey][sel.ex+1].c[0] != ' ') sel.ex++;
+					  term.line[sel.ey][sel.ex+1].c[0] != ' ') {
+					sel.ex++;
+				}
 				sel.e.x = sel.ex;
 				sel.b.y = sel.e.y = sel.ey;
 				selcopy();
 			}
-		} else
+		} else {
 			selcopy();
+		}
 	}
+
 	memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval));
 	gettimeofday(&sel.tclick1, NULL);
 }
 
 void
 bmotion(XEvent *e) {
+	int starty, endy, oldey, oldex;
+
 	if(IS_SET(MODE_MOUSE)) {
 		mousereport(e);
 		return;
 	}
+
 	if(sel.mode) {
-		int oldey = sel.ey, oldex = sel.ex;
+		oldey = sel.ey;
+		oldex = sel.ex;
 		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
 
 		if(oldey != sel.ey || oldex != sel.ex) {
-			int starty = MIN(oldey, sel.ey);
-			int endy = MAX(oldey, sel.ey);
+			starty = MIN(oldey, sel.ey);
+			endy = MAX(oldey, sel.ey);
 			tsetdirt(starty, endy);
 		}
 	}
@@ -864,9 +896,9 @@ sigchld(int a) {
 void
 ttynew(void) {
 	int m, s;
+	struct winsize w = {term.row, term.col, 0, 0};
 
 	/* seems to work fine on linux, openbsd and freebsd */
-	struct winsize w = {term.row, term.col, 0, 0};
 	if(openpty(&m, &s, NULL, NULL, &w) < 0)
 		die("openpty failed: %s\n", SERRNO);
 
@@ -905,6 +937,7 @@ ttynew(void) {
 void
 dump(char c) {
 	static int col;
+
 	fprintf(stderr, " %02x '%c' ", c, isprint(c)?c:'.');
 	if(++col % 10 == 0)
 		fprintf(stderr, "\n");
@@ -931,7 +964,7 @@ ttyread(void) {
 		charsize = utf8decode(ptr, &utf8c);
 		utf8encode(&utf8c, s);
 		tputc(s, charsize);
-		ptr    += charsize;
+		ptr += charsize;
 		buflen -= charsize;
 	}
 
@@ -958,8 +991,7 @@ ttyresize(void) {
 }
 
 void
-tsetdirt(int top, int bot)
-{
+tsetdirt(int top, int bot) {
 	int i;
 
 	LIMIT(top, 0, term.row-1);
@@ -970,8 +1002,7 @@ tsetdirt(int top, int bot)
 }
 
 void
-tfulldirt(void)
-{
+tfulldirt(void) {
 	tsetdirt(0, term.row-1);
 }
 
@@ -979,15 +1010,18 @@ void
 tcursor(int mode) {
 	static TCursor c;
 
-	if(mode == CURSOR_SAVE)
+	if(mode == CURSOR_SAVE) {
 		c = term.c;
-	else if(mode == CURSOR_LOAD)
-		term.c = c, tmoveto(c.x, c.y);
+	} else if(mode == CURSOR_LOAD) {
+		term.c = c;
+		tmoveto(c.x, c.y);
+	}
 }
 
 void
 treset(void) {
 	uint i;
+
 	term.c = (TCursor){{
 		.mode = ATTR_NULL,
 		.fg = DefaultFG,
@@ -1024,7 +1058,8 @@ tnew(int col, int row) {
 
 void
 tswapscreen(void) {
-	Line* tmp = term.line;
+	Line *tmp = term.line;
+
 	term.line = term.alt;
 	term.alt = tmp;
 	term.mode ^= MODE_ALTSCREEN;
@@ -1098,10 +1133,12 @@ selscroll(int orig, int n) {
 void
 tnewline(int first_col) {
 	int y = term.c.y;
-	if(y == term.bot)
+
+	if(y == term.bot) {
 		tscrollup(term.top, 1);
-	else
+	} else {
 		y++;
+	}
 	tmoveto(first_col ? 0 : term.c.x, y);
 }
 
@@ -1119,11 +1156,12 @@ csiparse(void) {
 			csiescseq.arg[csiescseq.narg] *= 10;
 			csiescseq.arg[csiescseq.narg] += *p++ - '0'/*, noarg = 0 */;
 		}
-		if(*p == ';' && csiescseq.narg+1 < ESC_ARG_SIZ)
+		if(*p == ';' && csiescseq.narg+1 < ESC_ARG_SIZ) {
 			csiescseq.narg++, p++;
-		else {
+		} else {
 			csiescseq.mode = *p;
 			csiescseq.narg++;
+
 			return;
 		}
 	}
@@ -1140,21 +1178,21 @@ tmoveto(int x, int y) {
 
 void
 tsetchar(char *c) {
+	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.c.attr.mode & ATTR_GFX) {
-		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 - ~ */
-		};
-
 		if(c[0] >= 0x41 && c[0] <= 0x7e
 				&& vt100_0[c[0] - 0x41]) {
 			c = vt100_0[c[0] - 0x41];
@@ -1200,7 +1238,9 @@ tdeletechar(int n) {
 		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
 		return;
 	}
-	memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph));
+
+	memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src],
+			size * sizeof(Glyph));
 	tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
 }
 
@@ -1216,7 +1256,9 @@ tinsertblank(int n) {
 		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
 		return;
 	}
-	memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph));
+
+	memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src],
+			size * sizeof(Glyph));
 	tclearregion(src, term.c.y, dst - 1, term.c.y);
 }
 
@@ -1282,13 +1324,18 @@ tsetattr(int *attr, int l) {
 		case 38:
 			if(i + 2 < l && attr[i + 1] == 5) {
 				i += 2;
-				if(BETWEEN(attr[i], 0, 255))
+				if(BETWEEN(attr[i], 0, 255)) {
 					term.c.attr.fg = attr[i];
-				else
-					fprintf(stderr, "erresc: bad fgcolor %d\n", attr[i]);
+				} else {
+					fprintf(stderr,
+						"erresc: bad fgcolor %d\n",
+						attr[i]);
+				}
+			} else {
+				fprintf(stderr,
+					"erresc(38): gfx attr %d unknown\n",
+					attr[i]);
 			}
-			else
-				fprintf(stderr, "erresc(38): gfx attr %d unknown\n", attr[i]);
 			break;
 		case 39:
 			term.c.attr.fg = DefaultFG;
@@ -1296,28 +1343,36 @@ tsetattr(int *attr, int l) {
 		case 48:
 			if(i + 2 < l && attr[i + 1] == 5) {
 				i += 2;
-				if(BETWEEN(attr[i], 0, 255))
+				if(BETWEEN(attr[i], 0, 255)) {
 					term.c.attr.bg = attr[i];
-				else
-					fprintf(stderr, "erresc: bad bgcolor %d\n", attr[i]);
+				} else {
+					fprintf(stderr,
+						"erresc: bad bgcolor %d\n",
+						attr[i]);
+				}
+			} else {
+				fprintf(stderr,
+					"erresc(48): gfx attr %d unknown\n",
+					attr[i]);
 			}
-			else
-				fprintf(stderr, "erresc(48): gfx attr %d unknown\n", attr[i]);
 			break;
 		case 49:
 			term.c.attr.bg = DefaultBG;
 			break;
 		default:
-			if(BETWEEN(attr[i], 30, 37))
+			if(BETWEEN(attr[i], 30, 37)) {
 				term.c.attr.fg = attr[i] - 30;
-			else if(BETWEEN(attr[i], 40, 47))
+			} else if(BETWEEN(attr[i], 40, 47)) {
 				term.c.attr.bg = attr[i] - 40;
-			else if(BETWEEN(attr[i], 90, 97))
+			} else if(BETWEEN(attr[i], 90, 97)) {
 				term.c.attr.fg = attr[i] - 90 + 8;
-			else if(BETWEEN(attr[i], 100, 107))
+			} 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();
+			} else {
+				fprintf(stderr,
+					"erresc(default): gfx attr %d unknown\n",
+					attr[i]), csidump();
+			}
 			break;
 		}
 	}
@@ -1573,9 +1628,9 @@ csihandle(void) {
 		tsetattr(csiescseq.arg, csiescseq.narg);
 		break;
 	case 'r': /* DECSTBM -- Set Scrolling Region */
-		if(csiescseq.priv)
+		if(csiescseq.priv) {
 			goto unknown;
-		else {
+		} else {
 			DEFAULT(csiescseq.arg[0], 1);
 			DEFAULT(csiescseq.arg[1], term.row);
 			tsetscroll(csiescseq.arg[0]-1, csiescseq.arg[1]-1);
@@ -1594,14 +1649,22 @@ csihandle(void) {
 void
 csidump(void) {
 	int i;
+	uint c;
+
 	printf("ESC[");
 	for(i = 0; i < csiescseq.len; i++) {
-		uint c = csiescseq.buf[i] & 0xff;
-		if(isprint(c)) putchar(c);
-		else if(c == '\n') printf("(\\n)");
-		else if(c == '\r') printf("(\\r)");
-		else if(c == 0x1b) printf("(\\e)");
-		else printf("(%02x)", c);
+		c = csiescseq.buf[i] & 0xff;
+		if(isprint(c)) {
+			putchar(c);
+		} else if(c == '\n') {
+			printf("(\\n)");
+		} else if(c == '\r') {
+			printf("(\\r)");
+		} else if(c == 0x1b) {
+			printf("(\\e)");
+		} else {
+			printf("(%02x)", c);
+		}
 	}
 	putchar('\n');
 }
@@ -1672,14 +1735,22 @@ strparse(void) {
 void
 strdump(void) {
 	int i;
+	uint c;
+
 	printf("ESC%c", strescseq.type);
 	for(i = 0; i < strescseq.len; i++) {
-		uint c = strescseq.buf[i] & 0xff;
-		if(isprint(c)) putchar(c);
-		else if(c == '\n') printf("(\\n)");
-		else if(c == '\r') printf("(\\r)");
-		else if(c == 0x1b) printf("(\\e)");
-		else printf("(%02x)", c);
+		c = strescseq.buf[i] & 0xff;
+		if(isprint(c)) {
+			putchar(c);
+		} else if(c == '\n') {
+			printf("(\\n)");
+		} else if(c == '\r') {
+			printf("(\\r)");
+		} else if(c == 0x1b) {
+			printf("(\\e)");
+		} else {
+			printf("(%02x)", c);
+		}
 	}
 	printf("ESC\\\n");
 }
@@ -1746,7 +1817,8 @@ tputc(char *c, int len) {
 	if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {
 			csiescseq.buf[csiescseq.len++] = ascii;
-			if(BETWEEN(ascii, 0x40, 0x7E) || csiescseq.len >= ESC_BUF_SIZ) {
+			if(BETWEEN(ascii, 0x40, 0x7E)
+					|| csiescseq.len >= ESC_BUF_SIZ) {
 				term.esc = 0;
 				csiparse(), csihandle();
 			}
@@ -1811,10 +1883,11 @@ tputc(char *c, int len) {
 				term.esc = 0;
 				break;
 			case 'D': /* IND -- Linefeed */
-				if(term.c.y == term.bot)
+				if(term.c.y == term.bot) {
 					tscrollup(term.top, 1);
-				else
+				} else {
 					tmoveto(term.c.x, term.c.y+1);
+				}
 				term.esc = 0;
 				break;
 			case 'E': /* NEL -- Next line */
@@ -1826,10 +1899,11 @@ tputc(char *c, int len) {
 				term.esc = 0;
 				break;
 			case 'M': /* RI -- Reverse index */
-				if(term.c.y == term.top)
+				if(term.c.y == term.top) {
 					tscrolldown(term.top, 1);
-				else
+				} else {
 					tmoveto(term.c.x, term.c.y-1);
+				}
 				term.esc = 0;
 				break;
 			case 'c': /* RIS -- Reset to inital state */
@@ -1859,7 +1933,7 @@ tputc(char *c, int len) {
 				break;
 			default:
 				fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
-				    (uchar) ascii, isprint(ascii)?ascii:'.');
+					(uchar) ascii, isprint(ascii)? ascii:'.');
 				term.esc = 0;
 			}
 		}
@@ -1870,10 +1944,11 @@ tputc(char *c, int len) {
 			if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
 				tnewline(1); /* always go to first col */
 			tsetchar(c);
-			if(term.c.x+1 < term.col)
+			if(term.c.x+1 < term.col) {
 				tmoveto(term.c.x+1, term.c.y);
-			else
+			} else {
 				term.c.state |= CURSOR_WRAPNEXT;
+			}
 		}
 	}
 }
@@ -1884,6 +1959,7 @@ tresize(int col, int row) {
 	int minrow = MIN(row, term.row);
 	int mincol = MIN(col, term.col);
 	int slide = term.c.y - row + 1;
+	bool *bp;
 
 	if(col < 1 || row < 1)
 		return 0;
@@ -1930,7 +2006,7 @@ tresize(int col, int row) {
 		term.alt [i] = xcalloc(col, sizeof(Glyph));
 	}
 	if(col > term.col) {
-		bool *bp = term.tabs + term.col;
+		bp = term.tabs + term.col;
 
 		memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
 		while(--bp > term.tabs && !*bp)
@@ -1987,7 +2063,8 @@ xloadcols(void) {
 
 	for(r = 0; r < 24; r++, i++) {
 		xft_color.red = xft_color.green = xft_color.blue = 0x0808 + 0x0a0a * r;
-		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color, &dc.xft_col[i])) {
+		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color,
+					&dc.xft_col[i])) {
 			die("Could not allocate color %d\n", i);
 		}
 	}
@@ -2263,8 +2340,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 void
 xdrawcursor(void) {
-	static int oldx = 0;
-	static int oldy = 0;
+	static int oldx = 0, oldy = 0;
 	int sl;
 	Glyph g = {{' '}, ATTR_NULL, DefaultBG, DefaultCS, 0};
 
@@ -2277,9 +2353,11 @@ xdrawcursor(void) {
 	/* remove the old cursor */
 	if(term.line[oldy][oldx].state & GLYPH_SET) {
 		sl = utf8size(term.line[oldy][oldx].c);
-		xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, 1, sl);
-	} else
+		xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx,
+				oldy, 1, sl);
+	} else {
 		xtermclear(oldx, oldy, oldx, oldy);
+	}
 
 	/* draw the new one */
 	if(!(term.c.state & CURSOR_HIDE)) {
@@ -2334,6 +2412,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 	for(y = y1; y < y2; y++) {
 		if(!term.dirty[y])
 			continue;
+
 		xtermclear(0, y, term.col, y);
 		term.dirty[y] = 0;
 		base = term.line[y][0];
@@ -2342,8 +2421,9 @@ drawregion(int x1, int y1, int x2, int y2) {
 			new = term.line[y][x];
 			if(ena_sel && *(new.c) && selected(x, y))
 				new.mode ^= ATTR_REVERSE;
-			if(ib > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) ||
-						  ib >= DRAW_BUF_SIZ-UTF_SIZ)) {
+			if(ib > 0 && (!(new.state & GLYPH_SET)
+					|| ATTRCMP(base, new)
+					|| ib >= DRAW_BUF_SIZ-UTF_SIZ)) {
 				xdraws(buf, base, ox, y, ic, ib);
 				ic = ib = 0;
 			}
@@ -2367,6 +2447,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 void
 expose(XEvent *ev) {
 	XExposeEvent *e = &ev->xexpose;
+
 	if(xw.state & WIN_REDRAW) {
 		if(!e->count)
 			xw.state &= ~WIN_REDRAW;
@@ -2376,11 +2457,13 @@ expose(XEvent *ev) {
 void
 visibility(XEvent *ev) {
 	XVisibilityEvent *e = &ev->xvisibility;
-	if(e->state == VisibilityFullyObscured)
+
+	if(e->state == VisibilityFullyObscured) {
 		xw.state &= ~WIN_VISIBLE;
-	else if(!(xw.state & WIN_VISIBLE))
+	} else if(!(xw.state & WIN_VISIBLE)) {
 		/* need a full redraw for next Expose, not just a buf copy */
 		xw.state |= WIN_VISIBLE | WIN_REDRAW;
+	}
 }
 
 void
@@ -2391,6 +2474,7 @@ unmap(XEvent *ev) {
 void
 xseturgency(int add) {
 	XWMHints *h = XGetWMHints(xw.dpy, xw.win);
+
 	h->flags = add ? (h->flags | XUrgencyHint) : (h->flags & ~XUrgencyHint);
 	XSetWMHints(xw.dpy, xw.win, h);
 	XFree(h);
@@ -2401,18 +2485,24 @@ focus(XEvent *ev) {
 	if(ev->type == FocusIn) {
 		xw.state |= WIN_FOCUSED;
 		xseturgency(0);
-	} else
+	} else {
 		xw.state &= ~WIN_FOCUSED;
+	}
 }
 
 char*
 kmap(KeySym k, uint state) {
 	int i;
+	uint mask;
+
 	state &= ~Mod2Mask;
 	for(i = 0; i < LEN(key); i++) {
-		uint mask = key[i].mask;
-		if(key[i].k == k && ((state & mask) == mask || (mask == XK_NO_MOD && !state)))
+		mask = key[i].mask;
+
+		if(key[i].k == k && ((state & mask) == mask
+				|| (mask == XK_NO_MOD && !state))) {
 			return (char*)key[i].s;
+		}
 	}
 	return NULL;
 }
@@ -2430,22 +2520,25 @@ kpress(XEvent *ev) {
 
 	if (IS_SET(MODE_KBDLOCK))
 		return;
+
 	meta = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
 	len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status);
 
 	/* 1. custom keys from config.h */
-	if((customkey = kmap(ksym, e->state)))
+	if((customkey = kmap(ksym, e->state))) {
 		ttywrite(customkey, strlen(customkey));
 	/* 2. hardcoded (overrides X lookup) */
-	else
+	} else {
 		switch(ksym) {
 		case XK_Up:
 		case XK_Down:
 		case XK_Left:
 		case XK_Right:
 			/* XXX: shift up/down doesn't work */
-			sprintf(buf, "\033%c%c", IS_SET(MODE_APPKEYPAD) ? 'O' : '[', (shift ? "dacb":"DACB")[ksym - XK_Left]);
+			sprintf(buf, "\033%c%c",
+				IS_SET(MODE_APPKEYPAD) ? 'O' : '[',
+				(shift ? "dacb":"DACB")[ksym - XK_Left]);
 			ttywrite(buf, 3);
 			break;
 		case XK_Insert:
@@ -2453,10 +2546,11 @@ kpress(XEvent *ev) {
 				selpaste();
 			break;
 		case XK_Return:
-			if(IS_SET(MODE_CRLF))
+			if(IS_SET(MODE_CRLF)) {
 				ttywrite("\r\n", 2);
-			else
+			} else {
 				ttywrite("\r", 1);
+			}
 			break;
 			/* 3. X lookup  */
 		default:
@@ -2467,6 +2561,7 @@ kpress(XEvent *ev) {
 			}
 			break;
 		}
+	}
 }
 
 void
@@ -2618,7 +2713,7 @@ main(int argc, char *argv[]) {
 		}
 	}
 
- run:
+run:
 	setlocale(LC_CTYPE, "");
 	tnew(80, 24);
 	ttynew();

From 0cc7ee5e737c9df5a41a4bca708e583117830085 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 6 Oct 2012 13:43:01 +0200
Subject: [PATCH 0342/1146] Removing the xclearborders() hack. St now cleans up
 the parts of the border,

if something needs to be drawn close to it.
---
 st.c | 59 +++++++++++++++++++++++++++++++----------------------------
 1 file changed, 31 insertions(+), 28 deletions(-)

diff --git a/st.c b/st.c
index f6c9f18..67b4942 100644
--- a/st.c
+++ b/st.c
@@ -224,7 +224,9 @@ typedef struct {
 	int mode;
 	int bx, by;
 	int ex, ey;
-	struct {int x, y;} b, e;
+	struct {
+		int x, y;
+	} b, e;
 	char *clip;
 	Atom xtarget;
 	bool alt;
@@ -587,10 +589,10 @@ selected(int x, int y) {
 		return BETWEEN(x, bx, ex);
 	}
 
-	return ((sel.b.y < y&&y < sel.e.y)
-			|| (y==sel.e.y && x<=sel.e.x))
-			|| (y==sel.b.y && x>=sel.b.x
-					&& (x<=sel.e.x || sel.b.y!=sel.e.y));
+	return ((sel.b.y < y && y < sel.e.y)
+			|| (y == sel.e.y && x <= sel.e.x))
+			|| (y == sel.b.y && x >= sel.b.x
+				&& (x <= sel.e.x || sel.b.y != sel.e.y));
 }
 
 void
@@ -803,12 +805,12 @@ brelease(XEvent *e) {
 				/* double click to select word */
 				sel.bx = sel.ex;
 				while(sel.bx > 0 && term.line[sel.ey][sel.bx-1].state & GLYPH_SET &&
-					  term.line[sel.ey][sel.bx-1].c[0] != ' ') {
+						term.line[sel.ey][sel.bx-1].c[0] != ' ') {
 					sel.bx--;
 				}
 				sel.b.x = sel.bx;
 				while(sel.ex < term.col-1 && term.line[sel.ey][sel.ex+1].state & GLYPH_SET &&
-					  term.line[sel.ey][sel.ex+1].c[0] != ' ') {
+						term.line[sel.ey][sel.ex+1].c[0] != ' ') {
 					sel.ex++;
 				}
 				sel.e.x = sel.ex;
@@ -1031,7 +1033,8 @@ treset(void) {
 	memset(term.tabs, 0, term.col * sizeof(*term.tabs));
 	for(i = TAB; i < term.col; i += TAB)
 		term.tabs[i] = 1;
-	term.top = 0, term.bot = term.row - 1;
+	term.top = 0;
+	term.bot = term.row - 1;
 	term.mode = MODE_WRAP;
 
 	tclearregion(0, 0, term.col-1, term.row-1);
@@ -1040,7 +1043,8 @@ treset(void) {
 void
 tnew(int col, int row) {
 	/* set screen size */
-	term.row = row, term.col = col;
+	term.row = row;
+	term.col = col;
 	term.line = xmalloc(term.row * sizeof(Line));
 	term.alt  = xmalloc(term.row * sizeof(Line));
 	term.dirty = xmalloc(term.row * sizeof(*term.dirty));
@@ -1437,8 +1441,8 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				if(IS_SET(MODE_ALTSCREEN))
 					tclearregion(0, 0, term.col-1, term.row-1);
 				if((set && !IS_SET(MODE_ALTSCREEN)) ||
-				    (!set && IS_SET(MODE_ALTSCREEN))) {
-					    tswapscreen();
+						(!set && IS_SET(MODE_ALTSCREEN))) {
+					tswapscreen();
 				}
 				if(*args != 1049)
 					break;
@@ -1909,7 +1913,6 @@ tputc(char *c, int len) {
 			case 'c': /* RIS -- Reset to inital state */
 				treset();
 				term.esc = 0;
-				xclearborders();
 				xresettitle();
 				break;
 			case '=': /* DECPAM -- Application keypad */
@@ -2090,18 +2093,6 @@ xclear(int x1, int y1, int x2, int y2) {
 			x1, y1, x2-x1, y2-y1);
 }
 
-void
-xclearborders(void) {
-	/* top and left border */
-	xclear(0, 0, BORDER, xw.h);
-	xclear(0, 0, xw.w, BORDER);
-
-	/* lower and right border */
-	xclear(BORDER, xw.th - 1, xw.w, xw.h);
-	/* Will just draw what hasn't been drawn by the previous call. */
-	xclear(xw.tw - 1, BORDER, xw.w, xw.h - xw.th - 2);
-}
-
 void
 xhints(void) {
 	XClassHint class = {opt_class ? opt_class : TNAME, TNAME};
@@ -2264,8 +2255,8 @@ xinit(void) {
 
 void
 xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
-	int winx = BORDER+x*xw.cw, winy = BORDER+y*xw.ch,
-	    width = charlen*xw.cw;
+	int winx = BORDER + x * xw.cw, winy = BORDER + y * xw.ch,
+	    width = charlen * xw.cw;
 	Font *font = &dc.font;
 	XGlyphInfo extents;
 	XftColor *fg = &dc.xft_col[base.fg], *bg = &dc.xft_col[base.bg],
@@ -2328,6 +2319,20 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			&extents);
 	width = extents.xOff;
 
+	/* Intelligent cleaning up of the borders. */
+	if(x == 0) {
+		xclear(0, (y == 0)? 0 : winy, BORDER,
+			winy + xw.ch + (y == term.row-1)? xw.h : 0);
+	}
+	if(x + charlen >= term.col-1) {
+		xclear(winx + width, (y == 0)? 0 : winy, xw.w,
+			winy + xw.ch + (y == term.row-1)? xw.h : 0);
+	}
+	if(y == 0)
+		xclear(winx, 0, winx + width, BORDER);
+	if(y == term.row-1)
+		xclear(winx, winy + xw.ch, winx + width, xw.h);
+
 	XftDrawRect(xw.xft_draw, bg, winx, winy, width, xw.ch);
 	XftDrawStringUtf8(xw.xft_draw, fg, font->xft_set, winx,
 			winy + font->ascent, (FcChar8 *)s, bytelen);
@@ -2382,7 +2387,6 @@ void
 redraw(void) {
 	struct timespec tv = {0, REDRAW_TIMEOUT * 1000};
 
-	xclearborders();
 	tfulldirt();
 	draw();
 	XSync(xw.dpy, False); /* necessary for a good tput flash */
@@ -2598,7 +2602,6 @@ resize(XEvent *e) {
 
 	tresize(col, row);
 	xresize(col, row);
-	xclearborders();
 	ttyresize();
 }
 

From 02f3b37a2d354c74169f5ed038bb1cb6225d691a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 6 Oct 2012 13:45:14 +0200
Subject: [PATCH 0343/1146] Forgot to remove the xclearborders() definition
 from the last commit.

---
 st.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.c b/st.c
index 67b4942..64e0aff 100644
--- a/st.c
+++ b/st.c
@@ -302,7 +302,6 @@ static void ttywrite(const char *, size_t);
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
 static void xclear(int, int, int, int);
-static void xclearborders(void);
 static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);

From ac8f05c45a65788523af7223b1a94e8baf890b6e Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 6 Oct 2012 19:12:46 +0200
Subject: [PATCH 0344/1146] Add documentation to control codes

Add the documentation from the vt100 manual programmer:

Control 	Octal      Action Taken
Character	Code
-------------------------------------------
NUL		000	Ignored on input (not stored in input buffer;
			see full duplex protocol).
ENQ		005	Transmit answerback message.
BEL		007	Sound bell tone from keyboard.
BS		010	Move the cursor to the left one character position,
			unless it is at the left margin,
			in which case no action occurs.
HT		011	Move the cursor to the next tab stop,
			or to the right margin if no further tab stops
			are present on the line.
LF		012	This code causes a line feed or
			a new line operation. (See new line mode).
VT		013	Interpreted as LF.
FF		014	Interpreted as LF.
CR		015	Move cursor to the left margin on the current line.
SO		016	Invoke G1 character set, as designated by SCS
			control sequence.
SI		017	Select G0 character set, as selected by ESC ( sequence.
XON		021	Causes terminal to resume transmission.
XOFF		023	Causes terminal to stop transmitted all codes
			except XOFF and XON.
CAN		030	If sent during a control sequence, the sequence is
			immediately terminated and not executed. It also causes
			the error character to be displayed.
SUB		032	Interpreted as CAN.
ESC		033	Invokes a control sequence.
DEL		177	Ignored on input (not stored in input buffer).
--------------------------------------------
---
 st.c |   28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)
---
 st.c | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index 64e0aff..aa5f085 100644
--- a/st.c
+++ b/st.c
@@ -1789,32 +1789,42 @@ tputc(char *c, int len) {
 		write(iofd, c, len);
 
 	switch(ascii) {
-	case '\t':
+	case '\t':	/* HT */
 		tputtab(1);
 		return;
-	case '\b':
+	case '\b':	/* BS */
 		tmoveto(term.c.x-1, term.c.y);
 		return;
-	case '\r':
+	case '\r':	/* CR */
 		tmoveto(0, term.c.y);
 		return;
-	case '\f':
-	case '\v':
-	case '\n':
+	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':
+	case '\a':	/* BEL */
 		if(term.esc & ESC_STR)
 			break;
-
 		if(!(xw.state & WIN_FOCUSED))
 			xseturgency(1);
 		return;
-	case '\033':
+	case '\033':	/* ESC */
 		csireset();
 		term.esc = ESC_START;
 		return;
+	case '\016':	/* XXX: SO */
+	case '\017':	/* XXX: SI */
+	case '\032':	/* XXX: SUB */
+	case '\030':	/* XXX: CAN */
+	default:
+	/* case '\005':	ENQ (IGNORED) */
+	/* case '\000':	NUL (IGNORED) */
+	/* case '\021':	XON (IGNORED) */
+	/* case '\023':	XOFF (IGNORED) */
+	/* case 0177:	DEL (IGNORED) */
+		break;
 	}
 
 	if(term.esc & ESC_START) {

From fbfa1f83eb501e885d1077e95739a7d7cab2397f Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 6 Oct 2012 19:13:08 +0200
Subject: [PATCH 0345/1146] Add SUB and CAN control codes

These control codes reset any escape sequence already initialised.
---
 st.c |    7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
---
 st.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index aa5f085..8e25d23 100644
--- a/st.c
+++ b/st.c
@@ -1816,8 +1816,11 @@ tputc(char *c, int len) {
 		return;
 	case '\016':	/* XXX: SO */
 	case '\017':	/* XXX: SI */
-	case '\032':	/* XXX: SUB */
-	case '\030':	/* XXX: CAN */
+		break;
+	case '\032':	/* SUB */
+	case '\030':	/* CAN */
+		csireset();
+		return;
 	default:
 	/* case '\005':	ENQ (IGNORED) */
 	/* case '\000':	NUL (IGNORED) */

From 034dc71fb8227e8963f22b123f30962ec0b6bca7 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 6 Oct 2012 19:13:36 +0200
Subject: [PATCH 0346/1146] Add SI and SO control codes

SI and SO allows change the G0 and G1 selection. This implementation is not
full vt100 compatible, but it is complatible with linux virtual terminal
implementation. For full vt100 compatibility we need remake a lot of stuff
relate to the different charmaps.
---
 st.c |    7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
---
 st.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 8e25d23..ba6973a 100644
--- a/st.c
+++ b/st.c
@@ -1814,9 +1814,12 @@ tputc(char *c, int len) {
 		csireset();
 		term.esc = ESC_START;
 		return;
-	case '\016':	/* XXX: SO */
-	case '\017':	/* XXX: SI */
+	case '\016':	/* SO */
+		term.c.attr.mode |= ATTR_GFX;
 		break;
+	case '\017':	/* SI */
+		term.c.attr.mode &= ~ATTR_GFX;
+		return;
 	case '\032':	/* SUB */
 	case '\030':	/* CAN */
 		csireset();

From 2bd0c23fa7bb42724c75416342d36e00c435f404 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 6 Oct 2012 19:15:30 +0200
Subject: [PATCH 0347/1146] Print control codes only in graphic mode

Non handled codes must be ignored, except in graphic mode. Also STR
sequences have higher priority than control codes, so they must be handled
before of them.
---
 st.c |  160 ++++++++++++++++++++++++++++++++++++------------------------------
 1 file changed, 87 insertions(+), 73 deletions(-)
---
 st.c | 160 ++++++++++++++++++++++++++++++++---------------------------
 1 file changed, 87 insertions(+), 73 deletions(-)

diff --git a/st.c b/st.c
index ba6973a..23ed213 100644
--- a/st.c
+++ b/st.c
@@ -1784,56 +1784,80 @@ tputtab(bool forward) {
 void
 tputc(char *c, int len) {
 	uchar ascii = *c;
+	bool control = ascii < '\x20' || ascii == 0177;
 
 	if(iofd != -1)
 		write(iofd, c, len);
-
-	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)
+	/*
+	 * STR sequences must be checked before of anything
+	 * because it can use some control codes as part of the sequence
+	 */
+	if(term.esc & ESC_STR) {
+		switch(ascii) {
+		case '\033':
+			term.esc = ESC_START | ESC_STR_END;
 			break;
-		if(!(xw.state & WIN_FOCUSED))
-			xseturgency(1);
+		case '\a': /* backwards compatibility to xterm */
+			term.esc = 0;
+			strhandle();
+			break;
+		default:
+			strescseq.buf[strescseq.len++] = ascii;
+			if(strescseq.len+1 >= STR_BUF_SIZ) {
+				term.esc = 0;
+				strhandle();
+			}
+		}
 		return;
-	case '\033':	/* ESC */
-		csireset();
-		term.esc = ESC_START;
-		return;
-	case '\016':	/* SO */
-		term.c.attr.mode |= ATTR_GFX;
-		break;
-	case '\017':	/* SI */
-		term.c.attr.mode &= ~ATTR_GFX;
-		return;
-	case '\032':	/* SUB */
-	case '\030':	/* CAN */
-		csireset();
-		return;
-	default:
-	/* case '\005':	ENQ (IGNORED) */
-	/* case '\000':	NUL (IGNORED) */
-	/* case '\021':	XON (IGNORED) */
-	/* case '\023':	XOFF (IGNORED) */
-	/* case 0177:	DEL (IGNORED) */
-		break;
 	}
-
-	if(term.esc & ESC_START) {
+	/*
+	 * 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) {
+		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(!(xw.state & WIN_FOCUSED))
+				xseturgency(1);
+			return;
+		case '\033':	/* ESC */
+			csireset();
+			term.esc = ESC_START;
+			return;
+		case '\016':	/* SO */
+			term.c.attr.mode |= ATTR_GFX;
+			return;
+		case '\017':	/* SI */
+			term.c.attr.mode &= ~ATTR_GFX;
+			return;
+		case '\032':	/* SUB */
+		case '\030':	/* CAN */
+			csireset();
+			return;
+		 case '\005':	/* ENQ (IGNORED) */
+		 case '\000':	/* NUL (IGNORED) */
+		 case '\021':	/* XON (IGNORED) */
+		 case '\023':	/* XOFF (IGNORED) */
+		 case 0177:	/* DEL (IGNORED) */
+			return;
+		}
+	} else if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {
 			csiescseq.buf[csiescseq.len++] = ascii;
 			if(BETWEEN(ascii, 0x40, 0x7E)
@@ -1841,22 +1865,6 @@ tputc(char *c, int len) {
 				term.esc = 0;
 				csiparse(), csihandle();
 			}
-		} else if(term.esc & ESC_STR) {
-			switch(ascii) {
-			case '\033':
-				term.esc = ESC_START | ESC_STR_END;
-				break;
-			case '\a': /* backwards compatibility to xterm */
-				term.esc = 0;
-				strhandle();
-				break;
-			default:
-				strescseq.buf[strescseq.len++] = ascii;
-				if(strescseq.len+1 >= STR_BUF_SIZ) {
-					term.esc = 0;
-					strhandle();
-				}
-			}
 		} else if(term.esc & ESC_STR_END) {
 			term.esc = 0;
 			if(ascii == '\\')
@@ -1955,20 +1963,26 @@ tputc(char *c, int len) {
 				term.esc = 0;
 			}
 		}
-	} else {
-		if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey))
-			sel.bx = -1;
-		if(ascii >= '\020' || term.c.attr.mode & ATTR_GFX) {
-			if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
-				tnewline(1); /* always go to first col */
-			tsetchar(c);
-			if(term.c.x+1 < term.col) {
-				tmoveto(term.c.x+1, term.c.y);
-			} else {
-				term.c.state |= CURSOR_WRAPNEXT;
-			}
-		}
+		/*
+		 * All characters which forms part of a sequence are not
+		 * printed
+		 */
+		return;
 	}
+	/*
+	 * Display control codes only if we are in graphic mode
+	 */
+	if(control && !(term.c.attr.mode & ATTR_GFX))
+		return;
+	if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey))
+		sel.bx = -1;
+	if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
+		tnewline(1); /* always go to first col */
+	tsetchar(c);
+	if(term.c.x+1 < term.col)
+		tmoveto(term.c.x+1, term.c.y);
+	else
+		term.c.state |= CURSOR_WRAPNEXT;
 }
 
 int

From b16b5d77d31c4c6b2577ab0986e85b43baaf834a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 6 Oct 2012 20:52:22 +0200
Subject: [PATCH 0348/1146] Fixing a off-by-one error in the new border
 clearing code.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 23ed213..16c64b1 100644
--- a/st.c
+++ b/st.c
@@ -2355,7 +2355,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	}
 	if(x + charlen >= term.col-1) {
 		xclear(winx + width, (y == 0)? 0 : winy, xw.w,
-			winy + xw.ch + (y == term.row-1)? xw.h : 0);
+			(y == term.row-1)? xw.h : (winy + xw.ch));
 	}
 	if(y == 0)
 		xclear(winx, 0, winx + width, BORDER);

From bffa6e5cc612dcead2d6ff3803ec72cb69c151bd Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 6 Oct 2012 21:02:25 +0200
Subject: [PATCH 0349/1146] Fixing a typo.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 16c64b1..ba44b1c 100644
--- a/st.c
+++ b/st.c
@@ -2310,7 +2310,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		 * Those ranges will not be brightened:
 		 *	8 - 15 – bright system colors
 		 *	196 - 231 – highest 256 color cube
-		 *	252 - 255 – brightest colors in grescale
+		 *	252 - 255 – brightest colors in greyscale
 		 */
 		font = &dc.bfont;
 	}

From ffeeb678c5c6c6b895ad494b5b62195dd9893f65 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 6 Oct 2012 21:19:56 +0200
Subject: [PATCH 0350/1146] Add DA and DECID sequences

These sequences are used by the host in order to can detect which kind of
terminal is connected. St will answer like a vt102 terminal with this patch.
---
 st.c |    9 +++++++++
 1 file changed, 9 insertions(+)
---
 st.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/st.c b/st.c
index ba44b1c..85b0b59 100644
--- a/st.c
+++ b/st.c
@@ -72,6 +72,8 @@
 #define X2COL(x) (((x) - BORDER)/xw.cw)
 #define Y2ROW(y) (((y) - BORDER)/xw.ch)
 
+#define VT102ID "\033[?6c"
+
 enum glyph_attribute {
 	ATTR_NULL      = 0,
 	ATTR_REVERSE   = 1,
@@ -1510,6 +1512,10 @@ csihandle(void) {
 		DEFAULT(csiescseq.arg[0], 1);
 		tmoveto(term.c.x, term.c.y+csiescseq.arg[0]);
 		break;
+	case 'c': /* DA -- Device Attributes */
+		if(csiescseq.arg[0] == 0)
+			ttywrite(VT102ID, sizeof(VT102ID));
+		break;
 	case 'C': /* CUF -- Cursor <n> Forward */
 	case 'a':
 		DEFAULT(csiescseq.arg[0], 1);
@@ -1933,6 +1939,9 @@ tputc(char *c, int len) {
 				}
 				term.esc = 0;
 				break;
+			case 'Z': /* DECID -- Identify Terminal */
+				ttywrite(VT102ID, sizeof(VT102ID));
+				break;
 			case 'c': /* RIS -- Reset to inital state */
 				treset();
 				term.esc = 0;

From 25f47cb83a71f7d2872a197209cc2d8cd1c955ec Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 7 Oct 2012 11:06:00 +0200
Subject: [PATCH 0351/1146] Fix Identification sequences

Do not send NUL character in the identification (use (sizeof(VT102ID) - 1),
and finish  the sequence once you execute it.
---
 st.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
---
 st.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 85b0b59..8c8efaf 100644
--- a/st.c
+++ b/st.c
@@ -1514,7 +1514,7 @@ csihandle(void) {
 		break;
 	case 'c': /* DA -- Device Attributes */
 		if(csiescseq.arg[0] == 0)
-			ttywrite(VT102ID, sizeof(VT102ID));
+			ttywrite(VT102ID, sizeof(VT102ID) - 1);
 		break;
 	case 'C': /* CUF -- Cursor <n> Forward */
 	case 'a':
@@ -1940,7 +1940,8 @@ tputc(char *c, int len) {
 				term.esc = 0;
 				break;
 			case 'Z': /* DECID -- Identify Terminal */
-				ttywrite(VT102ID, sizeof(VT102ID));
+				ttywrite(VT102ID, sizeof(VT102ID) - 1);
+				term.esc = 0;
 				break;
 			case 'c': /* RIS -- Reset to inital state */
 				treset();

From b7a7f171effb301ce8dbce07c1c77a6b06ef980f Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 7 Oct 2012 11:06:08 +0200
Subject: [PATCH 0352/1146] Avoid initialization of vt100_0 in each call to
 tsetchar

If vt100_0 is a automatic variable then it is initializated in each call to
tsetchar, but if the variable is static it is initializated only in compile
time.
---
 st.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 8c8efaf..33a1501 100644
--- a/st.c
+++ b/st.c
@@ -1183,7 +1183,7 @@ tmoveto(int x, int y) {
 
 void
 tsetchar(char *c) {
-	char *vt100_0[62] = { /* 0x41 - 0x7e */
+	static char *vt100_0[62] = { /* 0x41 - 0x7e */
 		"↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */
 		0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
 		0, 0, 0, 0, 0, 0, 0, 0, /* P - W */

From 9e813947cf4631c0ca8e5f73ebfb269ef2f8252b Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 7 Oct 2012 11:06:17 +0200
Subject: [PATCH 0353/1146] Add DEC alignment test

This sequence was used by DEC personal in to for verifying the screen adjust
of terminals. It is the unique test sequence implemented by all the
emulators, and I think it is because they want be conforms with vttest which
uses this sequence in some tests.
---
 st.c |   31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)
---
 st.c | 31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/st.c b/st.c
index 33a1501..693739e 100644
--- a/st.c
+++ b/st.c
@@ -123,6 +123,7 @@ enum escape_state {
 	ESC_STR	= 4, /* DSC, OSC, PM, APC */
 	ESC_ALTCHARSET = 8,
 	ESC_STR_END    = 16, /* a final string was encountered */
+	ESC_TEST       = 32, /* Enter in test mode */
 };
 
 enum window_state {
@@ -289,7 +290,7 @@ static int tresize(int, int);
 static void tscrollup(int, int);
 static void tscrolldown(int, int);
 static void tsetattr(int*, int);
-static void tsetchar(char*);
+static void tsetchar(char *, Glyph *, int, int);
 static void tsetscroll(int, int);
 static void tswapscreen(void);
 static void tsetdirt(int, int);
@@ -1182,7 +1183,7 @@ tmoveto(int x, int y) {
 }
 
 void
-tsetchar(char *c) {
+tsetchar(char *c, Glyph *attr, int x, int y) {
 	static char *vt100_0[62] = { /* 0x41 - 0x7e */
 		"↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */
 		0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
@@ -1197,17 +1198,17 @@ tsetchar(char *c) {
 	/*
 	 * The table is proudly stolen from rxvt.
 	 */
-	if(term.c.attr.mode & ATTR_GFX) {
+	if(attr->mode & ATTR_GFX) {
 		if(c[0] >= 0x41 && c[0] <= 0x7e
 				&& vt100_0[c[0] - 0x41]) {
 			c = vt100_0[c[0] - 0x41];
 		}
 	}
 
-	term.dirty[term.c.y] = 1;
-	term.line[term.c.y][term.c.x] = term.c.attr;
-	memcpy(term.line[term.c.y][term.c.x].c, c, UTF_SIZ);
-	term.line[term.c.y][term.c.x].state |= GLYPH_SET;
+	term.dirty[y] = 1;
+	term.line[y][x] = *attr;
+	memcpy(term.line[y][x].c, c, UTF_SIZ);
+	term.line[y][x].state |= GLYPH_SET;
 }
 
 void
@@ -1893,11 +1894,25 @@ tputc(char *c, int len) {
 				fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
 			}
 			term.esc = 0;
+		} else if(term.esc & ESC_TEST) {
+			if(ascii == '8') { /* DEC screen alignment test. */
+				char E[UTF_SIZ] = "E";
+				int x, y;
+
+				for(x = 0; x < term.col; ++x) {
+					for(y = 0; y < term.row; ++y)
+						tsetchar(E, &term.c.attr, x, y);
+				}
+			}
+			term.esc = 0;
 		} else {
 			switch(ascii) {
 			case '[':
 				term.esc |= ESC_CSI;
 				break;
+			case '#':
+				term.esc |= ESC_TEST;
+				break;
 			case 'P': /* DCS -- Device Control String */
 			case '_': /* APC -- Application Program Command */
 			case '^': /* PM -- Privacy Message */
@@ -1988,7 +2003,7 @@ tputc(char *c, int len) {
 		sel.bx = -1;
 	if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
 		tnewline(1); /* always go to first col */
-	tsetchar(c);
+	tsetchar(c, &term.c.attr, term.c.x, term.c.y);
 	if(term.c.x+1 < term.col)
 		tmoveto(term.c.x+1, term.c.y);
 	else

From eb6713acf1928ec94364627ed583252370051705 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 9 Oct 2012 19:33:26 +0200
Subject: [PATCH 0354/1146] If there is really someone without SHELL set, help
 him/her.

---
 st.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.c b/st.c
index 693739e..43f5bc2 100644
--- a/st.c
+++ b/st.c
@@ -865,6 +865,9 @@ execsh(void) {
 	char **args;
 	char *envshell = getenv("SHELL");
 
+	if (envshell == NULL)
+		envshell ="/bin/sh";
+
 	unsetenv("COLUMNS");
 	unsetenv("LINES");
 	unsetenv("TERMCAP");

From 2e38ab7afdc56e3853751918f1b7705362bea01c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 9 Oct 2012 19:40:37 +0200
Subject: [PATCH 0355/1146] Well, I was confused. Damn state exams. Instead of
 discussing this shit I

should really learn opthalmology instead. :O
---
 st.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 43f5bc2..f967d2c 100644
--- a/st.c
+++ b/st.c
@@ -865,9 +865,6 @@ execsh(void) {
 	char **args;
 	char *envshell = getenv("SHELL");
 
-	if (envshell == NULL)
-		envshell ="/bin/sh";
-
 	unsetenv("COLUMNS");
 	unsetenv("LINES");
 	unsetenv("TERMCAP");
@@ -881,7 +878,7 @@ execsh(void) {
 
 	DEFAULT(envshell, SHELL);
 	putenv("TERM="TNAME);
-	args = opt_cmd ? opt_cmd : (char*[]){envshell, "-i", NULL};
+	args = opt_cmd ? opt_cmd : (char *[]){envshell, "-i", NULL};
 	execvp(args[0], args);
 	exit(EXIT_FAILURE);
 }

From ee3fbeb6c8c354cf4db226a5b1583c531ea37af4 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 28 Oct 2012 06:27:42 +0100
Subject: [PATCH 0356/1146] Add error control to iofile

write can write less bytes than we request, so it is necessary check the
return value, in case of error print a message and don't continnue writing
in the file.
---
 st.c |   39 ++++++++++++++++++++++++++++++---------
 1 file changed, 30 insertions(+), 9 deletions(-)
---
 st.c | 39 ++++++++++++++++++++++++++++++---------
 1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index f967d2c..e19cefd 100644
--- a/st.c
+++ b/st.c
@@ -340,6 +340,7 @@ static int utf8encode(long *, char *);
 static int utf8size(char *);
 static int isfullutf8(char *, int);
 
+static ssize_t xwrite(int, char *, size_t);
 static void *xmalloc(size_t);
 static void *xrealloc(void *, size_t);
 static void *xcalloc(size_t nmemb, size_t size);
@@ -379,6 +380,21 @@ static char *opt_embed = NULL;
 static char *opt_class = NULL;
 static char *opt_font = NULL;
 
+
+ssize_t
+xwrite(int fd, char *s, size_t len) {
+	size_t aux = len;
+
+	while(len > 0) {
+		ssize_t r = write(fd, s, len);
+		if(r < 0)
+			return r;
+		len -= r;
+		s += r;
+	}
+	return aux;
+}
+
 void *
 xmalloc(size_t len) {
 	void *p = malloc(len);
@@ -926,13 +942,12 @@ ttynew(void) {
 		cmdfd = m;
 		signal(SIGCHLD, sigchld);
 		if(opt_io) {
-			if(!strcmp(opt_io, "-")) {
-				iofd = STDOUT_FILENO;
-			} else {
-				if((iofd = open(opt_io, O_WRONLY | O_CREAT, 0666)) < 0) {
-					fprintf(stderr, "Error opening %s:%s\n",
-						opt_io, strerror(errno));
-				}
+			iofd = (!strcmp(opt_io, "-")) ?
+				  STDOUT_FILENO :
+				  open(opt_io, O_WRONLY | O_CREAT, 0666);
+			if(iofd < 0) {
+				fprintf(stderr, "Error opening %s:%s\n",
+					opt_io, strerror(errno));
 			}
 		}
 	}
@@ -1793,8 +1808,14 @@ tputc(char *c, int len) {
 	uchar ascii = *c;
 	bool control = ascii < '\x20' || ascii == 0177;
 
-	if(iofd != -1)
-		write(iofd, c, len);
+	if(iofd != -1) {
+		if (xwrite(iofd, c, len) < 0) {
+			fprintf(stderr, "Error writting in %s:%s\n",
+				opt_io, strerror(errno));
+			close(iofd);
+			iofd = -1;
+		}
+	}
 	/*
 	 * STR sequences must be checked before of anything
 	 * because it can use some control codes as part of the sequence

From 35421371ca150b6bd0fd1330e7b30a99029dbce1 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 28 Oct 2012 06:32:54 +0100
Subject: [PATCH 0357/1146] Applying the patch of Rafa Garcia Gallega
 <rafael.garcia.gallego@gmail.com> to

not emulate the vt100 behaviour of selecting all whitespaces. Thanks!
---
 st.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index e19cefd..3cd7831 100644
--- a/st.c
+++ b/st.c
@@ -678,7 +678,7 @@ bpress(XEvent *e) {
 
 void
 selcopy(void) {
-	char *str, *ptr, *p;
+	char *str, *ptr;
 	int x, y, bufsize, is_selected = 0, size;
 	Glyph *gp;
 
@@ -693,11 +693,12 @@ selcopy(void) {
 			for(x = 0; x < term.col; x++) {
 				gp = &term.line[y][x];
 
-				if(!(is_selected = selected(x, y)))
+				if(!(is_selected = selected(x, y))
+						|| !(gp->state & GLYPH_SET)) {
 					continue;
-				p = (gp->state & GLYPH_SET) ? gp->c : " ";
-				size = utf8size(p);
-				memcpy(ptr, p, size);
+				}
+				size = utf8size(gp->c);
+				memcpy(ptr, gp->c, size);
 				ptr += size;
 			}
 			/* \n at the end of every selected line except for the last one */

From 6d4e525ed95fbddc38be441394a02dc9233b157d Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 28 Oct 2012 06:54:08 +0100
Subject: [PATCH 0358/1146] Applying the patch of Roberto Caballero to set
 WINDOWID and all the pwuid()

variables. Thanks! xinit() and ttynew() had to be switched in their
call-appearance. Otherwise xw.win is not set.
---
 st.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 3cd7831..f54e4d5 100644
--- a/st.c
+++ b/st.c
@@ -5,6 +5,7 @@
 #include <fcntl.h>
 #include <limits.h>
 #include <locale.h>
+#include <pwd.h>
 #include <stdarg.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -881,11 +882,23 @@ void
 execsh(void) {
 	char **args;
 	char *envshell = getenv("SHELL");
+	const struct passwd *pass = getpwuid(getuid());
+	char buf[sizeof(long) * 8 + 1];
 
 	unsetenv("COLUMNS");
 	unsetenv("LINES");
 	unsetenv("TERMCAP");
 
+	if(pass) {
+		setenv("LOGNAME", pass->pw_name, 1);
+		setenv("USER", pass->pw_name, 1);
+		setenv("SHELL", pass->pw_shell, 0);
+		setenv("HOME", pass->pw_dir, 0);
+	}
+
+	snprintf(buf, sizeof(buf), "%lu", xw.win);
+	setenv("WINDOWID", buf, 1);
+
 	signal(SIGCHLD, SIG_DFL);
 	signal(SIGHUP, SIG_DFL);
 	signal(SIGINT, SIG_DFL);
@@ -2795,8 +2808,8 @@ main(int argc, char *argv[]) {
 run:
 	setlocale(LC_CTYPE, "");
 	tnew(80, 24);
-	ttynew();
 	xinit();
+	ttynew();
 	selinit();
 	run();
 	return 0;

From 71b09ec4f172da9a89be2add54b5b94da8af3bea Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 28 Oct 2012 13:25:53 +0100
Subject: [PATCH 0359/1146] Adding a more flexible fontstring handling,
 shortcuts and a zoom function.

---
 config.def.h |  14 ++++
 config.mk    |   4 +-
 st.c         | 186 +++++++++++++++++++++++++++++++--------------------
 3 files changed, 128 insertions(+), 76 deletions(-)

diff --git a/config.def.h b/config.def.h
index 5c4c518..67b1316 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,4 +1,8 @@
 
+/*
+ * Do not include the »pixelsize« parameter in your font definition. It is
+ * used to calculate zooming.
+ */
 #define FONT "Liberation Mono:pixelsize=12:antialias=false:autohint=false"
 
 /* Space in pixels around the terminal buffer */
@@ -73,6 +77,15 @@ static Key key[] = {
 	{ XK_F12,       XK_NO_MOD, "\033[24~" },
 };
 
+/* Internal shortcuts. */
+#define MODKEY Mod1Mask
+
+static Shortcut shortcuts[] = {
+	/* modifier		key		function	argument */
+	{ MODKEY|ShiftMask,	XK_Prior,	xzoom,		{.i = +1} },
+	{ MODKEY|ShiftMask,	XK_Next,	xzoom,		{.i = -1} },
+};
+
 /* Set TERM to this */
 #define TNAME "st-256color"
 
@@ -81,3 +94,4 @@ static Key key[] = {
 #define TRIPLECLICK_TIMEOUT (2*DOUBLECLICK_TIMEOUT)
 
 #define TAB 8
+
diff --git a/config.mk b/config.mk
index 3cd714f..e45fc2d 100644
--- a/config.mk
+++ b/config.mk
@@ -16,8 +16,8 @@ LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext -lXft -lfontconfig
 
 # flags
 CPPFLAGS = -DVERSION=\"${VERSION}\"
-CFLAGS += -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
-LDFLAGS += -s ${LIBS}
+CFLAGS += -g -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
+LDFLAGS += -g ${LIBS}
 
 # compiler and linker
 CC ?= cc
diff --git a/st.c b/st.c
index f54e4d5..5703e96 100644
--- a/st.c
+++ b/st.c
@@ -60,6 +60,8 @@
 
 #define REDRAW_TIMEOUT (80*1000) /* 80 ms */
 
+/* macros */
+#define CLEANMASK(mask) (mask & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
 #define SERRNO strerror(errno)
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
 #define MAX(a, b)  ((a) < (b) ? (b) : (a))
@@ -238,6 +240,24 @@ typedef struct {
 	struct timeval tclick2;
 } Selection;
 
+typedef union {
+	int i;
+	unsigned int ui;
+	float f;
+	const void *v;
+} Arg;
+
+typedef struct {
+	unsigned int mod;
+	KeySym keysym;
+	void (*func)(const Arg *);
+	const Arg arg;
+} Shortcut;
+
+/* function definitions used in config.h */
+static void xzoom(const Arg *);
+
+/* Config.h for applying patches and the configuration. */
 #include "config.h"
 
 /* Font structure */
@@ -321,6 +341,7 @@ static void unmap(XEvent *);
 static char *kmap(KeySym, uint);
 static void kpress(XEvent *);
 static void cmessage(XEvent *);
+static void cresize(int width, int height);
 static void resize(XEvent *);
 static void focus(XEvent *);
 static void brelease(XEvent *);
@@ -345,7 +366,6 @@ static ssize_t xwrite(int, char *, size_t);
 static void *xmalloc(size_t);
 static void *xrealloc(void *, size_t);
 static void *xcalloc(size_t nmemb, size_t size);
-static char *smstrcat(char *, ...);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
@@ -381,6 +401,8 @@ static char *opt_embed = NULL;
 static char *opt_class = NULL;
 static char *opt_font = NULL;
 
+static char *usedfont = NULL;
+static int usedfontsize = 0;
 
 ssize_t
 xwrite(int fd, char *s, size_t len) {
@@ -424,44 +446,6 @@ xcalloc(size_t nmemb, size_t size) {
 	return p;
 }
 
-char *
-smstrcat(char *src, ...)
-{
-	va_list fmtargs;
-	char *ret, *p, *v;
-	int len, slen, flen;
-
-	len = slen = strlen(src);
-
-	va_start(fmtargs, src);
-	for(;;) {
-		v = va_arg(fmtargs, char *);
-		if(v == NULL)
-			break;
-		len += strlen(v);
-	}
-	va_end(fmtargs);
-
-	p = ret = xmalloc(len+1);
-	memmove(p, src, slen);
-	p += slen;
-
-	va_start(fmtargs, src);
-	for(;;) {
-		v = va_arg(fmtargs, char *);
-		if(v == NULL)
-			break;
-		flen = strlen(v);
-		memmove(p, v, flen);
-		p += flen;
-	}
-	va_end(fmtargs);
-
-	ret[len] = '\0';
-
-	return ret;
-}
-
 int
 utf8decode(char *s, long *u) {
 	uchar c;
@@ -2107,7 +2091,8 @@ tresize(int col, int row) {
 			*bp = 1;
 	}
 	/* update terminal size */
-	term.col = col, term.row = row;
+	term.col = col;
+	term.row = row;
 	/* make use of the LIMIT in tmoveto */
 	tmoveto(term.c.x, term.c.y);
 	/* reset scrolling region */
@@ -2207,22 +2192,17 @@ xhints(void) {
 	XFree(sizeh);
 }
 
-void
-xinitfont(Font *f, char *fontstr) {
-	FcPattern *pattern, *match;
+int
+xloadfont(Font *f, FcPattern *pattern) {
+	FcPattern *match;
 	FcResult result;
 
-	pattern = FcNameParse((FcChar8 *)fontstr);
-	if(!pattern)
-		die("st: can't open font %s\n", fontstr);
-
 	match = XftFontMatch(xw.dpy, xw.scr, pattern, &result);
-	FcPatternDestroy(pattern);
 	if(!match)
-		die("st: can't open font %s\n", fontstr);
+		return 1;
 	if(!(f->xft_set = XftFontOpenPattern(xw.dpy, match))) {
 		FcPatternDestroy(match);
-		die("st: can't open font %s.\n", fontstr);
+		return 1;
 	}
 
 	f->ascent = f->xft_set->ascent;
@@ -2232,27 +2212,68 @@ xinitfont(Font *f, char *fontstr) {
 
 	f->height = f->xft_set->height;
 	f->width = f->lbearing + f->rbearing;
+
+	return 0;
 }
 
 void
-initfonts(char *fontstr) {
-	char *fstr;
+xloadfonts(char *fontstr, int fontsize) {
+	FcPattern *pattern;
+	FcResult result;
+	double fontval;
 
-	xinitfont(&dc.font, fontstr);
+	pattern = FcNameParse((FcChar8 *)fontstr);
+	if(!pattern)
+		die("st: can't open font %s\n", fontstr);
+
+	if(fontsize > 0) {
+		FcPatternDel(pattern, FC_PIXEL_SIZE);
+		FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize);
+		usedfontsize = fontsize;
+	} else {
+		result = FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval);
+		if(result == FcResultMatch) {
+			usedfontsize = (int)fontval;
+		} 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;
+		}
+	}
+
+	if(xloadfont(&dc.font, pattern))
+		die("st: can't open font %s\n", fontstr);
+
+	/* Setting character width and height. */
 	xw.cw = dc.font.width;
 	xw.ch = dc.font.height;
 
-	fstr = smstrcat(fontstr, ":weight=bold", NULL);
-	xinitfont(&dc.bfont, fstr);
-	free(fstr);
+	FcPatternDel(pattern, FC_WEIGHT);
+	FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
+	if(xloadfont(&dc.bfont, pattern))
+		die("st: can't open font %s\n", fontstr);
 
-	fstr = smstrcat(fontstr, ":slant=italic,oblique", NULL);
-	xinitfont(&dc.ifont, fstr);
-	free(fstr);
+	FcPatternDel(pattern, FC_SLANT);
+	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+	if(xloadfont(&dc.ibfont, pattern))
+		die("st: can't open font %s\n", fontstr);
 
-	fstr = smstrcat(fontstr, ":weight=bold:slant=italic,oblique", NULL);
-	xinitfont(&dc.ibfont, fstr);
-	free(fstr);
+	FcPatternDel(pattern, FC_WEIGHT);
+	if(xloadfont(&dc.ifont, pattern))
+		die("st: can't open font %s\n", fontstr);
+
+	FcPatternDestroy(pattern);
+}
+
+void
+xzoom(const Arg *arg)
+{
+	xloadfonts(usedfont, usedfontsize + arg->i);
+	cresize(0, 0);
+	draw();
 }
 
 void
@@ -2268,7 +2289,8 @@ xinit(void) {
 	xw.vis = XDefaultVisual(xw.dpy, xw.scr);
 
 	/* font */
-	initfonts((opt_font != NULL)? opt_font : FONT);
+	usedfont = (opt_font == NULL)? FONT : opt_font;
+	xloadfonts(usedfont, 0);
 
 	/* colors */
 	xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
@@ -2604,11 +2626,8 @@ void
 kpress(XEvent *ev) {
 	XKeyEvent *e = &ev->xkey;
 	KeySym ksym;
-	char buf[32];
-	char *customkey;
-	int len;
-	int meta;
-	int shift;
+	char buf[32], *customkey;
+	int len, meta, shift, i;
 	Status status;
 
 	if (IS_SET(MODE_KBDLOCK))
@@ -2618,7 +2637,17 @@ kpress(XEvent *ev) {
 	shift = e->state & ShiftMask;
 	len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status);
 
-	/* 1. custom keys from config.h */
+	/* 1. shortcuts */
+	for(i = 0; i < LEN(shortcuts); i++) {
+		if((ksym == shortcuts[i].keysym)
+				&& (CLEANMASK(shortcuts[i].mod) == \
+					CLEANMASK(e->state))
+				&& shortcuts[i].func) {
+			shortcuts[i].func(&(shortcuts[i].arg));
+		}
+	}
+
+	/* 2. custom keys from config.h */
 	if((customkey = kmap(ksym, e->state))) {
 		ttywrite(customkey, strlen(customkey));
 	/* 2. hardcoded (overrides X lookup) */
@@ -2676,14 +2705,15 @@ cmessage(XEvent *e) {
 }
 
 void
-resize(XEvent *e) {
+cresize(int width, int height)
+{
 	int col, row;
 
-	if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
-		return;
+	if(width != 0)
+		xw.w = width;
+	if(height != 0)
+		xw.h = height;
 
-	xw.w = e->xconfigure.width;
-	xw.h = e->xconfigure.height;
 	col = (xw.w - 2*BORDER) / xw.cw;
 	row = (xw.h - 2*BORDER) / xw.ch;
 	if(col == term.col && row == term.row)
@@ -2694,6 +2724,14 @@ resize(XEvent *e) {
 	ttyresize();
 }
 
+void
+resize(XEvent *e) {
+	if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
+		return;
+
+	cresize(e->xconfigure.width, e->xconfigure.height);
+}
+
 void
 run(void) {
 	XEvent ev;

From b56a0da283bd09d5084f472353c1a0b1b084613e Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 28 Oct 2012 13:35:00 +0100
Subject: [PATCH 0360/1146] Applying the tab expansion patch from koga.

---
 st.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index 5703e96..ebc9962 100644
--- a/st.c
+++ b/st.c
@@ -663,9 +663,9 @@ bpress(XEvent *e) {
 
 void
 selcopy(void) {
-	char *str, *ptr;
+	char *str, *ptr, *p;
 	int x, y, bufsize, is_selected = 0, size;
-	Glyph *gp;
+	Glyph *gp, *last;
 
 	if(sel.bx == -1) {
 		str = NULL;
@@ -675,15 +675,19 @@ selcopy(void) {
 
 		/* append every set & selected glyph to the selection */
 		for(y = 0; y < term.row; y++) {
-			for(x = 0; x < term.col; x++) {
-				gp = &term.line[y][x];
+			gp = &term.line[y][0];
+			last = gp + term.col;
 
-				if(!(is_selected = selected(x, y))
-						|| !(gp->state & GLYPH_SET)) {
+			while(--last >= gp && !(last->state & GLYPH_SET))
+				/* nothing */;
+
+			for(x = 0; gp <= last; x++, ++gp) {
+				if(!(is_selected = selected(x, y)))
 					continue;
-				}
-				size = utf8size(gp->c);
-				memcpy(ptr, gp->c, size);
+
+				p = (gp->state & GLYPH_SET) ? gp->c : " ";
+				size = utf8size(p);
+				memcpy(ptr, p, size);
 				ptr += size;
 			}
 			/* \n at the end of every selected line except for the last one */

From c5dd7fb377d4bfe9988ef150a55b4a3756d09524 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 28 Oct 2012 13:37:11 +0100
Subject: [PATCH 0361/1146] Applying the patch of the little girl
 <yui@blekksprut.net> to make cjk input

possible. Thanks!
---
 st.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index ebc9962..c4ff67c 100644
--- a/st.c
+++ b/st.c
@@ -2602,9 +2602,11 @@ xseturgency(int add) {
 void
 focus(XEvent *ev) {
 	if(ev->type == FocusIn) {
+		XSetICFocus(xw.xic);
 		xw.state |= WIN_FOCUSED;
 		xseturgency(0);
 	} else {
+		XUnsetICFocus(xw.xic);
 		xw.state &= ~WIN_FOCUSED;
 	}
 }
@@ -2774,7 +2776,7 @@ run(void) {
 
 		while(XPending(xw.dpy)) {
 			XNextEvent(xw.dpy, &ev);
-			if(XFilterEvent(&ev, xw.win))
+			if(XFilterEvent(&ev, None))
 				continue;
 			if(handler[ev.type])
 				(handler[ev.type])(&ev);
@@ -2849,6 +2851,7 @@ main(int argc, char *argv[]) {
 
 run:
 	setlocale(LC_CTYPE, "");
+	XSetLocaleModifiers("");
 	tnew(80, 24);
 	xinit();
 	ttynew();

From 1d378227c0349d83c540771815250c4506d578f3 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 28 Oct 2012 14:13:39 +0100
Subject: [PATCH 0362/1146] Removing the now senseless comment in config.def.h.
 Thanks to bnwe!

---
 config.def.h | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index 67b1316..a8f48ea 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,8 +1,4 @@
 
-/*
- * Do not include the »pixelsize« parameter in your font definition. It is
- * used to calculate zooming.
- */
 #define FONT "Liberation Mono:pixelsize=12:antialias=false:autohint=false"
 
 /* Space in pixels around the terminal buffer */

From 784765ca35389a9579976d3e5ec9dc73de4bf4d9 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 31 Oct 2012 20:35:07 +0100
Subject: [PATCH 0363/1146] Cleaning up the TODO file.

---
 TODO | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/TODO b/TODO
index 201a1a3..f56a6d9 100644
--- a/TODO
+++ b/TODO
@@ -14,11 +14,7 @@ vt emulation
 code & interface
 ----------------
 
-* clean selection code
 * clean and complete terminfo entry
-* add border around cursor, when it could be hard to read
-	* white border when not selected would suffice
-	* + definition in config.h
 * add fallback fonts for the restricted xft code
 
 bugs

From e5d7c5a69e17d858984fe2c28b7d026672f42177 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 31 Oct 2012 20:36:32 +0100
Subject: [PATCH 0364/1146] Adding a FAQ to reference utmp(1).

---
 FAQ | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 FAQ

diff --git a/FAQ b/FAQ
new file mode 100644
index 0000000..594a873
--- /dev/null
+++ b/FAQ
@@ -0,0 +1,8 @@
+--
+Why does st not handle utmp entries?
+
+Use the excellent tool of utmp[0] for this task.
+
+[0] http://hg.suckless.org/utmp/
+--
+

From 393825f9f8a23dfcdfda5220aa8029e9356fa15b Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 2 Nov 2012 19:56:02 +0100
Subject: [PATCH 0365/1146] Moving to the dwm config.h variable usage.

---
 config.def.h | 56 +++++++++++++++++++-----------------
 st.c         | 80 ++++++++++++++++++++++++++--------------------------
 2 files changed, 70 insertions(+), 66 deletions(-)

diff --git a/config.def.h b/config.def.h
index a8f48ea..1ba6d8e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,11 +1,19 @@
+/* See LICENSE file for copyright and license details. */
 
-#define FONT "Liberation Mono:pixelsize=12:antialias=false:autohint=false"
+/* appearance */
+static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=false";
+static unsigned int borderpx = 2;
+static char shell[] = "/bin/sh";
 
-/* Space in pixels around the terminal buffer */
-#define BORDER 2
+/* double-click timeout (in milliseconds) between clicks for selection */
+static unsigned int doubleclicktimeout = 300;
+static unsigned int tripleclicktimeout = 600;
+
+/* TERM value */
+static char termname[] = "st-256color";
+
+static unsigned int tabspaces = 8;
 
-/* Default shell to use if SHELL is not set in the env */
-#define SHELL "/bin/sh"
 
 /* Terminal colors (16 first used in escape sequence) */
 static const char *colorname[] = {
@@ -36,21 +44,26 @@ static const char *colorname[] = {
 	"#333333",
 };
 
-/* Default colors (colorname index)
-   foreground, background, cursor, unfocused cursor */
-#define DefaultFG  7
-#define DefaultBG  0
-#define DefaultCS  256
-#define DefaultUCS 257
 
-/* Special keys (change & recompile st.info accordingly)
-   Keep in mind that kpress() in st.c hardcodes some keys.
+/*
+ * Default colors (colorname index)
+ * foreground, background, cursor, unfocused cursor
+ */
+static unsigned int defaultfg = 7;
+static unsigned int defaultbg = 0;
+static unsigned int defaultcs = 256;
+static unsigned int defaultucs = 257;
 
-   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)
+/*
+ * Special keys (change & recompile st.info accordingly)
+ * Keep in mind that kpress() in st.c hardcodes some keys.
+ *
+ * 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)
+ */
 
-      key,        mask,  output */
+/* key, mask, output */
 static Key key[] = {
 	{ XK_BackSpace, XK_NO_MOD, "\177" },
 	{ XK_Insert,    XK_NO_MOD, "\033[2~" },
@@ -82,12 +95,3 @@ static Shortcut shortcuts[] = {
 	{ MODKEY|ShiftMask,	XK_Next,	xzoom,		{.i = -1} },
 };
 
-/* Set TERM to this */
-#define TNAME "st-256color"
-
-/* double-click timeout (in milliseconds) between clicks for selection */
-#define DOUBLECLICK_TIMEOUT 300
-#define TRIPLECLICK_TIMEOUT (2*DOUBLECLICK_TIMEOUT)
-
-#define TAB 8
-
diff --git a/st.c b/st.c
index c4ff67c..cdf1fdc 100644
--- a/st.c
+++ b/st.c
@@ -72,8 +72,8 @@
 #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
 #define IS_SET(flag) (term.mode & (flag))
 #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
-#define X2COL(x) (((x) - BORDER)/xw.cw)
-#define Y2ROW(y) (((y) - BORDER)/xw.ch)
+#define X2COL(x) (((x) - borderpx)/xw.cw)
+#define Y2ROW(y) (((y) - borderpx)/xw.ch)
 
 #define VT102ID "\033[?6c"
 
@@ -803,13 +803,13 @@ brelease(XEvent *e) {
 			sel.bx = -1;
 			gettimeofday(&now, NULL);
 
-			if(TIMEDIFF(now, sel.tclick2) <= TRIPLECLICK_TIMEOUT) {
+			if(TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) {
 				/* triple click on the line */
 				sel.b.x = sel.bx = 0;
 				sel.e.x = sel.ex = term.col;
 				sel.b.y = sel.e.y = sel.ey;
 				selcopy();
-			} else if(TIMEDIFF(now, sel.tclick1) <= DOUBLECLICK_TIMEOUT) {
+			} else if(TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) {
 				/* double click to select word */
 				sel.bx = sel.ex;
 				while(sel.bx > 0 && term.line[sel.ey][sel.bx-1].state & GLYPH_SET &&
@@ -894,8 +894,8 @@ execsh(void) {
 	signal(SIGTERM, SIG_DFL);
 	signal(SIGALRM, SIG_DFL);
 
-	DEFAULT(envshell, SHELL);
-	putenv("TERM="TNAME);
+	DEFAULT(envshell, shell);
+	setenv("TERM", termname, 1);
 	args = opt_cmd ? opt_cmd : (char *[]){envshell, "-i", NULL};
 	execvp(args[0], args);
 	exit(EXIT_FAILURE);
@@ -1045,12 +1045,12 @@ treset(void) {
 
 	term.c = (TCursor){{
 		.mode = ATTR_NULL,
-		.fg = DefaultFG,
-		.bg = DefaultBG
+		.fg = defaultfg,
+		.bg = defaultbg
 	}, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
 
 	memset(term.tabs, 0, term.col * sizeof(*term.tabs));
-	for(i = TAB; i < term.col; i += TAB)
+	for(i = tabspaces; i < term.col; i += tabspaces)
 		term.tabs[i] = 1;
 	term.top = 0;
 	term.bot = term.row - 1;
@@ -1310,8 +1310,8 @@ tsetattr(int *attr, int l) {
 		case 0:
 			term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE | ATTR_BOLD \
 					| ATTR_ITALIC | ATTR_BLINK);
-			term.c.attr.fg = DefaultFG;
-			term.c.attr.bg = DefaultBG;
+			term.c.attr.fg = defaultfg;
+			term.c.attr.bg = defaultbg;
 			break;
 		case 1:
 			term.c.attr.mode |= ATTR_BOLD;
@@ -1361,7 +1361,7 @@ tsetattr(int *attr, int l) {
 			}
 			break;
 		case 39:
-			term.c.attr.fg = DefaultFG;
+			term.c.attr.fg = defaultfg;
 			break;
 		case 48:
 			if(i + 2 < l && attr[i + 1] == 5) {
@@ -1380,7 +1380,7 @@ tsetattr(int *attr, int l) {
 			}
 			break;
 		case 49:
-			term.c.attr.bg = DefaultBG;
+			term.c.attr.bg = defaultbg;
 			break;
 		default:
 			if(BETWEEN(attr[i], 30, 37)) {
@@ -2091,7 +2091,7 @@ tresize(int col, int row) {
 		memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
 		while(--bp > term.tabs && !*bp)
 			/* nothing */ ;
-		for(bp += TAB; bp < term.tabs + col; bp += TAB)
+		for(bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
 			*bp = 1;
 	}
 	/* update terminal size */
@@ -2107,8 +2107,8 @@ tresize(int col, int row) {
 
 void
 xresize(int col, int row) {
-	xw.tw = MAX(1, 2*BORDER + col * xw.cw);
-	xw.th = MAX(1, 2*BORDER + row * xw.ch);
+	xw.tw = MAX(1, 2*borderpx + col * xw.cw);
+	xw.th = MAX(1, 2*borderpx + row * xw.ch);
 
 	XftDrawChange(xw.xft_draw, xw.buf);
 }
@@ -2154,9 +2154,9 @@ xloadcols(void) {
 void
 xtermclear(int col1, int row1, int col2, int row2) {
 	XftDrawRect(xw.xft_draw,
-			&dc.xft_col[IS_SET(MODE_REVERSE) ? DefaultFG : DefaultBG],
-			BORDER + col1 * xw.cw,
-			BORDER + row1 * xw.ch,
+			&dc.xft_col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
+			borderpx + col1 * xw.cw,
+			borderpx + row1 * xw.ch,
 			(col2-col1+1) * xw.cw,
 			(row2-row1+1) * xw.ch);
 }
@@ -2167,13 +2167,13 @@ xtermclear(int col1, int row1, int col2, int row2) {
 void
 xclear(int x1, int y1, int x2, int y2) {
 	XftDrawRect(xw.xft_draw,
-			&dc.xft_col[IS_SET(MODE_REVERSE) ? DefaultFG : DefaultBG],
+			&dc.xft_col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
 			x1, y1, x2-x1, y2-y1);
 }
 
 void
 xhints(void) {
-	XClassHint class = {opt_class ? opt_class : TNAME, TNAME};
+	XClassHint class = {opt_class ? opt_class : termname, termname};
 	XWMHints wm = {.flags = InputHint, .input = 1};
 	XSizeHints *sizeh = NULL;
 
@@ -2184,8 +2184,8 @@ xhints(void) {
 		sizeh->width = xw.w;
 		sizeh->height_inc = xw.ch;
 		sizeh->width_inc = xw.cw;
-		sizeh->base_height = 2*BORDER;
-		sizeh->base_width = 2*BORDER;
+		sizeh->base_height = 2*borderpx;
+		sizeh->base_width = 2*borderpx;
 	} else {
 		sizeh->flags = PMaxSize | PMinSize;
 		sizeh->min_width = sizeh->max_width = xw.fw;
@@ -2293,7 +2293,7 @@ xinit(void) {
 	xw.vis = XDefaultVisual(xw.dpy, xw.scr);
 
 	/* font */
-	usedfont = (opt_font == NULL)? FONT : opt_font;
+	usedfont = (opt_font == NULL)? font : opt_font;
 	xloadfonts(usedfont, 0);
 
 	/* colors */
@@ -2313,14 +2313,14 @@ xinit(void) {
 		xw.w = xw.fw;
 	} else {
 		/* window - default size */
-		xw.h = 2*BORDER + term.row * xw.ch;
-		xw.w = 2*BORDER + term.col * xw.cw;
+		xw.h = 2*borderpx + term.row * xw.ch;
+		xw.w = 2*borderpx + term.col * xw.cw;
 		xw.fx = 0;
 		xw.fy = 0;
 	}
 
-	attrs.background_pixel = dc.xft_col[DefaultBG].pixel;
-	attrs.border_pixel = dc.xft_col[DefaultBG].pixel;
+	attrs.background_pixel = dc.xft_col[defaultbg].pixel;
+	attrs.border_pixel = dc.xft_col[defaultbg].pixel;
 	attrs.bit_gravity = NorthWestGravity;
 	attrs.event_mask = FocusChangeMask | KeyPressMask
 		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
@@ -2370,7 +2370,7 @@ xinit(void) {
 
 void
 xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
-	int winx = BORDER + x * xw.cw, winy = BORDER + y * xw.ch,
+	int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
 	    width = charlen * xw.cw;
 	Font *font = &dc.font;
 	XGlyphInfo extents;
@@ -2407,8 +2407,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		font = &dc.ibfont;
 
 	if(IS_SET(MODE_REVERSE)) {
-		if(fg == &dc.xft_col[DefaultFG]) {
-			fg = &dc.xft_col[DefaultBG];
+		if(fg == &dc.xft_col[defaultfg]) {
+			fg = &dc.xft_col[defaultbg];
 		} else {
 			colfg.red = ~fg->color.red;
 			colfg.green = ~fg->color.green;
@@ -2418,8 +2418,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			fg = &revfg;
 		}
 
-		if(bg == &dc.xft_col[DefaultBG]) {
-			bg = &dc.xft_col[DefaultFG];
+		if(bg == &dc.xft_col[defaultbg]) {
+			bg = &dc.xft_col[defaultfg];
 		} else {
 			colbg.red = ~bg->color.red;
 			colbg.green = ~bg->color.green;
@@ -2436,7 +2436,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 	/* Intelligent cleaning up of the borders. */
 	if(x == 0) {
-		xclear(0, (y == 0)? 0 : winy, BORDER,
+		xclear(0, (y == 0)? 0 : winy, borderpx,
 			winy + xw.ch + (y == term.row-1)? xw.h : 0);
 	}
 	if(x + charlen >= term.col-1) {
@@ -2444,7 +2444,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			(y == term.row-1)? xw.h : (winy + xw.ch));
 	}
 	if(y == 0)
-		xclear(winx, 0, winx + width, BORDER);
+		xclear(winx, 0, winx + width, borderpx);
 	if(y == term.row-1)
 		xclear(winx, winy + xw.ch, winx + width, xw.h);
 
@@ -2462,7 +2462,7 @@ void
 xdrawcursor(void) {
 	static int oldx = 0, oldy = 0;
 	int sl;
-	Glyph g = {{' '}, ATTR_NULL, DefaultBG, DefaultCS, 0};
+	Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs, 0};
 
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
@@ -2482,10 +2482,10 @@ xdrawcursor(void) {
 	/* draw the new one */
 	if(!(term.c.state & CURSOR_HIDE)) {
 		if(!(xw.state & WIN_FOCUSED))
-			g.bg = DefaultUCS;
+			g.bg = defaultucs;
 
 		if(IS_SET(MODE_REVERSE))
-			g.mode |= ATTR_REVERSE, g.fg = DefaultCS, g.bg = DefaultFG;
+			g.mode |= ATTR_REVERSE, g.fg = defaultcs, g.bg = defaultfg;
 
 		sl = utf8size(g.c);
 		xdraws(g.c, g, term.c.x, term.c.y, 1, sl);
@@ -2720,8 +2720,8 @@ cresize(int width, int height)
 	if(height != 0)
 		xw.h = height;
 
-	col = (xw.w - 2*BORDER) / xw.cw;
-	row = (xw.h - 2*BORDER) / xw.ch;
+	col = (xw.w - 2*borderpx) / xw.cw;
+	row = (xw.h - 2*borderpx) / xw.ch;
 	if(col == term.col && row == term.row)
 		return;
 

From c631e9bb917ec268463b3f1f331b286c43a6bd0b Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 2 Nov 2012 20:07:11 +0100
Subject: [PATCH 0366/1146] Make it possible to use the corefont font
 description too. It is not very

useful, but easy to implement.
---
 st.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index cdf1fdc..8e0df08 100644
--- a/st.c
+++ b/st.c
@@ -2226,7 +2226,12 @@ xloadfonts(char *fontstr, int fontsize) {
 	FcResult result;
 	double fontval;
 
-	pattern = FcNameParse((FcChar8 *)fontstr);
+	if(fontstr[0] == '-') {
+		pattern = XftXlfdParse(fontstr, False, False);
+	} else {
+		pattern = FcNameParse((FcChar8 *)fontstr);
+	}
+
 	if(!pattern)
 		die("st: can't open font %s\n", fontstr);
 

From b0ed3e289730e42195f3388ffcc437e6cb3b8377 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 2 Nov 2012 20:08:27 +0100
Subject: [PATCH 0367/1146] 0.3 release.

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index e45fc2d..20e519f 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.2.1-tip
+VERSION = 0.3
 
 # Customize below to fit your system
 

From cd90969cab2d980977a76b79f936929834f2bdba Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 2 Nov 2012 20:08:51 +0100
Subject: [PATCH 0368/1146] Added tag 0.3 for changeset 9d54ce4daf34

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 977dd47..a13fbc7 100644
--- a/.hgtags
+++ b/.hgtags
@@ -2,3 +2,4 @@ cbc18c988236c63a58ed24031805e8d36a3ad01a 0.1
 f245ac2efd8ac2f1ac6bffae876c2663e794f79d 0.1.1
 3c2f9f2ab5e433db1401047760ec31d66939b74b 0.2
 108926a0fe610b92c0296148721c3225932f39aa 0.2.1
+9d54ce4daf3453c5a33e446ef3c0f38e12ec4d72 0.3

From 091ae143ce09e930fd61dae15f8d613c7eab5a61 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 2 Nov 2012 23:19:56 +0100
Subject: [PATCH 0369/1146] Fixing the italic-bold font check. Thanks nsz.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 8e0df08..8ef1346 100644
--- a/st.c
+++ b/st.c
@@ -2408,7 +2408,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 	if(base.mode & ATTR_ITALIC)
 		font = &dc.ifont;
-	if(base.mode & (ATTR_ITALIC|ATTR_ITALIC))
+	if(base.mode & (ATTR_ITALIC|ATTR_BOLD))
 		font = &dc.ibfont;
 
 	if(IS_SET(MODE_REVERSE)) {

From abe85c0e997ed1882c69bde511f7e2746f68d9ab Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 3 Nov 2012 03:24:22 +0100
Subject: [PATCH 0370/1146] Fixing an out-of-bound bug in the selection code.
 Thanks Szabolczs Nagy!

---
 config.def.h |  2 +-
 st.c         | 31 +++++++++++++++++++++++--------
 2 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/config.def.h b/config.def.h
index 1ba6d8e..ee677a5 100644
--- a/config.def.h
+++ b/config.def.h
@@ -2,7 +2,7 @@
 
 /* appearance */
 static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=false";
-static unsigned int borderpx = 2;
+static int borderpx = 2;
 static char shell[] = "/bin/sh";
 
 /* double-click timeout (in milliseconds) between clicks for selection */
diff --git a/st.c b/st.c
index 8ef1346..d7a0fed 100644
--- a/st.c
+++ b/st.c
@@ -72,8 +72,6 @@
 #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
 #define IS_SET(flag) (term.mode & (flag))
 #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
-#define X2COL(x) (((x) - borderpx)/xw.cw)
-#define Y2ROW(y) (((y) - borderpx)/xw.ch)
 
 #define VT102ID "\033[?6c"
 
@@ -582,6 +580,22 @@ selinit(void) {
 		sel.xtarget = XA_STRING;
 }
 
+static int
+x2col(int x) {
+	x -= borderpx;
+	x /= xw.cw;
+
+	return LIMIT(x, 0, term.col-1);
+}
+
+static int
+y2row(int y) {
+	y -= borderpx;
+	y /= xw.ch;
+
+	return LIMIT(y, 0, term.row-1);
+}
+
 static inline bool
 selected(int x, int y) {
 	int bx, ex;
@@ -603,8 +617,9 @@ getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
 	if(b)
 		*b = e->xbutton.button;
 
-	*x = X2COL(e->xbutton.x);
-	*y = Y2ROW(e->xbutton.y);
+	*x = x2col(e->xbutton.x);
+	*y = y2row(e->xbutton.y);
+
 	sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex;
 	sel.b.y = MIN(sel.by, sel.ey);
 	sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx;
@@ -613,8 +628,8 @@ getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
 
 void
 mousereport(XEvent *e) {
-	int x = X2COL(e->xbutton.x);
-	int y = Y2ROW(e->xbutton.y);
+	int x = x2col(e->xbutton.x);
+	int y = y2row(e->xbutton.y);
 	int button = e->xbutton.button;
 	int state = e->xbutton.state;
 	char buf[] = { '\033', '[', 'M', 0, 32+x+1, 32+y+1 };
@@ -656,8 +671,8 @@ bpress(XEvent *e) {
 			draw();
 		}
 		sel.mode = 1;
-		sel.ex = sel.bx = X2COL(e->xbutton.x);
-		sel.ey = sel.by = Y2ROW(e->xbutton.y);
+		sel.ex = sel.bx = x2col(e->xbutton.x);
+		sel.ey = sel.by = y2row(e->xbutton.y);
 	}
 }
 

From 76a8e5f72b542f230d7248c09efe202a12bc3771 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 3 Nov 2012 08:35:32 +0100
Subject: [PATCH 0371/1146] Now italic and bold works.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index d7a0fed..bfbe799 100644
--- a/st.c
+++ b/st.c
@@ -2423,7 +2423,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 	if(base.mode & ATTR_ITALIC)
 		font = &dc.ifont;
-	if(base.mode & (ATTR_ITALIC|ATTR_BOLD))
+	if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD))
 		font = &dc.ibfont;
 
 	if(IS_SET(MODE_REVERSE)) {

From f8db65439a705f5e94c7a130ac44689e050e5654 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 3 Nov 2012 13:43:20 +0100
Subject: [PATCH 0372/1146] Fixing bold fonts in reverse mode.

---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index bfbe799..578c7ee 100644
--- a/st.c
+++ b/st.c
@@ -2398,9 +2398,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		 *temp, revfg, revbg;
 	XRenderColor colfg, colbg;
 
-	if(base.mode & ATTR_REVERSE)
-		temp = fg, fg = bg, bg = temp;
-
 	if(base.mode & ATTR_BOLD) {
 		if(BETWEEN(base.fg, 0, 7)) {
 			/* basic system colors */
@@ -2450,6 +2447,9 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		}
 	}
 
+	if(base.mode & ATTR_REVERSE)
+		temp = fg, fg = bg, bg = temp;
+
 	XftTextExtentsUtf8(xw.dpy, font->xft_set, (FcChar8 *)s, bytelen,
 			&extents);
 	width = extents.xOff;

From 9888c5064badc60cd5e894f60451c2be762a481c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 3 Nov 2012 14:05:15 +0100
Subject: [PATCH 0373/1146] Fixing a resize bug, if a smaller amount than the
 lineheight is resized.

Thanks c00kiemon5ter!
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 578c7ee..2654676 100644
--- a/st.c
+++ b/st.c
@@ -2742,8 +2742,6 @@ cresize(int width, int height)
 
 	col = (xw.w - 2*borderpx) / xw.cw;
 	row = (xw.h - 2*borderpx) / xw.ch;
-	if(col == term.col && row == term.row)
-		return;
 
 	tresize(col, row);
 	xresize(col, row);
@@ -2752,6 +2750,8 @@ cresize(int width, int height)
 
 void
 resize(XEvent *e) {
+	fprintf(stderr, "resize -> %d,%d\n", e->xconfigure.width,
+			e->xconfigure.height);
 	if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
 		return;
 

From 86261187ab92a037a44af72847f6ed304ea58e64 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 3 Nov 2012 14:05:45 +0100
Subject: [PATCH 0374/1146] Removing the debugging for the last fix too.

---
 st.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/st.c b/st.c
index 2654676..4c6783b 100644
--- a/st.c
+++ b/st.c
@@ -2750,8 +2750,6 @@ cresize(int width, int height)
 
 void
 resize(XEvent *e) {
-	fprintf(stderr, "resize -> %d,%d\n", e->xconfigure.width,
-			e->xconfigure.height);
 	if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
 		return;
 

From 0fbe1559c8a62a87ea3af19366220bd790179f4c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 4 Nov 2012 00:04:56 +0100
Subject: [PATCH 0375/1146] Fixing meta+return. Thanks Szabolcs Nagy!

---
 st.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.c b/st.c
index 4c6783b..f063029 100644
--- a/st.c
+++ b/st.c
@@ -2694,6 +2694,9 @@ kpress(XEvent *ev) {
 				selpaste();
 			break;
 		case XK_Return:
+			if(meta)
+				ttywrite("\033", 1);
+
 			if(IS_SET(MODE_CRLF)) {
 				ttywrite("\r\n", 2);
 			} else {

From 9df1e56142527de1b8917434093d25212dd9da1e Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 5 Nov 2012 04:02:20 +0100
Subject: [PATCH 0376/1146] Changing the license to MIT/X.

---
 LICENSE | 47 ++++++++++++++++++++++-------------------------
 1 file changed, 22 insertions(+), 25 deletions(-)

diff --git a/LICENSE b/LICENSE
index 1b91f2a..66f4b1b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,27 +1,24 @@
-Copyright (c) 2009-2012, Aurélien APTEL <aurelien dot aptel at gmail dot com>
-Copyright (c) 2012, Roberto E. Vargas Caballero <k0ga at shike2 dot com>
-Copyright (c) 2012, Christoph Lohmann <20h at r-36 dot net>
-Copyright (c) 2009, Anselm R Garbe <garbeam at gmail dot com>
+MIT/X Consortium License
 
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in the
-      documentation and/or other materials provided with the distribution.
-    * Neither the name of the copyright holder nor the names of its
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
+© 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com> 
+© 2012 Roberto E. Vargas Caballero <k0ga at shike2 dot com>
+© 2012 Christoph Lohmann <20h at r-36 dot net>
+© 2009 Anselm R Garbe <garbeam at gmail dot com>
 
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+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.

From 5d39afc9023bc9a692ba6faf590abf9397a890ae Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 6 Nov 2012 23:44:37 +0100
Subject: [PATCH 0377/1146] Adding scrollwheel support. Thanks Brandon Invergo!

---
 st.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index f063029..2ad13ef 100644
--- a/st.c
+++ b/st.c
@@ -673,6 +673,10 @@ bpress(XEvent *e) {
 		sel.mode = 1;
 		sel.ex = sel.bx = x2col(e->xbutton.x);
 		sel.ey = sel.by = y2row(e->xbutton.y);
+	} else if(e->xbutton.button == Button4) {
+		ttywrite("\031", 1);
+	} else if(e->xbutton.button == Button5) {
+		ttywrite("\005", 1);
 	}
 }
 
@@ -1834,8 +1838,8 @@ tputc(char *c, int len) {
 		}
 	}
 	/*
-	 * STR sequences must be checked before of anything
-	 * because it can use some control codes as part of the sequence
+	 * STR sequences must be checked before anything else
+	 * because it can use some control codes as part of the sequence.
 	 */
 	if(term.esc & ESC_STR) {
 		switch(ascii) {
@@ -1855,6 +1859,7 @@ tputc(char *c, int len) {
 		}
 		return;
 	}
+
 	/*
 	 * Actions of control codes must be performed as soon they arrive
 	 * because they can be embedded inside a control sequence, and
@@ -1895,11 +1900,11 @@ tputc(char *c, int len) {
 		case '\030':	/* CAN */
 			csireset();
 			return;
-		 case '\005':	/* ENQ (IGNORED) */
-		 case '\000':	/* NUL (IGNORED) */
-		 case '\021':	/* XON (IGNORED) */
-		 case '\023':	/* XOFF (IGNORED) */
-		 case 0177:	/* DEL (IGNORED) */
+		case '\005':	/* ENQ (IGNORED) */
+		case '\000':	/* NUL (IGNORED) */
+		case '\021':	/* XON (IGNORED) */
+		case '\023':	/* XOFF (IGNORED) */
+		case 0177:	/* DEL (IGNORED) */
 			return;
 		}
 	} else if(term.esc & ESC_START) {

From 950ff21e17af487b205ea0b666be015790114fa7 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 8 Nov 2012 17:15:26 +0100
Subject: [PATCH 0378/1146] Fix bug restoring cursor position

Sequences like DECSC, DECRC, ESC [?1047l or ESC [?1047h save and restore
cursor attributes, than taken from vt100 manual are:

       Save Cursor (DECSC) ESC   7
       ===========================
       Saves the following in terminal memory.

      - cursor position
      - graphic rendition
      - character set shift state
      - state of wrap flag
      - state of origin mode

      Restore Cursor (DECRC) ESC 8
      ===========================
      Restores the states described for (DECSC) above. If none of these
      characteristics were saved, the cursor moves to home position; origin
      mode is reset; no character attributes are assigned; and the default
      character set mapping is established.

This implies that hide attribute of the cursor should not be saved/restored
in these sequences. The best way to fix this problem is moving hide
attribute into the terminal mode, instead of having it in the cursor state.
---
 st.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
---
 st.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index 2ad13ef..67fa790 100644
--- a/st.c
+++ b/st.c
@@ -96,8 +96,7 @@ enum cursor_movement {
 
 enum cursor_state {
 	CURSOR_DEFAULT  = 0,
-	CURSOR_HIDE     = 1,
-	CURSOR_WRAPNEXT = 2
+	CURSOR_WRAPNEXT = 1,
 };
 
 enum glyph_state {
@@ -115,7 +114,8 @@ enum term_mode {
 	MODE_MOUSEMOTION = 64,
 	MODE_MOUSE       = 32|64,
 	MODE_REVERSE     = 128,
-	MODE_KBDLOCK     = 256
+	MODE_KBDLOCK     = 256,
+	MODE_HIDE      = 512
 };
 
 enum escape_state {
@@ -1464,8 +1464,8 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 0:  /* Error (IGNORED) */
 			case 12: /* att610 -- Start blinking cursor (IGNORED) */
 				break;
-			case 25:
-				MODBIT(term.c.state, !set, CURSOR_HIDE);
+			case 25: /* DECTCEM -- Text Cursor Enable Mode */
+				MODBIT(term.mode, !set, MODE_HIDE);
 				break;
 			case 1000: /* 1000,1002: enable xterm mouse report */
 				MODBIT(term.mode, set, MODE_MOUSEBTN);
@@ -2505,7 +2505,7 @@ xdrawcursor(void) {
 	}
 
 	/* draw the new one */
-	if(!(term.c.state & CURSOR_HIDE)) {
+	if(!(IS_SET(MODE_HIDE))) {
 		if(!(xw.state & WIN_FOCUSED))
 			g.bg = defaultucs;
 

From ba9d0365ac7e138b643d7179457f8465a1dc1191 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 8 Nov 2012 17:17:26 +0100
Subject: [PATCH 0379/1146] Clarify some or exclusive expressions

Since relational expresions are always evaluated to 0 or 1, we can use
bitwise xor operator instead of using more complex boolean expressions.
---
 st.c |   14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
---
 st.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index 67fa790..9864442 100644
--- a/st.c
+++ b/st.c
@@ -1475,15 +1475,15 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				break;
 			case 1049: /* = 1047 and 1048 */
 			case 47:
-			case 1047:
-				if(IS_SET(MODE_ALTSCREEN))
+			case 1047: {
+				bool alt = IS_SET(MODE_ALTSCREEN) != 0;
+				if(alt)
 					tclearregion(0, 0, term.col-1, term.row-1);
-				if((set && !IS_SET(MODE_ALTSCREEN)) ||
-						(!set && IS_SET(MODE_ALTSCREEN))) {
+				if(set ^ alt)		/* set is always 1 or 0 */
 					tswapscreen();
-				}
 				if(*args != 1049)
 					break;
+			}
 				/* pass through */
 			case 1048:
 				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
@@ -2546,9 +2546,9 @@ drawregion(int x1, int y1, int x2, int y2) {
 	int ic, ib, x, y, ox, sl;
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
-	bool ena_sel = sel.bx != -1, alt = IS_SET(MODE_ALTSCREEN);
+	bool ena_sel = sel.bx != -1, alt = IS_SET(MODE_ALTSCREEN) != 0;
 
-	if((sel.alt && !alt) || (!sel.alt && alt))
+	if((sel.alt != 0) ^ alt)
 		ena_sel = 0;
 	if(!(xw.state & WIN_VISIBLE))
 		return;

From ee3e0a9fd032bb35eea5c46fc0a9efcd6a80579a Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 8 Nov 2012 17:20:15 +0100
Subject: [PATCH 0380/1146] Save cursor position in terminal reset

After terminal reset saved terminal position is reset to 0, allowing know
where cursor will go in next restore cursor operation.
---
 st.c |    2 ++
 1 file changed, 2 insertions(+)
---
 st.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.c b/st.c
index 9864442..4a77d71 100644
--- a/st.c
+++ b/st.c
@@ -1076,6 +1076,8 @@ treset(void) {
 	term.mode = MODE_WRAP;
 
 	tclearregion(0, 0, term.col-1, term.row-1);
+	tmoveto(0, 0);
+	tcursor(CURSOR_SAVE);
 }
 
 void

From 5260a9ea2249b9159c188a6e27a39a38d131e411 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 8 Nov 2012 17:21:10 +0100
Subject: [PATCH 0381/1146] Add DECOM sequence

DECOM sequence allows to the user defines a new home position. The home
position is used as base for all the movement commands except HVP and
VPA. It is important notice than DECSLM moves cursor to absolute position
0,0.
---
 st.c |   33 ++++++++++++++++++++++++++-------
 1 file changed, 26 insertions(+), 7 deletions(-)
---
 st.c | 33 ++++++++++++++++++++++++++-------
 1 file changed, 26 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index 4a77d71..657fba7 100644
--- a/st.c
+++ b/st.c
@@ -97,6 +97,7 @@ enum cursor_movement {
 enum cursor_state {
 	CURSOR_DEFAULT  = 0,
 	CURSOR_WRAPNEXT = 1,
+	CURSOR_ORIGIN	= 2
 };
 
 enum glyph_state {
@@ -300,6 +301,7 @@ static void tdeleteline(int);
 static void tinsertblank(int);
 static void tinsertblankline(int);
 static void tmoveto(int, int);
+static void tmoveato(int x, int y);
 static void tnew(int, int);
 static void tnewline(int);
 static void tputtab(bool);
@@ -1211,10 +1213,25 @@ csiparse(void) {
 	}
 }
 
+/* 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;
+	}
 	LIMIT(x, 0, term.col-1);
-	LIMIT(y, 0, term.row-1);
+	LIMIT(y, miny, maxy);
 	term.c.state &= ~CURSOR_WRAPNEXT;
 	term.c.x = x;
 	term.c.y = y;
@@ -1456,7 +1473,9 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				if(mode != term.mode)
 					redraw();
 				break;
-			case 6: /* XXX: DECOM -- Origin */
+			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);
@@ -1593,7 +1612,7 @@ csihandle(void) {
 	case 'f': /* HVP */
 		DEFAULT(csiescseq.arg[0], 1);
 		DEFAULT(csiescseq.arg[1], 1);
-		tmoveto(csiescseq.arg[1]-1, csiescseq.arg[0]-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);
@@ -1667,7 +1686,7 @@ csihandle(void) {
 		break;
 	case 'd': /* VPA -- Move to <row> */
 		DEFAULT(csiescseq.arg[0], 1);
-		tmoveto(term.c.x, 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);
@@ -1682,7 +1701,7 @@ csihandle(void) {
 			DEFAULT(csiescseq.arg[0], 1);
 			DEFAULT(csiescseq.arg[1], term.row);
 			tsetscroll(csiescseq.arg[0]-1, csiescseq.arg[1]-1);
-			tmoveto(0, 0);
+			tmoveato(0, 0);
 		}
 		break;
 	case 's': /* DECSC -- Save cursor position (ANSI.SYS) */
@@ -2119,10 +2138,10 @@ tresize(int col, int row) {
 	/* update terminal size */
 	term.col = col;
 	term.row = row;
-	/* make use of the LIMIT in tmoveto */
-	tmoveto(term.c.x, term.c.y);
 	/* reset scrolling region */
 	tsetscroll(0, row-1);
+	/* make use of the LIMIT in tmoveto */
+	tmoveto(term.c.x, term.c.y);
 
 	return (slide > 0);
 }

From d5b80e05e8df29b989c072b6529745576056d0bc Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 8 Nov 2012 17:21:24 +0100
Subject: [PATCH 0382/1146] Fix VPR sequence

VPR stands for Move cursor down a number of rows, and the code was moving
the cursor up instead of moving it down.
---
 st.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 657fba7..f67a345 100644
--- a/st.c
+++ b/st.c
@@ -1562,11 +1562,11 @@ csihandle(void) {
 		tinsertblank(csiescseq.arg[0]);
 		break;
 	case 'A': /* CUU -- Cursor <n> Up */
-	case 'e':
 		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;
@@ -1575,7 +1575,7 @@ csihandle(void) {
 			ttywrite(VT102ID, sizeof(VT102ID) - 1);
 		break;
 	case 'C': /* CUF -- Cursor <n> Forward */
-	case 'a':
+	case 'a': /* HPR -- Cursor <n> Forward */
 		DEFAULT(csiescseq.arg[0], 1);
 		tmoveto(term.c.x+csiescseq.arg[0], term.c.y);
 		break;

From 27468403cc436cf8197c886158e6e61f24ae5b8d Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 8 Nov 2012 17:21:41 +0100
Subject: [PATCH 0383/1146] Ignore DECARM sequence

DECARM modify the auto repeat settings in the keyboard, and since we can not
modify this setting in the Xserver the best solution is only ignore it.
---
 st.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index f67a345..5e7e4ac 100644
--- a/st.c
+++ b/st.c
@@ -1480,8 +1480,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 7: /* DECAWM -- Auto wrap */
 				MODBIT(term.mode, set, MODE_WRAP);
 				break;
-			case 8: /* XXX: DECARM -- Auto repeat */
-				break;
+			case 8:  /* DECARM -- Auto repeat (IGNORED) */
 			case 0:  /* Error (IGNORED) */
 			case 12: /* att610 -- Start blinking cursor (IGNORED) */
 				break;

From 866590521609ba35606e53990e381bdc2adf742f Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 8 Nov 2012 17:22:04 +0100
Subject: [PATCH 0384/1146] Move unsupported sequences to ignored.

These sequences will be never implemented and in this moment they are
generating a lot of noise.
---
 st.c |   14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
---
 st.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index 5e7e4ac..8059b16 100644
--- a/st.c
+++ b/st.c
@@ -1480,8 +1480,14 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 7: /* DECAWM -- Auto wrap */
 				MODBIT(term.mode, set, MODE_WRAP);
 				break;
-			case 8:  /* DECARM -- Auto repeat (IGNORED) */
 			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 */
@@ -1509,12 +1515,6 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
 				break;
 			default:
-			/* case 2:  DECANM -- ANSI/VT52 (NOT SUPPOURTED) */
-			/* case 3:  DECCOLM -- Column  (NOT SUPPORTED) */
-			/* case 4:  DECSCLM -- Scroll (NOT SUPPORTED) */
-			/* case 18: DECPFF -- Printer feed (NOT SUPPORTED) */
-			/* case 19: DECPEX -- Printer extent (NOT SUPPORTED) */
-			/* case 42: DECNRCM -- National characters (NOT SUPPORTED) */
 				fprintf(stderr,
 					"erresc: unknown private set/reset mode %d\n",
 					*args);

From 5d5a7c627a3709c3758c516de87609bb6b518e13 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 8 Nov 2012 17:22:48 +0100
Subject: [PATCH 0385/1146] Moving the alt declaration to the beginning of the
 function.

---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 8059b16..2919082 100644
--- a/st.c
+++ b/st.c
@@ -1459,6 +1459,7 @@ tsetscroll(int t, int b) {
 void
 tsetmode(bool priv, bool set, int *args, int narg) {
 	int *lim, mode;
+	bool alt;
 
 	for(lim = args + narg; args < lim; ++args) {
 		if(priv) {
@@ -1502,7 +1503,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 1049: /* = 1047 and 1048 */
 			case 47:
 			case 1047: {
-				bool alt = IS_SET(MODE_ALTSCREEN) != 0;
+				alt = IS_SET(MODE_ALTSCREEN) != 0;
 				if(alt)
 					tclearregion(0, 0, term.col-1, term.row-1);
 				if(set ^ alt)		/* set is always 1 or 0 */

From c4a9ccec19b14a6bdc980d149e2c27c30f250945 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 11 Nov 2012 19:38:41 +0100
Subject: [PATCH 0386/1146] Removing some xft naming cruft.

---
 st.c | 82 +++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 43 insertions(+), 39 deletions(-)

diff --git a/st.c b/st.c
index 2919082..c043e3f 100644
--- a/st.c
+++ b/st.c
@@ -28,8 +28,12 @@
 #include <X11/extensions/Xdbe.h>
 #include <X11/Xft/Xft.h>
 #include <fontconfig/fontconfig.h>
+
 #define Glyph Glyph_
 #define Font Font_
+#define Draw XftDraw *
+#define Colour XftColor
+#define Colourmap Colormap
 
 #if   defined(__linux)
  #include <pty.h>
@@ -198,14 +202,14 @@ typedef struct {
 
 /* Purely graphic info */
 typedef struct {
-	Display* dpy;
-	Colormap cmap;
+	Display *dpy;
+	Colourmap cmap;
 	Window win;
 	XdbeBackBuffer buf;
 	Atom xembed, wmdeletewin;
 	XIM xim;
 	XIC xic;
-	XftDraw *xft_draw;
+	Draw draw;
 	Visual *vis;
 	int scr;
 	bool isfixed; /* is fixed geometry? */
@@ -267,12 +271,12 @@ typedef struct {
 	int descent;
 	short lbearing;
 	short rbearing;
-	XftFont *xft_set;
+	XftFont *set;
 } Font;
 
 /* Drawing Context */
 typedef struct {
-	XftColor xft_col[LEN(colorname) < 256 ? 256 : LEN(colorname)];
+	Colour col[LEN(colorname) < 256 ? 256 : LEN(colorname)];
 	GC gc;
 	Font font, bfont, ifont, ibfont;
 } DC;
@@ -2151,19 +2155,19 @@ xresize(int col, int row) {
 	xw.tw = MAX(1, 2*borderpx + col * xw.cw);
 	xw.th = MAX(1, 2*borderpx + row * xw.ch);
 
-	XftDrawChange(xw.xft_draw, xw.buf);
+	XftDrawChange(xw.draw, xw.buf);
 }
 
 void
 xloadcols(void) {
 	int i, r, g, b;
-	XRenderColor xft_color = { .alpha = 0 };
+	XRenderColor color = { .alpha = 0 };
 
 	/* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */
 	for(i = 0; i < LEN(colorname); i++) {
 		if(!colorname[i])
 			continue;
-		if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[i], &dc.xft_col[i])) {
+		if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[i], &dc.col[i])) {
 			die("Could not allocate color '%s'\n", colorname[i]);
 		}
 	}
@@ -2172,10 +2176,10 @@ xloadcols(void) {
 	for(i = 16, r = 0; r < 6; r++) {
 		for(g = 0; g < 6; g++) {
 			for(b = 0; b < 6; b++) {
-				xft_color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r;
-				xft_color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g;
-				xft_color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b;
-				if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color, &dc.xft_col[i])) {
+				color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r;
+				color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g;
+				color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b;
+				if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i])) {
 					die("Could not allocate color %d\n", i);
 				}
 				i++;
@@ -2184,9 +2188,9 @@ xloadcols(void) {
 	}
 
 	for(r = 0; r < 24; r++, i++) {
-		xft_color.red = xft_color.green = xft_color.blue = 0x0808 + 0x0a0a * r;
-		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color,
-					&dc.xft_col[i])) {
+		color.red = color.green = color.blue = 0x0808 + 0x0a0a * r;
+		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color,
+					&dc.col[i])) {
 			die("Could not allocate color %d\n", i);
 		}
 	}
@@ -2194,8 +2198,8 @@ xloadcols(void) {
 
 void
 xtermclear(int col1, int row1, int col2, int row2) {
-	XftDrawRect(xw.xft_draw,
-			&dc.xft_col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
+	XftDrawRect(xw.draw,
+			&dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
 			borderpx + col1 * xw.cw,
 			borderpx + row1 * xw.ch,
 			(col2-col1+1) * xw.cw,
@@ -2207,8 +2211,8 @@ xtermclear(int col1, int row1, int col2, int row2) {
  */
 void
 xclear(int x1, int y1, int x2, int y2) {
-	XftDrawRect(xw.xft_draw,
-			&dc.xft_col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
+	XftDrawRect(xw.draw,
+			&dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
 			x1, y1, x2-x1, y2-y1);
 }
 
@@ -2245,17 +2249,17 @@ xloadfont(Font *f, FcPattern *pattern) {
 	match = XftFontMatch(xw.dpy, xw.scr, pattern, &result);
 	if(!match)
 		return 1;
-	if(!(f->xft_set = XftFontOpenPattern(xw.dpy, match))) {
+	if(!(f->set = XftFontOpenPattern(xw.dpy, match))) {
 		FcPatternDestroy(match);
 		return 1;
 	}
 
-	f->ascent = f->xft_set->ascent;
-	f->descent = f->xft_set->descent;
+	f->ascent = f->set->ascent;
+	f->descent = f->set->descent;
 	f->lbearing = 0;
-	f->rbearing = f->xft_set->max_advance_width;
+	f->rbearing = f->set->max_advance_width;
 
-	f->height = f->xft_set->height;
+	f->height = f->set->height;
 	f->width = f->lbearing + f->rbearing;
 
 	return 0;
@@ -2365,8 +2369,8 @@ xinit(void) {
 		xw.fy = 0;
 	}
 
-	attrs.background_pixel = dc.xft_col[defaultbg].pixel;
-	attrs.border_pixel = dc.xft_col[defaultbg].pixel;
+	attrs.background_pixel = dc.col[defaultbg].pixel;
+	attrs.border_pixel = dc.col[defaultbg].pixel;
 	attrs.bit_gravity = NorthWestGravity;
 	attrs.event_mask = FocusChangeMask | KeyPressMask
 		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
@@ -2387,7 +2391,7 @@ xinit(void) {
 	xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeCopied);
 
 	/* Xft rendering context */
-	xw.xft_draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
+	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
 
 	/* input methods */
 	xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
@@ -2420,20 +2424,20 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	    width = charlen * xw.cw;
 	Font *font = &dc.font;
 	XGlyphInfo extents;
-	XftColor *fg = &dc.xft_col[base.fg], *bg = &dc.xft_col[base.bg],
+	Colour *fg = &dc.col[base.fg], *bg = &dc.col[base.bg],
 		 *temp, revfg, revbg;
 	XRenderColor colfg, colbg;
 
 	if(base.mode & ATTR_BOLD) {
 		if(BETWEEN(base.fg, 0, 7)) {
 			/* basic system colors */
-			fg = &dc.xft_col[base.fg + 8];
+			fg = &dc.col[base.fg + 8];
 		} else if(BETWEEN(base.fg, 16, 195)) {
 			/* 256 colors */
-			fg = &dc.xft_col[base.fg + 36];
+			fg = &dc.col[base.fg + 36];
 		} else if(BETWEEN(base.fg, 232, 251)) {
 			/* greyscale */
-			fg = &dc.xft_col[base.fg + 4];
+			fg = &dc.col[base.fg + 4];
 		}
 		/*
 		 * Those ranges will not be brightened:
@@ -2450,8 +2454,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		font = &dc.ibfont;
 
 	if(IS_SET(MODE_REVERSE)) {
-		if(fg == &dc.xft_col[defaultfg]) {
-			fg = &dc.xft_col[defaultbg];
+		if(fg == &dc.col[defaultfg]) {
+			fg = &dc.col[defaultbg];
 		} else {
 			colfg.red = ~fg->color.red;
 			colfg.green = ~fg->color.green;
@@ -2461,8 +2465,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			fg = &revfg;
 		}
 
-		if(bg == &dc.xft_col[defaultbg]) {
-			bg = &dc.xft_col[defaultfg];
+		if(bg == &dc.col[defaultbg]) {
+			bg = &dc.col[defaultfg];
 		} else {
 			colbg.red = ~bg->color.red;
 			colbg.green = ~bg->color.green;
@@ -2476,7 +2480,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	if(base.mode & ATTR_REVERSE)
 		temp = fg, fg = bg, bg = temp;
 
-	XftTextExtentsUtf8(xw.dpy, font->xft_set, (FcChar8 *)s, bytelen,
+	XftTextExtentsUtf8(xw.dpy, font->set, (FcChar8 *)s, bytelen,
 			&extents);
 	width = extents.xOff;
 
@@ -2494,12 +2498,12 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	if(y == term.row-1)
 		xclear(winx, winy + xw.ch, winx + width, xw.h);
 
-	XftDrawRect(xw.xft_draw, bg, winx, winy, width, xw.ch);
-	XftDrawStringUtf8(xw.xft_draw, fg, font->xft_set, winx,
+	XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch);
+	XftDrawStringUtf8(xw.draw, fg, font->set, winx,
 			winy + font->ascent, (FcChar8 *)s, bytelen);
 
 	if(base.mode & ATTR_UNDERLINE) {
-		XftDrawRect(xw.xft_draw, fg, winx, winy + font->ascent + 1,
+		XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1,
 				width, 1);
 	}
 }

From ace789a79fc44c1c3b629f5c0fb477c651d84a48 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 11 Nov 2012 19:46:34 +0100
Subject: [PATCH 0387/1146] Gc is not used anymore.

---
 st.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/st.c b/st.c
index c043e3f..8b18607 100644
--- a/st.c
+++ b/st.c
@@ -277,7 +277,6 @@ typedef struct {
 /* Drawing Context */
 typedef struct {
 	Colour col[LEN(colorname) < 256 ? 256 : LEN(colorname)];
-	GC gc;
 	Font font, bfont, ifont, ibfont;
 } DC;
 
@@ -2398,8 +2397,6 @@ xinit(void) {
 	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
 					   | XIMStatusNothing, XNClientWindow, xw.win,
 					   XNFocusWindow, xw.win, NULL);
-	/* gc */
-	dc.gc = XCreateGC(xw.dpy, xw.win, 0, NULL);
 
 	/* white cursor, black outline */
 	cursor = XCreateFontCursor(xw.dpy, XC_xterm);

From 73177ba366e5363b8a6695882b52617a8909a925 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 13 Nov 2012 20:04:26 +0100
Subject: [PATCH 0388/1146] Add SRM sequence

This sequence enable/disable the local echo.
---
 st.c |   76 ++++++++++++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 56 insertions(+), 20 deletions(-)
---
 st.c | 76 ++++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 56 insertions(+), 20 deletions(-)

diff --git a/st.c b/st.c
index 8b18607..8bf9337 100644
--- a/st.c
+++ b/st.c
@@ -110,17 +110,18 @@ enum glyph_state {
 };
 
 enum term_mode {
-	MODE_WRAP	= 1,
+	MODE_WRAP	 = 1,
 	MODE_INSERT      = 2,
 	MODE_APPKEYPAD   = 4,
 	MODE_ALTSCREEN   = 8,
-	MODE_CRLF	= 16,
+	MODE_CRLF	 = 16,
 	MODE_MOUSEBTN    = 32,
 	MODE_MOUSEMOTION = 64,
 	MODE_MOUSE       = 32|64,
 	MODE_REVERSE     = 128,
 	MODE_KBDLOCK     = 256,
-	MODE_HIDE      = 512
+	MODE_HIDE	 = 512,
+	MODE_ECHO	 = 1024
 };
 
 enum escape_state {
@@ -320,6 +321,7 @@ static void tswapscreen(void);
 static void tsetdirt(int, int);
 static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
+static void techo(char *, int);
 
 static void ttynew(void);
 static void ttyread(void);
@@ -1534,7 +1536,8 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 4:  /* IRM -- Insertion-replacement */
 				MODBIT(term.mode, set, MODE_INSERT);
 				break;
-			case 12: /* XXX: SRM -- Send/Receive */
+			case 12: /* SRM -- Send/Receive */
+				MODBIT(term.mode, !set, MODE_ECHO);
 				break;
 			case 20: /* LNM -- Linefeed/new line */
 				MODBIT(term.mode, set, MODE_CRLF);
@@ -1848,6 +1851,28 @@ tputtab(bool forward) {
 	tmoveto(x, term.c.y);
 }
 
+void
+techo(char *buf, int len) {
+	for(; len > 0; buf++, len--) {
+		char c = *buf;
+
+		if(c == '\033') {		/* escape */
+			tputc("^", 1);
+			tputc("[", 1);
+		} else if (c < '\x20') {	/* control code */
+			if(c != '\n' && c != '\r' && c != '\t') {
+				c |= '\x40';
+				tputc("^", 1);
+			}
+			tputc(&c, 1);
+		} else {
+			break;
+		}
+	}
+	if (len)
+		tputc(buf, len);
+}
+
 void
 tputc(char *c, int len) {
 	uchar ascii = *c;
@@ -2679,7 +2704,7 @@ void
 kpress(XEvent *ev) {
 	XKeyEvent *e = &ev->xkey;
 	KeySym ksym;
-	char buf[32], *customkey;
+	char xstr[31], buf[32], *customkey, *cp = buf;
 	int len, meta, shift, i;
 	Status status;
 
@@ -2688,7 +2713,7 @@ kpress(XEvent *ev) {
 
 	meta = e->state & Mod1Mask;
 	shift = e->state & ShiftMask;
-	len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status);
+	len = XmbLookupString(xw.xic, e, xstr, sizeof(xstr), &ksym, &status);
 
 	/* 1. shortcuts */
 	for(i = 0; i < LEN(shortcuts); i++) {
@@ -2702,7 +2727,8 @@ kpress(XEvent *ev) {
 
 	/* 2. custom keys from config.h */
 	if((customkey = kmap(ksym, e->state))) {
-		ttywrite(customkey, strlen(customkey));
+		len = strlen(customkey);
+		memcpy(buf, customkey, len);
 	/* 2. hardcoded (overrides X lookup) */
 	} else {
 		switch(ksym) {
@@ -2714,34 +2740,44 @@ kpress(XEvent *ev) {
 			sprintf(buf, "\033%c%c",
 				IS_SET(MODE_APPKEYPAD) ? 'O' : '[',
 				(shift ? "dacb":"DACB")[ksym - XK_Left]);
-			ttywrite(buf, 3);
+			len = 3;
 			break;
 		case XK_Insert:
-			if(shift)
+			if(shift) {
 				selpaste();
+				return;
+			}
+			memcpy(buf, xstr, len);
 			break;
 		case XK_Return:
+			len = 0;
 			if(meta)
-				ttywrite("\033", 1);
+				*cp++ = '\033', len++;
 
-			if(IS_SET(MODE_CRLF)) {
-				ttywrite("\r\n", 2);
-			} else {
-				ttywrite("\r", 1);
-			}
+			*cp++ = '\r', len++;
+
+			if(IS_SET(MODE_CRLF))
+				*cp = '\n', len++;
 			break;
 			/* 3. X lookup  */
 		default:
-			if(len > 0) {
-				if(meta && len == 1)
-					ttywrite("\033", 1);
-				ttywrite(buf, len);
-			}
+			if(len == 0)
+				return;
+
+			if (len == 1 && meta)
+				*cp++ = '\033';
+
+			memcpy(cp, xstr, len);
+			len = cp - buf + len;
 			break;
 		}
 	}
+	ttywrite(buf, len);
+	if(IS_SET(MODE_ECHO))
+		techo(buf, len);
 }
 
+
 void
 cmessage(XEvent *e) {
 	/* See xembed specs

From 69ee3ba3a771ca60bc8738174c79fc851818a36b Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 13 Nov 2012 20:04:34 +0100
Subject: [PATCH 0389/1146] Fix keypad mode and cursor mode

Keypad mode is used for detecting when keys in the auxiliary keypad are
pressed, while cursor mode is used for detecting when a cursor is pressed,
but they are different modes.

St was mixing both modes and DECPAM and DECPNM modified the cursor mode, and
this was incorrect.
---
 st.c    |    5 +++--
 st.info |    4 ++--
 2 files changed, 5 insertions(+), 4 deletions(-)
---
 st.c    | 5 +++--
 st.info | 4 ++--
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 8bf9337..683a0e9 100644
--- a/st.c
+++ b/st.c
@@ -121,7 +121,8 @@ enum term_mode {
 	MODE_REVERSE     = 128,
 	MODE_KBDLOCK     = 256,
 	MODE_HIDE	 = 512,
-	MODE_ECHO	 = 1024
+	MODE_ECHO	 = 1024,
+	MODE_APPCURSOR	 = 2048
 };
 
 enum escape_state {
@@ -1471,7 +1472,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			switch(*args) {
 				break;
 			case 1: /* DECCKM -- Cursor key */
-				MODBIT(term.mode, set, MODE_APPKEYPAD);
+				MODBIT(term.mode, set, MODE_APPCURSOR);
 				break;
 			case 5: /* DECSCNM -- Reverse video */
 				mode = term.mode;
diff --git a/st.info b/st.info
index 58e2139..63af234 100644
--- a/st.info
+++ b/st.info
@@ -89,7 +89,7 @@ st| simpleterm,
 	ritm=\E[23m,
 	rmacs=\E(B,
 	rmcup=\E[?1049l,
-#	rmkx=\E>,
+	rmkx=\E[?1l\E>,
 	rmso=\E[23m,
 	rmul=\E[m,
 	rs1=\Ec,
@@ -104,7 +104,7 @@ st| simpleterm,
 	sitm=\E[3m,
 	smacs=\E(0,
 	smcup=\E[?1049h,
-#	smkx=\E=,
+	smkx=\E[?1h\E=,
 	smso=\E[3m,
 	smul=\E[4m,
 	tbc=\E[3g,

From 93f31166bfff317e050dde1723cfa8302c6f85d3 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 13 Nov 2012 20:04:39 +0100
Subject: [PATCH 0390/1146] Move Shift + Insert to shortcut

Shift + Insert is used like a hot key for paste the selection, so it is more
logical move it to shortcut array instead of having special code for it.
---
 config.def.h |    1 +
 st.c         |   13 +++----------
 2 files changed, 4 insertions(+), 10 deletions(-)
---
 config.def.h |  1 +
 st.c         | 13 +++----------
 2 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/config.def.h b/config.def.h
index ee677a5..3bf35d9 100644
--- a/config.def.h
+++ b/config.def.h
@@ -93,5 +93,6 @@ static Shortcut shortcuts[] = {
 	/* modifier		key		function	argument */
 	{ MODKEY|ShiftMask,	XK_Prior,	xzoom,		{.i = +1} },
 	{ MODKEY|ShiftMask,	XK_Next,	xzoom,		{.i = -1} },
+	{ ShiftMask,		XK_Insert,	selpaste,	{.i =  0} },
 };
 
diff --git a/st.c b/st.c
index 683a0e9..02a3502 100644
--- a/st.c
+++ b/st.c
@@ -261,6 +261,7 @@ typedef struct {
 
 /* function definitions used in config.h */
 static void xzoom(const Arg *);
+static void selpaste(const Arg *);
 
 /* Config.h for applying patches and the configuration. */
 #include "config.h"
@@ -360,7 +361,6 @@ static void selrequest(XEvent *);
 static void selinit(void);
 static inline bool selected(int, int);
 static void selcopy(void);
-static void selpaste(void);
 static void selscroll(int, int);
 
 static int utf8decode(char *, long *);
@@ -750,7 +750,7 @@ selnotify(XEvent *e) {
 }
 
 void
-selpaste(void) {
+selpaste(const Arg *dummy) {
 	XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY,
 			xw.win, CurrentTime);
 }
@@ -821,7 +821,7 @@ brelease(XEvent *e) {
 	}
 
 	if(e->xbutton.button == Button2) {
-		selpaste();
+		selpaste(NULL);
 	} else if(e->xbutton.button == Button1) {
 		sel.mode = 0;
 		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
@@ -2743,13 +2743,6 @@ kpress(XEvent *ev) {
 				(shift ? "dacb":"DACB")[ksym - XK_Left]);
 			len = 3;
 			break;
-		case XK_Insert:
-			if(shift) {
-				selpaste();
-				return;
-			}
-			memcpy(buf, xstr, len);
-			break;
 		case XK_Return:
 			len = 0;
 			if(meta)

From ea782bfc5d34d712bc9391e498935d2d27f3116c Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 13 Nov 2012 20:04:45 +0100
Subject: [PATCH 0391/1146] Remove hardcoded keys form kpress

Some keys were in the Key array while others were hardcoded in
kpress().This cause some problems with some keys which can generate more of
one string based in the configuration of the terminal.
---
 config.def.h |   70 ++++++++++++++++++++++++++++++++++++++++-----------------
 st.c         |   71 +++++++++++++++++++++++++---------------------------------
 2 files changed, 79 insertions(+), 62 deletions(-)
---
 config.def.h | 70 +++++++++++++++++++++++++++++++++++----------------
 st.c         | 71 ++++++++++++++++++++++------------------------------
 2 files changed, 79 insertions(+), 62 deletions(-)

diff --git a/config.def.h b/config.def.h
index 3bf35d9..622499e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -56,34 +56,62 @@ static unsigned int defaultucs = 257;
 
 /*
  * Special keys (change & recompile st.info accordingly)
- * Keep in mind that kpress() in st.c hardcodes some keys.
  *
  * 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)
+ * keypad value:
+ * * 0: no value
+ * * > 0: keypad application mode enabled
+ * * < 0: keypad application mode disabled
+ * cursor value:
+ * * 0: no value
+ * * > 0: cursor application mode enabled
+ * * < 0: cursor application mode disabled
+ * crlf value
+ * * 0: no value
+ * * > 0: crlf mode is enabled
+ * * < 0: crlf mode is disabled
  */
 
-/* key, mask, output */
+/* key, mask, output, keypad, cursor, crlf */
 static Key key[] = {
-	{ XK_BackSpace, XK_NO_MOD, "\177" },
-	{ XK_Insert,    XK_NO_MOD, "\033[2~" },
-	{ XK_Delete,    XK_NO_MOD, "\033[3~" },
-	{ XK_Home,      XK_NO_MOD, "\033[1~" },
-	{ XK_End,       XK_NO_MOD, "\033[4~" },
-	{ XK_Prior,     XK_NO_MOD, "\033[5~" },
-	{ XK_Next,      XK_NO_MOD, "\033[6~" },
-	{ XK_F1,        XK_NO_MOD, "\033OP"   },
-	{ XK_F2,        XK_NO_MOD, "\033OQ"   },
-	{ XK_F3,        XK_NO_MOD, "\033OR"   },
-	{ XK_F4,        XK_NO_MOD, "\033OS"   },
-	{ XK_F5,        XK_NO_MOD, "\033[15~" },
-	{ XK_F6,        XK_NO_MOD, "\033[17~" },
-	{ XK_F7,        XK_NO_MOD, "\033[18~" },
-	{ XK_F8,        XK_NO_MOD, "\033[19~" },
-	{ XK_F9,        XK_NO_MOD, "\033[20~" },
-	{ XK_F10,       XK_NO_MOD, "\033[21~" },
-	{ XK_F11,       XK_NO_MOD, "\033[23~" },
-	{ XK_F12,       XK_NO_MOD, "\033[24~" },
+	/* keysym             mask         string         keypad cursor crlf */
+	{ XK_BackSpace,     XK_NO_MOD,      "\177",          0,    0,    0},
+	{ XK_Up,            XK_NO_MOD,      "\033[A",        0,   -1,    0},
+	{ XK_Up,            XK_NO_MOD,      "\033OA",        0,   +1,    0},
+	{ XK_Up,            ShiftMask,      "\033[a",        0,    0,    0},
+	{ XK_Down,          XK_NO_MOD,      "\033[B",        0,   -1,    0},
+	{ XK_Down,          XK_NO_MOD,      "\033OB",        0,   +1,    0},
+	{ XK_Down,          ShiftMask,      "\033[b",        0,    0,    0},
+	{ XK_Left,     	    XK_NO_MOD,      "\033[D",        0,   -1,    0},
+	{ XK_Left,          XK_NO_MOD,      "\033OD",        0,   +1,    0},
+	{ XK_Left,          ShiftMask,      "\033[d",        0,    0,    0},
+	{ XK_Right,         XK_NO_MOD,      "\033[C",        0,   -1,    0},
+	{ XK_Right,         XK_NO_MOD,      "\033OC",        0,   +1,    0},
+	{ XK_Right,         ShiftMask,      "\033[c",        0,    0,    0},
+	{ XK_Return,        XK_NO_MOD,      "\n",            0,    0,   -1},
+	{ XK_Return,        XK_NO_MOD,      "\r\n",          0,    0,   +1},
+	{ XK_Return,        Mod1Mask,       "\033\n",        0,    0,   -1},
+	{ XK_Return,        Mod1Mask,       "\033\r\n",      0,    0,   +1},
+	{ XK_Insert,        XK_NO_MOD,      "\033[2~",       0,    0,    0},
+	{ XK_Delete,        XK_NO_MOD,      "\033[3~",       0,    0,    0},
+	{ XK_Home,          XK_NO_MOD,      "\033[1~",       0,    0,    0},
+	{ XK_End,           XK_NO_MOD,      "\033[4~",       0,    0,    0},
+	{ XK_Prior,         XK_NO_MOD,      "\033[5~",       0,    0,    0},
+	{ XK_Next,          XK_NO_MOD,      "\033[6~",       0,    0,    0},
+	{ XK_F1,            XK_NO_MOD,      "\033OP" ,       0,    0,    0},
+	{ XK_F2,            XK_NO_MOD,      "\033OQ" ,       0,    0,    0},
+	{ XK_F3,            XK_NO_MOD,      "\033OR" ,       0,    0,    0},
+	{ XK_F4,            XK_NO_MOD,      "\033OS" ,       0,    0,    0},
+	{ XK_F5,            XK_NO_MOD,      "\033[15~",      0,    0,    0},
+	{ XK_F6,            XK_NO_MOD,      "\033[17~",      0,    0,    0},
+	{ XK_F7,            XK_NO_MOD,      "\033[18~",      0,    0,    0},
+	{ XK_F8,            XK_NO_MOD,      "\033[19~",      0,    0,    0},
+	{ XK_F9,            XK_NO_MOD,      "\033[20~",      0,    0,    0},
+	{ XK_F10,           XK_NO_MOD,      "\033[21~",      0,    0,    0},
+	{ XK_F11,           XK_NO_MOD,      "\033[23~",      0,    0,    0},
+	{ XK_F12,           XK_NO_MOD,      "\033[24~",      0,    0,    0},
 };
 
 /* Internal shortcuts. */
diff --git a/st.c b/st.c
index 02a3502..14408c5 100644
--- a/st.c
+++ b/st.c
@@ -228,6 +228,10 @@ typedef struct {
 	KeySym k;
 	uint mask;
 	char s[ESC_BUF_SIZ];
+	/* three valued logic variables: 0 indifferent, 1 on, -1 off */
+	signed char appkey;		/* application keypad */
+	signed char appcursor;		/* application cursor */
+	signed char crlf;		/* crlf mode          */
 } Key;
 
 /* TODO: use better name for vars... */
@@ -2686,17 +2690,29 @@ focus(XEvent *ev) {
 
 char*
 kmap(KeySym k, uint state) {
-	int i;
 	uint mask;
+	Key *kp;
 
 	state &= ~Mod2Mask;
-	for(i = 0; i < LEN(key); i++) {
-		mask = key[i].mask;
+	for(kp = key; kp < key + LEN(key); kp++) {
+		mask = kp->mask;
 
-		if(key[i].k == k && ((state & mask) == mask
-				|| (mask == XK_NO_MOD && !state))) {
-			return (char*)key[i].s;
-		}
+		if(kp->k != k)
+			continue;
+		if((state & mask) != mask &&
+		   (mask == XK_NO_MOD && state))
+			continue;
+		if((kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) ||
+		   (kp->appkey > 0 && !IS_SET(MODE_APPKEYPAD)))
+			continue;
+		if((kp->appcursor < 0 && IS_SET(MODE_APPCURSOR)) ||
+		   (kp->appcursor > 0 && !IS_SET(MODE_APPCURSOR)))
+			continue;
+		if((kp->crlf < 0 && IS_SET(MODE_CRLF)) ||
+		   (kp->crlf > 0 && !IS_SET(MODE_CRLF)))
+			continue;
+
+		return kp->s;
 	}
 	return NULL;
 }
@@ -2706,14 +2722,12 @@ kpress(XEvent *ev) {
 	XKeyEvent *e = &ev->xkey;
 	KeySym ksym;
 	char xstr[31], buf[32], *customkey, *cp = buf;
-	int len, meta, shift, i;
+	int len, i;
 	Status status;
 
 	if (IS_SET(MODE_KBDLOCK))
 		return;
 
-	meta = e->state & Mod1Mask;
-	shift = e->state & ShiftMask;
 	len = XmbLookupString(xw.xic, e, xstr, sizeof(xstr), &ksym, &status);
 
 	/* 1. shortcuts */
@@ -2732,39 +2746,14 @@ kpress(XEvent *ev) {
 		memcpy(buf, customkey, len);
 	/* 2. hardcoded (overrides X lookup) */
 	} else {
-		switch(ksym) {
-		case XK_Up:
-		case XK_Down:
-		case XK_Left:
-		case XK_Right:
-			/* XXX: shift up/down doesn't work */
-			sprintf(buf, "\033%c%c",
-				IS_SET(MODE_APPKEYPAD) ? 'O' : '[',
-				(shift ? "dacb":"DACB")[ksym - XK_Left]);
-			len = 3;
-			break;
-		case XK_Return:
-			len = 0;
-			if(meta)
-				*cp++ = '\033', len++;
+		if(len == 0)
+			return;
 
-			*cp++ = '\r', len++;
+		if (len == 1 && e->state & Mod1Mask)
+			*cp++ = '\033';
 
-			if(IS_SET(MODE_CRLF))
-				*cp = '\n', len++;
-			break;
-			/* 3. X lookup  */
-		default:
-			if(len == 0)
-				return;
-
-			if (len == 1 && meta)
-				*cp++ = '\033';
-
-			memcpy(cp, xstr, len);
-			len = cp - buf + len;
-			break;
-		}
+		memcpy(cp, xstr, len);
+		len = cp - buf + len;
 	}
 	ttywrite(buf, len);
 	if(IS_SET(MODE_ECHO))

From 3b16695f4e8a29f47ad273912065dfba53544a29 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 13 Nov 2012 20:04:50 +0100
Subject: [PATCH 0392/1146] Fix arrow keys terminfo capabilities

Usually the arrow keys generate the ANSI sequence which terminal will
understand like a movement, so it is not necessary any dealing for them, the
program can not know if the sequence is generate for a echo key or directly
from the program. If you need really know if the key was pressed then you
need activate the keypad mode where the keys will generate a special code
for each keypad key.

The terminfo capabilities kcub1, kcud1, kcuf1 and kcuu1 are used for this
keypad code, not for the sequence generate in the ansi mode.
---
 st.info |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
---
 st.info | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.info b/st.info
index 63af234..199aff6 100644
--- a/st.info
+++ b/st.info
@@ -50,10 +50,10 @@ st| simpleterm,
 	is2=\E[4l\E>,
 	it#8,
 	kbs=\177,
-	kcub1=\E[D,
-	kcud1=\E[B,
-	kcuf1=\E[C,
-	kcuu1=\E[A,
+	kcub1=\EOD,
+	kcud1=\EOB,
+	kcuf1=\EOC,
+	kcuu1=\EOA,
 	kLFT=\E[d,
 	kRIT=\E[c,
 	kind=\E[a,

From 44597b359e030d86e16ab9b6510f54366d57e5ac Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 13 Nov 2012 20:04:54 +0100
Subject: [PATCH 0393/1146] Add control and meta combinations for arrow keys

Since there isn't any terminfo capability for control and meta modifiers for
arrows keys it is necessary use the same that almost terminal emulators use,
because there are a lot of programs which have these codes hardcoded.

This cause also that shift combinations are also changed, but in this case
this is not a problem since there are terminfo capabilities for them. After
this patch shift-up and shift-down continue not working in emacs with
TERM=st, but they work with TERM=xterm, so it is possible some other changes
are necessary in the terminfo entry.
---
 config.def.h |   16 ++++++++++++----
 st.info      |    8 ++++----
 2 files changed, 16 insertions(+), 8 deletions(-)
---
 config.def.h | 16 ++++++++++++----
 st.info      |  8 ++++----
 2 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/config.def.h b/config.def.h
index 622499e..3d406d4 100644
--- a/config.def.h
+++ b/config.def.h
@@ -80,16 +80,24 @@ static Key key[] = {
 	{ XK_BackSpace,     XK_NO_MOD,      "\177",          0,    0,    0},
 	{ XK_Up,            XK_NO_MOD,      "\033[A",        0,   -1,    0},
 	{ XK_Up,            XK_NO_MOD,      "\033OA",        0,   +1,    0},
-	{ XK_Up,            ShiftMask,      "\033[a",        0,    0,    0},
+	{ XK_Up,            ShiftMask,      "\033[1;2A",     0,    0,    0},
+	{ XK_Up,            ControlMask,    "\033[1;5A",     0,    0,    0},
+	{ XK_Up,            Mod1Mask,       "\033[1;3A",     0,    0,    0},
 	{ XK_Down,          XK_NO_MOD,      "\033[B",        0,   -1,    0},
 	{ XK_Down,          XK_NO_MOD,      "\033OB",        0,   +1,    0},
-	{ XK_Down,          ShiftMask,      "\033[b",        0,    0,    0},
+	{ XK_Down,          ShiftMask,      "\033[1;2B",     0,    0,    0},
+	{ XK_Down,          ControlMask,    "\033[1;5B",     0,    0,    0},
+	{ XK_Down,          Mod1Mask,       "\033[1;3B",     0,    0,    0},
 	{ XK_Left,     	    XK_NO_MOD,      "\033[D",        0,   -1,    0},
 	{ XK_Left,          XK_NO_MOD,      "\033OD",        0,   +1,    0},
-	{ XK_Left,          ShiftMask,      "\033[d",        0,    0,    0},
+	{ XK_Left,          ShiftMask,      "\033[1;2D",     0,    0,    0},
+	{ XK_Left,          ControlMask,    "\033[1;5D",     0,    0,    0},
+	{ XK_Left,          Mod1Mask,       "\033[1;3D",     0,    0,    0},
 	{ XK_Right,         XK_NO_MOD,      "\033[C",        0,   -1,    0},
 	{ XK_Right,         XK_NO_MOD,      "\033OC",        0,   +1,    0},
-	{ XK_Right,         ShiftMask,      "\033[c",        0,    0,    0},
+	{ XK_Right,         ShiftMask,      "\033[1;2C",     0,    0,    0},
+	{ XK_Right,         ControlMask,    "\033[1;5C",     0,    0,    0},
+	{ XK_Right,         Mod1Mask,       "\033[1;3C",     0,    0,    0},
 	{ XK_Return,        XK_NO_MOD,      "\n",            0,    0,   -1},
 	{ XK_Return,        XK_NO_MOD,      "\r\n",          0,    0,   +1},
 	{ XK_Return,        Mod1Mask,       "\033\n",        0,    0,   -1},
diff --git a/st.info b/st.info
index 199aff6..be2a47e 100644
--- a/st.info
+++ b/st.info
@@ -54,10 +54,10 @@ st| simpleterm,
 	kcud1=\EOB,
 	kcuf1=\EOC,
 	kcuu1=\EOA,
-	kLFT=\E[d,
-	kRIT=\E[c,
-	kind=\E[a,
-	kri=\E[b,
+	kLFT=\E[1;2D,
+	kRIT=\E[1;2C,
+	kind=\E[1;2B,
+	kri=\E[1;2A,
 	kdch1=\E[3~,
 	kich1=\E[2~,
 	kend=\E[4~,

From 620e3bb39ebe617b69b5cb1323b4f47c2f699527 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 13 Nov 2012 20:05:02 +0100
Subject: [PATCH 0394/1146] Add missed key definitions

This patch adds the keys for the keypad (in both modes, application mode or
ansi mode) and function keys. It uses the same convention than xterm and
instead of using the XK_Fxx values it generates them using F1-F12 and
modifiers. For example:

   F1 -> ^[OP
   F1 + Shift = F13 -> ^[[1;2P
   F1 + Control = F25 -> ^[[1;5P
   F1 + Mod2 = F37 -> ^[[1;6P
   F1 + Mod1 = F49 -> ^[[1;3P
   F1 + Mod3 = F61 -> ^[[1;4P

It is also important notice than the terminfo capability kIC (shifted insert
key) only can be generated using the keypad keyboard, because the shorcut
for selection paste is using the same combination.

After this path the number of elements in the Key array becomes high, and
maybe a sequencial search is not enough efficient now.
---
 TODO         |    6 +---
 config.def.h |  102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 st.info      |   70 ++++++++++++++++++++++++++++++++++++++--
 3 files changed, 169 insertions(+), 9 deletions(-)
---
 TODO         |   6 +--
 config.def.h | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 st.info      |  70 +++++++++++++++++++++++++++++++++--
 3 files changed, 169 insertions(+), 9 deletions(-)

diff --git a/TODO b/TODO
index f56a6d9..e1168a1 100644
--- a/TODO
+++ b/TODO
@@ -5,11 +5,7 @@ vt emulation
 * color definition in CSI
 	* implement CSI parsing
 * make the keypad keys really work
-	* kf0 .. kf44
-	* kend, kel, kent, kfnd, ked, kext
-	* kNXT, kPRV
-	* ka1, ka3, kb2
-* add arrow keys handling
+	* kel, kfnd, ked, kext
 
 code & interface
 ----------------
diff --git a/config.def.h b/config.def.h
index 3d406d4..d6103b5 100644
--- a/config.def.h
+++ b/config.def.h
@@ -77,6 +77,49 @@ static unsigned int defaultucs = 257;
 /* key, mask, output, keypad, cursor, crlf */
 static Key key[] = {
 	/* keysym             mask         string         keypad cursor crlf */
+	{ XK_KP_Home,       XK_NO_MOD,      "\033[H",        0,    0,    0},
+	{ XK_KP_Home,       ShiftMask,      "\033[1;2H",     0,    0,    0},
+	{ XK_KP_Up,         XK_NO_MOD,      "\033Ox",       +1,    0,    0},
+	{ XK_KP_Up,         XK_NO_MOD,      "\033[A",        0,   -1,    0},
+	{ XK_KP_Up,         XK_NO_MOD,      "\033OA",        0,   +1,    0},
+	{ XK_KP_Down,       XK_NO_MOD,      "\033Or",       +1,    0,    0},
+	{ XK_KP_Down,       XK_NO_MOD,      "\033[B",        0,   -1,    0},
+	{ XK_KP_Down,       XK_NO_MOD,      "\033OB",        0,   +1,    0},
+	{ XK_KP_Left,       XK_NO_MOD,      "\033Ot",       +1,    0,    0},
+	{ XK_KP_Left,       XK_NO_MOD,      "\033[D",        0,   -1,    0},
+	{ XK_KP_Left,       XK_NO_MOD,      "\033OD",        0,   +1,    0},
+	{ XK_KP_Right,      XK_NO_MOD,      "\033Ov",       +1,    0,    0},
+	{ XK_KP_Right,      XK_NO_MOD,      "\033[C",        0,   -1,    0},
+	{ XK_KP_Right,      XK_NO_MOD,      "\033OC",        0,   +1,    0},
+	{ XK_KP_Prior,      XK_NO_MOD,      "\033[5~",	     0,    0,    0},
+	{ XK_KP_Prior,      ShiftMask,      "\033[5;2~",     0,    0,    0},
+	{ XK_KP_Begin,      XK_NO_MOD,      "\033[E",        0,    0,    0},
+	{ XK_KP_End,        XK_NO_MOD,      "\033[4~",       0,    0,    0},
+	{ XK_KP_End,        ShiftMask,      "\033[1;2F",     0,    0,    0},
+	{ XK_KP_Next,       XK_NO_MOD,      "\033[6~",       0,    0,    0},
+	{ XK_KP_Next,       ShiftMask,      "\033[6;2~",     0,    0,    0},
+	{ XK_KP_Insert,     XK_NO_MOD,      "\033[2~",       0,    0,    0},
+	{ XK_KP_Insert,     ShiftMask,      "\033[2;2~",     0,    0,    0},
+	{ XK_KP_Delete,     XK_NO_MOD,      "\033[3~",       0,    0,    0},
+	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",     0,    0,    0},
+	{ XK_KP_Multiply,   XK_NO_MOD,      "\033Oj",       +1,    0,    0},
+	{ XK_KP_Add,        XK_NO_MOD,      "\033Ok",       +1,    0,    0},
+	{ XK_KP_Enter,      XK_NO_MOD,      "\033OM",       +1,    0,    0},
+	{ XK_KP_Enter,      XK_NO_MOD,      "\n",           -1,    0,   -1},
+	{ XK_KP_Enter,      XK_NO_MOD,      "\r\n",         -1,    0,    0},
+	{ XK_KP_Subtract,   XK_NO_MOD,      "\033Om",       +1,    0,    0},
+	{ XK_KP_Decimal,    XK_NO_MOD,      "\033On",       +1,    0,    0},
+	{ XK_KP_Divide,     XK_NO_MOD,      "\033Oo",       +1,    0,    0},
+	{ XK_KP_0,          XK_NO_MOD,      "\033Op",       +1,    0,    0},
+	{ XK_KP_1,          XK_NO_MOD,      "\033Oq",       +1,    0,    0},
+	{ XK_KP_2,          XK_NO_MOD,      "\033Or",       +1,    0,    0},
+	{ XK_KP_3,          XK_NO_MOD,      "\033Os",       +1,    0,    0},
+	{ XK_KP_4,          XK_NO_MOD,      "\033Ot",       +1,    0,    0},
+	{ XK_KP_5,          XK_NO_MOD,      "\033Ou",       +1,    0,    0},
+	{ XK_KP_6,          XK_NO_MOD,      "\033Ov",       +1,    0,    0},
+	{ XK_KP_7,          XK_NO_MOD,      "\033Ow",       +1,    0,    0},
+	{ XK_KP_8,          XK_NO_MOD,      "\033Ox",       +1,    0,    0},
+	{ XK_KP_9,          XK_NO_MOD,      "\033Oy",       +1,    0,    0},
 	{ XK_BackSpace,     XK_NO_MOD,      "\177",          0,    0,    0},
 	{ XK_Up,            XK_NO_MOD,      "\033[A",        0,   -1,    0},
 	{ XK_Up,            XK_NO_MOD,      "\033OA",        0,   +1,    0},
@@ -98,28 +141,85 @@ static Key key[] = {
 	{ XK_Right,         ShiftMask,      "\033[1;2C",     0,    0,    0},
 	{ XK_Right,         ControlMask,    "\033[1;5C",     0,    0,    0},
 	{ XK_Right,         Mod1Mask,       "\033[1;3C",     0,    0,    0},
+	{ XK_Tab,           ShiftMask,      "\033[Z",        0,    0,    0},
 	{ XK_Return,        XK_NO_MOD,      "\n",            0,    0,   -1},
 	{ XK_Return,        XK_NO_MOD,      "\r\n",          0,    0,   +1},
 	{ XK_Return,        Mod1Mask,       "\033\n",        0,    0,   -1},
 	{ XK_Return,        Mod1Mask,       "\033\r\n",      0,    0,   +1},
 	{ XK_Insert,        XK_NO_MOD,      "\033[2~",       0,    0,    0},
+	{ XK_Insert,        ShiftMask,      "\033[2;2~",     0,    0,    0},
 	{ XK_Delete,        XK_NO_MOD,      "\033[3~",       0,    0,    0},
-	{ XK_Home,          XK_NO_MOD,      "\033[1~",       0,    0,    0},
+	{ XK_Delete,        ShiftMask,      "\033[3;2~",     0,    0,    0},
+	{ XK_Home,          XK_NO_MOD,      "\033[H",        0,    0,    0},
+	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,    0,    0},
 	{ XK_End,           XK_NO_MOD,      "\033[4~",       0,    0,    0},
+	{ XK_End,           ShiftMask,      "\033[1;2F",     0,    0,    0},
 	{ XK_Prior,         XK_NO_MOD,      "\033[5~",       0,    0,    0},
 	{ XK_Next,          XK_NO_MOD,      "\033[6~",       0,    0,    0},
+	{ XK_Next,          ShiftMask,      "\033[6;2~",     0,    0,    0},
 	{ XK_F1,            XK_NO_MOD,      "\033OP" ,       0,    0,    0},
+	{ XK_F1, /* F13 */  ShiftMask,      "\033[1;2P",     0,    0,    0},
+	{ XK_F1, /* F25 */  ControlMask,    "\033[1;5P",     0,    0,    0},
+	{ XK_F1, /* F37 */  Mod2Mask,       "\033[1;6P",     0,    0,    0},
+	{ XK_F1, /* F49 */  Mod1Mask,       "\033[1;3P",     0,    0,    0},
+	{ XK_F1, /* F61 */  Mod3Mask,       "\033[1;4P",     0,    0,    0},
 	{ XK_F2,            XK_NO_MOD,      "\033OQ" ,       0,    0,    0},
+	{ XK_F2, /* F14 */  ShiftMask,      "\033[1;2Q",     0,    0,    0},
+	{ XK_F2, /* F26 */  ControlMask,    "\033[1;5Q",     0,    0,    0},
+	{ XK_F2, /* F38 */  Mod2Mask,       "\033[1;6Q",     0,    0,    0},
+	{ XK_F2, /* F50 */  Mod1Mask,       "\033[1;3Q",     0,    0,    0},
+	{ XK_F2, /* F62 */  Mod3Mask,       "\033[1;4Q",     0,    0,    0},
 	{ XK_F3,            XK_NO_MOD,      "\033OR" ,       0,    0,    0},
+	{ XK_F3, /* F15 */  ShiftMask,      "\033[1;2R",     0,    0,    0},
+	{ XK_F3, /* F27 */  ControlMask,    "\033[1;5R",     0,    0,    0},
+	{ XK_F3, /* F39 */  Mod2Mask,       "\033[1;6R",     0,    0,    0},
+	{ XK_F3, /* F51 */  Mod1Mask,       "\033[1;3R",     0,    0,    0},
+	{ XK_F3, /* F63 */  Mod3Mask,       "\033[1;4R",     0,    0,    0},
 	{ XK_F4,            XK_NO_MOD,      "\033OS" ,       0,    0,    0},
+	{ XK_F4, /* F16 */  ShiftMask,      "\033[1;2S",     0,    0,    0},
+	{ XK_F4, /* F28 */  ShiftMask,      "\033[1;5S",     0,    0,    0},
+	{ XK_F4, /* F40 */  Mod2Mask,       "\033[1;6S",     0,    0,    0},
+	{ XK_F4, /* F52 */  Mod1Mask,       "\033[1;3S",     0,    0,    0},
 	{ XK_F5,            XK_NO_MOD,      "\033[15~",      0,    0,    0},
+	{ XK_F5, /* F17 */  ShiftMask,      "\033[15;2~",    0,    0,    0},
+	{ XK_F5, /* F29 */  ControlMask,    "\033[15;5~",    0,    0,    0},
+	{ XK_F5, /* F41 */  Mod2Mask,       "\033[15;6~",    0,    0,    0},
+	{ XK_F5, /* F53 */  Mod1Mask,       "\033[15;3~",    0,    0,    0},
 	{ XK_F6,            XK_NO_MOD,      "\033[17~",      0,    0,    0},
+	{ XK_F6, /* F18 */  ShiftMask,      "\033[17;2~",    0,    0,    0},
+	{ XK_F6, /* F30 */  ControlMask,    "\033[17;5~",    0,    0,    0},
+	{ XK_F6, /* F42 */  Mod2Mask,       "\033[17;6~",    0,    0,    0},
+	{ XK_F6, /* F54 */  Mod1Mask,       "\033[17;3~",    0,    0,    0},
 	{ XK_F7,            XK_NO_MOD,      "\033[18~",      0,    0,    0},
+	{ XK_F7, /* F19 */  ShiftMask,      "\033[18;2~",    0,    0,    0},
+	{ XK_F7, /* F31 */  ControlMask,    "\033[18;5~",    0,    0,    0},
+	{ XK_F7, /* F43 */  Mod2Mask,       "\033[18;6~",    0,    0,    0},
+	{ XK_F7, /* F55 */  Mod1Mask,       "\033[18;3~",    0,    0,    0},
 	{ XK_F8,            XK_NO_MOD,      "\033[19~",      0,    0,    0},
+	{ XK_F8, /* F20 */  ShiftMask,      "\033[19;2~",    0,    0,    0},
+	{ XK_F8, /* F32 */  ControlMask,    "\033[19;5~",    0,    0,    0},
+	{ XK_F8, /* F44 */  Mod2Mask,       "\033[19;6~",    0,    0,    0},
+	{ XK_F8, /* F56 */  Mod1Mask,       "\033[19;3~",    0,    0,    0},
 	{ XK_F9,            XK_NO_MOD,      "\033[20~",      0,    0,    0},
+	{ XK_F9, /* F21 */  ShiftMask,      "\033[20;2~",    0,    0,    0},
+	{ XK_F9, /* F33 */  ControlMask,    "\033[20;5~",    0,    0,    0},
+	{ XK_F9, /* F45 */  Mod2Mask,       "\033[20;6~",    0,    0,    0},
+	{ XK_F9, /* F57 */  Mod1Mask,       "\033[20;3~",    0,    0,    0},
 	{ XK_F10,           XK_NO_MOD,      "\033[21~",      0,    0,    0},
+	{ XK_F10, /* F22 */ ShiftMask,      "\033[21;2~",    0,    0,    0},
+	{ XK_F10, /* F34 */ ControlMask,    "\033[21;5~",    0,    0,    0},
+	{ XK_F10, /* F46 */ Mod2Mask,       "\033[21;6~",    0,    0,    0},
+	{ XK_F10, /* F58 */ Mod1Mask,       "\033[21;3~",    0,    0,    0},
 	{ XK_F11,           XK_NO_MOD,      "\033[23~",      0,    0,    0},
+	{ XK_F11, /* F23 */ ShiftMask,      "\033[23;2~",    0,    0,    0},
+	{ XK_F11, /* F35 */ ControlMask,    "\033[23;5~",    0,    0,    0},
+	{ XK_F11, /* F47 */ Mod2Mask,       "\033[23;6~",    0,    0,    0},
+	{ XK_F11, /* F59 */ Mod1Mask,       "\033[23;3~",    0,    0,    0},
 	{ XK_F12,           XK_NO_MOD,      "\033[24~",      0,    0,    0},
+	{ XK_F12, /* F24 */ ShiftMask,      "\033[24;2~",    0,    0,    0},
+	{ XK_F12, /* F36 */ ControlMask,    "\033[24;5~",    0,    0,    0},
+	{ XK_F12, /* F48 */ Mod2Mask,       "\033[24;6~",    0,    0,    0},
+	{ XK_F12, /* F60 */ Mod1Mask,       "\033[24;3~",    0,    0,    0},
 };
 
 /* Internal shortcuts. */
diff --git a/st.info b/st.info
index be2a47e..4a05160 100644
--- a/st.info
+++ b/st.info
@@ -49,11 +49,24 @@ st| simpleterm,
 	invis=\E[8m,
 	is2=\E[4l\E>,
 	it#8,
+	ka1=\E[E,
+	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,
@@ -61,9 +74,6 @@ st| simpleterm,
 	kdch1=\E[3~,
 	kich1=\E[2~,
 	kend=\E[4~,
-	kf10=\E[21~,
-	kf11=\E[23~,
-	kf12=\E[24~,
 	kf1=\EOP,
 	kf2=\EOQ,
 	kf3=\EOR,
@@ -73,6 +83,60 @@ st| simpleterm,
 	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~,
 	knp=\E[6~,
 	kmous=\E[M,

From 7474a2fc3785eb1aad00f8cf2b50711bbe1fff0b Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 13 Nov 2012 20:13:39 +0100
Subject: [PATCH 0395/1146] The style inquisition was here again.

---
 config.def.h |  2 +-
 config.mk    |  1 +
 st.c         | 16 +++++++++++-----
 3 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/config.def.h b/config.def.h
index d6103b5..5d887fc 100644
--- a/config.def.h
+++ b/config.def.h
@@ -131,7 +131,7 @@ static Key key[] = {
 	{ XK_Down,          ShiftMask,      "\033[1;2B",     0,    0,    0},
 	{ XK_Down,          ControlMask,    "\033[1;5B",     0,    0,    0},
 	{ XK_Down,          Mod1Mask,       "\033[1;3B",     0,    0,    0},
-	{ XK_Left,     	    XK_NO_MOD,      "\033[D",        0,   -1,    0},
+	{ XK_Left,	    XK_NO_MOD,      "\033[D",        0,   -1,    0},
 	{ XK_Left,          XK_NO_MOD,      "\033OD",        0,   +1,    0},
 	{ XK_Left,          ShiftMask,      "\033[1;2D",     0,    0,    0},
 	{ XK_Left,          ControlMask,    "\033[1;5D",     0,    0,    0},
diff --git a/config.mk b/config.mk
index 20e519f..f1757ed 100644
--- a/config.mk
+++ b/config.mk
@@ -21,3 +21,4 @@ LDFLAGS += -g ${LIBS}
 
 # compiler and linker
 CC ?= cc
+
diff --git a/st.c b/st.c
index 14408c5..dbbc1f6 100644
--- a/st.c
+++ b/st.c
@@ -2700,17 +2700,21 @@ kmap(KeySym k, uint state) {
 		if(kp->k != k)
 			continue;
 		if((state & mask) != mask &&
-		   (mask == XK_NO_MOD && state))
+				(mask == XK_NO_MOD && state)) {
 			continue;
+		}
 		if((kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) ||
-		   (kp->appkey > 0 && !IS_SET(MODE_APPKEYPAD)))
+				(kp->appkey > 0 && !IS_SET(MODE_APPKEYPAD))) {
 			continue;
+		}
 		if((kp->appcursor < 0 && IS_SET(MODE_APPCURSOR)) ||
-		   (kp->appcursor > 0 && !IS_SET(MODE_APPCURSOR)))
+				(kp->appcursor > 0 && !IS_SET(MODE_APPCURSOR))) {
 			continue;
+		}
 		if((kp->crlf < 0 && IS_SET(MODE_CRLF)) ||
-		   (kp->crlf > 0 && !IS_SET(MODE_CRLF)))
+				(kp->crlf > 0 && !IS_SET(MODE_CRLF))) {
 			continue;
+		}
 
 		return kp->s;
 	}
@@ -2755,6 +2759,7 @@ kpress(XEvent *ev) {
 		memcpy(cp, xstr, len);
 		len = cp - buf + len;
 	}
+
 	ttywrite(buf, len);
 	if(IS_SET(MODE_ECHO))
 		techo(buf, len);
@@ -2869,7 +2874,7 @@ main(int argc, char *argv[]) {
 				opt_class = argv[i];
 			break;
 		case 'e':
-			/* eat every remaining arguments */
+			/* eat all remaining arguments */
 			if(++i < argc)
 				opt_cmd = &argv[i];
 			goto run;
@@ -2924,6 +2929,7 @@ run:
 	ttynew();
 	selinit();
 	run();
+
 	return 0;
 }
 

From 461aac159cf3dbb8514e645df6387e03e7c26084 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 14 Nov 2012 06:37:24 +0100
Subject: [PATCH 0396/1146] Fixing the tab key, when no mask is wanted.

---
 st.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index dbbc1f6..ca4248a 100644
--- a/st.c
+++ b/st.c
@@ -2699,18 +2699,22 @@ kmap(KeySym k, uint state) {
 
 		if(kp->k != k)
 			continue;
-		if((state & mask) != mask &&
+
+		if((state & mask) != mask ||
 				(mask == XK_NO_MOD && state)) {
 			continue;
 		}
+
 		if((kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) ||
 				(kp->appkey > 0 && !IS_SET(MODE_APPKEYPAD))) {
 			continue;
 		}
+
 		if((kp->appcursor < 0 && IS_SET(MODE_APPCURSOR)) ||
 				(kp->appcursor > 0 && !IS_SET(MODE_APPCURSOR))) {
 			continue;
 		}
+
 		if((kp->crlf < 0 && IS_SET(MODE_CRLF)) ||
 				(kp->crlf > 0 && !IS_SET(MODE_CRLF))) {
 			continue;
@@ -2718,6 +2722,7 @@ kmap(KeySym k, uint state) {
 
 		return kp->s;
 	}
+
 	return NULL;
 }
 

From 16ccf344deccbae53865b6efbe9dc23ebdceccb7 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 14 Nov 2012 11:14:29 +0100
Subject: [PATCH 0397/1146] Fix tab key

When Shift + Tab is pressed X server send the event XK_ISO_Left_Tab with
ShiftMask, so this is the entry we need in config.def.h

This patch also revert the previous patch for this issue because it breaks
the keyboard.
---
 config.def.h |    2 +-
 st.c         |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
---
 config.def.h | 2 +-
 st.c         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/config.def.h b/config.def.h
index 5d887fc..972285b 100644
--- a/config.def.h
+++ b/config.def.h
@@ -141,7 +141,7 @@ static Key key[] = {
 	{ XK_Right,         ShiftMask,      "\033[1;2C",     0,    0,    0},
 	{ XK_Right,         ControlMask,    "\033[1;5C",     0,    0,    0},
 	{ XK_Right,         Mod1Mask,       "\033[1;3C",     0,    0,    0},
-	{ XK_Tab,           ShiftMask,      "\033[Z",        0,    0,    0},
+	{ XK_ISO_Left_Tab,  ShiftMask,      "\033[Z",        0,    0,    0},
 	{ XK_Return,        XK_NO_MOD,      "\n",            0,    0,   -1},
 	{ XK_Return,        XK_NO_MOD,      "\r\n",          0,    0,   +1},
 	{ XK_Return,        Mod1Mask,       "\033\n",        0,    0,   -1},
diff --git a/st.c b/st.c
index ca4248a..932253c 100644
--- a/st.c
+++ b/st.c
@@ -2700,7 +2700,7 @@ kmap(KeySym k, uint state) {
 		if(kp->k != k)
 			continue;
 
-		if((state & mask) != mask ||
+		if((state & mask) != mask &&
 				(mask == XK_NO_MOD && state)) {
 			continue;
 		}

From 88bb76c1bccbc8bb68b6776062cd2ef28bda8561 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 15 Nov 2012 15:36:13 +0100
Subject: [PATCH 0398/1146] Fix XK_NO_MOD and XK_ANY_MOD behavior

XK_NO_MOD match a key without modifiers and XK_ANY_MOD match a key does not
matter what modifiers are pressed to. Like they are mask the best value for
XK_ANY_MOD is all the bits to 1, so the and with any state will be equal to
the state. This also imply that is necessary check the case for XK_NO_MOD
(no modifiers at all) with some modifier in state, and the inverse
(some mask different to XK_ANY_MOD or XK_NO_MOD and no modifiers in state).
---
 st.c |   12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
---
 st.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 932253c..b8b2bbf 100644
--- a/st.c
+++ b/st.c
@@ -59,8 +59,8 @@
 #define STR_ARG_SIZ   16
 #define DRAW_BUF_SIZ  20*1024
 #define UTF_SIZ       4
-#define XK_NO_MOD     UINT_MAX
-#define XK_ANY_MOD    0
+#define XK_ANY_MOD    UINT_MAX
+#define XK_NO_MOD     0
 
 #define REDRAW_TIMEOUT (80*1000) /* 80 ms */
 
@@ -2700,10 +2700,12 @@ kmap(KeySym k, uint state) {
 		if(kp->k != k)
 			continue;
 
-		if((state & mask) != mask &&
-				(mask == XK_NO_MOD && state)) {
+		if(mask == XK_NO_MOD && state)
+			continue;
+		if(mask != XK_ANY_MOD && mask != XK_NO_MOD && !state)
+			continue;
+		if((state & mask) != state)
 			continue;
-		}
 
 		if((kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) ||
 				(kp->appkey > 0 && !IS_SET(MODE_APPKEYPAD))) {

From 4389f2eb1b27f7a210e1f631e703c48a8ca8d50b Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 15 Nov 2012 15:36:20 +0100
Subject: [PATCH 0399/1146] Use XK_ANY_MOD instead of XK_NO_MOD in key
 definition

Usually terminal emulators don't generate any sequence for a combination
they don't have registered, for example Shift + Next, but st behavior
previous to the keyboard patch generates the sequence without the modifier,
in this example Next. This patch uses the XK_ANY_MOD in order to get this
same behaviour.
---
 config.def.h |  114 ++++++++++++++++++++++++++++++----------------------------
 1 file changed, 59 insertions(+), 55 deletions(-)
---
 config.def.h | 114 ++++++++++++++++++++++++++-------------------------
 1 file changed, 59 insertions(+), 55 deletions(-)

diff --git a/config.def.h b/config.def.h
index 972285b..bd5a888 100644
--- a/config.def.h
+++ b/config.def.h
@@ -72,91 +72,95 @@ static unsigned int defaultucs = 257;
  * * 0: no value
  * * > 0: crlf mode is enabled
  * * < 0: crlf mode is disabled
+ *
+ * Be careful with the order of the definitons because st searchs in
+ * this table sequencially, so any XK_ANY_MOD must be in the last
+ * position for a key.
  */
 
 /* key, mask, output, keypad, cursor, crlf */
 static Key key[] = {
 	/* keysym             mask         string         keypad cursor crlf */
-	{ XK_KP_Home,       XK_NO_MOD,      "\033[H",        0,    0,    0},
 	{ XK_KP_Home,       ShiftMask,      "\033[1;2H",     0,    0,    0},
-	{ XK_KP_Up,         XK_NO_MOD,      "\033Ox",       +1,    0,    0},
-	{ XK_KP_Up,         XK_NO_MOD,      "\033[A",        0,   -1,    0},
-	{ XK_KP_Up,         XK_NO_MOD,      "\033OA",        0,   +1,    0},
-	{ XK_KP_Down,       XK_NO_MOD,      "\033Or",       +1,    0,    0},
-	{ XK_KP_Down,       XK_NO_MOD,      "\033[B",        0,   -1,    0},
-	{ XK_KP_Down,       XK_NO_MOD,      "\033OB",        0,   +1,    0},
-	{ XK_KP_Left,       XK_NO_MOD,      "\033Ot",       +1,    0,    0},
-	{ XK_KP_Left,       XK_NO_MOD,      "\033[D",        0,   -1,    0},
-	{ XK_KP_Left,       XK_NO_MOD,      "\033OD",        0,   +1,    0},
-	{ XK_KP_Right,      XK_NO_MOD,      "\033Ov",       +1,    0,    0},
-	{ XK_KP_Right,      XK_NO_MOD,      "\033[C",        0,   -1,    0},
-	{ XK_KP_Right,      XK_NO_MOD,      "\033OC",        0,   +1,    0},
-	{ XK_KP_Prior,      XK_NO_MOD,      "\033[5~",	     0,    0,    0},
+	{ XK_KP_Home,       XK_ANY_MOD,     "\033[H",        0,    0,    0},
+	{ XK_KP_Up,         XK_ANY_MOD,     "\033Ox",       +1,    0,    0},
+	{ XK_KP_Up,         XK_ANY_MOD,     "\033[A",        0,   -1,    0},
+	{ XK_KP_Up,         XK_ANY_MOD,     "\033OA",        0,   +1,    0},
+	{ XK_KP_Down,       XK_ANY_MOD,     "\033Or",       +1,    0,    0},
+	{ XK_KP_Down,       XK_ANY_MOD,     "\033[B",        0,   -1,    0},
+	{ XK_KP_Down,       XK_ANY_MOD,     "\033OB",        0,   +1,    0},
+	{ XK_KP_Left,       XK_ANY_MOD,     "\033Ot",       +1,    0,    0},
+	{ XK_KP_Left,       XK_ANY_MOD,     "\033[D",        0,   -1,    0},
+	{ XK_KP_Left,       XK_ANY_MOD,     "\033OD",        0,   +1,    0},
+	{ XK_KP_Right,      XK_ANY_MOD,     "\033Ov",       +1,    0,    0},
+	{ XK_KP_Right,      XK_ANY_MOD,     "\033[C",        0,   -1,    0},
+	{ XK_KP_Right,      XK_ANY_MOD,     "\033OC",        0,   +1,    0},
 	{ XK_KP_Prior,      ShiftMask,      "\033[5;2~",     0,    0,    0},
-	{ XK_KP_Begin,      XK_NO_MOD,      "\033[E",        0,    0,    0},
-	{ XK_KP_End,        XK_NO_MOD,      "\033[4~",       0,    0,    0},
+	{ XK_KP_Prior,      XK_ANY_MOD,     "\033[5~",	     0,    0,    0},
+	{ XK_KP_Begin,      XK_ANY_MOD,     "\033[E",        0,    0,    0},
 	{ XK_KP_End,        ShiftMask,      "\033[1;2F",     0,    0,    0},
-	{ XK_KP_Next,       XK_NO_MOD,      "\033[6~",       0,    0,    0},
+	{ XK_KP_End,        XK_ANY_MOD,     "\033[4~",       0,    0,    0},
 	{ XK_KP_Next,       ShiftMask,      "\033[6;2~",     0,    0,    0},
-	{ XK_KP_Insert,     XK_NO_MOD,      "\033[2~",       0,    0,    0},
+	{ XK_KP_Next,       XK_ANY_MOD,     "\033[6~",       0,    0,    0},
 	{ XK_KP_Insert,     ShiftMask,      "\033[2;2~",     0,    0,    0},
-	{ XK_KP_Delete,     XK_NO_MOD,      "\033[3~",       0,    0,    0},
+	{ XK_KP_Insert,     XK_ANY_MOD,     "\033[2~",       0,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",     0,    0,    0},
-	{ XK_KP_Multiply,   XK_NO_MOD,      "\033Oj",       +1,    0,    0},
-	{ XK_KP_Add,        XK_NO_MOD,      "\033Ok",       +1,    0,    0},
-	{ XK_KP_Enter,      XK_NO_MOD,      "\033OM",       +1,    0,    0},
-	{ XK_KP_Enter,      XK_NO_MOD,      "\n",           -1,    0,   -1},
-	{ XK_KP_Enter,      XK_NO_MOD,      "\r\n",         -1,    0,    0},
-	{ XK_KP_Subtract,   XK_NO_MOD,      "\033Om",       +1,    0,    0},
-	{ XK_KP_Decimal,    XK_NO_MOD,      "\033On",       +1,    0,    0},
-	{ XK_KP_Divide,     XK_NO_MOD,      "\033Oo",       +1,    0,    0},
-	{ XK_KP_0,          XK_NO_MOD,      "\033Op",       +1,    0,    0},
-	{ XK_KP_1,          XK_NO_MOD,      "\033Oq",       +1,    0,    0},
-	{ XK_KP_2,          XK_NO_MOD,      "\033Or",       +1,    0,    0},
-	{ XK_KP_3,          XK_NO_MOD,      "\033Os",       +1,    0,    0},
-	{ XK_KP_4,          XK_NO_MOD,      "\033Ot",       +1,    0,    0},
-	{ XK_KP_5,          XK_NO_MOD,      "\033Ou",       +1,    0,    0},
-	{ XK_KP_6,          XK_NO_MOD,      "\033Ov",       +1,    0,    0},
-	{ XK_KP_7,          XK_NO_MOD,      "\033Ow",       +1,    0,    0},
-	{ XK_KP_8,          XK_NO_MOD,      "\033Ox",       +1,    0,    0},
-	{ XK_KP_9,          XK_NO_MOD,      "\033Oy",       +1,    0,    0},
-	{ XK_BackSpace,     XK_NO_MOD,      "\177",          0,    0,    0},
-	{ XK_Up,            XK_NO_MOD,      "\033[A",        0,   -1,    0},
-	{ XK_Up,            XK_NO_MOD,      "\033OA",        0,   +1,    0},
+	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",       0,    0,    0},
+	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +1,    0,    0},
+	{ XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +1,    0,    0},
+	{ XK_KP_Enter,      XK_ANY_MOD,     "\033OM",       +1,    0,    0},
+	{ XK_KP_Enter,      XK_ANY_MOD,     "\n",           -1,    0,   +1},
+	{ XK_KP_Enter,      XK_ANY_MOD,     "\r\n",         -1,    0,   -1},
+	{ XK_KP_Subtract,   XK_ANY_MOD,     "\033Om",       +1,    0,    0},
+	{ XK_KP_Decimal,    XK_ANY_MOD,     "\033On",       +1,    0,    0},
+	{ XK_KP_Divide,     XK_ANY_MOD,     "\033Oo",       +1,    0,    0},
+	{ XK_KP_0,          XK_ANY_MOD,     "\033Op",       +1,    0,    0},
+	{ XK_KP_1,          XK_ANY_MOD,     "\033Oq",       +1,    0,    0},
+	{ XK_KP_2,          XK_ANY_MOD,     "\033Or",       +1,    0,    0},
+	{ XK_KP_3,          XK_ANY_MOD,     "\033Os",       +1,    0,    0},
+	{ XK_KP_4,          XK_ANY_MOD,     "\033Ot",       +1,    0,    0},
+	{ XK_KP_5,          XK_ANY_MOD,     "\033Ou",       +1,    0,    0},
+	{ XK_KP_6,          XK_ANY_MOD,     "\033Ov",       +1,    0,    0},
+	{ XK_KP_7,          XK_ANY_MOD,     "\033Ow",       +1,    0,    0},
+	{ XK_KP_8,          XK_ANY_MOD,     "\033Ox",       +1,    0,    0},
+	{ XK_KP_9,          XK_ANY_MOD,     "\033Oy",       +1,    0,    0},
+	{ XK_BackSpace,     XK_ANY_MOD,     "\177",          0,    0,    0},
 	{ XK_Up,            ShiftMask,      "\033[1;2A",     0,    0,    0},
 	{ XK_Up,            ControlMask,    "\033[1;5A",     0,    0,    0},
 	{ XK_Up,            Mod1Mask,       "\033[1;3A",     0,    0,    0},
-	{ XK_Down,          XK_NO_MOD,      "\033[B",        0,   -1,    0},
-	{ XK_Down,          XK_NO_MOD,      "\033OB",        0,   +1,    0},
+	{ XK_Up,            XK_ANY_MOD,     "\033[A",        0,   -1,    0},
+	{ XK_Up,            XK_ANY_MOD,     "\033OA",        0,   +1,    0},
 	{ XK_Down,          ShiftMask,      "\033[1;2B",     0,    0,    0},
 	{ XK_Down,          ControlMask,    "\033[1;5B",     0,    0,    0},
 	{ XK_Down,          Mod1Mask,       "\033[1;3B",     0,    0,    0},
-	{ XK_Left,	    XK_NO_MOD,      "\033[D",        0,   -1,    0},
-	{ XK_Left,          XK_NO_MOD,      "\033OD",        0,   +1,    0},
+	{ XK_Down,          XK_ANY_MOD,     "\033[B",        0,   -1,    0},
+	{ XK_Down,          XK_ANY_MOD,     "\033OB",        0,   +1,    0},
 	{ XK_Left,          ShiftMask,      "\033[1;2D",     0,    0,    0},
 	{ XK_Left,          ControlMask,    "\033[1;5D",     0,    0,    0},
 	{ XK_Left,          Mod1Mask,       "\033[1;3D",     0,    0,    0},
-	{ XK_Right,         XK_NO_MOD,      "\033[C",        0,   -1,    0},
-	{ XK_Right,         XK_NO_MOD,      "\033OC",        0,   +1,    0},
+	{ XK_Left,	    XK_ANY_MOD,     "\033[D",        0,   -1,    0},
+	{ XK_Left,          XK_ANY_MOD,     "\033OD",        0,   +1,    0},
 	{ XK_Right,         ShiftMask,      "\033[1;2C",     0,    0,    0},
 	{ XK_Right,         ControlMask,    "\033[1;5C",     0,    0,    0},
 	{ XK_Right,         Mod1Mask,       "\033[1;3C",     0,    0,    0},
+	{ XK_Right,         XK_ANY_MOD,     "\033[C",        0,   -1,    0},
+	{ XK_Right,         XK_ANY_MOD,     "\033OC",        0,   +1,    0},
 	{ XK_ISO_Left_Tab,  ShiftMask,      "\033[Z",        0,    0,    0},
-	{ XK_Return,        XK_NO_MOD,      "\n",            0,    0,   -1},
-	{ XK_Return,        XK_NO_MOD,      "\r\n",          0,    0,   +1},
-	{ XK_Return,        Mod1Mask,       "\033\n",        0,    0,   -1},
-	{ XK_Return,        Mod1Mask,       "\033\r\n",      0,    0,   +1},
-	{ XK_Insert,        XK_NO_MOD,      "\033[2~",       0,    0,    0},
+	{ XK_Return,        Mod1Mask,       "\033\n",        0,    0,   +1},
+	{ XK_Return,        Mod1Mask,       "\033\r\n",      0,    0,   -1},
+	{ XK_Return,        XK_ANY_MOD,     "\n",            0,    0,   +1},
+	{ XK_Return,        XK_ANY_MOD,     "\r\n",          0,    0,   -1},
 	{ XK_Insert,        ShiftMask,      "\033[2;2~",     0,    0,    0},
-	{ XK_Delete,        XK_NO_MOD,      "\033[3~",       0,    0,    0},
+	{ XK_Insert,        XK_ANY_MOD,     "\033[2~",       0,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",     0,    0,    0},
-	{ XK_Home,          XK_NO_MOD,      "\033[H",        0,    0,    0},
+	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",       0,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,    0,    0},
-	{ XK_End,           XK_NO_MOD,      "\033[4~",       0,    0,    0},
+	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,    0,    0},
 	{ XK_End,           ShiftMask,      "\033[1;2F",     0,    0,    0},
+	{ XK_End,           XK_ANY_MOD,     "\033[4~",       0,    0,    0},
 	{ XK_Prior,         XK_NO_MOD,      "\033[5~",       0,    0,    0},
-	{ XK_Next,          XK_NO_MOD,      "\033[6~",       0,    0,    0},
 	{ XK_Next,          ShiftMask,      "\033[6;2~",     0,    0,    0},
+	{ XK_Next,          XK_ANY_MOD,     "\033[6~",       0,    0,    0},
 	{ XK_F1,            XK_NO_MOD,      "\033OP" ,       0,    0,    0},
 	{ XK_F1, /* F13 */  ShiftMask,      "\033[1;2P",     0,    0,    0},
 	{ XK_F1, /* F25 */  ControlMask,    "\033[1;5P",     0,    0,    0},

From e7bb14e03e383daf2505ca304adca78b57884513 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 15 Nov 2012 15:54:34 +0100
Subject: [PATCH 0400/1146] Fixing Return in non-crlf mode.

---
 config.def.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config.def.h b/config.def.h
index bd5a888..ea29ab5 100644
--- a/config.def.h
+++ b/config.def.h
@@ -148,8 +148,8 @@ static Key key[] = {
 	{ XK_ISO_Left_Tab,  ShiftMask,      "\033[Z",        0,    0,    0},
 	{ XK_Return,        Mod1Mask,       "\033\n",        0,    0,   +1},
 	{ XK_Return,        Mod1Mask,       "\033\r\n",      0,    0,   -1},
-	{ XK_Return,        XK_ANY_MOD,     "\n",            0,    0,   +1},
-	{ XK_Return,        XK_ANY_MOD,     "\r\n",          0,    0,   -1},
+	{ XK_Return,        XK_ANY_MOD,     "\n",            0,    0,   -1},
+	{ XK_Return,        XK_ANY_MOD,     "\r\n",          0,    0,   +1},
 	{ XK_Insert,        ShiftMask,      "\033[2;2~",     0,    0,    0},
 	{ XK_Insert,        XK_ANY_MOD,     "\033[2~",       0,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",     0,    0,    0},

From e87d21bb3d6b48f68340c193dff8b6021f00be10 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 15 Nov 2012 15:57:01 +0100
Subject: [PATCH 0401/1146] The crlf mode was reversed.

---
 config.def.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index ea29ab5..e02bc29 100644
--- a/config.def.h
+++ b/config.def.h
@@ -109,8 +109,8 @@ static Key key[] = {
 	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +1,    0,    0},
 	{ XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +1,    0,    0},
 	{ XK_KP_Enter,      XK_ANY_MOD,     "\033OM",       +1,    0,    0},
-	{ XK_KP_Enter,      XK_ANY_MOD,     "\n",           -1,    0,   +1},
-	{ XK_KP_Enter,      XK_ANY_MOD,     "\r\n",         -1,    0,   -1},
+	{ XK_KP_Enter,      XK_ANY_MOD,     "\n",           -1,    0,   -1},
+	{ XK_KP_Enter,      XK_ANY_MOD,     "\r\n",         -1,    0,   +1},
 	{ XK_KP_Subtract,   XK_ANY_MOD,     "\033Om",       +1,    0,    0},
 	{ XK_KP_Decimal,    XK_ANY_MOD,     "\033On",       +1,    0,    0},
 	{ XK_KP_Divide,     XK_ANY_MOD,     "\033Oo",       +1,    0,    0},
@@ -146,8 +146,8 @@ static Key key[] = {
 	{ XK_Right,         XK_ANY_MOD,     "\033[C",        0,   -1,    0},
 	{ XK_Right,         XK_ANY_MOD,     "\033OC",        0,   +1,    0},
 	{ XK_ISO_Left_Tab,  ShiftMask,      "\033[Z",        0,    0,    0},
-	{ XK_Return,        Mod1Mask,       "\033\n",        0,    0,   +1},
-	{ XK_Return,        Mod1Mask,       "\033\r\n",      0,    0,   -1},
+	{ XK_Return,        Mod1Mask,       "\033\n",        0,    0,   -1},
+	{ XK_Return,        Mod1Mask,       "\033\r\n",      0,    0,   +1},
 	{ XK_Return,        XK_ANY_MOD,     "\n",            0,    0,   -1},
 	{ XK_Return,        XK_ANY_MOD,     "\r\n",          0,    0,   +1},
 	{ XK_Insert,        ShiftMask,      "\033[2;2~",     0,    0,    0},

From 801ea034b652025dc22d26f6e1b802de932346da Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 15 Nov 2012 16:21:23 +0100
Subject: [PATCH 0402/1146] Import the patch of Eckehard Berns to add insert
 mode. Thanks!

---
 st.c    | 4 ++++
 st.info | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/st.c b/st.c
index b8b2bbf..7b7bd55 100644
--- a/st.c
+++ b/st.c
@@ -2100,6 +2100,10 @@ tputc(char *c, int len) {
 		sel.bx = -1;
 	if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
 		tnewline(1); /* always go to first col */
+	if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col)
+		memmove(&term.line[term.c.y][term.c.x+1],
+			&term.line[term.c.y][term.c.x],
+			(term.col - term.c.x - 1) * sizeof(Glyph));
 	tsetchar(c, &term.c.attr, term.c.x, term.c.y);
 	if(term.c.x+1 < term.col)
 		tmoveto(term.c.x+1, term.c.y);
diff --git a/st.info b/st.info
index 4a05160..bb8145b 100644
--- a/st.info
+++ b/st.info
@@ -153,6 +153,7 @@ st| simpleterm,
 	ritm=\E[23m,
 	rmacs=\E(B,
 	rmcup=\E[?1049l,
+	rmir=\E[4l,
 	rmkx=\E[?1l\E>,
 	rmso=\E[23m,
 	rmul=\E[m,
@@ -168,6 +169,7 @@ st| simpleterm,
 	sitm=\E[3m,
 	smacs=\E(0,
 	smcup=\E[?1049h,
+	smir=\E[4h,
 	smkx=\E[?1h\E=,
 	smso=\E[3m,
 	smul=\E[4m,

From d5640c772998de7bccd76c3f8e934fa685cb2bb4 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 15 Nov 2012 16:26:50 +0100
Subject: [PATCH 0403/1146] Fixing the return and keypad enter sent characters.
 Terminals produce \r. And

some minor style changes.
---
 config.def.h |  6 +++---
 st.c         | 10 +++++++---
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/config.def.h b/config.def.h
index e02bc29..da1191c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -109,7 +109,7 @@ static Key key[] = {
 	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +1,    0,    0},
 	{ XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +1,    0,    0},
 	{ XK_KP_Enter,      XK_ANY_MOD,     "\033OM",       +1,    0,    0},
-	{ XK_KP_Enter,      XK_ANY_MOD,     "\n",           -1,    0,   -1},
+	{ XK_KP_Enter,      XK_ANY_MOD,     "\r",           -1,    0,   -1},
 	{ XK_KP_Enter,      XK_ANY_MOD,     "\r\n",         -1,    0,   +1},
 	{ XK_KP_Subtract,   XK_ANY_MOD,     "\033Om",       +1,    0,    0},
 	{ XK_KP_Decimal,    XK_ANY_MOD,     "\033On",       +1,    0,    0},
@@ -146,9 +146,9 @@ static Key key[] = {
 	{ XK_Right,         XK_ANY_MOD,     "\033[C",        0,   -1,    0},
 	{ XK_Right,         XK_ANY_MOD,     "\033OC",        0,   +1,    0},
 	{ XK_ISO_Left_Tab,  ShiftMask,      "\033[Z",        0,    0,    0},
-	{ XK_Return,        Mod1Mask,       "\033\n",        0,    0,   -1},
+	{ XK_Return,        Mod1Mask,       "\033\r",        0,    0,   -1},
 	{ XK_Return,        Mod1Mask,       "\033\r\n",      0,    0,   +1},
-	{ XK_Return,        XK_ANY_MOD,     "\n",            0,    0,   -1},
+	{ XK_Return,        XK_ANY_MOD,     "\r",            0,    0,   -1},
 	{ XK_Return,        XK_ANY_MOD,     "\r\n",          0,    0,   +1},
 	{ XK_Insert,        ShiftMask,      "\033[2;2~",     0,    0,    0},
 	{ XK_Insert,        XK_ANY_MOD,     "\033[2~",       0,    0,    0},
diff --git a/st.c b/st.c
index 7b7bd55..ba93f2f 100644
--- a/st.c
+++ b/st.c
@@ -2100,15 +2100,19 @@ tputc(char *c, int len) {
 		sel.bx = -1;
 	if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
 		tnewline(1); /* always go to first col */
-	if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col)
+
+	if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col) {
 		memmove(&term.line[term.c.y][term.c.x+1],
 			&term.line[term.c.y][term.c.x],
 			(term.col - term.c.x - 1) * sizeof(Glyph));
+	}
+
 	tsetchar(c, &term.c.attr, term.c.x, term.c.y);
-	if(term.c.x+1 < term.col)
+	if(term.c.x+1 < term.col) {
 		tmoveto(term.c.x+1, term.c.y);
-	else
+	} else {
 		term.c.state |= CURSOR_WRAPNEXT;
+	}
 }
 
 int

From cc86d148cb4092a57af2b58eeae96bbd721de803 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 15 Nov 2012 16:36:48 +0100
Subject: [PATCH 0404/1146] Changing the TODO to the current state.

---
 TODO | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/TODO b/TODO
index e1168a1..b1af774 100644
--- a/TODO
+++ b/TODO
@@ -4,14 +4,15 @@ vt emulation
 * implement BCE right
 * color definition in CSI
 	* implement CSI parsing
-* make the keypad keys really work
-	* kel, kfnd, ked, kext
+* wide-character support in conjunction with fallback xft code 
+* mouse selection support
 
 code & interface
 ----------------
 
 * clean and complete terminfo entry
 * add fallback fonts for the restricted xft code
+* add a simple way to do multiplexing
 
 bugs
 ----
@@ -21,6 +22,10 @@ bugs
 * fix selection paste for xatom STRING
 * fix umlaut handling in settitle
 * fix rows and column definition in fixed geometry
+* fix -e handling
+* remove DEC test sequence when appropriate
+* reverse cursor when drawin light on light background
+	* text should be readable
 
 misc
 ----

From 90e1427632d6c5852d10c8d2bafa787012903eb9 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 15 Nov 2012 19:01:16 +0100
Subject: [PATCH 0405/1146] Fix Shift + Insert shortcut

This patch apply the same code for shortcuts that it is used now for defined
keys. So it is possible use now XK_NO_MOD and XK_ANY_MOD for defining shortcuts.
---
 st.c |   35 ++++++++++++++++++++---------------
 1 file changed, 20 insertions(+), 15 deletions(-)
---
 st.c | 35 ++++++++++++++++++++---------------
 1 file changed, 20 insertions(+), 15 deletions(-)

diff --git a/st.c b/st.c
index ba93f2f..477a8f8 100644
--- a/st.c
+++ b/st.c
@@ -65,7 +65,6 @@
 #define REDRAW_TIMEOUT (80*1000) /* 80 ms */
 
 /* macros */
-#define CLEANMASK(mask) (mask & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
 #define SERRNO strerror(errno)
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
 #define MAX(a, b)  ((a) < (b) ? (b) : (a))
@@ -329,6 +328,7 @@ static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 static void techo(char *, int);
 
+static inline bool match(uint, uint);
 static void ttynew(void);
 static void ttyread(void);
 static void ttyresize(void);
@@ -2696,23 +2696,29 @@ focus(XEvent *ev) {
 	}
 }
 
+inline bool
+match(uint mask, uint state) {
+	if(mask == XK_NO_MOD && state)
+		return false;
+	if(mask != XK_ANY_MOD && mask != XK_NO_MOD && !state)
+		return false;
+	if((state & mask) != state)
+		return false;
+	return true;
+}
+
 char*
 kmap(KeySym k, uint state) {
 	uint mask;
 	Key *kp;
 
-	state &= ~Mod2Mask;
 	for(kp = key; kp < key + LEN(key); kp++) {
 		mask = kp->mask;
 
 		if(kp->k != k)
 			continue;
 
-		if(mask == XK_NO_MOD && state)
-			continue;
-		if(mask != XK_ANY_MOD && mask != XK_NO_MOD && !state)
-			continue;
-		if((state & mask) != state)
+		if(!match(mask, state))
 			continue;
 
 		if((kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) ||
@@ -2741,21 +2747,20 @@ kpress(XEvent *ev) {
 	XKeyEvent *e = &ev->xkey;
 	KeySym ksym;
 	char xstr[31], buf[32], *customkey, *cp = buf;
-	int len, i;
+	int len;
 	Status status;
+	Shortcut *bp;
 
 	if (IS_SET(MODE_KBDLOCK))
 		return;
 
 	len = XmbLookupString(xw.xic, e, xstr, sizeof(xstr), &ksym, &status);
-
+	e->state &= ~Mod2Mask;
 	/* 1. shortcuts */
-	for(i = 0; i < LEN(shortcuts); i++) {
-		if((ksym == shortcuts[i].keysym)
-				&& (CLEANMASK(shortcuts[i].mod) == \
-					CLEANMASK(e->state))
-				&& shortcuts[i].func) {
-			shortcuts[i].func(&(shortcuts[i].arg));
+	for(bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
+		if(ksym == bp->keysym && match(bp->mod, e->state)) {
+			bp->func(&(bp->arg));
+			return;
 		}
 	}
 

From a29ab30f256439dd701a475bb0c51eb2d02cafa9 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 15 Nov 2012 20:00:46 +0100
Subject: [PATCH 0406/1146] Adding support for XK_F35.

---
 config.def.h | 43 +++++++++++++++++++++++++++++++++----------
 1 file changed, 33 insertions(+), 10 deletions(-)

diff --git a/config.def.h b/config.def.h
index da1191c..86fefa7 100644
--- a/config.def.h
+++ b/config.def.h
@@ -54,6 +54,16 @@ static unsigned int defaultbg = 0;
 static unsigned int defaultcs = 256;
 static unsigned int defaultucs = 257;
 
+/* Internal shortcuts. */
+#define MODKEY Mod1Mask
+
+static Shortcut shortcuts[] = {
+	/* modifier		key		function	argument */
+	{ MODKEY|ShiftMask,	XK_Prior,	xzoom,		{.i = +1} },
+	{ MODKEY|ShiftMask,	XK_Next,	xzoom,		{.i = -1} },
+	{ ShiftMask,		XK_Insert,	selpaste,	{.i =  0} },
+};
+
 /*
  * Special keys (change & recompile st.info accordingly)
  *
@@ -224,15 +234,28 @@ static Key key[] = {
 	{ XK_F12, /* F36 */ ControlMask,    "\033[24;5~",    0,    0,    0},
 	{ XK_F12, /* F48 */ Mod2Mask,       "\033[24;6~",    0,    0,    0},
 	{ XK_F12, /* F60 */ Mod1Mask,       "\033[24;3~",    0,    0,    0},
-};
-
-/* Internal shortcuts. */
-#define MODKEY Mod1Mask
-
-static Shortcut shortcuts[] = {
-	/* modifier		key		function	argument */
-	{ MODKEY|ShiftMask,	XK_Prior,	xzoom,		{.i = +1} },
-	{ MODKEY|ShiftMask,	XK_Next,	xzoom,		{.i = -1} },
-	{ ShiftMask,		XK_Insert,	selpaste,	{.i =  0} },
+	{ XK_F13,           XK_NO_MOD,      "\033[1;2P",     0,    0,    0},
+	{ XK_F14,           XK_NO_MOD,      "\033[1;2Q",     0,    0,    0},
+	{ XK_F15,           XK_NO_MOD,      "\033[1;2R",     0,    0,    0},
+	{ XK_F16,           XK_NO_MOD,      "\033[1;2S",     0,    0,    0},
+	{ XK_F17,           XK_NO_MOD,      "\033[15;2~",    0,    0,    0},
+	{ XK_F18,           XK_NO_MOD,      "\033[17;2~",    0,    0,    0},
+	{ XK_F19,           XK_NO_MOD,      "\033[18;2~",    0,    0,    0},
+	{ XK_F20,           XK_NO_MOD,      "\033[19;2~",    0,    0,    0},
+	{ XK_F21,           XK_NO_MOD,      "\033[20;2~",    0,    0,    0},
+	{ XK_F22,           XK_NO_MOD,      "\033[21;2~",    0,    0,    0},
+	{ XK_F23,           XK_NO_MOD,      "\033[23;2~",    0,    0,    0},
+	{ XK_F24,           XK_NO_MOD,      "\033[24;2~",    0,    0,    0},
+	{ XK_F25,           XK_NO_MOD,      "\033[1;5P",     0,    0,    0},
+	{ XK_F26,           XK_NO_MOD,      "\033[1;5Q",     0,    0,    0},
+	{ XK_F27,           XK_NO_MOD,      "\033[1;5R",     0,    0,    0},
+	{ XK_F28,           XK_NO_MOD,      "\033[1;5S",     0,    0,    0},
+	{ XK_F29,           XK_NO_MOD,      "\033[15;5~",    0,    0,    0},
+	{ XK_F30,           XK_NO_MOD,      "\033[17;5~",    0,    0,    0},
+	{ XK_F31,           XK_NO_MOD,      "\033[18;5~",    0,    0,    0},
+	{ XK_F32,           XK_NO_MOD,      "\033[19;5~",    0,    0,    0},
+	{ XK_F33,           XK_NO_MOD,      "\033[20;5~",    0,    0,    0},
+	{ XK_F34,           XK_NO_MOD,      "\033[21;5~",    0,    0,    0},
+	{ XK_F35,           XK_NO_MOD,      "\033[23;5~",    0,    0,    0},
 };
 

From 927d8fb45971ddf0eac115ad04161aba6bbd8bc7 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 15 Nov 2012 20:03:18 +0100
Subject: [PATCH 0407/1146] Making all function keys accessible.

---
 config.def.h | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/config.def.h b/config.def.h
index 86fefa7..7a7262c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -174,65 +174,65 @@ static Key key[] = {
 	{ XK_F1,            XK_NO_MOD,      "\033OP" ,       0,    0,    0},
 	{ XK_F1, /* F13 */  ShiftMask,      "\033[1;2P",     0,    0,    0},
 	{ XK_F1, /* F25 */  ControlMask,    "\033[1;5P",     0,    0,    0},
-	{ XK_F1, /* F37 */  Mod2Mask,       "\033[1;6P",     0,    0,    0},
+	{ XK_F1, /* F37 */  Mod4Mask,       "\033[1;6P",     0,    0,    0},
 	{ XK_F1, /* F49 */  Mod1Mask,       "\033[1;3P",     0,    0,    0},
 	{ XK_F1, /* F61 */  Mod3Mask,       "\033[1;4P",     0,    0,    0},
 	{ XK_F2,            XK_NO_MOD,      "\033OQ" ,       0,    0,    0},
 	{ XK_F2, /* F14 */  ShiftMask,      "\033[1;2Q",     0,    0,    0},
 	{ XK_F2, /* F26 */  ControlMask,    "\033[1;5Q",     0,    0,    0},
-	{ XK_F2, /* F38 */  Mod2Mask,       "\033[1;6Q",     0,    0,    0},
+	{ XK_F2, /* F38 */  Mod4Mask,       "\033[1;6Q",     0,    0,    0},
 	{ XK_F2, /* F50 */  Mod1Mask,       "\033[1;3Q",     0,    0,    0},
 	{ XK_F2, /* F62 */  Mod3Mask,       "\033[1;4Q",     0,    0,    0},
 	{ XK_F3,            XK_NO_MOD,      "\033OR" ,       0,    0,    0},
 	{ XK_F3, /* F15 */  ShiftMask,      "\033[1;2R",     0,    0,    0},
 	{ XK_F3, /* F27 */  ControlMask,    "\033[1;5R",     0,    0,    0},
-	{ XK_F3, /* F39 */  Mod2Mask,       "\033[1;6R",     0,    0,    0},
+	{ XK_F3, /* F39 */  Mod4Mask,       "\033[1;6R",     0,    0,    0},
 	{ XK_F3, /* F51 */  Mod1Mask,       "\033[1;3R",     0,    0,    0},
 	{ XK_F3, /* F63 */  Mod3Mask,       "\033[1;4R",     0,    0,    0},
 	{ XK_F4,            XK_NO_MOD,      "\033OS" ,       0,    0,    0},
 	{ XK_F4, /* F16 */  ShiftMask,      "\033[1;2S",     0,    0,    0},
 	{ XK_F4, /* F28 */  ShiftMask,      "\033[1;5S",     0,    0,    0},
-	{ XK_F4, /* F40 */  Mod2Mask,       "\033[1;6S",     0,    0,    0},
+	{ XK_F4, /* F40 */  Mod4Mask,       "\033[1;6S",     0,    0,    0},
 	{ XK_F4, /* F52 */  Mod1Mask,       "\033[1;3S",     0,    0,    0},
 	{ XK_F5,            XK_NO_MOD,      "\033[15~",      0,    0,    0},
 	{ XK_F5, /* F17 */  ShiftMask,      "\033[15;2~",    0,    0,    0},
 	{ XK_F5, /* F29 */  ControlMask,    "\033[15;5~",    0,    0,    0},
-	{ XK_F5, /* F41 */  Mod2Mask,       "\033[15;6~",    0,    0,    0},
+	{ XK_F5, /* F41 */  Mod4Mask,       "\033[15;6~",    0,    0,    0},
 	{ XK_F5, /* F53 */  Mod1Mask,       "\033[15;3~",    0,    0,    0},
 	{ XK_F6,            XK_NO_MOD,      "\033[17~",      0,    0,    0},
 	{ XK_F6, /* F18 */  ShiftMask,      "\033[17;2~",    0,    0,    0},
 	{ XK_F6, /* F30 */  ControlMask,    "\033[17;5~",    0,    0,    0},
-	{ XK_F6, /* F42 */  Mod2Mask,       "\033[17;6~",    0,    0,    0},
+	{ XK_F6, /* F42 */  Mod4Mask,       "\033[17;6~",    0,    0,    0},
 	{ XK_F6, /* F54 */  Mod1Mask,       "\033[17;3~",    0,    0,    0},
 	{ XK_F7,            XK_NO_MOD,      "\033[18~",      0,    0,    0},
 	{ XK_F7, /* F19 */  ShiftMask,      "\033[18;2~",    0,    0,    0},
 	{ XK_F7, /* F31 */  ControlMask,    "\033[18;5~",    0,    0,    0},
-	{ XK_F7, /* F43 */  Mod2Mask,       "\033[18;6~",    0,    0,    0},
+	{ XK_F7, /* F43 */  Mod4Mask,       "\033[18;6~",    0,    0,    0},
 	{ XK_F7, /* F55 */  Mod1Mask,       "\033[18;3~",    0,    0,    0},
 	{ XK_F8,            XK_NO_MOD,      "\033[19~",      0,    0,    0},
 	{ XK_F8, /* F20 */  ShiftMask,      "\033[19;2~",    0,    0,    0},
 	{ XK_F8, /* F32 */  ControlMask,    "\033[19;5~",    0,    0,    0},
-	{ XK_F8, /* F44 */  Mod2Mask,       "\033[19;6~",    0,    0,    0},
+	{ XK_F8, /* F44 */  Mod4Mask,       "\033[19;6~",    0,    0,    0},
 	{ XK_F8, /* F56 */  Mod1Mask,       "\033[19;3~",    0,    0,    0},
 	{ XK_F9,            XK_NO_MOD,      "\033[20~",      0,    0,    0},
 	{ XK_F9, /* F21 */  ShiftMask,      "\033[20;2~",    0,    0,    0},
 	{ XK_F9, /* F33 */  ControlMask,    "\033[20;5~",    0,    0,    0},
-	{ XK_F9, /* F45 */  Mod2Mask,       "\033[20;6~",    0,    0,    0},
+	{ XK_F9, /* F45 */  Mod4Mask,       "\033[20;6~",    0,    0,    0},
 	{ XK_F9, /* F57 */  Mod1Mask,       "\033[20;3~",    0,    0,    0},
 	{ XK_F10,           XK_NO_MOD,      "\033[21~",      0,    0,    0},
 	{ XK_F10, /* F22 */ ShiftMask,      "\033[21;2~",    0,    0,    0},
 	{ XK_F10, /* F34 */ ControlMask,    "\033[21;5~",    0,    0,    0},
-	{ XK_F10, /* F46 */ Mod2Mask,       "\033[21;6~",    0,    0,    0},
+	{ XK_F10, /* F46 */ Mod4Mask,       "\033[21;6~",    0,    0,    0},
 	{ XK_F10, /* F58 */ Mod1Mask,       "\033[21;3~",    0,    0,    0},
 	{ XK_F11,           XK_NO_MOD,      "\033[23~",      0,    0,    0},
 	{ XK_F11, /* F23 */ ShiftMask,      "\033[23;2~",    0,    0,    0},
 	{ XK_F11, /* F35 */ ControlMask,    "\033[23;5~",    0,    0,    0},
-	{ XK_F11, /* F47 */ Mod2Mask,       "\033[23;6~",    0,    0,    0},
+	{ XK_F11, /* F47 */ Mod4Mask,       "\033[23;6~",    0,    0,    0},
 	{ XK_F11, /* F59 */ Mod1Mask,       "\033[23;3~",    0,    0,    0},
 	{ XK_F12,           XK_NO_MOD,      "\033[24~",      0,    0,    0},
 	{ XK_F12, /* F24 */ ShiftMask,      "\033[24;2~",    0,    0,    0},
 	{ XK_F12, /* F36 */ ControlMask,    "\033[24;5~",    0,    0,    0},
-	{ XK_F12, /* F48 */ Mod2Mask,       "\033[24;6~",    0,    0,    0},
+	{ XK_F12, /* F48 */ Mod4Mask,       "\033[24;6~",    0,    0,    0},
 	{ XK_F12, /* F60 */ Mod1Mask,       "\033[24;3~",    0,    0,    0},
 	{ XK_F13,           XK_NO_MOD,      "\033[1;2P",     0,    0,    0},
 	{ XK_F14,           XK_NO_MOD,      "\033[1;2Q",     0,    0,    0},

From 2b6521f5d23da404a597d675d12d4c0cf89657de Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 15 Nov 2012 20:19:35 +0100
Subject: [PATCH 0408/1146] Optimizing the key lookup to the X11 function key.
 It is still possible to

remap other keys.
---
 config.def.h |  6 ++++++
 st.c         | 14 ++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/config.def.h b/config.def.h
index 7a7262c..c0519a8 100644
--- a/config.def.h
+++ b/config.def.h
@@ -88,6 +88,12 @@ static Shortcut shortcuts[] = {
  * position for a key.
  */
 
+/*
+ * If you want something else but the function keys of X11 (0xFF00 - 0xFFFF)
+ * mapped below, add them to this array.
+ */
+static KeySym mappedkeys[] = { -1 };
+
 /* key, mask, output, keypad, cursor, crlf */
 static Key key[] = {
 	/* keysym             mask         string         keypad cursor crlf */
diff --git a/st.c b/st.c
index 477a8f8..02ef411 100644
--- a/st.c
+++ b/st.c
@@ -2711,6 +2711,20 @@ char*
 kmap(KeySym k, uint state) {
 	uint mask;
 	Key *kp;
+	int i;
+
+	/* Check for mapped keys out of X11 function keys. */
+	for(i = 0; i < LEN(mappedkeys); i++) {
+		if(mappedkeys[i] == k) {
+			fprintf(stderr, "mapped function key.\n");
+			break;
+		}
+	}
+	if(i == LEN(mappedkeys)) {
+		if((k & 0xFFFF) < 0xFF00)
+			return NULL;
+	}
+	fprintf(stderr, "Function key.\n");
 
 	for(kp = key; kp < key + LEN(key); kp++) {
 		mask = kp->mask;

From 1cea02be8d331597b3cfccf1d23eb22e57433c85 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 15 Nov 2012 20:25:16 +0100
Subject: [PATCH 0409/1146] Removing my debug fprintf().

---
 st.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 02ef411..0a8382c 100644
--- a/st.c
+++ b/st.c
@@ -2715,16 +2715,13 @@ kmap(KeySym k, uint state) {
 
 	/* Check for mapped keys out of X11 function keys. */
 	for(i = 0; i < LEN(mappedkeys); i++) {
-		if(mappedkeys[i] == k) {
-			fprintf(stderr, "mapped function key.\n");
+		if(mappedkeys[i] == k)
 			break;
-		}
 	}
 	if(i == LEN(mappedkeys)) {
 		if((k & 0xFFFF) < 0xFF00)
 			return NULL;
 	}
-	fprintf(stderr, "Function key.\n");
 
 	for(kp = key; kp < key + LEN(key); kp++) {
 		mask = kp->mask;

From 0df350cd0b64f83fbc2324bb2a1bc04b51e657e0 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 15 Nov 2012 20:57:33 +0100
Subject: [PATCH 0410/1146] Remove unused fields in cursor_movement

---
 st.c |    4 ----
 1 file changed, 4 deletions(-)
---
 st.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/st.c b/st.c
index 0a8382c..db21901 100644
--- a/st.c
+++ b/st.c
@@ -89,10 +89,6 @@ enum glyph_attribute {
 };
 
 enum cursor_movement {
-	CURSOR_UP,
-	CURSOR_DOWN,
-	CURSOR_LEFT,
-	CURSOR_RIGHT,
 	CURSOR_SAVE,
 	CURSOR_LOAD
 };

From 6312f76ca47f94119a7740dd36f7dd6ce037e907 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 15 Nov 2012 20:57:37 +0100
Subject: [PATCH 0411/1146] Fix speech error in comment

---
 st.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index db21901..367ab51 100644
--- a/st.c
+++ b/st.c
@@ -2082,7 +2082,7 @@ tputc(char *c, int len) {
 			}
 		}
 		/*
-		 * All characters which forms part of a sequence are not
+		 * All characters which form part of a sequence are not
 		 * printed
 		 */
 		return;

From 440a19a662cec7aaec07cec47e7743f22f0e5f26 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 15 Nov 2012 21:42:58 +0100
Subject: [PATCH 0412/1146] Getbuttoninfo is always used the same and just a
 helper function. Shrinking it

a bit. Thanks nsz!
---
 st.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/st.c b/st.c
index 367ab51..6dc20fb 100644
--- a/st.c
+++ b/st.c
@@ -621,12 +621,9 @@ selected(int x, int y) {
 }
 
 void
-getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
-	if(b)
-		*b = e->xbutton.button;
-
-	*x = x2col(e->xbutton.x);
-	*y = y2row(e->xbutton.y);
+getbuttoninfo(XEvent *e) {
+	sel.ex = x2col(e->xbutton.x);
+	sel.ey = y2row(e->xbutton.y);
 
 	sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex;
 	sel.b.y = MIN(sel.by, sel.ey);
@@ -824,7 +821,7 @@ brelease(XEvent *e) {
 		selpaste(NULL);
 	} else if(e->xbutton.button == Button1) {
 		sel.mode = 0;
-		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
+		getbuttoninfo(e);
 		term.dirty[sel.ey] = 1;
 		if(sel.bx == sel.ex && sel.by == sel.ey) {
 			sel.bx = -1;
@@ -873,7 +870,7 @@ bmotion(XEvent *e) {
 	if(sel.mode) {
 		oldey = sel.ey;
 		oldex = sel.ex;
-		getbuttoninfo(e, NULL, &sel.ex, &sel.ey);
+		getbuttoninfo(e);
 
 		if(oldey != sel.ey || oldex != sel.ex) {
 			starty = MIN(oldey, sel.ey);

From 1cbe56026b1003d96d81c17e43ff21d1b0064b21 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 16 Nov 2012 05:43:00 +0100
Subject: [PATCH 0413/1146] Fixing some key issues with mc. Thanks nsz!

---
 config.def.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/config.def.h b/config.def.h
index c0519a8..3a2e38b 100644
--- a/config.def.h
+++ b/config.def.h
@@ -170,6 +170,7 @@ static Key key[] = {
 	{ XK_Insert,        XK_ANY_MOD,     "\033[2~",       0,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",     0,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",       0,    0,    0},
+	{ XK_Home,          XK_NO_MOD,      "\033[1~",       0,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,    0,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,    0,    0},
 	{ XK_End,           ShiftMask,      "\033[1;2F",     0,    0,    0},

From 55087ec2c7e78e4349259c4547aa58fa705fa915 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 16 Nov 2012 11:32:17 +0100
Subject: [PATCH 0414/1146] Add application cursor sequences for Home

The commit 'Fixing some key issues with mc' fix the problem where mc didn't
recognize home key because the generated code and the terminfo entry were
different (terminfo khome = \E[1~ but generates \033[H).

Home key in ansi mode should generate the sequence CUP (\033[H) to 0,0 (home
position), but it is also interesting generate a application code which
identifies the key. Real vt520 only generates the ansi sequence CUP, linux
console generates only the application code \033[1~, xterm generates CUP in
ansi mode and \033OH in cursor application mode, rxvt only generates the
application code \033[7~.

This patch sets CUP in ansi mode and \033[1~ in cursor application mode, so
it can be used in both modes and the application mode value is similar to
near values (insert = \033[2~, Prior = \033[5~, Next = \033[6~, End =
\033[4~, Supr = \033[3).
---
 config.def.h |    7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
---
 config.def.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/config.def.h b/config.def.h
index 3a2e38b..023634e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -98,7 +98,8 @@ static KeySym mappedkeys[] = { -1 };
 static Key key[] = {
 	/* keysym             mask         string         keypad cursor crlf */
 	{ XK_KP_Home,       ShiftMask,      "\033[1;2H",     0,    0,    0},
-	{ XK_KP_Home,       XK_ANY_MOD,     "\033[H",        0,    0,    0},
+	{ XK_KP_Home,       XK_ANY_MOD,     "\033[H",        0,   -1,    0},
+	{ XK_KP_Home,       XK_ANY_MOD,     "\033[1~",       0,   +1,    0},
 	{ XK_KP_Up,         XK_ANY_MOD,     "\033Ox",       +1,    0,    0},
 	{ XK_KP_Up,         XK_ANY_MOD,     "\033[A",        0,   -1,    0},
 	{ XK_KP_Up,         XK_ANY_MOD,     "\033OA",        0,   +1,    0},
@@ -170,9 +171,9 @@ static Key key[] = {
 	{ XK_Insert,        XK_ANY_MOD,     "\033[2~",       0,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",     0,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",       0,    0,    0},
-	{ XK_Home,          XK_NO_MOD,      "\033[1~",       0,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,    0,    0},
-	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,    0,    0},
+	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1,    0},
+	{ XK_Home,          XK_ANY_MOD,     "\033[1~",       0,   +1,    0},
 	{ XK_End,           ShiftMask,      "\033[1;2F",     0,    0,    0},
 	{ XK_End,           XK_ANY_MOD,     "\033[4~",       0,    0,    0},
 	{ XK_Prior,         XK_NO_MOD,      "\033[5~",       0,    0,    0},

From cf04354e06aa0ee54b0f8e9b9491dd0e39d8c4ea Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 19 Nov 2012 17:22:32 +0100
Subject: [PATCH 0415/1146] Restoring the Alt + Backspace functionality. Thanks
 Brandon Invergo!

---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 023634e..8543ea2 100644
--- a/config.def.h
+++ b/config.def.h
@@ -141,7 +141,7 @@ static Key key[] = {
 	{ XK_KP_7,          XK_ANY_MOD,     "\033Ow",       +1,    0,    0},
 	{ XK_KP_8,          XK_ANY_MOD,     "\033Ox",       +1,    0,    0},
 	{ XK_KP_9,          XK_ANY_MOD,     "\033Oy",       +1,    0,    0},
-	{ XK_BackSpace,     XK_ANY_MOD,     "\177",          0,    0,    0},
+	{ XK_BackSpace,     XK_NO_MOD,      "\177",          0,    0,    0},
 	{ XK_Up,            ShiftMask,      "\033[1;2A",     0,    0,    0},
 	{ XK_Up,            ControlMask,    "\033[1;5A",     0,    0,    0},
 	{ XK_Up,            Mod1Mask,       "\033[1;3A",     0,    0,    0},

From b26df1d0d3f7791504150820e7c105b20c6b1c3b Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 21 Nov 2012 20:38:15 +0100
Subject: [PATCH 0416/1146] Fixing the calculation of the base tty pixel size.

---
 st.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/st.c b/st.c
index 6dc20fb..1647cbd 100644
--- a/st.c
+++ b/st.c
@@ -2182,8 +2182,8 @@ tresize(int col, int row) {
 
 void
 xresize(int col, int row) {
-	xw.tw = MAX(1, 2*borderpx + col * xw.cw);
-	xw.th = MAX(1, 2*borderpx + row * xw.ch);
+	xw.tw = MAX(1, col * xw.cw);
+	xw.th = MAX(1, row * xw.ch);
 
 	XftDrawChange(xw.draw, xw.buf);
 }
@@ -2259,8 +2259,8 @@ xhints(void) {
 		sizeh->width = xw.w;
 		sizeh->height_inc = xw.ch;
 		sizeh->width_inc = xw.cw;
-		sizeh->base_height = 2*borderpx;
-		sizeh->base_width = 2*borderpx;
+		sizeh->base_height = 2 * borderpx;
+		sizeh->base_width = 2 * borderpx;
 	} else {
 		sizeh->flags = PMaxSize | PMinSize;
 		sizeh->min_width = sizeh->max_width = xw.fw;
@@ -2393,8 +2393,8 @@ xinit(void) {
 		xw.w = xw.fw;
 	} else {
 		/* window - default size */
-		xw.h = 2*borderpx + term.row * xw.ch;
-		xw.w = 2*borderpx + term.col * xw.cw;
+		xw.h = 2 * borderpx + term.row * xw.ch;
+		xw.w = 2 * borderpx + term.col * xw.cw;
 		xw.fx = 0;
 		xw.fy = 0;
 	}
@@ -2818,8 +2818,8 @@ cresize(int width, int height)
 	if(height != 0)
 		xw.h = height;
 
-	col = (xw.w - 2*borderpx) / xw.cw;
-	row = (xw.h - 2*borderpx) / xw.ch;
+	col = (xw.w - 2 * borderpx) / xw.cw;
+	row = (xw.h - 2 * borderpx) / xw.ch;
 
 	tresize(col, row);
 	xresize(col, row);

From 172f65436ce14a52842d67b862fdc45f8ff3ada3 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 25 Nov 2012 09:23:02 +0100
Subject: [PATCH 0417/1146] Add key for toogling numlock handling

Keypad will generate keycodes when keypad application mode is enabled. It
can cause problems with some programs like vi, which operates in such
mode.

This patch change by default don't generate the keycodes never, but this
behaviour can be changed using the combination Alt + NumLock.
---
 config.def.h |   34 ++++++++++++++++++----------------
 st.c         |   17 +++++++++++++++--
 2 files changed, 33 insertions(+), 18 deletions(-)
---
 config.def.h | 34 ++++++++++++++++++----------------
 st.c         | 17 +++++++++++++++--
 2 files changed, 33 insertions(+), 18 deletions(-)

diff --git a/config.def.h b/config.def.h
index 8543ea2..7c55ef2 100644
--- a/config.def.h
+++ b/config.def.h
@@ -62,6 +62,7 @@ static Shortcut shortcuts[] = {
 	{ MODKEY|ShiftMask,	XK_Prior,	xzoom,		{.i = +1} },
 	{ MODKEY|ShiftMask,	XK_Next,	xzoom,		{.i = -1} },
 	{ ShiftMask,		XK_Insert,	selpaste,	{.i =  0} },
+	{ MODKEY,		XK_Num_Lock,	numlock,	{.i =  0} },
 };
 
 /*
@@ -73,6 +74,7 @@ static Shortcut shortcuts[] = {
  * keypad value:
  * * 0: no value
  * * > 0: keypad application mode enabled
+ * *   = 2: term.numlock = 1
  * * < 0: keypad application mode disabled
  * cursor value:
  * * 0: no value
@@ -123,24 +125,24 @@ static Key key[] = {
 	{ XK_KP_Insert,     XK_ANY_MOD,     "\033[2~",       0,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",     0,    0,    0},
 	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",       0,    0,    0},
-	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +1,    0,    0},
-	{ XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +1,    0,    0},
-	{ XK_KP_Enter,      XK_ANY_MOD,     "\033OM",       +1,    0,    0},
+	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +2,    0,    0},
+	{ XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +2,    0,    0},
+	{ XK_KP_Enter,      XK_ANY_MOD,     "\033OM",       +2,    0,    0},
 	{ XK_KP_Enter,      XK_ANY_MOD,     "\r",           -1,    0,   -1},
 	{ XK_KP_Enter,      XK_ANY_MOD,     "\r\n",         -1,    0,   +1},
-	{ XK_KP_Subtract,   XK_ANY_MOD,     "\033Om",       +1,    0,    0},
-	{ XK_KP_Decimal,    XK_ANY_MOD,     "\033On",       +1,    0,    0},
-	{ XK_KP_Divide,     XK_ANY_MOD,     "\033Oo",       +1,    0,    0},
-	{ XK_KP_0,          XK_ANY_MOD,     "\033Op",       +1,    0,    0},
-	{ XK_KP_1,          XK_ANY_MOD,     "\033Oq",       +1,    0,    0},
-	{ XK_KP_2,          XK_ANY_MOD,     "\033Or",       +1,    0,    0},
-	{ XK_KP_3,          XK_ANY_MOD,     "\033Os",       +1,    0,    0},
-	{ XK_KP_4,          XK_ANY_MOD,     "\033Ot",       +1,    0,    0},
-	{ XK_KP_5,          XK_ANY_MOD,     "\033Ou",       +1,    0,    0},
-	{ XK_KP_6,          XK_ANY_MOD,     "\033Ov",       +1,    0,    0},
-	{ XK_KP_7,          XK_ANY_MOD,     "\033Ow",       +1,    0,    0},
-	{ XK_KP_8,          XK_ANY_MOD,     "\033Ox",       +1,    0,    0},
-	{ XK_KP_9,          XK_ANY_MOD,     "\033Oy",       +1,    0,    0},
+	{ XK_KP_Subtract,   XK_ANY_MOD,     "\033Om",       +2,    0,    0},
+	{ XK_KP_Decimal,    XK_ANY_MOD,     "\033On",       +2,    0,    0},
+	{ XK_KP_Divide,     XK_ANY_MOD,     "\033Oo",       +2,    0,    0},
+	{ XK_KP_0,          XK_ANY_MOD,     "\033Op",       +2,    0,    0},
+	{ XK_KP_1,          XK_ANY_MOD,     "\033Oq",       +2,    0,    0},
+	{ XK_KP_2,          XK_ANY_MOD,     "\033Or",       +2,    0,    0},
+	{ XK_KP_3,          XK_ANY_MOD,     "\033Os",       +2,    0,    0},
+	{ XK_KP_4,          XK_ANY_MOD,     "\033Ot",       +2,    0,    0},
+	{ XK_KP_5,          XK_ANY_MOD,     "\033Ou",       +2,    0,    0},
+	{ XK_KP_6,          XK_ANY_MOD,     "\033Ov",       +2,    0,    0},
+	{ XK_KP_7,          XK_ANY_MOD,     "\033Ow",       +2,    0,    0},
+	{ XK_KP_8,          XK_ANY_MOD,     "\033Ox",       +2,    0,    0},
+	{ XK_KP_9,          XK_ANY_MOD,     "\033Oy",       +2,    0,    0},
 	{ XK_BackSpace,     XK_NO_MOD,      "\177",          0,    0,    0},
 	{ XK_Up,            ShiftMask,      "\033[1;2A",     0,    0,    0},
 	{ XK_Up,            ControlMask,    "\033[1;5A",     0,    0,    0},
diff --git a/st.c b/st.c
index 1647cbd..671b386 100644
--- a/st.c
+++ b/st.c
@@ -194,6 +194,7 @@ typedef struct {
 	int bot;	/* bottom scroll limit */
 	int mode;	/* terminal mode flags */
 	int esc;	/* escape state flags */
+	bool numlock;	/* lock numbers in keyboard */
 	bool *tabs;
 } Term;
 
@@ -261,6 +262,7 @@ typedef struct {
 /* function definitions used in config.h */
 static void xzoom(const Arg *);
 static void selpaste(const Arg *);
+static void numlock(const Arg *);
 
 /* Config.h for applying patches and the configuration. */
 #include "config.h"
@@ -1100,6 +1102,7 @@ tnew(int col, int row) {
 		term.alt [row] = xmalloc(term.col * sizeof(Glyph));
 		term.dirty[row] = 0;
 	}
+	term.numlock = 1;
 	memset(term.tabs, 0, term.col * sizeof(*term.tabs));
 	/* setup screen */
 	treset();
@@ -2700,6 +2703,12 @@ match(uint mask, uint state) {
 	return true;
 }
 
+void
+numlock(const Arg *dummy)
+{
+	term.numlock ^= 1;
+}
+
 char*
 kmap(KeySym k, uint state) {
 	uint mask;
@@ -2725,8 +2734,12 @@ kmap(KeySym k, uint state) {
 		if(!match(mask, state))
 			continue;
 
-		if((kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) ||
-				(kp->appkey > 0 && !IS_SET(MODE_APPKEYPAD))) {
+		if(kp->appkey > 0) {
+			if(!IS_SET(MODE_APPKEYPAD))
+				continue;
+			if(term.numlock && kp->appkey == 2)
+				continue;
+		} else if (kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) {
 			continue;
 		}
 

From 373a8f56286d72ae10c9d3a2a7326e2515d141d9 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 25 Nov 2012 09:23:34 +0100
Subject: [PATCH 0418/1146] The style inquisition was here.

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 671b386..900b567 100644
--- a/st.c
+++ b/st.c
@@ -1102,6 +1102,7 @@ tnew(int col, int row) {
 		term.alt [row] = xmalloc(term.col * sizeof(Glyph));
 		term.dirty[row] = 0;
 	}
+
 	term.numlock = 1;
 	memset(term.tabs, 0, term.col * sizeof(*term.tabs));
 	/* setup screen */
@@ -2704,8 +2705,7 @@ match(uint mask, uint state) {
 }
 
 void
-numlock(const Arg *dummy)
-{
+numlock(const Arg *dummy) {
 	term.numlock ^= 1;
 }
 

From 61b20f4bc1eae90fd9d5f3582252d6181ee21b4f Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 25 Nov 2012 15:59:16 +0100
Subject: [PATCH 0419/1146] Add a notice in the config.def.h file how to obtain
 the syntax for

xft/fontcache.
---
 config.def.h | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 7c55ef2..742e84e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,6 +1,10 @@
 /* See LICENSE file for copyright and license details. */
 
-/* appearance */
+/*
+ * appearance
+ *
+ * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
+ */
 static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=false";
 static int borderpx = 2;
 static char shell[] = "/bin/sh";

From e7904128c61f96b2adbed6e946964053c70e3d4e Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 25 Nov 2012 22:13:13 +0100
Subject: [PATCH 0420/1146] Fix value of ka1 terminfo capability

ka1 stands for upper left of keypad, so the correct value is the one
generated by Home in application keypad mode.
---
 st.info |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
---
 st.info | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.info b/st.info
index bb8145b..d0064db 100644
--- a/st.info
+++ b/st.info
@@ -49,7 +49,7 @@ st| simpleterm,
 	invis=\E[8m,
 	is2=\E[4l\E>,
 	it#8,
-	ka1=\E[E,
+	ka1=\E[1~,
 	ka3=\E[5~,
 	kc1=\E[4~,
 	kc3=\E[6~,

From 3c99be68e8d3c4d67b2db54b8650bf55d769b98e Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 25 Nov 2012 22:13:19 +0100
Subject: [PATCH 0421/1146] Add support for insert key

Insert key stands for a key which allows enter or leaves insert mode, so let
it generates the correct sequence to change between these modes:

   - Insert: Enter in insert mode.
   - Shift + Insert: Leave insert mode (replace mode).
   - Control + Insert: Insert a blank line.

Like Shift + Insert also paste text, if a user want this feature be full
functional he has to modify such shortcut.
---
 config.def.h |   16 ++++++++++++----
 st.info      |    3 +++
 2 files changed, 15 insertions(+), 4 deletions(-)
---
 config.def.h | 16 ++++++++++++----
 st.info      |  3 +++
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index 742e84e..a3e87e2 100644
--- a/config.def.h
+++ b/config.def.h
@@ -125,8 +125,12 @@ static Key key[] = {
 	{ XK_KP_End,        XK_ANY_MOD,     "\033[4~",       0,    0,    0},
 	{ XK_KP_Next,       ShiftMask,      "\033[6;2~",     0,    0,    0},
 	{ XK_KP_Next,       XK_ANY_MOD,     "\033[6~",       0,    0,    0},
-	{ XK_KP_Insert,     ShiftMask,      "\033[2;2~",     0,    0,    0},
-	{ XK_KP_Insert,     XK_ANY_MOD,     "\033[2~",       0,    0,    0},
+	{ XK_KP_Insert,     ShiftMask,      "\033[2;2~",    +1,    0,    0},
+	{ XK_KP_Insert,     ShiftMask,      "\033[4l",      -1,    0,    0},
+	{ XK_KP_Insert,     ControlMask,    "\033[L",       -1,    0,    0},
+	{ XK_KP_Insert,     ControlMask,    "\033[2;5~",    +1,    0,    0},
+	{ XK_KP_Insert,     XK_ANY_MOD,     "\033[4h",      -1,    0,    0},
+	{ XK_KP_Insert,     XK_ANY_MOD,     "\033[2~",      +1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",     0,    0,    0},
 	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",       0,    0,    0},
 	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +2,    0,    0},
@@ -173,8 +177,12 @@ static Key key[] = {
 	{ XK_Return,        Mod1Mask,       "\033\r\n",      0,    0,   +1},
 	{ XK_Return,        XK_ANY_MOD,     "\r",            0,    0,   -1},
 	{ XK_Return,        XK_ANY_MOD,     "\r\n",          0,    0,   +1},
-	{ XK_Insert,        ShiftMask,      "\033[2;2~",     0,    0,    0},
-	{ XK_Insert,        XK_ANY_MOD,     "\033[2~",       0,    0,    0},
+	{ XK_Insert,        ShiftMask,      "\033[4l",      -1,    0,    0},
+	{ XK_Insert,        ShiftMask,      "\033[2;2~",    +1,    0,    0},
+	{ XK_Insert,        ControlMask,    "\033[L",       -1,    0,    0},
+	{ XK_Insert,        ControlMask,    "\033[2;5~",    +1,    0,    0},
+	{ XK_Insert,        XK_ANY_MOD,     "\033[4h",      -1,    0,    0},
+	{ XK_Insert,        XK_ANY_MOD,     "\033[2~",      +1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",     0,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",       0,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,    0,    0},
diff --git a/st.info b/st.info
index d0064db..4fc9bdb 100644
--- a/st.info
+++ b/st.info
@@ -138,6 +138,9 @@ st| simpleterm,
 	kf62=\E[1;4Q,
 	kf63=\E[1;4R,
 	khome=\E[1~,
+	kil1=\E[2;5~,
+	krmir=\E[2;2~,
+	kich1=\E[2~,
 	knp=\E[6~,
 	kmous=\E[M,
 	kpp=\E[5~,

From 7c34ff1703381c4d0c2ea602ddd607597bd32ad5 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 25 Nov 2012 22:13:24 +0100
Subject: [PATCH 0422/1146] Add support for Supr key

    Del : Delete character under cursor.
    Shift + Del : Delete the line under cursor.
    Ctrl + Del: Delete the full screen.
---
 config.def.h |   16 ++++++++++++----
 st.info      |    2 ++
 2 files changed, 14 insertions(+), 4 deletions(-)
---
 config.def.h | 16 ++++++++++++----
 st.info      |  2 ++
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index a3e87e2..6d74668 100644
--- a/config.def.h
+++ b/config.def.h
@@ -131,8 +131,12 @@ static Key key[] = {
 	{ XK_KP_Insert,     ControlMask,    "\033[2;5~",    +1,    0,    0},
 	{ XK_KP_Insert,     XK_ANY_MOD,     "\033[4h",      -1,    0,    0},
 	{ XK_KP_Insert,     XK_ANY_MOD,     "\033[2~",      +1,    0,    0},
-	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",     0,    0,    0},
-	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",       0,    0,    0},
+	{ XK_KP_Delete,     ControlMask,    "\033[2J",      -1,    0,    0},
+	{ XK_KP_Delete,     ControlMask,    "\033[3;5~",    +1,    0,    0},
+	{ XK_KP_Delete,     ShiftMask,      "\033[2K",      +1,    0,    0},
+	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",    -1,    0,    0},
+	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[P",       -1,    0,    0},
+	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
 	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +2,    0,    0},
 	{ XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +2,    0,    0},
 	{ XK_KP_Enter,      XK_ANY_MOD,     "\033OM",       +2,    0,    0},
@@ -183,8 +187,12 @@ static Key key[] = {
 	{ XK_Insert,        ControlMask,    "\033[2;5~",    +1,    0,    0},
 	{ XK_Insert,        XK_ANY_MOD,     "\033[4h",      -1,    0,    0},
 	{ XK_Insert,        XK_ANY_MOD,     "\033[2~",      +1,    0,    0},
-	{ XK_Delete,        ShiftMask,      "\033[3;2~",     0,    0,    0},
-	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",       0,    0,    0},
+	{ XK_Delete,        ControlMask,    "\033[2J",      -1,    0,    0},
+	{ XK_Delete,        ControlMask,    "\033[3;5~",    +1,    0,    0},
+	{ XK_Delete,        ShiftMask,      "\033[2K",      +1,    0,    0},
+	{ XK_Delete,        ShiftMask,      "\033[3;2~",    -1,    0,    0},
+	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
+	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,    0,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[1~",       0,   +1,    0},
diff --git a/st.info b/st.info
index 4fc9bdb..9a7edfe 100644
--- a/st.info
+++ b/st.info
@@ -71,6 +71,8 @@ st| simpleterm,
 	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~,

From d5994b43ca78196b81ea276d7acb5ef2d4a671f7 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 25 Nov 2012 22:13:29 +0100
Subject: [PATCH 0423/1146] Add support for End key

    - Shift + End : Delete until end of line.
    - Control + End : Delete until end of screen.

When  the End  key is  pressed  without any  modifier is  not generated  the
correct sequence for it  (going to the end of the  screen), because the size
of the  terminal is not known,  so it is  not possible write a  sequence for
this purpouse.
---
 config.def.h |   10 ++++++++--
 st.info      |    2 ++
 2 files changed, 10 insertions(+), 2 deletions(-)
---
 config.def.h | 10 ++++++++--
 st.info      |  2 ++
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/config.def.h b/config.def.h
index 6d74668..684adf7 100644
--- a/config.def.h
+++ b/config.def.h
@@ -121,7 +121,10 @@ static Key key[] = {
 	{ XK_KP_Prior,      ShiftMask,      "\033[5;2~",     0,    0,    0},
 	{ XK_KP_Prior,      XK_ANY_MOD,     "\033[5~",	     0,    0,    0},
 	{ XK_KP_Begin,      XK_ANY_MOD,     "\033[E",        0,    0,    0},
-	{ XK_KP_End,        ShiftMask,      "\033[1;2F",     0,    0,    0},
+	{ XK_KP_End,        ControlMask,    "\033[J",       -1,    0,    0},
+	{ XK_KP_End,        ControlMask,    "\033[1;5F",    +1,    0,    0},
+	{ XK_KP_End,        ShiftMask,      "\033[K",       -1,    0,    0},
+	{ XK_KP_End,        ShiftMask,      "\033[1;2F",    +1,    0,    0},
 	{ XK_KP_End,        XK_ANY_MOD,     "\033[4~",       0,    0,    0},
 	{ XK_KP_Next,       ShiftMask,      "\033[6;2~",     0,    0,    0},
 	{ XK_KP_Next,       XK_ANY_MOD,     "\033[6~",       0,    0,    0},
@@ -196,7 +199,10 @@ static Key key[] = {
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,    0,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[1~",       0,   +1,    0},
-	{ XK_End,           ShiftMask,      "\033[1;2F",     0,    0,    0},
+	{ XK_End,           ControlMask,    "\033[J",       -1,    0,    0},
+	{ XK_End,           ControlMask,    "\033[1;5F",    +1,    0,    0},
+	{ XK_End,           ShiftMask,      "\033[K",       -1,    0,    0},
+	{ XK_End,           ShiftMask,      "\033[1;2F",    +1,    0,    0},
 	{ XK_End,           XK_ANY_MOD,     "\033[4~",       0,    0,    0},
 	{ XK_Prior,         XK_NO_MOD,      "\033[5~",       0,    0,    0},
 	{ XK_Next,          ShiftMask,      "\033[6;2~",     0,    0,    0},
diff --git a/st.info b/st.info
index 9a7edfe..52ae851 100644
--- a/st.info
+++ b/st.info
@@ -49,6 +49,8 @@ st| simpleterm,
 	invis=\E[8m,
 	is2=\E[4l\E>,
 	it#8,
+	kel=\E[1;2F,
+	ked=\E[1;5F,
 	ka1=\E[1~,
 	ka3=\E[5~,
 	kc1=\E[4~,

From fdce8bba1a87fe1639aa9e7537ed93cf29138761 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 9 Dec 2012 21:39:02 +0100
Subject: [PATCH 0424/1146] =?UTF-8?q?Applying=20the=20change=20of=20the=20?=
 =?UTF-8?q?Del=20key=20assingment.=20Thanks=20Martti=20K=C3=BChne!?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 config.def.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config.def.h b/config.def.h
index 684adf7..a3d777c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -138,8 +138,8 @@ static Key key[] = {
 	{ XK_KP_Delete,     ControlMask,    "\033[3;5~",    +1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[2K",      +1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",    -1,    0,    0},
-	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[P",       -1,    0,    0},
 	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
+	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[P",       -1,    0,    0},
 	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +2,    0,    0},
 	{ XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +2,    0,    0},
 	{ XK_KP_Enter,      XK_ANY_MOD,     "\033OM",       +2,    0,    0},
@@ -194,8 +194,8 @@ static Key key[] = {
 	{ XK_Delete,        ControlMask,    "\033[3;5~",    +1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[2K",      +1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",    -1,    0,    0},
-	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
+	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,    0,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[1~",       0,   +1,    0},

From fe3fb82d29bd4c3b2194aa7b66733de4c8cd2161 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 10 Dec 2012 15:02:32 +0100
Subject: [PATCH 0425/1146] Applying the patch of mar771 right.

---
 config.def.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index a3d777c..b10c730 100644
--- a/config.def.h
+++ b/config.def.h
@@ -138,8 +138,8 @@ static Key key[] = {
 	{ XK_KP_Delete,     ControlMask,    "\033[3;5~",    +1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[2K",      +1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",    -1,    0,    0},
-	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
-	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[P",       -1,    0,    0},
+	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",      -1,    0,    0},
+	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[P",       +1,    0,    0},
 	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +2,    0,    0},
 	{ XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +2,    0,    0},
 	{ XK_KP_Enter,      XK_ANY_MOD,     "\033OM",       +2,    0,    0},
@@ -194,8 +194,8 @@ static Key key[] = {
 	{ XK_Delete,        ControlMask,    "\033[3;5~",    +1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[2K",      +1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",    -1,    0,    0},
-	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
-	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
+	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      -1,    0,    0},
+	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       +1,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,    0,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[1~",       0,   +1,    0},

From 78215c8ee0f4cb62655730260520f185ce97c620 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 10 Dec 2012 20:45:46 +0100
Subject: [PATCH 0426/1146] Fixing the nasty selection bug. Thanks
 p37sitdu@lavabit.com!

---
 st.c | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index 900b567..fc64a77 100644
--- a/st.c
+++ b/st.c
@@ -73,7 +73,7 @@
 #define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (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 IS_SET(flag) (term.mode & (flag))
+#define IS_SET(flag) ((term.mode & (flag)) != 0)
 #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
 
 #define VT102ID "\033[?6c"
@@ -624,6 +624,8 @@ selected(int x, int y) {
 
 void
 getbuttoninfo(XEvent *e) {
+	sel.alt = IS_SET(MODE_ALTSCREEN);
+
 	sel.ex = x2col(e->xbutton.x);
 	sel.ey = y2row(e->xbutton.y);
 
@@ -722,7 +724,6 @@ selcopy(void) {
 		}
 		*ptr = 0;
 	}
-	sel.alt = IS_SET(MODE_ALTSCREEN);
 	xsetsel(str);
 }
 
@@ -869,16 +870,17 @@ bmotion(XEvent *e) {
 		return;
 	}
 
-	if(sel.mode) {
-		oldey = sel.ey;
-		oldex = sel.ex;
-		getbuttoninfo(e);
+	if(!sel.mode)
+		return;
 
-		if(oldey != sel.ey || oldex != sel.ex) {
-			starty = MIN(oldey, sel.ey);
-			endy = MAX(oldey, sel.ey);
-			tsetdirt(starty, endy);
-		}
+	oldey = sel.ey;
+	oldex = sel.ex;
+	getbuttoninfo(e);
+
+	if(oldey != sel.ey || oldex != sel.ex) {
+		starty = MIN(oldey, sel.ey);
+		endy = MAX(oldey, sel.ey);
+		tsetdirt(starty, endy);
 	}
 }
 
@@ -1510,7 +1512,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 1049: /* = 1047 and 1048 */
 			case 47:
 			case 1047: {
-				alt = IS_SET(MODE_ALTSCREEN) != 0;
+				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 */
@@ -2603,10 +2605,11 @@ drawregion(int x1, int y1, int x2, int y2) {
 	int ic, ib, x, y, ox, sl;
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
-	bool ena_sel = sel.bx != -1, alt = IS_SET(MODE_ALTSCREEN) != 0;
+	bool ena_sel = sel.bx != -1;
 
-	if((sel.alt != 0) ^ alt)
+	if(sel.alt ^ IS_SET(MODE_ALTSCREEN))
 		ena_sel = 0;
+
 	if(!(xw.state & WIN_VISIBLE))
 		return;
 

From 2696f8187509eb94644bbac5b05348e37c391bea Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 10 Dec 2012 23:02:58 +0100
Subject: [PATCH 0427/1146] Be careful about mar77i's patches.

---
 config.def.h | 8 ++++----
 st.c         | 5 +++--
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/config.def.h b/config.def.h
index b10c730..684adf7 100644
--- a/config.def.h
+++ b/config.def.h
@@ -138,8 +138,8 @@ static Key key[] = {
 	{ XK_KP_Delete,     ControlMask,    "\033[3;5~",    +1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[2K",      +1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",    -1,    0,    0},
-	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",      -1,    0,    0},
-	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[P",       +1,    0,    0},
+	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[P",       -1,    0,    0},
+	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
 	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +2,    0,    0},
 	{ XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +2,    0,    0},
 	{ XK_KP_Enter,      XK_ANY_MOD,     "\033OM",       +2,    0,    0},
@@ -194,8 +194,8 @@ static Key key[] = {
 	{ XK_Delete,        ControlMask,    "\033[3;5~",    +1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[2K",      +1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",    -1,    0,    0},
-	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      -1,    0,    0},
-	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       +1,    0,    0},
+	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
+	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,    0,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[1~",       0,   +1,    0},
diff --git a/st.c b/st.c
index fc64a77..42061b9 100644
--- a/st.c
+++ b/st.c
@@ -2742,12 +2742,13 @@ kmap(KeySym k, uint state) {
 				continue;
 			if(term.numlock && kp->appkey == 2)
 				continue;
-		} else if (kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) {
+		} else if(kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) {
 			continue;
 		}
 
 		if((kp->appcursor < 0 && IS_SET(MODE_APPCURSOR)) ||
-				(kp->appcursor > 0 && !IS_SET(MODE_APPCURSOR))) {
+				(kp->appcursor > 0
+				 && !IS_SET(MODE_APPCURSOR))) {
 			continue;
 		}
 

From 3c6ec1995d8ec4d8d5da7ca81d15adfdb08086aa Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 11 Dec 2012 08:32:08 +0100
Subject: [PATCH 0428/1146] Adding error checks for XCreateIC and XOpenIM.

---
 TODO | 1 -
 st.c | 4 ++++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/TODO b/TODO
index b1af774..a4cfeee 100644
--- a/TODO
+++ b/TODO
@@ -17,7 +17,6 @@ code & interface
 bugs
 ----
 
-* handle XOpenMI() errors
 * fix shift up/down (shift selection in emacs)
 * fix selection paste for xatom STRING
 * fix umlaut handling in settitle
diff --git a/st.c b/st.c
index 42061b9..da5f78d 100644
--- a/st.c
+++ b/st.c
@@ -2431,9 +2431,13 @@ xinit(void) {
 
 	/* input methods */
 	xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
+	if(xw.xim == NULL)
+		die("XOpenIM failed. Could not open input device.\n");
 	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
 					   | XIMStatusNothing, XNClientWindow, xw.win,
 					   XNFocusWindow, xw.win, NULL);
+	if(xw.xic == NULL)
+		die("XCreateIC failed. Could not obtain input method.\n");
 
 	/* white cursor, black outline */
 	cursor = XCreateFontCursor(xw.dpy, XC_xterm);

From fc2b3669682eaf571fc96762bd3c8e48bccac989 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 13 Dec 2012 20:57:15 +0100
Subject: [PATCH 0429/1146] Checking for the lower X11 special keys too. Thanks
 Benjamin R. Haskell!

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index da5f78d..433f7b4 100644
--- a/st.c
+++ b/st.c
@@ -2728,7 +2728,7 @@ kmap(KeySym k, uint state) {
 			break;
 	}
 	if(i == LEN(mappedkeys)) {
-		if((k & 0xFFFF) < 0xFF00)
+		if((k & 0xFFFF) < 0xFD00)
 			return NULL;
 	}
 

From 4d37763ee767d0c8bd8425744c3375817967dda3 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 18 Dec 2012 13:00:00 +0100
Subject: [PATCH 0430/1146] Fixing a precedence problem. Thanks tridactyla!

---
 README | 1 +
 st.c   | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/README b/README
index f6c5d78..e801c02 100644
--- a/README
+++ b/README
@@ -33,3 +33,4 @@ 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.c b/st.c
index 433f7b4..aa72a43 100644
--- a/st.c
+++ b/st.c
@@ -2525,11 +2525,11 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	/* Intelligent cleaning up of the borders. */
 	if(x == 0) {
 		xclear(0, (y == 0)? 0 : winy, borderpx,
-			winy + xw.ch + (y == term.row-1)? xw.h : 0);
+			winy + xw.ch + ((y == term.row-1)? xw.h : 0));
 	}
 	if(x + charlen >= term.col-1) {
 		xclear(winx + width, (y == 0)? 0 : winy, xw.w,
-			(y == term.row-1)? xw.h : (winy + xw.ch));
+			((y == term.row-1)? xw.h : (winy + xw.ch)));
 	}
 	if(y == 0)
 		xclear(winx, 0, winx + width, borderpx);

From ac4c6da4ef9b05e2886c26272745effc4f975042 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 22 Dec 2012 13:39:27 +0100
Subject: [PATCH 0431/1146] Fixing a off-by-one error in the penultimate row
 drawing.

---
 st.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index aa72a43..d47bebc 100644
--- a/st.c
+++ b/st.c
@@ -2248,7 +2248,7 @@ xtermclear(int col1, int row1, int col2, int row2) {
 void
 xclear(int x1, int y1, int x2, int y2) {
 	XftDrawRect(xw.draw,
-			&dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
+			&dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg],
 			x1, y1, x2-x1, y2-y1);
 }
 
@@ -2515,8 +2515,11 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		}
 	}
 
-	if(base.mode & ATTR_REVERSE)
-		temp = fg, fg = bg, bg = temp;
+	if(base.mode & ATTR_REVERSE) {
+		temp = fg;
+		fg = bg;
+		bg = temp;
+	}
 
 	XftTextExtentsUtf8(xw.dpy, font->set, (FcChar8 *)s, bytelen,
 			&extents);
@@ -2525,11 +2528,11 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	/* Intelligent cleaning up of the borders. */
 	if(x == 0) {
 		xclear(0, (y == 0)? 0 : winy, borderpx,
-			winy + xw.ch + ((y == term.row-1)? xw.h : 0));
+			winy + xw.ch + ((y >= term.row-1)? xw.h : 0));
 	}
-	if(x + charlen >= term.col-1) {
+	if(x + charlen >= term.col)
 		xclear(winx + width, (y == 0)? 0 : winy, xw.w,
-			((y == term.row-1)? xw.h : (winy + xw.ch)));
+			((y >= term.row-1)? xw.h : (winy + xw.ch)));
 	}
 	if(y == 0)
 		xclear(winx, 0, winx + width, borderpx);

From 082bab29f3551e5cee332832ff767c3fb65a5cbc Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 22 Dec 2012 19:50:02 +0100
Subject: [PATCH 0432/1146] Fixing a compile error.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index d47bebc..8074df9 100644
--- a/st.c
+++ b/st.c
@@ -2530,7 +2530,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		xclear(0, (y == 0)? 0 : winy, borderpx,
 			winy + xw.ch + ((y >= term.row-1)? xw.h : 0));
 	}
-	if(x + charlen >= term.col)
+	if(x + charlen >= term.col) {
 		xclear(winx + width, (y == 0)? 0 : winy, xw.w,
 			((y >= term.row-1)? xw.h : (winy + xw.ch)));
 	}

From 9c44229c626ea7351a7809540435f40cffb624bc Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 28 Dec 2012 23:52:04 +0100
Subject: [PATCH 0433/1146] Adding fallback support to st.

---
 st.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 189 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index 8074df9..a440959 100644
--- a/st.c
+++ b/st.c
@@ -275,7 +275,9 @@ typedef struct {
 	int descent;
 	short lbearing;
 	short rbearing;
-	XftFont *set;
+	XftFont *match;
+	FcFontSet *set;
+	FcPattern *pattern;
 } Font;
 
 /* Drawing Context */
@@ -338,10 +340,13 @@ static void xclear(int, int, int, int);
 static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
+static int xloadfont(Font *, FcPattern *);
+static void xloadfonts(char *, int);
 static void xresettitle(void);
 static void xseturgency(int);
 static void xsetsel(char*);
 static void xtermclear(int, int, int, int);
+static void xunloadfonts(void);
 static void xresize(int, int);
 
 static void expose(XEvent *);
@@ -350,7 +355,7 @@ static void unmap(XEvent *);
 static char *kmap(KeySym, uint);
 static void kpress(XEvent *);
 static void cmessage(XEvent *);
-static void cresize(int width, int height);
+static void cresize(int, int);
 static void resize(XEvent *);
 static void focus(XEvent *);
 static void brelease(XEvent *);
@@ -373,7 +378,7 @@ static int isfullutf8(char *, int);
 static ssize_t xwrite(int, char *, size_t);
 static void *xmalloc(size_t);
 static void *xrealloc(void *, size_t);
-static void *xcalloc(size_t nmemb, size_t size);
+static void *xcalloc(size_t, size_t);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
@@ -412,6 +417,28 @@ static char *opt_font = NULL;
 static char *usedfont = NULL;
 static int usedfontsize = 0;
 
+/* Font Ring Cache */
+enum {
+	FRC_NORMAL,
+	FRC_ITALIC,
+	FRC_BOLD,
+	FRC_ITALICBOLD
+};
+
+typedef struct {
+	XftFont *font;
+	long c;
+	int flags;
+} Fontcache;
+
+/*
+ * Fontcache is a ring buffer, with frccur as current position and frclen as
+ * the current length of used elements.
+ */
+
+static Fontcache frc[256];
+static int frccur = 0, frclen = 0;
+
 ssize_t
 xwrite(int fd, char *s, size_t len) {
 	size_t aux = len;
@@ -2282,20 +2309,28 @@ xloadfont(Font *f, FcPattern *pattern) {
 	FcPattern *match;
 	FcResult result;
 
-	match = XftFontMatch(xw.dpy, xw.scr, pattern, &result);
+	match = FcFontMatch(NULL, pattern, &result);
 	if(!match)
 		return 1;
-	if(!(f->set = XftFontOpenPattern(xw.dpy, match))) {
+
+	if(!(f->set = FcFontSort(0, match, FcTrue, 0, &result))) {
 		FcPatternDestroy(match);
 		return 1;
 	}
 
-	f->ascent = f->set->ascent;
-	f->descent = f->set->descent;
-	f->lbearing = 0;
-	f->rbearing = f->set->max_advance_width;
+	if(!(f->match = XftFontOpenPattern(xw.dpy, match))) {
+		FcPatternDestroy(match);
+		return 1;
+	}
 
-	f->height = f->set->height;
+	f->pattern = FcPatternDuplicate(pattern);
+
+	f->ascent = f->match->ascent;
+	f->descent = f->match->descent;
+	f->lbearing = 0;
+	f->rbearing = f->match->max_advance_width;
+
+	f->height = f->match->height;
 	f->width = f->lbearing + f->rbearing;
 
 	return 0;
@@ -2334,6 +2369,9 @@ xloadfonts(char *fontstr, int fontsize) {
 		}
 	}
 
+	FcConfigSubstitute(0, pattern, FcMatchPattern);
+	FcDefaultSubstitute(pattern);
+
 	if(xloadfont(&dc.font, pattern))
 		die("st: can't open font %s\n", fontstr);
 
@@ -2358,9 +2396,41 @@ xloadfonts(char *fontstr, int fontsize) {
 	FcPatternDestroy(pattern);
 }
 
+void
+xunloadfonts(void)
+{
+	int i, ip;
+
+	/*
+	 * Free the loaded fonts in the font cache. This is done backwards
+	 * from the frccur.
+	 */
+	for (i = 0, ip = frccur; i < frclen; i++, ip--) {
+		if (ip <= 0)
+			ip = LEN(frc) - 1;
+		XftFontClose(xw.dpy, frc[ip].font);
+	}
+	frccur = 0;
+	frclen = 0;
+
+	XftFontClose(xw.dpy, dc.font.match);
+	FcPatternDestroy(dc.font.pattern);
+	FcFontSetDestroy(dc.font.set);
+	XftFontClose(xw.dpy, dc.bfont.match);
+	FcPatternDestroy(dc.bfont.pattern);
+	FcFontSetDestroy(dc.bfont.set);
+	XftFontClose(xw.dpy, dc.ifont.match);
+	FcPatternDestroy(dc.ifont.pattern);
+	FcFontSetDestroy(dc.ifont.set);
+	XftFontClose(xw.dpy, dc.ibfont.match);
+	FcPatternDestroy(dc.ibfont.pattern);
+	FcFontSetDestroy(dc.ibfont.set);
+}
+
 void
 xzoom(const Arg *arg)
 {
+	xunloadfonts();
 	xloadfonts(usedfont, usedfontsize + arg->i);
 	cresize(0, 0);
 	draw();
@@ -2379,6 +2449,9 @@ xinit(void) {
 	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);
 
@@ -2459,13 +2532,22 @@ xinit(void) {
 void
 xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
-	    width = charlen * xw.cw;
+	    width = charlen * xw.cw, u8clen, xp, i, frp, frcflags;
+	long u8char;
+	char *u8c;
 	Font *font = &dc.font;
+	XftFont *sfont;
+	FcResult fcres;
+	FcPattern *fcpattern, *fontpattern;
+	FcFontSet *fcsets[] = { NULL };
+	FcCharSet *fccharset;
 	XGlyphInfo extents;
 	Colour *fg = &dc.col[base.fg], *bg = &dc.col[base.bg],
 		 *temp, revfg, revbg;
 	XRenderColor colfg, colbg;
 
+	frcflags = FRC_NORMAL;
+
 	if(base.mode & ATTR_BOLD) {
 		if(BETWEEN(base.fg, 0, 7)) {
 			/* basic system colors */
@@ -2484,12 +2566,17 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		 *	252 - 255 – brightest colors in greyscale
 		 */
 		font = &dc.bfont;
+		frcflags = FRC_BOLD;
 	}
 
-	if(base.mode & ATTR_ITALIC)
+	if(base.mode & ATTR_ITALIC) {
 		font = &dc.ifont;
-	if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD))
+		frcflags = FRC_ITALIC;
+	}
+	if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) {
 		font = &dc.ibfont;
+		frcflags = FRC_ITALICBOLD;
+	}
 
 	if(IS_SET(MODE_REVERSE)) {
 		if(fg == &dc.col[defaultfg]) {
@@ -2521,7 +2608,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		bg = temp;
 	}
 
-	XftTextExtentsUtf8(xw.dpy, font->set, (FcChar8 *)s, bytelen,
+	/* Width of the whole string that should be printed. */
+	XftTextExtentsUtf8(xw.dpy, font->match, (FcChar8 *)s, bytelen,
 			&extents);
 	width = extents.xOff;
 
@@ -2539,9 +2627,96 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	if(y == term.row-1)
 		xclear(winx, winy + xw.ch, winx + width, xw.h);
 
+	/* Clean up the region we want to draw to. */
 	XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch);
+
+	/*
+	 * Step through all UTF-8 characters one by one and search in the font
+	 * cache ring buffer, whether there was some font found to display the
+	 * unicode value of that UTF-8 character.
+	 */
+	fcsets[0] = font->set;
+	for (xp = winx; bytelen > 0; ) {
+		u8c = s;
+		u8clen = utf8decode(s, &u8char);
+		s += u8clen;
+		bytelen -= u8clen;
+
+		sfont = font->match;
+		/*
+		 * Only check the font cache or load new fonts, if the
+		 * characters is not represented in main font.
+		 */
+		if (!XftCharExists(xw.dpy, font->match, u8char)) {
+			frp = frccur;
+			/* Search the font cache. */
+			for (i = 0; i < frclen; i++, frp--) {
+				if (frp <= 0)
+					frp = LEN(frc) - 1;
+
+				if (frc[frp].c == u8char
+					&& frc[frp].flags == frcflags) {
+					break;
+				}
+			}
+			if (i >= frclen) {
+				/*
+				 * Nothing was found in the cache. Now use
+				 * some dozen of Fontconfig calls to get the
+				 * font for one single character.
+				 */
+				fcpattern = FcPatternDuplicate(font->pattern);
+				fccharset = FcCharSetCreate();
+
+				FcCharSetAddChar(fccharset, u8char);
+				FcPatternAddCharSet(fcpattern, FC_CHARSET,
+						fccharset);
+				FcPatternAddBool(fcpattern, FC_SCALABLE,
+						FcTrue);
+
+				FcConfigSubstitute(0, fcpattern,
+						FcMatchPattern);
+				FcDefaultSubstitute(fcpattern);
+
+				fontpattern = FcFontSetMatch(0, fcsets,
+						FcTrue, fcpattern, &fcres);
+
+				frccur++;
+				frclen++;
+				if (frccur >= LEN(frc))
+					frccur = 0;
+				if (frclen >= LEN(frc)) {
+					frclen = LEN(frc);
+					XftFontClose(xw.dpy, frc[frccur].font);
+				}
+
+				/*
+				 * Overwrite or create the new cache entry
+				 * entry.
+				 */
+				frc[frccur].font = XftFontOpenPattern(xw.dpy,
+						fontpattern);
+				frc[frccur].c = u8char;
+				frc[frccur].flags = frcflags;
+
+				FcPatternDestroy(fcpattern);
+				FcCharSetDestroy(fccharset);
+
+				frp = frccur;
+			}
+			sfont = frc[frp].font;
+		}
+
+		XftDrawStringUtf8(xw.draw, fg, sfont, xp, winy + sfont->ascent,
+				(FcChar8 *)u8c, u8clen);
+
+		xp += font->width;
+	}
+
+	/*
 	XftDrawStringUtf8(xw.draw, fg, font->set, winx,
 			winy + font->ascent, (FcChar8 *)s, bytelen);
+	*/
 
 	if(base.mode & ATTR_UNDERLINE) {
 		XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1,

From addc84834506e24387c1fb70b5d33b3f2ba55b66 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 29 Dec 2012 15:03:03 +0100
Subject: [PATCH 0434/1146] Speeding up the drawing, then all characters are
 known.

---
 st.c | 184 +++++++++++++++++++++++++++++++++--------------------------
 1 file changed, 103 insertions(+), 81 deletions(-)

diff --git a/st.c b/st.c
index a440959..cc8a22a 100644
--- a/st.c
+++ b/st.c
@@ -437,7 +437,7 @@ typedef struct {
  */
 
 static Fontcache frc[256];
-static int frccur = 0, frclen = 0;
+static int frccur = -1, frclen = 0;
 
 ssize_t
 xwrite(int fd, char *s, size_t len) {
@@ -2410,7 +2410,7 @@ xunloadfonts(void)
 			ip = LEN(frc) - 1;
 		XftFontClose(xw.dpy, frc[ip].font);
 	}
-	frccur = 0;
+	frccur = -1;
 	frclen = 0;
 
 	XftFontClose(xw.dpy, dc.font.match);
@@ -2532,11 +2532,12 @@ xinit(void) {
 void
 xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
-	    width = charlen * xw.cw, u8clen, xp, i, frp, frcflags;
+	    width = charlen * xw.cw, xp, i;
+	int frp, frcflags;
+	int u8fl, u8fblen, u8cblen, doesexist;
+	char *u8c, *u8fs;
 	long u8char;
-	char *u8c;
 	Font *font = &dc.font;
-	XftFont *sfont;
 	FcResult fcres;
 	FcPattern *fcpattern, *fontpattern;
 	FcFontSet *fcsets[] = { NULL };
@@ -2608,11 +2609,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		bg = temp;
 	}
 
-	/* Width of the whole string that should be printed. */
-	XftTextExtentsUtf8(xw.dpy, font->match, (FcChar8 *)s, bytelen,
-			&extents);
-	width = extents.xOff;
-
 	/* Intelligent cleaning up of the borders. */
 	if(x == 0) {
 		xclear(0, (y == 0)? 0 : winy, borderpx,
@@ -2630,85 +2626,111 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	/* Clean up the region we want to draw to. */
 	XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch);
 
-	/*
-	 * Step through all UTF-8 characters one by one and search in the font
-	 * cache ring buffer, whether there was some font found to display the
-	 * unicode value of that UTF-8 character.
-	 */
 	fcsets[0] = font->set;
-	for (xp = winx; bytelen > 0; ) {
-		u8c = s;
-		u8clen = utf8decode(s, &u8char);
-		s += u8clen;
-		bytelen -= u8clen;
-
-		sfont = font->match;
+	for (xp = winx; bytelen > 0;) {
 		/*
-		 * Only check the font cache or load new fonts, if the
-		 * characters is not represented in main font.
+		 * Search for the range in the to be printed string of glyphs
+		 * that are in the main font. Then print that range. If
+		 * some glyph is found that is not in the font, do the
+		 * fallback dance.
 		 */
-		if (!XftCharExists(xw.dpy, font->match, u8char)) {
-			frp = frccur;
-			/* Search the font cache. */
-			for (i = 0; i < frclen; i++, frp--) {
-				if (frp <= 0)
-					frp = LEN(frc) - 1;
+		u8fs = s;
+		u8fblen = 0;
+		u8fl = 0;
+		for (;;) {
+			u8c = s;
+			u8cblen = utf8decode(s, &u8char);
+			s += u8cblen;
+			bytelen -= u8cblen;
 
-				if (frc[frp].c == u8char
+			doesexist = XftCharIndex(xw.dpy, font->match, u8char);
+			if (!doesexist || bytelen <= 0) {
+				if (bytelen <= 0) {
+					if (doesexist) {
+						u8fl++;
+						u8fblen += u8cblen;
+					}
+				}
+
+				if (u8fl > 0) {
+					XftDrawStringUtf8(xw.draw, fg,
+							font->match, xp,
+							winy + font->ascent,
+							(FcChar8 *)u8fs,
+							u8fblen);
+					xp += font->width * u8fl;
+				}
+				break;
+			}
+
+			u8fl++;
+			u8fblen += u8cblen;
+		}
+		if (doesexist)
+			break;
+
+		frp = frccur;
+		/* Search the font cache. */
+		for (i = 0; i < frclen; i++, frp--) {
+			if (frp <= 0)
+				frp = LEN(frc) - 1;
+
+			if (frc[frp].c == u8char
 					&& frc[frp].flags == frcflags) {
-					break;
-				}
+				break;
 			}
-			if (i >= frclen) {
-				/*
-				 * Nothing was found in the cache. Now use
-				 * some dozen of Fontconfig calls to get the
-				 * font for one single character.
-				 */
-				fcpattern = FcPatternDuplicate(font->pattern);
-				fccharset = FcCharSetCreate();
-
-				FcCharSetAddChar(fccharset, u8char);
-				FcPatternAddCharSet(fcpattern, FC_CHARSET,
-						fccharset);
-				FcPatternAddBool(fcpattern, FC_SCALABLE,
-						FcTrue);
-
-				FcConfigSubstitute(0, fcpattern,
-						FcMatchPattern);
-				FcDefaultSubstitute(fcpattern);
-
-				fontpattern = FcFontSetMatch(0, fcsets,
-						FcTrue, fcpattern, &fcres);
-
-				frccur++;
-				frclen++;
-				if (frccur >= LEN(frc))
-					frccur = 0;
-				if (frclen >= LEN(frc)) {
-					frclen = LEN(frc);
-					XftFontClose(xw.dpy, frc[frccur].font);
-				}
-
-				/*
-				 * Overwrite or create the new cache entry
-				 * entry.
-				 */
-				frc[frccur].font = XftFontOpenPattern(xw.dpy,
-						fontpattern);
-				frc[frccur].c = u8char;
-				frc[frccur].flags = frcflags;
-
-				FcPatternDestroy(fcpattern);
-				FcCharSetDestroy(fccharset);
-
-				frp = frccur;
-			}
-			sfont = frc[frp].font;
 		}
 
-		XftDrawStringUtf8(xw.draw, fg, sfont, xp, winy + sfont->ascent,
-				(FcChar8 *)u8c, u8clen);
+		/* Nothing was found. */
+		if (i >= frclen) {
+			/*
+			 * Nothing was found in the cache. Now use
+			 * some dozen of Fontconfig calls to get the
+			 * font for one single character.
+			 */
+			fcpattern = FcPatternDuplicate(font->pattern);
+			fccharset = FcCharSetCreate();
+
+			FcCharSetAddChar(fccharset, u8char);
+			FcPatternAddCharSet(fcpattern, FC_CHARSET,
+					fccharset);
+			FcPatternAddBool(fcpattern, FC_SCALABLE,
+					FcTrue);
+
+			FcConfigSubstitute(0, fcpattern,
+					FcMatchPattern);
+			FcDefaultSubstitute(fcpattern);
+
+			fontpattern = FcFontSetMatch(0, fcsets,
+					FcTrue, fcpattern, &fcres);
+
+			/*
+			 * Overwrite or create the new cache entry
+			 * entry.
+			 */
+			frccur++;
+			frclen++;
+			if (frccur >= LEN(frc))
+				frccur = 0;
+			if (frclen > LEN(frc)) {
+				frclen = LEN(frc);
+				XftFontClose(xw.dpy, frc[frccur].font);
+			}
+
+			frc[frccur].font = XftFontOpenPattern(xw.dpy,
+					fontpattern);
+			frc[frccur].c = u8char;
+			frc[frccur].flags = frcflags;
+
+			FcPatternDestroy(fcpattern);
+			FcCharSetDestroy(fccharset);
+
+			frp = frccur;
+		}
+
+		XftDrawStringUtf8(xw.draw, fg, frc[frp].font,
+				xp, winy + frc[frp].font->ascent,
+				(FcChar8 *)u8c, u8cblen);
 
 		xp += font->width;
 	}

From 08e06ef079e5190c7f219c7e50044745c57cea86 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 29 Dec 2012 16:24:33 +0100
Subject: [PATCH 0435/1146] Fixing the font unloading in case of zoom.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index cc8a22a..6dcf0c7 100644
--- a/st.c
+++ b/st.c
@@ -2406,7 +2406,7 @@ xunloadfonts(void)
 	 * from the frccur.
 	 */
 	for (i = 0, ip = frccur; i < frclen; i++, ip--) {
-		if (ip <= 0)
+		if (ip < 0)
 			ip = LEN(frc) - 1;
 		XftFontClose(xw.dpy, frc[ip].font);
 	}

From 44e1b79abfe81d5d9d1b4845a68533e84b37e2f0 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 30 Dec 2012 17:35:15 +0100
Subject: [PATCH 0436/1146] Removing the warning about extents.

---
 st.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.c b/st.c
index 6dcf0c7..6baa086 100644
--- a/st.c
+++ b/st.c
@@ -2542,7 +2542,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	FcPattern *fcpattern, *fontpattern;
 	FcFontSet *fcsets[] = { NULL };
 	FcCharSet *fccharset;
-	XGlyphInfo extents;
 	Colour *fg = &dc.col[base.fg], *bg = &dc.col[base.bg],
 		 *temp, revfg, revbg;
 	XRenderColor colfg, colbg;

From c99db5b0170555c5bb0359ac8a8229cdada64b30 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 30 Dec 2012 17:35:41 +0100
Subject: [PATCH 0437/1146] Increasing font cache for speeding up UTF8 demos.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 6baa086..7ceed75 100644
--- a/st.c
+++ b/st.c
@@ -436,7 +436,7 @@ typedef struct {
  * the current length of used elements.
  */
 
-static Fontcache frc[256];
+static Fontcache frc[2048];
 static int frccur = -1, frclen = 0;
 
 ssize_t

From 4e14a4a97f7f7ef134fdc25d2fa34c8db7bb6e6c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 1 Jan 2013 13:15:43 +0100
Subject: [PATCH 0438/1146] A fix for the XopenIM() errors.

---
 st.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 7ceed75..163f160 100644
--- a/st.c
+++ b/st.c
@@ -2503,9 +2503,17 @@ xinit(void) {
 	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
 
 	/* input methods */
-	xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
-	if(xw.xim == NULL)
-		die("XOpenIM failed. Could not open input device.\n");
+	if((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+		XSetLocaleModifiers("@im=local");
+		if((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+			XSetLocaleModifiers("@im=");
+			if((xw.xim = XOpenIM(xw.dpy,
+					NULL, NULL, NULL)) == NULL) {
+				die("XOpenIM failed. Could not open input"
+					" device.\n");
+			}
+		}
+	}
 	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
 					   | XIMStatusNothing, XNClientWindow, xw.win,
 					   XNFocusWindow, xw.win, NULL);

From 4682cc9596a5c82325882bdf1313728de95467d2 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 4 Jan 2013 20:52:22 +0100
Subject: [PATCH 0439/1146] Making the fontconfig and freetype paths portable
 in config.mk.

---
 config.mk | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/config.mk b/config.mk
index f1757ed..ecc5c83 100644
--- a/config.mk
+++ b/config.mk
@@ -11,8 +11,12 @@ X11INC = /usr/X11R6/include
 X11LIB = /usr/X11R6/lib
 
 # includes and libs
-INCS = -I. -I/usr/include -I${X11INC} -I/usr/include/freetype2
-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext -lXft -lfontconfig
+INCS = -I. -I/usr/include -I${X11INC} \
+       $(shell pkg-config --cflags fontconfig) \
+       $(shell pkg-config --cflags freetype2)
+LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext -lXft \
+       $(shell pkg-config --libs fontconfig)  \
+       $(shell pkg-config --libs freetype2)
 
 # flags
 CPPFLAGS = -DVERSION=\"${VERSION}\"

From c772a6e5719aa24d10d664262383b76a36e3458b Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 5 Jan 2013 20:30:25 +0100
Subject: [PATCH 0440/1146] Applying the changes to the docs; by Peter Hartman.

---
 Makefile | 3 +--
 README   | 8 +++-----
 st.c     | 2 +-
 3 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/Makefile b/Makefile
index 8fc9674..52af636 100644
--- a/Makefile
+++ b/Makefile
@@ -48,8 +48,7 @@ install: all
 	@mkdir -p ${DESTDIR}${MANPREFIX}/man1
 	@sed "s/VERSION/${VERSION}/g" < st.1 > ${DESTDIR}${MANPREFIX}/man1/st.1
 	@chmod 644 ${DESTDIR}${MANPREFIX}/man1/st.1
-	@echo If things do not seem to work, be sure that there is no \
-		floating st terminfo in the .terminfo directory in your home dir.
+	@echo Please see the README file regarding the terminfo entry of st.
 	@tic -s st.info
 
 uninstall:
diff --git a/README b/README
index e801c02..25606a2 100644
--- a/README
+++ b/README
@@ -21,16 +21,14 @@ necessary as root):
 
 Running st
 ----------
-If you don't install st, define TNAME to "xterm" in config.h or make sure to at
-least compile st terminfo entry with the following command:
+If you did not install st with make clean install, you must compile
+the st terminfo entry with the following command:
 
     tic -s st.info
 
-It should print the path of the compiled terminfo entry. You can
-safely remove it if you don't plan to use st anymore.
 See the man page for additional details.
 
 Credits
 -------
-Based on  Aurélien APTEL <aurelien dot aptel at gmail dot com> bt source code.
+Based on Aurélien APTEL <aurelien dot aptel at gmail dot com> bt source code.
 
diff --git a/st.c b/st.c
index 163f160..7010195 100644
--- a/st.c
+++ b/st.c
@@ -436,7 +436,7 @@ typedef struct {
  * the current length of used elements.
  */
 
-static Fontcache frc[2048];
+static Fontcache frc[2];
 static int frccur = -1, frclen = 0;
 
 ssize_t

From b233007e0fddbb5ad8da3e436533254d099c8861 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 5 Jan 2013 20:56:58 +0100
Subject: [PATCH 0441/1146] Damn, my fault. The cache should have at least some
 entries.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 7010195..6f5ca80 100644
--- a/st.c
+++ b/st.c
@@ -436,7 +436,7 @@ typedef struct {
  * the current length of used elements.
  */
 
-static Fontcache frc[2];
+static Fontcache frc[1024];
 static int frccur = -1, frclen = 0;
 
 ssize_t

From 5facd29f75401891fbac9c83d64c684bdb8f7c39 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 6 Jan 2013 09:52:03 +0100
Subject: [PATCH 0442/1146] Synchronizing the FAQ of the website and the
 repository.

---
 FAQ | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/FAQ b/FAQ
index 594a873..b624145 100644
--- a/FAQ
+++ b/FAQ
@@ -3,6 +3,38 @@ Why does st not handle utmp entries?
 
 Use the excellent tool of utmp[0] for this task.
 
-[0] http://hg.suckless.org/utmp/
+[0] http://git.suckless.org/utmp/
+--
+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 manualy run tic -s st.info in st dir. It will compile st.info into a
+fully working local terminfo description. You can delete it when you’re done.
+--
+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.
+--
+I get some weird glitches/visual bug on _random program_!
+
+Try lauching it with a different TERM: $ TERM=xterm myapp. toe(1) will give
+you a list of available terminals, but you’ll most likely switch between
+xterm, st or st-256color. The default value for TERM can be changed in
+config.h (TNAME).
+--
+How do I scroll back up?
+
+Invoke st with a screen multiplexer like GNU screen[0] or tmux[1].
+st -e screen works better for text reflowing. To enter screen’s scroll
+back mode aka “copy mode”, it’s C-a ESC. You probably want defscrollback
+10000 in your ~/.screenrc too.
+
+[0] http://en.wikipedia.org/wiki/GNU_Screen
+[1] http://en.wikipedia.org/wiki/Tmux
 --
 

From 73879c172943928542225cdc975b3b7e2449ddc0 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 7 Jan 2013 19:53:41 +0100
Subject: [PATCH 0443/1146] Adding an FAQ entry for the keypad handling.

Thanks "Roberto E. Vargas Caballero" <k0ga@shike2.com>!
---
 FAQ | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/FAQ b/FAQ
index b624145..438e7d8 100644
--- a/FAQ
+++ b/FAQ
@@ -37,4 +37,39 @@ back mode aka “copy mode”, it’s C-a ESC. You probably want defscrollback
 [0] http://en.wikipedia.org/wiki/GNU_Screen
 [1] http://en.wikipedia.org/wiki/Tmux
 --
+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, tive these
+	codes as smkx and rmkx. Otherwise the keypad is assumed to
+	always transmit.
+
+In the st case smkx=\E[?1h\E= and rmkx=\E[?1l\E>, so it is mandatory that
+applications which want to test against keypad keys, have to 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:
+
+	$ echo ^[?1h^[= >/dev/tty
+
+or
+	$ echo $(tput smkx) >/dev/tty
+
+In the case of bash it is using readline, which has a different not in its
+manpage:
+
+	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.
+--
 

From f741df9cda4d4aa597cf9eff4ac62a610daf44f2 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 8 Jan 2013 19:46:28 +0100
Subject: [PATCH 0444/1146] Standout is now reverse. This makes bsd-games work
 in st.

---
 st.info | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.info b/st.info
index 52ae851..fcaa024 100644
--- a/st.info
+++ b/st.info
@@ -162,7 +162,7 @@ st| simpleterm,
 	rmcup=\E[?1049l,
 	rmir=\E[4l,
 	rmkx=\E[?1l\E>,
-	rmso=\E[23m,
+	rmso=\E[27m,
 	rmul=\E[m,
 	rs1=\Ec,
 	rs2=\E[4l\E>,
@@ -178,7 +178,7 @@ st| simpleterm,
 	smcup=\E[?1049h,
 	smir=\E[4h,
 	smkx=\E[?1h\E=,
-	smso=\E[3m,
+	smso=\E[7m,
 	smul=\E[4m,
 	tbc=\E[3g,
 	tsl=\E]0;,

From b3326ab63be167ddd883dbf7be33603f38bbd31d Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 8 Jan 2013 20:09:33 +0100
Subject: [PATCH 0445/1146] A different double buffering strategy so the
 background is default set.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 6f5ca80..a992005 100644
--- a/st.c
+++ b/st.c
@@ -2497,7 +2497,7 @@ xinit(void) {
 	/* double buffering */
 	if(!XdbeQueryExtension(xw.dpy, &major, &minor))
 		die("Xdbe extension is not present\n");
-	xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeCopied);
+	xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeBackground);
 
 	/* Xft rendering context */
 	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);

From 1827e0643fc95b44d12eaf951be5994637d1b30d Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 8 Jan 2013 20:36:49 +0100
Subject: [PATCH 0446/1146] Standout mode has changed. Thanks
 p37sitdu@lavabit.com!

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index a992005..213541f 100644
--- a/st.c
+++ b/st.c
@@ -1390,7 +1390,7 @@ tsetattr(int *attr, int l) {
 		case 1:
 			term.c.attr.mode |= ATTR_BOLD;
 			break;
-		case 3: /* enter standout (highlight) */
+		case 3:
 			term.c.attr.mode |= ATTR_ITALIC;
 			break;
 		case 4:
@@ -1406,7 +1406,7 @@ tsetattr(int *attr, int l) {
 		case 22:
 			term.c.attr.mode &= ~ATTR_BOLD;
 			break;
-		case 23: /* leave standout (highlight) mode */
+		case 23:
 			term.c.attr.mode &= ~ATTR_ITALIC;
 			break;
 		case 24:

From f25c75d72a07edaec7750cfe5ca251ca395b65e5 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 9 Jan 2013 17:36:59 +0100
Subject: [PATCH 0447/1146] Removing the .hgtags file. Thanks ilf.

---
 .hgtags | 5 -----
 1 file changed, 5 deletions(-)
 delete mode 100644 .hgtags

diff --git a/.hgtags b/.hgtags
deleted file mode 100644
index a13fbc7..0000000
--- a/.hgtags
+++ /dev/null
@@ -1,5 +0,0 @@
-cbc18c988236c63a58ed24031805e8d36a3ad01a 0.1
-f245ac2efd8ac2f1ac6bffae876c2663e794f79d 0.1.1
-3c2f9f2ab5e433db1401047760ec31d66939b74b 0.2
-108926a0fe610b92c0296148721c3225932f39aa 0.2.1
-9d54ce4daf3453c5a33e446ef3c0f38e12ec4d72 0.3

From c9bd58e4dd04e61aa3613eab57ba6fb716a41146 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 16 Jan 2013 18:53:32 +0100
Subject: [PATCH 0448/1146] Adding a nasty resize bug. Maybe it can be fixed.

---
 TODO | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/TODO b/TODO
index a4cfeee..efecd50 100644
--- a/TODO
+++ b/TODO
@@ -25,6 +25,10 @@ bugs
 * remove DEC test sequence when appropriate
 * reverse cursor when drawin light on light background
 	* text should be readable
+* When some application outputting long text is run in the shell init scripts,
+  then this text might be stripped to the standard 80x25 due to st running the
+  virtual terminal at first priority. Maybe the vt initialisation could be
+  moved somewhere after knowing the right window size.
 
 misc
 ----

From ed90afb743911b7b95dc2bf36b65076532779269 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 18 Jan 2013 19:11:25 +0100
Subject: [PATCH 0449/1146] The title can now be set with UTF-8 characters.

Thanks Mihail Zenkov <mihail.zenkov@gmail.com>!
---
 st.c | 36 +++++++++++++++++++++++++-----------
 1 file changed, 25 insertions(+), 11 deletions(-)

diff --git a/st.c b/st.c
index 213541f..0ea51d9 100644
--- a/st.c
+++ b/st.c
@@ -53,12 +53,12 @@
 #define XEMBED_FOCUS_OUT 5
 
 /* Arbitrary sizes */
-#define ESC_BUF_SIZ   256
-#define ESC_ARG_SIZ   16
-#define STR_BUF_SIZ   256
-#define STR_ARG_SIZ   16
-#define DRAW_BUF_SIZ  20*1024
 #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
+#define DRAW_BUF_SIZ  20*1024
 #define XK_ANY_MOD    UINT_MAX
 #define XK_NO_MOD     0
 
@@ -168,7 +168,7 @@ typedef struct {
 	int len;	       /* raw string length */
 	char priv;
 	int arg[ESC_ARG_SIZ];
-	int narg;	      /* nb of args */
+	int narg;	       /* nb of args */
 	char mode;
 } CSIEscape;
 
@@ -1911,12 +1911,13 @@ tputc(char *c, int len) {
 
 	if(iofd != -1) {
 		if (xwrite(iofd, c, len) < 0) {
-			fprintf(stderr, "Error writting in %s:%s\n",
+			fprintf(stderr, "Error writing in %s:%s\n",
 				opt_io, strerror(errno));
 			close(iofd);
 			iofd = -1;
 		}
 	}
+
 	/*
 	 * STR sequences must be checked before anything else
 	 * because it can use some control codes as part of the sequence.
@@ -1931,10 +1932,23 @@ tputc(char *c, int len) {
 			strhandle();
 			break;
 		default:
-			strescseq.buf[strescseq.len++] = ascii;
-			if(strescseq.len+1 >= STR_BUF_SIZ) {
-				term.esc = 0;
-				strhandle();
+			if(strescseq.len + len < sizeof(strescseq.buf)) {
+				memmove(&strescseq.buf[strescseq.len], c, len);
+				strescseq.len += len;
+			} else {
+			/*
+			 * Here is a bug in terminals. If the user never sends
+			 * some code to stop the str or esc command, then st
+			 * will stop responding. But this is better than
+			 * silently failing with unknown characters. At least
+			 * then users will report back.
+			 *
+			 * In the case users ever get fixed, here is the code:
+			 */
+			/*
+			 * term.esc = 0;
+			 * strhandle();
+			 */
 			}
 		}
 		return;

From 3ce96aea8af566c88ed1e076d270b4d1abcf6e96 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 18 Jan 2013 19:22:11 +0100
Subject: [PATCH 0450/1146] Adding the FAQ entry for zsh.

Thanks Roberto E. Vargas Caballero! You were committing this patch against the
wrong version of the FAQ, so I had to rewrite it.
---
 FAQ | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/FAQ b/FAQ
index 438e7d8..9d29335 100644
--- a/FAQ
+++ b/FAQ
@@ -56,13 +56,13 @@ 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:
 
-	$ echo ^[?1h^[= >/dev/tty
+	$ printf "\033?1h\033=" >/dev/tty
 
 or
 	$ echo $(tput smkx) >/dev/tty
 
-In the case of bash it is using readline, which has a different not in its
-manpage:
+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
@@ -71,5 +71,25 @@ manpage:
 
 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.
 --
 

From 0e232a41150d67539df05e60c7e829f0bfb431d0 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 19 Jan 2013 09:13:52 +0100
Subject: [PATCH 0451/1146] Dbe is not required anymore.

---
 st.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index 0ea51d9..979fdc8 100644
--- a/st.c
+++ b/st.c
@@ -203,7 +203,7 @@ typedef struct {
 	Display *dpy;
 	Colourmap cmap;
 	Window win;
-	XdbeBackBuffer buf;
+	Drawable buf;
 	Atom xembed, wmdeletewin;
 	XIM xim;
 	XIC xic;
@@ -414,6 +414,8 @@ static char *opt_embed = NULL;
 static char *opt_class = NULL;
 static char *opt_font = NULL;
 
+bool usedbe = False;
+
 static char *usedfont = NULL;
 static int usedfontsize = 0;
 
@@ -2500,7 +2502,8 @@ xinit(void) {
 		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
 	attrs.colormap = xw.cmap;
 
-	parent = opt_embed ? strtol(opt_embed, NULL, 0) : XRootWindow(xw.dpy, xw.scr);
+	parent = opt_embed ? strtol(opt_embed, NULL, 0) : \
+			XRootWindow(xw.dpy, xw.scr);
 	xw.win = XCreateWindow(xw.dpy, parent, xw.fx, xw.fy,
 			xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
 			xw.vis,
@@ -2509,12 +2512,16 @@ xinit(void) {
 			&attrs);
 
 	/* double buffering */
-	if(!XdbeQueryExtension(xw.dpy, &major, &minor))
-		die("Xdbe extension is not present\n");
-	xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeBackground);
+	if(XdbeQueryExtension(xw.dpy, &major, &minor)) {
+		xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win,
+				XdbeBackground);
+		usedbe = True;
+	} else {
+		xw.buf = xw.win;
+	}
 
 	/* Xft rendering context */
-	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
+	xw.draw = XftDrawCreate(xw.dpy, xw.win, xw.vis, xw.cmap);
 
 	/* input methods */
 	if((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
@@ -2822,7 +2829,8 @@ draw(void) {
 	XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
 
 	drawregion(0, 0, term.col, term.row);
-	XdbeSwapBuffers(xw.dpy, swpinfo, 1);
+	if(usedbe)
+		XdbeSwapBuffers(xw.dpy, swpinfo, 1);
 }
 
 void

From c7b033b8f0a31ec08d3d9dafa390b24c6e232e09 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 19 Jan 2013 15:00:16 +0100
Subject: [PATCH 0452/1146] Trying out the double buffering without dbe.

---
 st.c | 50 +++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 39 insertions(+), 11 deletions(-)

diff --git a/st.c b/st.c
index 979fdc8..ef78896 100644
--- a/st.c
+++ b/st.c
@@ -213,8 +213,7 @@ typedef struct {
 	bool isfixed; /* is fixed geometry? */
 	int fx, fy, fw, fh; /* fixed geometry */
 	int tw, th; /* tty width and height */
-	int w;	/* window width */
-	int h;	/* window height */
+	int w, h; /* window width and height */
 	int ch; /* char height */
 	int cw; /* char width  */
 	char state; /* focus, redraw, visible */
@@ -284,11 +283,12 @@ typedef struct {
 typedef struct {
 	Colour col[LEN(colorname) < 256 ? 256 : LEN(colorname)];
 	Font font, bfont, ifont, ibfont;
+	GC gc;
 } DC;
 
 static void die(const char *, ...);
 static void draw(void);
-static void redraw(void);
+static void redraw(int);
 static void drawregion(int, int, int, int);
 static void execsh(void);
 static void sigchld(int);
@@ -1510,7 +1510,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				mode = term.mode;
 				MODBIT(term.mode, set, MODE_REVERSE);
 				if(mode != term.mode)
-					redraw();
+					redraw(REDRAW_TIMEOUT);
 				break;
 			case 6: /* DECOM -- Origin */
 				MODBIT(term.c.state, set, CURSOR_ORIGIN);
@@ -2234,6 +2234,14 @@ xresize(int col, int row) {
 	xw.tw = MAX(1, col * xw.cw);
 	xw.th = MAX(1, row * xw.ch);
 
+	if(!usedbe) {
+		XFreePixmap(xw.dpy, xw.buf);
+		xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
+				DefaultDepth(xw.dpy, xw.scr));
+		XSetForeground(xw.dpy, dc.gc, 0);
+		XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
+	}
+
 	XftDrawChange(xw.draw, xw.buf);
 }
 
@@ -2449,7 +2457,7 @@ xzoom(const Arg *arg)
 	xunloadfonts();
 	xloadfonts(usedfont, usedfontsize + arg->i);
 	cresize(0, 0);
-	draw();
+	redraw(0);
 }
 
 void
@@ -2512,13 +2520,22 @@ xinit(void) {
 			&attrs);
 
 	/* double buffering */
+	/*
 	if(XdbeQueryExtension(xw.dpy, &major, &minor)) {
 		xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win,
 				XdbeBackground);
 		usedbe = True;
 	} else {
-		xw.buf = xw.win;
+	*/
+		dc.gc = XCreateGC(xw.dpy, parent, 0, 0);
+		xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
+				DefaultDepth(xw.dpy, xw.scr));
+		XSetForeground(xw.dpy, dc.gc, 0);
+		XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
+		//xw.buf = xw.win;
+	/*
 	}
+	*/
 
 	/* Xft rendering context */
 	xw.draw = XftDrawCreate(xw.dpy, xw.win, xw.vis, xw.cmap);
@@ -2815,13 +2832,17 @@ xresettitle(void) {
 }
 
 void
-redraw(void) {
-	struct timespec tv = {0, REDRAW_TIMEOUT * 1000};
+redraw(int timeout) {
+	struct timespec tv = {0, timeout * 1000};
 
 	tfulldirt();
+	fprintf(stderr, "draw from redraw\n");
 	draw();
-	XSync(xw.dpy, False); /* necessary for a good tput flash */
-	nanosleep(&tv, NULL);
+
+	if(timeout > 0) {
+		nanosleep(&tv, NULL);
+		XSync(xw.dpy, False); /* necessary for a good tput flash */
+	}
 }
 
 void
@@ -2829,8 +2850,14 @@ draw(void) {
 	XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
 
 	drawregion(0, 0, term.col, term.row);
-	if(usedbe)
+	if(usedbe) {
 		XdbeSwapBuffers(xw.dpy, swpinfo, 1);
+	} else {
+		XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
+				xw.h, 0, 0);
+		XSetForeground(xw.dpy, dc.gc, 0);
+		XSync(xw.dpy, False);
+	}
 }
 
 void
@@ -2889,6 +2916,7 @@ expose(XEvent *ev) {
 		if(!e->count)
 			xw.state &= ~WIN_REDRAW;
 	}
+	redraw(0);
 }
 
 void

From 15c2bff9faa87644abf96c19b17133d03d40b974 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 19 Jan 2013 15:49:34 +0100
Subject: [PATCH 0453/1146] Yes, xft should be on the buffer. Thanks Mihail
 Zenkov.

---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index ef78896..7b0fb21 100644
--- a/st.c
+++ b/st.c
@@ -2538,7 +2538,7 @@ xinit(void) {
 	*/
 
 	/* Xft rendering context */
-	xw.draw = XftDrawCreate(xw.dpy, xw.win, xw.vis, xw.cmap);
+	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
 
 	/* input methods */
 	if((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
@@ -2836,7 +2836,6 @@ redraw(int timeout) {
 	struct timespec tv = {0, timeout * 1000};
 
 	tfulldirt();
-	fprintf(stderr, "draw from redraw\n");
 	draw();
 
 	if(timeout > 0) {

From b4b513c791e01e46399b460789b830ddfc7cb425 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 19 Jan 2013 18:38:28 +0100
Subject: [PATCH 0454/1146] Make line drawing work again.

---
 st.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 7b0fb21..769de8b 100644
--- a/st.c
+++ b/st.c
@@ -1987,10 +1987,13 @@ tputc(char *c, int len) {
 			term.esc = ESC_START;
 			return;
 		case '\016':	/* SO */
-			term.c.attr.mode |= ATTR_GFX;
-			return;
 		case '\017':	/* SI */
-			term.c.attr.mode &= ~ATTR_GFX;
+			/*
+			 * Different charsets are hard to handle. Applications
+			 * should use the right alt charset escapes for the
+			 * only reason they still exist: line drawing. The
+			 * rest is incompatible history st should not support.
+			 */
 			return;
 		case '\032':	/* SUB */
 		case '\030':	/* CAN */

From b78c5085f72d66de26468e2c07fb3c72d0afe63b Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 20 Jan 2013 14:54:35 +0100
Subject: [PATCH 0455/1146] Implementing Back Color Erase (BCE).

---
 st.c    | 63 +++++++++++++++++++++++++++++++++++----------------------
 st.info |  2 +-
 2 files changed, 40 insertions(+), 25 deletions(-)

diff --git a/st.c b/st.c
index 769de8b..5f75c39 100644
--- a/st.c
+++ b/st.c
@@ -152,7 +152,7 @@ typedef struct {
 	uchar state; /* state flags    */
 } Glyph;
 
-typedef Glyph* Line;
+typedef Glyph *Line;
 
 typedef struct {
 	Glyph attr;	 /* current char attributes */
@@ -303,7 +303,7 @@ static void strhandle(void);
 static void strparse(void);
 static void strreset(void);
 
-static void tclearregion(int, int, int, int);
+static void tclearregion(int, int, int, int, int);
 static void tcursor(int);
 static void tdeletechar(int);
 static void tdeleteline(int);
@@ -1113,7 +1113,7 @@ treset(void) {
 	term.bot = term.row - 1;
 	term.mode = MODE_WRAP;
 
-	tclearregion(0, 0, term.col-1, term.row-1);
+	tclearregion(0, 0, term.col-1, term.row-1, 0);
 	tmoveto(0, 0);
 	tcursor(CURSOR_SAVE);
 }
@@ -1157,7 +1157,7 @@ tscrolldown(int orig, int n) {
 
 	LIMIT(n, 0, term.bot-orig+1);
 
-	tclearregion(0, term.bot-n+1, term.col-1, term.bot);
+	tclearregion(0, term.bot-n+1, term.col-1, term.bot, 0);
 
 	for(i = term.bot; i >= orig+n; i--) {
 		temp = term.line[i];
@@ -1177,7 +1177,7 @@ tscrollup(int orig, int n) {
 	Line temp;
 	LIMIT(n, 0, term.bot-orig+1);
 
-	tclearregion(0, orig, term.col-1, orig+n-1);
+	tclearregion(0, orig, term.col-1, orig+n-1, 0);
 
 	for(i = orig; i <= term.bot-n; i++) {
 		 temp = term.line[i];
@@ -1305,7 +1305,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 }
 
 void
-tclearregion(int x1, int y1, int x2, int y2) {
+tclearregion(int x1, int y1, int x2, int y2, int bce) {
 	int x, y, temp;
 
 	if(x1 > x2)
@@ -1320,8 +1320,15 @@ tclearregion(int x1, int y1, int x2, int y2) {
 
 	for(y = y1; y <= y2; y++) {
 		term.dirty[y] = 1;
-		for(x = x1; x <= x2; x++)
-			term.line[y][x].state = 0;
+		for(x = x1; x <= x2; x++) {
+			if(bce) {
+				term.line[y][x] = term.c.attr;
+				memcpy(term.line[y][x].c, " ", 2);
+				term.line[y][x].state |= GLYPH_SET;
+			} else {
+				term.line[y][x].state = 0;
+			}
+		}
 	}
 }
 
@@ -1334,13 +1341,13 @@ tdeletechar(int n) {
 	term.dirty[term.c.y] = 1;
 
 	if(src >= term.col) {
-		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
+		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 0);
 		return;
 	}
 
 	memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src],
 			size * sizeof(Glyph));
-	tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
+	tclearregion(term.col-n, term.c.y, term.col-1, term.c.y, 0);
 }
 
 void
@@ -1352,13 +1359,13 @@ tinsertblank(int n) {
 	term.dirty[term.c.y] = 1;
 
 	if(dst >= term.col) {
-		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
+		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 0);
 		return;
 	}
 
 	memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src],
 			size * sizeof(Glyph));
-	tclearregion(src, term.c.y, dst - 1, term.c.y);
+	tclearregion(src, term.c.y, dst - 1, term.c.y, 0);
 }
 
 void
@@ -1542,8 +1549,10 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 47:
 			case 1047: {
 				alt = IS_SET(MODE_ALTSCREEN);
-				if(alt)
-					tclearregion(0, 0, term.col-1, term.row-1);
+				if(alt) {
+					tclearregion(0, 0, term.col-1,
+							term.row-1, 0);
+				}
 				if(set ^ alt)		/* set is always 1 or 0 */
 					tswapscreen();
 				if(*args != 1049)
@@ -1662,17 +1671,19 @@ csihandle(void) {
 		sel.bx = -1;
 		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);
+			tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1);
+			if(term.c.y < term.row-1) {
+				tclearregion(0, term.c.y+1, term.col-1,
+						term.row-1, 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);
+				tclearregion(0, 0, term.col-1, term.c.y-1, 1);
+			tclearregion(0, term.c.y, term.c.x, term.c.y, 1);
 			break;
 		case 2: /* all */
-			tclearregion(0, 0, term.col-1, term.row-1);
+			tclearregion(0, 0, term.col-1, term.row-1, 1);
 			break;
 		default:
 			goto unknown;
@@ -1681,13 +1692,14 @@ csihandle(void) {
 	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);
+			tclearregion(term.c.x, term.c.y, term.col-1,
+					term.c.y, 1);
 			break;
 		case 1: /* left */
-			tclearregion(0, term.c.y, term.c.x, term.c.y);
+			tclearregion(0, term.c.y, term.c.x, term.c.y, 1);
 			break;
 		case 2: /* all */
-			tclearregion(0, term.c.y, term.col-1, term.c.y);
+			tclearregion(0, term.c.y, term.col-1, term.c.y, 1);
 			break;
 		}
 		break;
@@ -1712,7 +1724,8 @@ csihandle(void) {
 		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], term.c.y);
+		tclearregion(term.c.x, term.c.y, term.c.x + csiescseq.arg[0],
+				term.c.y, 0);
 		break;
 	case 'P': /* DCH -- Delete <n> char */
 		DEFAULT(csiescseq.arg[0], 1);
@@ -2505,6 +2518,7 @@ xinit(void) {
 		xw.fy = 0;
 	}
 
+	/* Events */
 	attrs.background_pixel = dc.col[defaultbg].pixel;
 	attrs.border_pixel = dc.col[defaultbg].pixel;
 	attrs.bit_gravity = NorthWestGravity;
@@ -2898,6 +2912,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 					ox = x;
 					base = new;
 				}
+
 				sl = utf8size(new.c);
 				memcpy(buf+ib, new.c, sl);
 				ib += sl;
diff --git a/st.info b/st.info
index fcaa024..1c83dc1 100644
--- a/st.info
+++ b/st.info
@@ -3,7 +3,7 @@
 st| simpleterm,
 	acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
 	am,
-#	bce,
+	bce,
 	bel=^G,
 #	blink=\E[5m,
 	bold=\E[1m,

From d8f3809345d62477c204e03071db61fe8443fd5f Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 20 Jan 2013 14:55:08 +0100
Subject: [PATCH 0456/1146] Removing BCE from the TODO list.

---
 TODO | 1 -
 1 file changed, 1 deletion(-)

diff --git a/TODO b/TODO
index efecd50..2f42720 100644
--- a/TODO
+++ b/TODO
@@ -1,7 +1,6 @@
 vt emulation
 ------------
 
-* implement BCE right
 * color definition in CSI
 	* implement CSI parsing
 * wide-character support in conjunction with fallback xft code 

From 3036051fb18addd8ac15eac9e0ef3ee6aeb8bbc6 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 20 Jan 2013 15:12:45 +0100
Subject: [PATCH 0457/1146] St is in 2013 now.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 5f75c39..6749dbd 100644
--- a/st.c
+++ b/st.c
@@ -44,7 +44,7 @@
 #endif
 
 #define USAGE \
-	"st " VERSION " (c) 2010-2012 st engineers\n" \
+	"st " VERSION " (c) 2010-2013 st engineers\n" \
 	"usage: st [-v] [-c class] [-f font] [-g geometry] [-o file]" \
 	" [-t title] [-w windowid] [-e command ...]\n"
 

From 57f39defaf3f84b5d9efb3e7a8494cc7ff09e7af Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 20 Jan 2013 17:12:41 +0100
Subject: [PATCH 0458/1146] Fixing the clipboard copying to st itself.

---
 st.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 6749dbd..1a40765 100644
--- a/st.c
+++ b/st.c
@@ -793,6 +793,7 @@ void selclear(XEvent *e) {
 
 void
 selrequest(XEvent *e) {
+	fprintf(stderr, "selrequest\n");
 	XSelectionRequestEvent *xsre;
 	XSelectionEvent xev;
 	Atom xa_targets, string;
@@ -828,6 +829,7 @@ selrequest(XEvent *e) {
 
 void
 xsetsel(char *str) {
+	fprintf(stderr, "xsetsel: %s\n", str);
 	/* register the selection for both the clipboard and the primary */
 	Atom clipboard;
 
@@ -842,6 +844,7 @@ xsetsel(char *str) {
 
 void
 brelease(XEvent *e) {
+	fprintf(stderr, "brelease\n");
 	struct timeval now;
 
 	if(IS_SET(MODE_MOUSE)) {
@@ -2479,6 +2482,7 @@ xzoom(const Arg *arg)
 void
 xinit(void) {
 	XSetWindowAttributes attrs;
+	XGCValues gcvalues;
 	Cursor cursor;
 	Window parent;
 	int sw, sh, major, minor;
@@ -2544,7 +2548,10 @@ xinit(void) {
 		usedbe = True;
 	} else {
 	*/
-		dc.gc = XCreateGC(xw.dpy, parent, 0, 0);
+		memset(&gcvalues, 0, sizeof(gcvalues));
+		gcvalues.graphics_exposures = False;
+		dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
+				&gcvalues);
 		xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
 				DefaultDepth(xw.dpy, xw.scr));
 		XSetForeground(xw.dpy, dc.gc, 0);
@@ -2872,7 +2879,6 @@ draw(void) {
 		XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
 				xw.h, 0, 0);
 		XSetForeground(xw.dpy, dc.gc, 0);
-		XSync(xw.dpy, False);
 	}
 }
 
@@ -3169,6 +3175,7 @@ run(void) {
 			XNextEvent(xw.dpy, &ev);
 			if(XFilterEvent(&ev, None))
 				continue;
+			fprintf(stderr, "ev.type = %d\n", ev.type);
 			if(handler[ev.type])
 				(handler[ev.type])(&ev);
 		}

From deb720af7fe480b03c881818e79164817ce6f85f Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 20 Jan 2013 17:13:48 +0100
Subject: [PATCH 0459/1146] Removing the debug messages again.

---
 st.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/st.c b/st.c
index 1a40765..96e66fb 100644
--- a/st.c
+++ b/st.c
@@ -844,7 +844,6 @@ xsetsel(char *str) {
 
 void
 brelease(XEvent *e) {
-	fprintf(stderr, "brelease\n");
 	struct timeval now;
 
 	if(IS_SET(MODE_MOUSE)) {
@@ -3175,7 +3174,6 @@ run(void) {
 			XNextEvent(xw.dpy, &ev);
 			if(XFilterEvent(&ev, None))
 				continue;
-			fprintf(stderr, "ev.type = %d\n", ev.type);
 			if(handler[ev.type])
 				(handler[ev.type])(&ev);
 		}

From 384fabdb5b2ac6c700a974a7fac539c8c14107f6 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 26 Jan 2013 15:13:56 +0100
Subject: [PATCH 0460/1146] Adding extended mouse reporting in st.

Thanks Egmont Koblinger <egmont@gmail.com>!
---
 st.c | 35 ++++++++++++++++++++++++++---------
 1 file changed, 26 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index 96e66fb..38cec50 100644
--- a/st.c
+++ b/st.c
@@ -117,7 +117,8 @@ enum term_mode {
 	MODE_KBDLOCK     = 256,
 	MODE_HIDE	 = 512,
 	MODE_ECHO	 = 1024,
-	MODE_APPCURSOR	 = 2048
+	MODE_APPCURSOR	 = 2048,
+	MODE_MOUSESGR    = 4096,
 };
 
 enum escape_state {
@@ -666,11 +667,10 @@ getbuttoninfo(XEvent *e) {
 
 void
 mousereport(XEvent *e) {
-	int x = x2col(e->xbutton.x);
-	int y = y2row(e->xbutton.y);
-	int button = e->xbutton.button;
-	int state = e->xbutton.state;
-	char buf[] = { '\033', '[', 'M', 0, 32+x+1, 32+y+1 };
+	int x = x2col(e->xbutton.x), y = y2row(e->xbutton.y),
+	    button = e->xbutton.button, state = e->xbutton.state,
+	    len;
+	char buf[40];
 	static int ob, ox, oy;
 
 	/* from urxvt */
@@ -679,7 +679,9 @@ mousereport(XEvent *e) {
 			return;
 		button = ob + 32;
 		ox = x, oy = y;
-	} else if(e->xbutton.type == ButtonRelease || button == AnyButton) {
+	} else if(!IS_SET(MODE_MOUSESGR)
+			&& (e->xbutton.type == ButtonRelease
+				|| button == AnyButton)) {
 		button = 3;
 	} else {
 		button -= Button1;
@@ -691,11 +693,23 @@ mousereport(XEvent *e) {
 		}
 	}
 
-	buf[3] = 32 + button + (state & ShiftMask ? 4 : 0)
+	button += (state & ShiftMask   ? 4  : 0)
 		+ (state & Mod4Mask    ? 8  : 0)
 		+ (state & ControlMask ? 16 : 0);
 
-	ttywrite(buf, sizeof(buf));
+	len = 0;
+	if(IS_SET(MODE_MOUSESGR)) {
+		len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
+				button, x+1, y+1,
+				e->xbutton.type == ButtonRelease ? 'm' : 'M');
+	} else if(x < 223 && y < 223) {
+		len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
+				32+button, 32+x+1, 32+y+1);
+	} else {
+		return;
+	}
+
+	ttywrite(buf, len);
 }
 
 void
@@ -1547,6 +1561,9 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 1002:
 				MODBIT(term.mode, set, MODE_MOUSEMOTION);
 				break;
+			case 1006:
+				MODBIT(term.mode, set, MODE_MOUSESGR);
+				break;
 			case 1049: /* = 1047 and 1048 */
 			case 47:
 			case 1047: {

From 26c101b70671d1adbdd4e31af70502605fe3ebbf Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 27 Jan 2013 13:26:06 +0100
Subject: [PATCH 0461/1146] Fixing the black remaining lines in mc and dialog.

This also applies some style fixes and handles some old blink codes.
---
 st.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/st.c b/st.c
index 38cec50..fa4136a 100644
--- a/st.c
+++ b/st.c
@@ -1421,7 +1421,8 @@ tsetattr(int *attr, int l) {
 		case 4:
 			term.c.attr.mode |= ATTR_UNDERLINE;
 			break;
-		case 5:
+		case 5: /* slow blink */
+		case 6: /* rapid blink */
 			term.c.attr.mode |= ATTR_BLINK;
 			break;
 		case 7:
@@ -1438,6 +1439,7 @@ tsetattr(int *attr, int l) {
 			term.c.attr.mode &= ~ATTR_UNDERLINE;
 			break;
 		case 25:
+		case 26:
 			term.c.attr.mode &= ~ATTR_BLINK;
 			break;
 		case 27:
@@ -1744,7 +1746,7 @@ csihandle(void) {
 	case 'X': /* ECH -- Erase <n> char */
 		DEFAULT(csiescseq.arg[0], 1);
 		tclearregion(term.c.x, term.c.y, term.c.x + csiescseq.arg[0],
-				term.c.y, 0);
+				term.c.y, 1);
 		break;
 	case 'P': /* DCH -- Delete <n> char */
 		DEFAULT(csiescseq.arg[0], 1);
@@ -2206,9 +2208,11 @@ tresize(int col, int row) {
 	/* free unneeded rows */
 	i = 0;
 	if(slide > 0) {
-		/* slide screen to keep cursor where we expect it -
+		/*
+		 * 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 */
+		 * memmove because we're freeing the earlier lines
+		 */
 		for(/* i = 0 */; i < slide; i++) {
 			free(term.line[i]);
 			free(term.alt[i]);
@@ -2456,8 +2460,7 @@ xloadfonts(char *fontstr, int fontsize) {
 }
 
 void
-xunloadfonts(void)
-{
+xunloadfonts(void) {
 	int i, ip;
 
 	/*
@@ -2487,8 +2490,7 @@ xunloadfonts(void)
 }
 
 void
-xzoom(const Arg *arg)
-{
+xzoom(const Arg *arg) {
 	xunloadfonts();
 	xloadfonts(usedfont, usedfontsize + arg->i);
 	cresize(0, 0);
@@ -3109,8 +3111,10 @@ kpress(XEvent *ev) {
 
 void
 cmessage(XEvent *e) {
-	/* See xembed specs
-	   http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html */
+	/*
+	 * 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) {
 			xw.state |= WIN_FOCUSED;
@@ -3126,8 +3130,7 @@ cmessage(XEvent *e) {
 }
 
 void
-cresize(int width, int height)
-{
+cresize(int width, int height) {
 	int col, row;
 
 	if(width != 0)

From efd04ccad6d3c4e981b3efdb0423d8f5ca40f984 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 27 Jan 2013 17:48:01 +0100
Subject: [PATCH 0462/1146] Fixing the menus in mc.

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index fa4136a..a1932dd 100644
--- a/st.c
+++ b/st.c
@@ -1745,8 +1745,8 @@ csihandle(void) {
 		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],
-				term.c.y, 1);
+		tclearregion(term.c.x, term.c.y,
+				term.c.x + csiescseq.arg[0] - 1, term.c.y, 1);
 		break;
 	case 'P': /* DCH -- Delete <n> char */
 		DEFAULT(csiescseq.arg[0], 1);

From ce3efa9e9b50b0d86ef2d030657dfc69034d6ef7 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 8 Feb 2013 20:24:26 +0100
Subject: [PATCH 0463/1146] Removing some debug messages.

---
 st.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/st.c b/st.c
index a1932dd..4d1c1bb 100644
--- a/st.c
+++ b/st.c
@@ -807,7 +807,6 @@ void selclear(XEvent *e) {
 
 void
 selrequest(XEvent *e) {
-	fprintf(stderr, "selrequest\n");
 	XSelectionRequestEvent *xsre;
 	XSelectionEvent xev;
 	Atom xa_targets, string;
@@ -843,7 +842,6 @@ selrequest(XEvent *e) {
 
 void
 xsetsel(char *str) {
-	fprintf(stderr, "xsetsel: %s\n", str);
 	/* register the selection for both the clipboard and the primary */
 	Atom clipboard;
 

From 8a9475a0dd9b8751b9b0ed4c7da4db09232e318e Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 10 Feb 2013 16:36:03 +0100
Subject: [PATCH 0464/1146] Setting the surrounding border to defaultbg.

Thanks Stephen Caraher <moskvax@gmail.com>!
---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 4d1c1bb..08cda34 100644
--- a/st.c
+++ b/st.c
@@ -2275,7 +2275,7 @@ xresize(int col, int row) {
 		XFreePixmap(xw.dpy, xw.buf);
 		xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
 				DefaultDepth(xw.dpy, xw.scr));
-		XSetForeground(xw.dpy, dc.gc, 0);
+		XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
 		XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
 	}
 
@@ -2570,7 +2570,7 @@ xinit(void) {
 				&gcvalues);
 		xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
 				DefaultDepth(xw.dpy, xw.scr));
-		XSetForeground(xw.dpy, dc.gc, 0);
+		XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
 		XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
 		//xw.buf = xw.win;
 	/*
@@ -2894,7 +2894,7 @@ draw(void) {
 	} else {
 		XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
 				xw.h, 0, 0);
-		XSetForeground(xw.dpy, dc.gc, 0);
+		XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
 	}
 }
 

From eeffbe11ab8b3ea94eefcf178003e36d389f8776 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 11 Feb 2013 22:20:16 +0100
Subject: [PATCH 0465/1146] Making st not activate the cursor in case of Mod +
 k in dwm.

Thanks Jens Nyberg <jens.nyberg@gmail.com>!
---
 st.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/st.c b/st.c
index 08cda34..2c803fa 100644
--- a/st.c
+++ b/st.c
@@ -2986,6 +2986,11 @@ xseturgency(int add) {
 
 void
 focus(XEvent *ev) {
+	XFocusChangeEvent *e = &ev->xfocus;
+
+	if(e->mode == NotifyGrab)
+		return;
+
 	if(ev->type == FocusIn) {
 		XSetICFocus(xw.xic);
 		xw.state |= WIN_FOCUSED;

From 05a1ff03e95877a3b4c0ffee3164db65bb36d3ed Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 13 Feb 2013 21:35:27 +0100
Subject: [PATCH 0466/1146] Adding mor explict font patterns.

---
 st.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.c b/st.c
index 2c803fa..72f12a7 100644
--- a/st.c
+++ b/st.c
@@ -2440,7 +2440,9 @@ xloadfonts(char *fontstr, int fontsize) {
 	xw.cw = dc.font.width;
 	xw.ch = dc.font.height;
 
+	FcPatternDel(pattern, FC_SLANT);
 	FcPatternDel(pattern, FC_WEIGHT);
+	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
 	FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
 	if(xloadfont(&dc.bfont, pattern))
 		die("st: can't open font %s\n", fontstr);
@@ -2451,6 +2453,7 @@ xloadfonts(char *fontstr, int fontsize) {
 		die("st: can't open font %s\n", fontstr);
 
 	FcPatternDel(pattern, FC_WEIGHT);
+	FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_MEDIUM);
 	if(xloadfont(&dc.ifont, pattern))
 		die("st: can't open font %s\n", fontstr);
 

From b7261c84aa3af984d5a7e5f5239c4173255a215d Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 15 Feb 2013 17:45:38 +0100
Subject: [PATCH 0467/1146] Tmux wants this to be mutually exclusive.

Thanks Egmont Koblinger <egmont@gmail.com> for noticing this!
---
 st.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.c b/st.c
index 72f12a7..8206001 100644
--- a/st.c
+++ b/st.c
@@ -1557,9 +1557,11 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				break;
 			case 1000: /* 1000,1002: enable xterm mouse report */
 				MODBIT(term.mode, set, MODE_MOUSEBTN);
+				MODBIT(term.mode, 0, MODE_MOUSEMOTION);
 				break;
 			case 1002:
 				MODBIT(term.mode, set, MODE_MOUSEMOTION);
+				MODBIT(term.mode, 0, MODE_MOUSEBTN);
 				break;
 			case 1006:
 				MODBIT(term.mode, set, MODE_MOUSESGR);

From 95033753be32e93915ddce14ea41b8765b665771 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 15 Feb 2013 19:10:22 +0100
Subject: [PATCH 0468/1146] Adding a more efficient drawing code.

Thanks Mihail Zenkov <mihail.zenkov@gmail.com> for giving the hint!
---
 config.def.h |  5 +++-
 st.c         | 65 ++++++++++++++++++++++++++++++----------------------
 2 files changed, 42 insertions(+), 28 deletions(-)

diff --git a/config.def.h b/config.def.h
index 684adf7..8732ca3 100644
--- a/config.def.h
+++ b/config.def.h
@@ -9,10 +9,13 @@ static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=fals
 static int borderpx = 2;
 static char shell[] = "/bin/sh";
 
-/* double-click timeout (in milliseconds) between clicks for selection */
+/* timeouts (in milliseconds) */
 static unsigned int doubleclicktimeout = 300;
 static unsigned int tripleclicktimeout = 600;
 
+/* frames per second st should at maximum draw to the screen */
+static unsigned int framespersecond = 60;
+
 /* TERM value */
 static char termname[] = "st-256color";
 
diff --git a/st.c b/st.c
index 8206001..f4b419e 100644
--- a/st.c
+++ b/st.c
@@ -3166,10 +3166,12 @@ void
 run(void) {
 	XEvent ev;
 	fd_set rfd;
-	int xfd = XConnectionNumber(xw.dpy), i;
-	struct timeval drawtimeout, *tv = NULL;
+	int xfd = XConnectionNumber(xw.dpy);
+	struct timeval drawtimeout, *tv = NULL, now, last;
 
-	for(i = 0;; i++) {
+	gettimeofday(&last, NULL);
+
+	for(;;) {
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);
@@ -3179,35 +3181,44 @@ run(void) {
 			die("select failed: %s\n", SERRNO);
 		}
 
-		/*
-		 * Stop after a certain number of reads so the user does not
-		 * feel like the system is stuttering.
-		 */
-		if(i < 1000 && FD_ISSET(cmdfd, &rfd)) {
+		gettimeofday(&now, NULL);
+		/* usecs until (next) frame */
+		drawtimeout.tv_sec = 0;
+		drawtimeout.tv_usec = \
+			((1000/framespersecond) - TIMEDIFF(now, last)) * 1000;
+
+		/* Let us draw a frame. */
+		if(drawtimeout.tv_usec <= 0) {
+			draw();
+			XFlush(xw.dpy);
+
+			last = now;
+			tv = NULL;
+		}
+
+		if(FD_ISSET(cmdfd, &rfd))
 			ttyread();
 
-			/*
-			 * Just wait a bit so it isn't disturbing the
-			 * user and the system is able to write something.
-			 */
-			drawtimeout.tv_sec = 0;
-			drawtimeout.tv_usec = 5;
+		if(FD_ISSET(xfd, &rfd)) {
+			while(XPending(xw.dpy)) {
+				XNextEvent(xw.dpy, &ev);
+				if(XFilterEvent(&ev, None))
+					continue;
+				if(handler[ev.type])
+					(handler[ev.type])(&ev);
+			}
+
+			if(drawtimeout.tv_usec <= 0) {
+				draw();
+				XFlush(xw.dpy);
+			}
+		}
+
+		/* There is still some time to wait until next frame. */
+		if(drawtimeout.tv_usec > 0) {
 			tv = &drawtimeout;
 			continue;
 		}
-		i = 0;
-		tv = NULL;
-
-		while(XPending(xw.dpy)) {
-			XNextEvent(xw.dpy, &ev);
-			if(XFilterEvent(&ev, None))
-				continue;
-			if(handler[ev.type])
-				(handler[ev.type])(&ev);
-		}
-
-		draw();
-		XFlush(xw.dpy);
 	}
 }
 

From 086cd61511aa5ca4cbef0048137bb9ae0467d283 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 15 Feb 2013 19:30:43 +0100
Subject: [PATCH 0469/1146] Doing it like the new run() was proposed.

---
 config.def.h |  3 ++-
 st.c         | 38 +++++++++++++++-----------------------
 2 files changed, 17 insertions(+), 24 deletions(-)

diff --git a/config.def.h b/config.def.h
index 8732ca3..35e5cf9 100644
--- a/config.def.h
+++ b/config.def.h
@@ -14,7 +14,8 @@ static unsigned int doubleclicktimeout = 300;
 static unsigned int tripleclicktimeout = 600;
 
 /* frames per second st should at maximum draw to the screen */
-static unsigned int framespersecond = 60;
+static unsigned int xfps = 30;
+static unsigned int actionfps = 5;
 
 /* TERM value */
 static char termname[] = "st-256color";
diff --git a/st.c b/st.c
index f4b419e..f6e606b 100644
--- a/st.c
+++ b/st.c
@@ -3166,12 +3166,12 @@ void
 run(void) {
 	XEvent ev;
 	fd_set rfd;
-	int xfd = XConnectionNumber(xw.dpy);
+	int xfd = XConnectionNumber(xw.dpy), xev;
 	struct timeval drawtimeout, *tv = NULL, now, last;
 
 	gettimeofday(&last, NULL);
 
-	for(;;) {
+	for(xev = actionfps;;) {
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);
@@ -3184,22 +3184,16 @@ run(void) {
 		gettimeofday(&now, NULL);
 		/* usecs until (next) frame */
 		drawtimeout.tv_sec = 0;
-		drawtimeout.tv_usec = \
-			((1000/framespersecond) - TIMEDIFF(now, last)) * 1000;
-
-		/* Let us draw a frame. */
-		if(drawtimeout.tv_usec <= 0) {
-			draw();
-			XFlush(xw.dpy);
-
-			last = now;
-			tv = NULL;
-		}
+		drawtimeout.tv_usec = (1000/xfps) * 1000;
+		tv = &drawtimeout;
 
 		if(FD_ISSET(cmdfd, &rfd))
 			ttyread();
 
-		if(FD_ISSET(xfd, &rfd)) {
+		if(FD_ISSET(xfd, &rfd))
+			xev = actionfps;
+
+		if(TIMEDIFF(now, last) > (xev ? (1000/xfps) : (1000/actionfps))) {
 			while(XPending(xw.dpy)) {
 				XNextEvent(xw.dpy, &ev);
 				if(XFilterEvent(&ev, None))
@@ -3208,16 +3202,14 @@ run(void) {
 					(handler[ev.type])(&ev);
 			}
 
-			if(drawtimeout.tv_usec <= 0) {
-				draw();
-				XFlush(xw.dpy);
-			}
-		}
+			draw();
+			XFlush(xw.dpy);
+			last = now;
 
-		/* There is still some time to wait until next frame. */
-		if(drawtimeout.tv_usec > 0) {
-			tv = &drawtimeout;
-			continue;
+			if(xev && !FD_ISSET(xfd, &rfd))
+				xev--;
+			if(!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd))
+				tv = NULL;
 		}
 	}
 }

From de7e0e9c8d978f581328962b39e94b59e86f077e Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 15 Feb 2013 19:32:37 +0100
Subject: [PATCH 0470/1146] Changing the fps to something reasonable high.

---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 35e5cf9..baf56f5 100644
--- a/config.def.h
+++ b/config.def.h
@@ -14,7 +14,7 @@ static unsigned int doubleclicktimeout = 300;
 static unsigned int tripleclicktimeout = 600;
 
 /* frames per second st should at maximum draw to the screen */
-static unsigned int xfps = 30;
+static unsigned int xfps = 60;
 static unsigned int actionfps = 5;
 
 /* TERM value */

From a92a678e252aeeb54537dfa7e3f106eac88f8d77 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 15 Feb 2013 19:34:53 +0100
Subject: [PATCH 0471/1146] The refresh rate for the action needs to be high
 too.

---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index baf56f5..93fc26d 100644
--- a/config.def.h
+++ b/config.def.h
@@ -15,7 +15,7 @@ static unsigned int tripleclicktimeout = 600;
 
 /* frames per second st should at maximum draw to the screen */
 static unsigned int xfps = 60;
-static unsigned int actionfps = 5;
+static unsigned int actionfps = 30;
 
 /* TERM value */
 static char termname[] = "st-256color";

From e0ec2cf984ff8006b99cf4ca8590ceec7113daac Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 15 Feb 2013 19:36:20 +0100
Subject: [PATCH 0472/1146] Style inquisition.

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index f6e606b..0ae2c90 100644
--- a/st.c
+++ b/st.c
@@ -3182,7 +3182,6 @@ run(void) {
 		}
 
 		gettimeofday(&now, NULL);
-		/* usecs until (next) frame */
 		drawtimeout.tv_sec = 0;
 		drawtimeout.tv_usec = (1000/xfps) * 1000;
 		tv = &drawtimeout;
@@ -3193,7 +3192,8 @@ run(void) {
 		if(FD_ISSET(xfd, &rfd))
 			xev = actionfps;
 
-		if(TIMEDIFF(now, last) > (xev ? (1000/xfps) : (1000/actionfps))) {
+		if(TIMEDIFF(now, last) > \
+				(xev ? (1000/xfps) : (1000/actionfps))) {
 			while(XPending(xw.dpy)) {
 				XNextEvent(xw.dpy, &ev);
 				if(XFilterEvent(&ev, None))

From f4a6c20f464df79a9b15b4a2a11daaa7a06c60a0 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 16 Feb 2013 13:57:12 +0100
Subject: [PATCH 0473/1146] Adding a way to ignore bits in the state.

---
 config.def.h | 6 ++++++
 st.c         | 3 +++
 2 files changed, 9 insertions(+)

diff --git a/config.def.h b/config.def.h
index 93fc26d..07a22ed 100644
--- a/config.def.h
+++ b/config.def.h
@@ -104,6 +104,12 @@ static Shortcut shortcuts[] = {
  */
 static KeySym mappedkeys[] = { -1 };
 
+/*
+ * Which bits of the state should be ignored. By default the state bit for the
+ * keyboard layout (XK_SWITCH_MOD) is ignored.
+ */
+uint ignoremod = XK_SWITCH_MOD;
+
 /* key, mask, output, keypad, cursor, crlf */
 static Key key[] = {
 	/* keysym             mask         string         keypad cursor crlf */
diff --git a/st.c b/st.c
index 0ae2c90..64366af 100644
--- a/st.c
+++ b/st.c
@@ -61,6 +61,7 @@
 #define DRAW_BUF_SIZ  20*1024
 #define XK_ANY_MOD    UINT_MAX
 #define XK_NO_MOD     0
+#define XK_SWITCH_MOD (1<<13)
 
 #define REDRAW_TIMEOUT (80*1000) /* 80 ms */
 
@@ -3008,6 +3009,8 @@ focus(XEvent *ev) {
 
 inline bool
 match(uint mask, uint state) {
+	state &= ~(ignoremod);
+
 	if(mask == XK_NO_MOD && state)
 		return false;
 	if(mask != XK_ANY_MOD && mask != XK_NO_MOD && !state)

From 7f297e297ccec99a66b7af46e2b1725545ba3746 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 19 Feb 2013 15:51:25 +0100
Subject: [PATCH 0474/1146] Fixing the reverse mode of st colors.

Thanks Alexander Sedov <alex0player@gmail.com> for finding this!
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 64366af..8320695 100644
--- a/st.c
+++ b/st.c
@@ -2288,7 +2288,7 @@ xresize(int col, int row) {
 void
 xloadcols(void) {
 	int i, r, g, b;
-	XRenderColor color = { .alpha = 0 };
+	XRenderColor color = { .alpha = 0xffff };
 
 	/* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */
 	for(i = 0; i < LEN(colorname); i++) {

From 0e738c3d7291675472380a25b74f0358306541e5 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 19 Feb 2013 16:04:54 +0100
Subject: [PATCH 0475/1146] Style inquisition.

---
 st.c | 44 ++++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/st.c b/st.c
index 8320695..19f8346 100644
--- a/st.c
+++ b/st.c
@@ -1662,7 +1662,7 @@ csihandle(void) {
 		tmoveto(0, term.c.y-csiescseq.arg[0]);
 		break;
 	case 'g': /* TBC -- Tabulation clear */
-		switch (csiescseq.arg[0]) {
+		switch(csiescseq.arg[0]) {
 		case 0: /* clear current tab stop */
 			term.tabs[term.c.x] = 0;
 			break;
@@ -1927,7 +1927,7 @@ techo(char *buf, int len) {
 		if(c == '\033') {		/* escape */
 			tputc("^", 1);
 			tputc("[", 1);
-		} else if (c < '\x20') {	/* control code */
+		} else if(c < '\x20') {	/* control code */
 			if(c != '\n' && c != '\r' && c != '\t') {
 				c |= '\x40';
 				tputc("^", 1);
@@ -1937,7 +1937,7 @@ techo(char *buf, int len) {
 			break;
 		}
 	}
-	if (len)
+	if(len)
 		tputc(buf, len);
 }
 
@@ -1947,7 +1947,7 @@ tputc(char *c, int len) {
 	bool control = ascii < '\x20' || ascii == 0177;
 
 	if(iofd != -1) {
-		if (xwrite(iofd, c, len) < 0) {
+		if(xwrite(iofd, c, len) < 0) {
 			fprintf(stderr, "Error writing in %s:%s\n",
 				opt_io, strerror(errno));
 			close(iofd);
@@ -2471,8 +2471,8 @@ xunloadfonts(void) {
 	 * Free the loaded fonts in the font cache. This is done backwards
 	 * from the frccur.
 	 */
-	for (i = 0, ip = frccur; i < frclen; i++, ip--) {
-		if (ip < 0)
+	for(i = 0, ip = frccur; i < frclen; i++, ip--) {
+		if(ip < 0)
 			ip = LEN(frc) - 1;
 		XftFontClose(xw.dpy, frc[ip].font);
 	}
@@ -2515,7 +2515,7 @@ xinit(void) {
 	xw.vis = XDefaultVisual(xw.dpy, xw.scr);
 
 	/* font */
-	if (!FcInit())
+	if(!FcInit())
 		die("Could not init fontconfig.\n");
 
 	usedfont = (opt_font == NULL)? font : opt_font;
@@ -2718,7 +2718,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch);
 
 	fcsets[0] = font->set;
-	for (xp = winx; bytelen > 0;) {
+	for(xp = winx; bytelen > 0;) {
 		/*
 		 * Search for the range in the to be printed string of glyphs
 		 * that are in the main font. Then print that range. If
@@ -2728,22 +2728,22 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		u8fs = s;
 		u8fblen = 0;
 		u8fl = 0;
-		for (;;) {
+		for(;;) {
 			u8c = s;
 			u8cblen = utf8decode(s, &u8char);
 			s += u8cblen;
 			bytelen -= u8cblen;
 
 			doesexist = XftCharIndex(xw.dpy, font->match, u8char);
-			if (!doesexist || bytelen <= 0) {
-				if (bytelen <= 0) {
-					if (doesexist) {
+			if(!doesexist || bytelen <= 0) {
+				if(bytelen <= 0) {
+					if(doesexist) {
 						u8fl++;
 						u8fblen += u8cblen;
 					}
 				}
 
-				if (u8fl > 0) {
+				if(u8fl > 0) {
 					XftDrawStringUtf8(xw.draw, fg,
 							font->match, xp,
 							winy + font->ascent,
@@ -2757,23 +2757,23 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			u8fl++;
 			u8fblen += u8cblen;
 		}
-		if (doesexist)
+		if(doesexist)
 			break;
 
 		frp = frccur;
 		/* Search the font cache. */
-		for (i = 0; i < frclen; i++, frp--) {
-			if (frp <= 0)
+		for(i = 0; i < frclen; i++, frp--) {
+			if(frp <= 0)
 				frp = LEN(frc) - 1;
 
-			if (frc[frp].c == u8char
+			if(frc[frp].c == u8char
 					&& frc[frp].flags == frcflags) {
 				break;
 			}
 		}
 
 		/* Nothing was found. */
-		if (i >= frclen) {
+		if(i >= frclen) {
 			/*
 			 * Nothing was found in the cache. Now use
 			 * some dozen of Fontconfig calls to get the
@@ -2801,9 +2801,9 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			 */
 			frccur++;
 			frclen++;
-			if (frccur >= LEN(frc))
+			if(frccur >= LEN(frc))
 				frccur = 0;
-			if (frclen > LEN(frc)) {
+			if(frclen > LEN(frc)) {
 				frclen = LEN(frc);
 				XftFontClose(xw.dpy, frc[frccur].font);
 			}
@@ -3085,7 +3085,7 @@ kpress(XEvent *ev) {
 	Status status;
 	Shortcut *bp;
 
-	if (IS_SET(MODE_KBDLOCK))
+	if(IS_SET(MODE_KBDLOCK))
 		return;
 
 	len = XmbLookupString(xw.xic, e, xstr, sizeof(xstr), &ksym, &status);
@@ -3107,7 +3107,7 @@ kpress(XEvent *ev) {
 		if(len == 0)
 			return;
 
-		if (len == 1 && e->state & Mod1Mask)
+		if(len == 1 && e->state & Mod1Mask)
 			*cp++ = '\033';
 
 		memcpy(cp, xstr, len);

From e5295629cdffb711001f3fdffbb9aa4ef772add0 Mon Sep 17 00:00:00 2001
From: joe9 <joe9mail@gmail.com>
Date: Mon, 18 Feb 2013 12:31:29 -0500
Subject: [PATCH 0476/1146] ensure that the italic font has the same weight as
 the normal font

The specified font[] pattern need not have a medium weight. It could be
specified as a number too or have a different weight other than medium.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index 19f8346..7befdc0 100644
--- a/st.c
+++ b/st.c
@@ -2444,20 +2444,18 @@ xloadfonts(char *fontstr, int fontsize) {
 	xw.ch = dc.font.height;
 
 	FcPatternDel(pattern, FC_SLANT);
-	FcPatternDel(pattern, FC_WEIGHT);
-	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
-	FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
-	if(xloadfont(&dc.bfont, pattern))
+	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+	if(xloadfont(&dc.ifont, pattern))
 		die("st: can't open font %s\n", fontstr);
 
-	FcPatternDel(pattern, FC_SLANT);
-	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+	FcPatternDel(pattern, FC_WEIGHT);
+	FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
 	if(xloadfont(&dc.ibfont, pattern))
 		die("st: can't open font %s\n", fontstr);
 
-	FcPatternDel(pattern, FC_WEIGHT);
-	FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_MEDIUM);
-	if(xloadfont(&dc.ifont, pattern))
+	FcPatternDel(pattern, FC_SLANT);
+	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
+	if(xloadfont(&dc.bfont, pattern))
 		die("st: can't open font %s\n", fontstr);
 
 	FcPatternDestroy(pattern);

From 3865e9eaaf4e1c7820b1f41ce9d0b1d7b109fb26 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 19 Feb 2013 19:08:41 +0100
Subject: [PATCH 0477/1146] Implement rectangular mouse selection.

Thanks Alexander Sedov <alex0player@gmail.com>!
---
 config.def.h | 12 ++++++++++
 st.c         | 68 +++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 66 insertions(+), 14 deletions(-)

diff --git a/config.def.h b/config.def.h
index 07a22ed..a31a235 100644
--- a/config.def.h
+++ b/config.def.h
@@ -305,3 +305,15 @@ static Key key[] = {
 	{ XK_F35,           XK_NO_MOD,      "\033[23;5~",    0,    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,
+};
+
diff --git a/st.c b/st.c
index 7befdc0..300e5ec 100644
--- a/st.c
+++ b/st.c
@@ -137,6 +137,11 @@ enum window_state {
 	WIN_FOCUSED = 4
 };
 
+enum selection_type {
+	SEL_REGULAR = 1,
+	SEL_RECTANGULAR = 2
+};
+
 /* bit macro */
 #undef B0
 enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 };
@@ -234,6 +239,7 @@ typedef struct {
 /* TODO: use better name for vars... */
 typedef struct {
 	int mode;
+	int type;
 	int bx, by;
 	int ex, ey;
 	struct {
@@ -651,10 +657,23 @@ selected(int x, int y) {
 			|| (y == sel.e.y && x <= sel.e.x))
 			|| (y == sel.b.y && x >= sel.b.x
 				&& (x <= sel.e.x || sel.b.y != sel.e.y));
+	switch(sel.type) {
+	case SEL_REGULAR:
+		return ((sel.b.y < y && y < sel.e.y)
+			|| (y == sel.e.y && x <= sel.e.x))
+			|| (y == sel.b.y && x >= sel.b.x
+				&& (x <= sel.e.x || sel.b.y != sel.e.y));
+	case SEL_RECTANGULAR:
+		return ((sel.b.y <= y && y <= sel.e.y)
+			&& (sel.b.x <= x && x <= sel.e.x));
+	};
 }
 
 void
 getbuttoninfo(XEvent *e) {
+	int type;
+	uint state = e->xbutton.state &~Button1Mask;
+
 	sel.alt = IS_SET(MODE_ALTSCREEN);
 
 	sel.ex = x2col(e->xbutton.x);
@@ -664,6 +683,14 @@ getbuttoninfo(XEvent *e) {
 	sel.b.y = MIN(sel.by, sel.ey);
 	sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx;
 	sel.e.y = MAX(sel.by, sel.ey);
+
+	sel.type = SEL_REGULAR;
+	for(type = 1; type < LEN(selmasks); ++type) {
+		if(match(selmasks[type], state)) {
+			sel.type = type;
+			break;
+		}
+	}
 }
 
 void
@@ -724,6 +751,7 @@ bpress(XEvent *e) {
 			draw();
 		}
 		sel.mode = 1;
+		sel.type = SEL_REGULAR;
 		sel.ex = sel.bx = x2col(e->xbutton.x);
 		sel.ey = sel.by = y2row(e->xbutton.y);
 	} else if(e->xbutton.button == Button4) {
@@ -746,7 +774,8 @@ selcopy(void) {
 		ptr = str = xmalloc(bufsize);
 
 		/* append every set & selected glyph to the selection */
-		for(y = 0; y < term.row; y++) {
+		for(y = sel.b.y; y < sel.e.y + 1; y++) {
+			is_selected = 0;
 			gp = &term.line[y][0];
 			last = gp + term.col;
 
@@ -754,8 +783,11 @@ selcopy(void) {
 				/* nothing */;
 
 			for(x = 0; gp <= last; x++, ++gp) {
-				if(!(is_selected = selected(x, y)))
+				if(!selected(x, y)) {
 					continue;
+				} else {
+					is_selected = 1;
+				}
 
 				p = (gp->state & GLYPH_SET) ? gp->c : " ";
 				size = utf8size(p);
@@ -907,7 +939,7 @@ brelease(XEvent *e) {
 
 void
 bmotion(XEvent *e) {
-	int starty, endy, oldey, oldex;
+	int oldey, oldex;
 
 	if(IS_SET(MODE_MOUSE)) {
 		mousereport(e);
@@ -922,9 +954,7 @@ bmotion(XEvent *e) {
 	getbuttoninfo(e);
 
 	if(oldey != sel.ey || oldex != sel.ex) {
-		starty = MIN(oldey, sel.ey);
-		endy = MAX(oldey, sel.ey);
-		tsetdirt(starty, endy);
+		tsetdirt(sel.b.y, sel.e.y);
 	}
 }
 
@@ -1216,14 +1246,24 @@ selscroll(int orig, int n) {
 			sel.bx = -1;
 			return;
 		}
-		if(sel.by < term.top) {
-			sel.by = term.top;
-			sel.bx = 0;
-		}
-		if(sel.ey > term.bot) {
-			sel.ey = term.bot;
-			sel.ex = term.col;
-		}
+		switch(sel.type) {
+		case SEL_REGULAR:
+			if(sel.by < term.top) {
+				sel.by = term.top;
+				sel.bx = 0;
+			}
+			if(sel.ey > term.bot) {
+				sel.ey = term.bot;
+				sel.ex = term.col;
+			}
+			break;
+		case SEL_RECTANGULAR:
+			if(sel.by < term.top)
+				sel.by = term.top;
+			if(sel.ey > term.bot)
+				sel.ey = term.bot;
+			break;
+		};
 		sel.b.y = sel.by, sel.b.x = sel.bx;
 		sel.e.y = sel.ey, sel.e.x = sel.ex;
 	}

From 800800a3bba020f1e71e821b31c1ad037aab64ee Mon Sep 17 00:00:00 2001
From: Alexander Sedov <alex0player@gmail.com>
Date: Tue, 19 Feb 2013 21:39:13 +0400
Subject: [PATCH 0478/1146] Added basic xterm-ish palette swap support.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 93 insertions(+), 18 deletions(-)

diff --git a/st.c b/st.c
index 300e5ec..c25f24c 100644
--- a/st.c
+++ b/st.c
@@ -302,6 +302,7 @@ static void execsh(void);
 static void sigchld(int);
 static void run(void);
 
+static inline int parse_int(char *);
 static void csidump(void);
 static void csihandle(void);
 static void csiparse(void);
@@ -348,6 +349,7 @@ static void xclear(int, int, int, int);
 static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
+static int xsetcolorname(int, const char *);
 static int xloadfont(Font *, FcPattern *);
 static void xloadfonts(char *, int);
 static void xresettitle(void);
@@ -1855,35 +1857,59 @@ csireset(void) {
 	memset(&csiescseq, 0, sizeof(csiescseq));
 }
 
+inline int
+parse_int(char *s) {
+	int x = 0;
+	char c;
+	while(isdigit(c = *s)) {
+		if((INT_MAX - c + '0') / 10 >= x) {
+			x = x * 10 + c - '0';
+		} else
+			return -1;
+		s++;
+	}
+	if(*s != '\0')
+		return -1;
+	return x;
+}
+
 void
 strhandle(void) {
-	char *p;
+	char *p = NULL;
+	int i, j;
+	int narg;
 
 	/*
 	 * TODO: make this being useful in case of color palette change.
 	 */
 	strparse();
-
-	p = strescseq.buf;
+	narg = strescseq.narg;
 
 	switch(strescseq.type) {
 	case ']': /* OSC -- Operating System Command */
-		switch(p[0]) {
-		case '0':
-		case '1':
-		case '2':
+		switch(i = parse_int(strescseq.args[0])) {
+		case 0:
+		case 1:
+		case 2:
 			/*
 			 * TODO: Handle special chars in string, like umlauts.
 			 */
-			if(p[1] == ';') {
-				XStoreName(xw.dpy, xw.win, strescseq.buf+2);
+			if(narg > 1)
+				XStoreName(xw.dpy, xw.win, strescseq.args[2]);
+			break;
+		case 4: /* color set */
+			if(narg < 3)
+				break;
+			p = strescseq.args[2];
+			/* fall through */
+		case 104: /* color reset, here p = NULL */
+			j = (narg > 1) ? parse_int(strescseq.args[1]) : -1;
+			if (!xsetcolorname(j, p))
+				fprintf(stderr, "erresc: invalid color %s\n", p);
+			else {
+				redraw(0); /* TODO if defaultbg color is changed, borders are dirty */
 			}
 			break;
-		case ';':
-			XStoreName(xw.dpy, xw.win, strescseq.buf+1);
-			break;
-		case '4': /* TODO: Set color (arg0) to "rgb:%hexr/$hexg/$hexb" (arg1) */
-			break;
 		default:
 			fprintf(stderr, "erresc: unknown str ");
 			strdump();
@@ -1910,7 +1936,19 @@ strparse(void) {
 	 * TODO: Implement parsing like for CSI when required.
 	 * Format: ESC type cmd ';' arg0 [';' argn] ESC \
 	 */
-	return;
+	int narg = 0;
+	char *start = strescseq.buf, *end = start + strescseq.len;
+	strescseq.args[0] = start;
+	while(start < end && narg < LEN(strescseq.args)) {
+		start = memchr(start, ';', end - start);
+		if(!start)
+			break;
+		*start++ = '\0';
+		if(start < end) {
+			strescseq.args[++narg] = start;
+		}
+	}
+	strescseq.narg = narg + 1;
 }
 
 void
@@ -2325,6 +2363,11 @@ xresize(int col, int row) {
 	XftDrawChange(xw.draw, xw.buf);
 }
 
+static inline ushort
+sixd_to_16bit(int x) {
+	return x == 0 ? 0 : 0x3737 + 0x2828 * x;
+}
+
 void
 xloadcols(void) {
 	int i, r, g, b;
@@ -2343,9 +2386,9 @@ xloadcols(void) {
 	for(i = 16, r = 0; r < 6; r++) {
 		for(g = 0; g < 6; g++) {
 			for(b = 0; b < 6; b++) {
-				color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r;
-				color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g;
-				color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b;
+				color.red = sixd_to_16bit(r);
+				color.green = sixd_to_16bit(g);
+				color.blue = sixd_to_16bit(b);
 				if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i])) {
 					die("Could not allocate color %d\n", i);
 				}
@@ -2363,6 +2406,38 @@ xloadcols(void) {
 	}
 }
 
+int
+xsetcolorname(int x, const char *name) {
+	XRenderColor color = { .alpha = 0xffff };
+	Colour colour;
+	if (x < 0 || x > LEN(colorname))
+		return -1;
+	if(!name) {
+		if(16 <= x && x < 16 + 216) {
+			int r = (x - 16) / 36, g = ((x - 16) % 36) / 6, b = (x - 16) % 6;
+			color.red = sixd_to_16bit(r);
+			color.green = sixd_to_16bit(g);
+			color.blue = sixd_to_16bit(b);
+			if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour))
+				return 0; /* something went wrong */
+			dc.col[x] = colour;
+			return 1;
+		} else if (16 + 216 <= x && x < 256) {
+			color.red = color.green = color.blue = 0x0808 + 0x0a0a * (x - (16 + 216));
+			if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour))
+				return 0; /* something went wrong */
+			dc.col[x] = colour;
+			return 1;
+		} else {
+			name = colorname[x];
+		}
+	}
+	if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &colour))
+		return 0;
+	dc.col[x] = colour;
+	return 1;
+}
+
 void
 xtermclear(int col1, int row1, int col2, int row2) {
 	XftDrawRect(xw.draw,

From 1b6c6535c10172facb350f4b8fef442f7f8ddc5a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 23 Feb 2013 21:17:25 +0100
Subject: [PATCH 0479/1146] Replace parse_int with atoi().

---
 st.c | 31 ++++++++-----------------------
 1 file changed, 8 insertions(+), 23 deletions(-)

diff --git a/st.c b/st.c
index c25f24c..c6a840d 100644
--- a/st.c
+++ b/st.c
@@ -302,7 +302,6 @@ static void execsh(void);
 static void sigchld(int);
 static void run(void);
 
-static inline int parse_int(char *);
 static void csidump(void);
 static void csihandle(void);
 static void csiparse(void);
@@ -941,7 +940,7 @@ brelease(XEvent *e) {
 
 void
 bmotion(XEvent *e) {
-	int oldey, oldex;
+	int oldey, oldex, oldsby, oldsey;
 
 	if(IS_SET(MODE_MOUSE)) {
 		mousereport(e);
@@ -953,10 +952,12 @@ bmotion(XEvent *e) {
 
 	oldey = sel.ey;
 	oldex = sel.ex;
+	oldsby = sel.b.y;
+	oldsey = sel.e.y;
 	getbuttoninfo(e);
 
 	if(oldey != sel.ey || oldex != sel.ex) {
-		tsetdirt(sel.b.y, sel.e.y);
+		tsetdirt(MIN(sel.b.y, oldsby), MAX(sel.e.y, oldsey));
 	}
 }
 
@@ -1857,22 +1858,6 @@ csireset(void) {
 	memset(&csiescseq, 0, sizeof(csiescseq));
 }
 
-inline int
-parse_int(char *s) {
-	int x = 0;
-	char c;
-	while(isdigit(c = *s)) {
-		if((INT_MAX - c + '0') / 10 >= x) {
-			x = x * 10 + c - '0';
-		} else
-			return -1;
-		s++;
-	}
-	if(*s != '\0')
-		return -1;
-	return x;
-}
-
 void
 strhandle(void) {
 	char *p = NULL;
@@ -1887,7 +1872,7 @@ strhandle(void) {
 
 	switch(strescseq.type) {
 	case ']': /* OSC -- Operating System Command */
-		switch(i = parse_int(strescseq.args[0])) {
+		switch(i = atoi(strescseq.args[0])) {
 		case 0:
 		case 1:
 		case 2:
@@ -1903,10 +1888,10 @@ strhandle(void) {
 			p = strescseq.args[2];
 			/* fall through */
 		case 104: /* color reset, here p = NULL */
-			j = (narg > 1) ? parse_int(strescseq.args[1]) : -1;
-			if (!xsetcolorname(j, p))
+			j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
+			if (!xsetcolorname(j, p)) {
 				fprintf(stderr, "erresc: invalid color %s\n", p);
-			else {
+			} else {
 				redraw(0); /* TODO if defaultbg color is changed, borders are dirty */
 			}
 			break;

From efaf1c2a94ed9193c04c3a67f374d31f988b0e9a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 23 Feb 2013 21:20:21 +0100
Subject: [PATCH 0480/1146] Add umlaut support for title change.

Thanks Alexander Sedov <alex0player@gmail.com>!
---
 TODO |  1 -
 st.c | 23 ++++++++++++-----------
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/TODO b/TODO
index 2f42720..67615f8 100644
--- a/TODO
+++ b/TODO
@@ -18,7 +18,6 @@ bugs
 
 * fix shift up/down (shift selection in emacs)
 * fix selection paste for xatom STRING
-* fix umlaut handling in settitle
 * fix rows and column definition in fixed geometry
 * fix -e handling
 * remove DEC test sequence when appropriate
diff --git a/st.c b/st.c
index c6a840d..6117c92 100644
--- a/st.c
+++ b/st.c
@@ -1861,12 +1861,9 @@ csireset(void) {
 void
 strhandle(void) {
 	char *p = NULL;
-	int i, j;
-	int narg;
+	int i, j, narg;
+	XTextProperty prop;
 
-	/*
-	 * TODO: make this being useful in case of color palette change.
-	 */
 	strparse();
 	narg = strescseq.narg;
 
@@ -1876,11 +1873,12 @@ strhandle(void) {
 		case 0:
 		case 1:
 		case 2:
-			/*
-			 * TODO: Handle special chars in string, like umlauts.
-			 */
-			if(narg > 1)
-				XStoreName(xw.dpy, xw.win, strescseq.args[2]);
+			if(narg > 1) {
+				p += 2;
+				Xutf8TextListToTextProperty(xw.dpy, &p, 1,
+						XUTF8StringStyle, &prop);
+				XSetWMName(xw.dpy, xw.win, &prop);
+			}
 			break;
 		case 4: /* color set */
 			if(narg < 3)
@@ -1902,7 +1900,10 @@ strhandle(void) {
 		}
 		break;
 	case 'k': /* old title set compatibility */
-		XStoreName(xw.dpy, xw.win, strescseq.buf);
+		p += 1;
+		Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
+				&prop);
+		XSetWMName(xw.dpy, xw.win, &prop);
 		break;
 	case 'P': /* DSC -- Device Control String */
 	case '_': /* APC -- Application Program Command */

From e40d8da194cb02b400b09d2c8642f701c5c16821 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 23 Feb 2013 21:44:06 +0100
Subject: [PATCH 0481/1146] Removing dbe and introducing umlauts to titles.

Thanks Alexander Sedov <alex0player@gmail.com> for the title patch!
---
 st.c | 92 ++++++++++++++++++++++++++----------------------------------
 1 file changed, 39 insertions(+), 53 deletions(-)

diff --git a/st.c b/st.c
index 6117c92..2ebb15b 100644
--- a/st.c
+++ b/st.c
@@ -25,7 +25,6 @@
 #include <X11/Xutil.h>
 #include <X11/cursorfont.h>
 #include <X11/keysym.h>
-#include <X11/extensions/Xdbe.h>
 #include <X11/Xft/Xft.h>
 #include <fontconfig/fontconfig.h>
 
@@ -351,6 +350,7 @@ static void xloadcols(void);
 static int xsetcolorname(int, const char *);
 static int xloadfont(Font *, FcPattern *);
 static void xloadfonts(char *, int);
+static void xsettitle(char *);
 static void xresettitle(void);
 static void xseturgency(int);
 static void xsetsel(char*);
@@ -423,8 +423,6 @@ static char *opt_embed = NULL;
 static char *opt_class = NULL;
 static char *opt_font = NULL;
 
-bool usedbe = False;
-
 static char *usedfont = NULL;
 static int usedfontsize = 0;
 
@@ -1862,7 +1860,6 @@ void
 strhandle(void) {
 	char *p = NULL;
 	int i, j, narg;
-	XTextProperty prop;
 
 	strparse();
 	narg = strescseq.narg;
@@ -1873,12 +1870,8 @@ strhandle(void) {
 		case 0:
 		case 1:
 		case 2:
-			if(narg > 1) {
-				p += 2;
-				Xutf8TextListToTextProperty(xw.dpy, &p, 1,
-						XUTF8StringStyle, &prop);
-				XSetWMName(xw.dpy, xw.win, &prop);
-			}
+			if(narg > 1)
+				xsettitle(strescseq.args[1]);
 			break;
 		case 4: /* color set */
 			if(narg < 3)
@@ -1890,7 +1883,11 @@ strhandle(void) {
 			if (!xsetcolorname(j, p)) {
 				fprintf(stderr, "erresc: invalid color %s\n", p);
 			} else {
-				redraw(0); /* TODO if defaultbg color is changed, borders are dirty */
+				/*
+				 * TODO if defaultbg color is changed, borders
+				 * are dirty
+				 */
+				redraw(0);
 			}
 			break;
 		default:
@@ -1900,10 +1897,7 @@ strhandle(void) {
 		}
 		break;
 	case 'k': /* old title set compatibility */
-		p += 1;
-		Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
-				&prop);
-		XSetWMName(xw.dpy, xw.win, &prop);
+		xsettitle(strescseq.args[0]);
 		break;
 	case 'P': /* DSC -- Device Control String */
 	case '_': /* APC -- Application Program Command */
@@ -2338,13 +2332,11 @@ xresize(int col, int row) {
 	xw.tw = MAX(1, col * xw.cw);
 	xw.th = MAX(1, row * xw.ch);
 
-	if(!usedbe) {
-		XFreePixmap(xw.dpy, xw.buf);
-		xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
-				DefaultDepth(xw.dpy, xw.scr));
-		XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
-		XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
-	}
+	XFreePixmap(xw.dpy, xw.buf);
+	xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
+			DefaultDepth(xw.dpy, xw.scr));
+	XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
+	XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
 
 	XftDrawChange(xw.draw, xw.buf);
 }
@@ -2606,7 +2598,7 @@ xinit(void) {
 	XGCValues gcvalues;
 	Cursor cursor;
 	Window parent;
-	int sw, sh, major, minor;
+	int sw, sh;
 
 	if(!(xw.dpy = XOpenDisplay(NULL)))
 		die("Can't open display\n");
@@ -2661,26 +2653,14 @@ xinit(void) {
 			| CWColormap,
 			&attrs);
 
-	/* double buffering */
-	/*
-	if(XdbeQueryExtension(xw.dpy, &major, &minor)) {
-		xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win,
-				XdbeBackground);
-		usedbe = True;
-	} else {
-	*/
-		memset(&gcvalues, 0, sizeof(gcvalues));
-		gcvalues.graphics_exposures = False;
-		dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
-				&gcvalues);
-		xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
-				DefaultDepth(xw.dpy, xw.scr));
-		XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
-		XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
-		//xw.buf = xw.win;
-	/*
-	}
-	*/
+	memset(&gcvalues, 0, sizeof(gcvalues));
+	gcvalues.graphics_exposures = False;
+	dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
+			&gcvalues);
+	xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
+			DefaultDepth(xw.dpy, xw.scr));
+	XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
+	XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
 
 	/* Xft rendering context */
 	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
@@ -2971,9 +2951,19 @@ xdrawcursor(void) {
 	}
 }
 
+
+void
+xsettitle(char *p) {
+	XTextProperty prop;
+
+	Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
+			&prop);
+	XSetWMName(xw.dpy, xw.win, &prop);
+}
+
 void
 xresettitle(void) {
-	XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st");
+	xsettitle(opt_title ? opt_title : "st");
 }
 
 void
@@ -2991,16 +2981,12 @@ redraw(int timeout) {
 
 void
 draw(void) {
-	XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
-
 	drawregion(0, 0, term.col, term.row);
-	if(usedbe) {
-		XdbeSwapBuffers(xw.dpy, swpinfo, 1);
-	} else {
-		XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
-				xw.h, 0, 0);
-		XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
-	}
+	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
+			xw.h, 0, 0);
+	XSetForeground(xw.dpy, dc.gc,
+			dc.col[IS_SET(MODE_REVERSE)?
+				defaultfg : defaultbg].pixel);
 }
 
 void

From be7c6d7fb09ff50127332060d771b94a3bc8e44c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 23 Feb 2013 21:50:13 +0100
Subject: [PATCH 0482/1146] Add insert for the primary clipboard to MOD + Shift
 + Ins.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Thanks Mantas Mikulėnas <grawity@gmail.com> for the patch!
---
 config.def.h |  1 +
 st.c         | 17 ++++++++++++++---
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/config.def.h b/config.def.h
index a31a235..34884c0 100644
--- a/config.def.h
+++ b/config.def.h
@@ -70,6 +70,7 @@ static Shortcut shortcuts[] = {
 	{ MODKEY|ShiftMask,	XK_Prior,	xzoom,		{.i = +1} },
 	{ MODKEY|ShiftMask,	XK_Next,	xzoom,		{.i = -1} },
 	{ ShiftMask,		XK_Insert,	selpaste,	{.i =  0} },
+	{ MODKEY|ShiftMask,	XK_Insert,	clippaste,	{.i =  0} },
 	{ MODKEY,		XK_Num_Lock,	numlock,	{.i =  0} },
 };
 
diff --git a/st.c b/st.c
index 2ebb15b..afa6813 100644
--- a/st.c
+++ b/st.c
@@ -266,9 +266,10 @@ typedef struct {
 } Shortcut;
 
 /* function definitions used in config.h */
-static void xzoom(const Arg *);
-static void selpaste(const Arg *);
+static void clippaste(const Arg *);
 static void numlock(const Arg *);
+static void selpaste(const Arg *);
+static void xzoom(const Arg *);
 
 /* Config.h for applying patches and the configuration. */
 #include "config.h"
@@ -830,7 +831,17 @@ selpaste(const Arg *dummy) {
 			xw.win, CurrentTime);
 }
 
-void selclear(XEvent *e) {
+void
+clippaste(const Arg *dummy) {
+	Atom clipboard;
+
+	clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+	XConvertSelection(xw.dpy, clipboard, sel.xtarget, XA_PRIMARY,
+			xw.win, CurrentTime);
+}
+
+void
+selclear(XEvent *e) {
 	if(sel.bx == -1)
 		return;
 	sel.bx = -1;

From 37863356b00cd41c24e10243121649473b98824f Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 25 Feb 2013 13:23:56 +0100
Subject: [PATCH 0483/1146] Using strtol with overflow checking.

---
 st.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index afa6813..23c4caf 100644
--- a/st.c
+++ b/st.c
@@ -1296,17 +1296,22 @@ tnewline(int first_col) {
 void
 csiparse(void) {
 	/* int noarg = 1; */
-	char *p = csiescseq.buf;
+	char *p = csiescseq.buf, *np;
+	long int v;
 
 	csiescseq.narg = 0;
 	if(*p == '?')
 		csiescseq.priv = 1, p++;
 
 	while(p < csiescseq.buf+csiescseq.len) {
-		while(isdigit(*p)) {
-			csiescseq.arg[csiescseq.narg] *= 10;
-			csiescseq.arg[csiescseq.narg] += *p++ - '0'/*, noarg = 0 */;
-		}
+		np = NULL;
+		v = strtol(p, &np, 10);
+		if(v == LONG_MAX || v == LONG_MIN)
+			v = -1;
+		csiescseq.arg[csiescseq.narg] = v;
+		if(np != NULL)
+			p = np;
+
 		if(*p == ';' && csiescseq.narg+1 < ESC_ARG_SIZ) {
 			csiescseq.narg++, p++;
 		} else {
@@ -2116,7 +2121,8 @@ tputc(char *c, int len) {
 			if(BETWEEN(ascii, 0x40, 0x7E)
 					|| csiescseq.len >= ESC_BUF_SIZ) {
 				term.esc = 0;
-				csiparse(), csihandle();
+				csiparse();
+				csihandle();
 			}
 		} else if(term.esc & ESC_STR_END) {
 			term.esc = 0;

From 7cb0d95509d1b2837e4fa7d131f497800b20d22c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 25 Feb 2013 13:36:40 +0100
Subject: [PATCH 0484/1146] Using strtok_r for the string parsing.

---
 st.c | 32 ++++++++++++++------------------
 1 file changed, 14 insertions(+), 18 deletions(-)

diff --git a/st.c b/st.c
index 23c4caf..7ddce0c 100644
--- a/st.c
+++ b/st.c
@@ -1300,8 +1300,10 @@ csiparse(void) {
 	long int v;
 
 	csiescseq.narg = 0;
-	if(*p == '?')
-		csiescseq.priv = 1, p++;
+	if(*p == '?') {
+		csiescseq.priv = 1;
+		p++;
+	}
 
 	while(p < csiescseq.buf+csiescseq.len) {
 		np = NULL;
@@ -1928,23 +1930,17 @@ strhandle(void) {
 
 void
 strparse(void) {
-	/*
-	 * TODO: Implement parsing like for CSI when required.
-	 * Format: ESC type cmd ';' arg0 [';' argn] ESC \
-	 */
-	int narg = 0;
-	char *start = strescseq.buf, *end = start + strescseq.len;
-	strescseq.args[0] = start;
-	while(start < end && narg < LEN(strescseq.args)) {
-		start = memchr(start, ';', end - start);
-		if(!start)
-			break;
-		*start++ = '\0';
-		if(start < end) {
-			strescseq.args[++narg] = start;
-		}
+	char *p = strescseq.buf, *np, *sp;
+
+	strescseq.narg = 0;
+	np = strtok_r(strescseq.buf, ";", &sp);
+	while(p < strescseq.buf+strescseq.len && np != NULL) {
+		strescseq.args[strescseq.narg++] = p;
+
+		np = strtok_r(NULL, ";", &sp);
+		if(np != NULL)
+			p = np;
 	}
-	strescseq.narg = narg + 1;
 }
 
 void

From 7d32471efffa825f52d24930b5ee617105f9c83e Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 26 Feb 2013 18:19:44 +0100
Subject: [PATCH 0485/1146] Fixing bugs in the strtol and strtok_r
 replacements.

Thanks "Roberto E. Vargas Caballero" <k0ga@shike2.com> for the comments!
---
 st.c | 40 +++++++++++++++++-----------------------
 1 file changed, 17 insertions(+), 23 deletions(-)

diff --git a/st.c b/st.c
index 7ddce0c..9f5793c 100644
--- a/st.c
+++ b/st.c
@@ -1306,23 +1306,18 @@ csiparse(void) {
 	}
 
 	while(p < csiescseq.buf+csiescseq.len) {
-		np = NULL;
 		v = strtol(p, &np, 10);
+		if(np == p)
+			break;
 		if(v == LONG_MAX || v == LONG_MIN)
 			v = -1;
-		csiescseq.arg[csiescseq.narg] = v;
-		if(np != NULL)
-			p = np;
-
-		if(*p == ';' && csiescseq.narg+1 < ESC_ARG_SIZ) {
-			csiescseq.narg++, p++;
-		} else {
-			csiescseq.mode = *p;
-			csiescseq.narg++;
-
-			return;
-		}
+		csiescseq.arg[csiescseq.narg++] = v;
+		p = np;
+		if(*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
+			break;
+		p++;
 	}
+	csiescseq.mode = *p;
 }
 
 /* for absolute user moves, when decom is set */
@@ -1930,16 +1925,13 @@ strhandle(void) {
 
 void
 strparse(void) {
-	char *p = strescseq.buf, *np, *sp;
+	char *p = strescseq.buf, *sp;
 
-	strescseq.narg = 0;
-	np = strtok_r(strescseq.buf, ";", &sp);
-	while(p < strescseq.buf+strescseq.len && np != NULL) {
+	strescseq.buf[strescseq.len] = '\0';
+	for(p = strtok_r(p, ";", &sp); p; p = strtok_r(NULL, ";", &sp)) {
+		if(strescseq.narg == STR_ARG_SIZ)
+			return;
 		strescseq.args[strescseq.narg++] = p;
-
-		np = strtok_r(NULL, ";", &sp);
-		if(np != NULL)
-			p = np;
 	}
 }
 
@@ -1951,7 +1943,9 @@ strdump(void) {
 	printf("ESC%c", strescseq.type);
 	for(i = 0; i < strescseq.len; i++) {
 		c = strescseq.buf[i] & 0xff;
-		if(isprint(c)) {
+		if(c == '\0') {
+			return;
+		} else if(isprint(c)) {
 			putchar(c);
 		} else if(c == '\n') {
 			printf("(\\n)");
@@ -2039,7 +2033,7 @@ tputc(char *c, int len) {
 			strhandle();
 			break;
 		default:
-			if(strescseq.len + len < sizeof(strescseq.buf)) {
+			if(strescseq.len + len < sizeof(strescseq.buf) - 1) {
 				memmove(&strescseq.buf[strescseq.len], c, len);
 				strescseq.len += len;
 			} else {

From 1aa26b4ecd68e6071d36e9103aa9c21711bbf6ea Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 26 Feb 2013 19:07:23 +0100
Subject: [PATCH 0486/1146] Fixing a bug while parsing empty arguments in
 csiparse.

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 9f5793c..83fdc6d 100644
--- a/st.c
+++ b/st.c
@@ -1295,7 +1295,6 @@ tnewline(int first_col) {
 
 void
 csiparse(void) {
-	/* int noarg = 1; */
 	char *p = csiescseq.buf, *np;
 	long int v;
 
@@ -1306,9 +1305,10 @@ csiparse(void) {
 	}
 
 	while(p < csiescseq.buf+csiescseq.len) {
+		np = NULL;
 		v = strtol(p, &np, 10);
 		if(np == p)
-			break;
+			v = 0;
 		if(v == LONG_MAX || v == LONG_MIN)
 			v = -1;
 		csiescseq.arg[csiescseq.narg++] = v;

From 1c1621da699adae49a4344b145f856dacb57270c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 26 Feb 2013 19:08:51 +0100
Subject: [PATCH 0487/1146] Changing the way how paste is handled, just for the
 nano people.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 83fdc6d..8b5ba64 100644
--- a/st.c
+++ b/st.c
@@ -796,7 +796,7 @@ selcopy(void) {
 			}
 			/* \n at the end of every selected line except for the last one */
 			if(is_selected && y < sel.e.y)
-				*ptr++ = '\n';
+				*ptr++ = '\r';
 		}
 		*ptr = 0;
 	}

From c6b89f23e7546c30dea42a3c49f99682c5818190 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 26 Feb 2013 21:43:40 +0100
Subject: [PATCH 0488/1146] Using strsep and fixing null termination in
 csiparse.

Thanks for the hint from Alexander Sedov <alex0player@gmail.com>!
---
 config.mk |  2 +-
 st.c      | 15 +++++++--------
 2 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/config.mk b/config.mk
index ecc5c83..abf25c1 100644
--- a/config.mk
+++ b/config.mk
@@ -19,7 +19,7 @@ LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext -lXft \
        $(shell pkg-config --libs freetype2)
 
 # flags
-CPPFLAGS = -DVERSION=\"${VERSION}\"
+CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_XOPEN_SOURCE=600
 CFLAGS += -g -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
 LDFLAGS += -g ${LIBS}
 
diff --git a/st.c b/st.c
index 8b5ba64..fc9ed70 100644
--- a/st.c
+++ b/st.c
@@ -1,5 +1,4 @@
 /* See LICENSE for licence details. */
-#define _XOPEN_SOURCE 600
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -1304,6 +1303,7 @@ csiparse(void) {
 		p++;
 	}
 
+	csiescseq.buf[csiescseq.len] = '\0';
 	while(p < csiescseq.buf+csiescseq.len) {
 		np = NULL;
 		v = strtol(p, &np, 10);
@@ -1925,14 +1925,12 @@ strhandle(void) {
 
 void
 strparse(void) {
-	char *p = strescseq.buf, *sp;
+	char *p = strescseq.buf;
 
+	strescseq.narg = 0;
 	strescseq.buf[strescseq.len] = '\0';
-	for(p = strtok_r(p, ";", &sp); p; p = strtok_r(NULL, ";", &sp)) {
-		if(strescseq.narg == STR_ARG_SIZ)
-			return;
-		strescseq.args[strescseq.narg++] = p;
-	}
+	while(p && strescseq.narg < STR_ARG_SIZ)
+		strescseq.args[strescseq.narg++] = strsep(&p, ";");
 }
 
 void
@@ -2109,7 +2107,8 @@ tputc(char *c, int len) {
 		if(term.esc & ESC_CSI) {
 			csiescseq.buf[csiescseq.len++] = ascii;
 			if(BETWEEN(ascii, 0x40, 0x7E)
-					|| csiescseq.len >= ESC_BUF_SIZ) {
+					|| csiescseq.len >= \
+					sizeof(csiescseq.buf)-1) {
 				term.esc = 0;
 				csiparse();
 				csihandle();

From 82494f248d778e1195a9eabfac916ce08c52b6da Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 5 Mar 2013 22:12:11 +0100
Subject: [PATCH 0489/1146] Making st compile on OS X.

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index abf25c1..4d10df4 100644
--- a/config.mk
+++ b/config.mk
@@ -20,7 +20,7 @@ LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext -lXft \
 
 # flags
 CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_XOPEN_SOURCE=600
-CFLAGS += -g -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
+CFLAGS += -g -std=c99 -pedantic -Wall -Wvariadic-macros -Os ${INCS} ${CPPFLAGS}
 LDFLAGS += -g ${LIBS}
 
 # compiler and linker

From 55adf0aad1d5acf0b9a00e2a9f834cef8b61b3b3 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 10 Mar 2013 21:16:51 +0100
Subject: [PATCH 0490/1146] Pange seems to use ascent + descent instead of
 height.

Thanks Bobby Powers <bobbypowers@gmail.com> for noticing this!
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index fc9ed70..0923cec 100644
--- a/st.c
+++ b/st.c
@@ -2493,7 +2493,7 @@ xloadfont(Font *f, FcPattern *pattern) {
 	f->lbearing = 0;
 	f->rbearing = f->match->max_advance_width;
 
-	f->height = f->match->height;
+	f->height = f->ascent + f->descent;
 	f->width = f->lbearing + f->rbearing;
 
 	return 0;

From 4b17dddb104bd2ac87dd6e334aafd325197c1407 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 20 Mar 2013 21:19:28 +0100
Subject: [PATCH 0491/1146] Making rectangular selection work again.

People sending me patches against strange revisions and basing on their own
revisions make me having to reapply them. Then such errors appear.

Thanks Alexander Sedov <alex0player@gmail.com> for noticing this.
---
 st.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 0923cec..131cba8 100644
--- a/st.c
+++ b/st.c
@@ -649,13 +649,10 @@ selected(int x, int y) {
 	if(sel.ey == y && sel.by == y) {
 		bx = MIN(sel.bx, sel.ex);
 		ex = MAX(sel.bx, sel.ex);
+
 		return BETWEEN(x, bx, ex);
 	}
 
-	return ((sel.b.y < y && y < sel.e.y)
-			|| (y == sel.e.y && x <= sel.e.x))
-			|| (y == sel.b.y && x >= sel.b.x
-				&& (x <= sel.e.x || sel.b.y != sel.e.y));
 	switch(sel.type) {
 	case SEL_REGULAR:
 		return ((sel.b.y < y && y < sel.e.y)

From a1e3b94b374c269f9d379f40b67b8519a485b8a6 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 29 Mar 2013 18:39:01 +0100
Subject: [PATCH 0492/1146] Removing an undefined case. just do regular
 selections.

---
 st.c | 31 +++++++++++++------------------
 1 file changed, 13 insertions(+), 18 deletions(-)

diff --git a/st.c b/st.c
index 131cba8..599685c 100644
--- a/st.c
+++ b/st.c
@@ -653,16 +653,14 @@ selected(int x, int y) {
 		return BETWEEN(x, bx, ex);
 	}
 
-	switch(sel.type) {
-	case SEL_REGULAR:
-		return ((sel.b.y < y && y < sel.e.y)
-			|| (y == sel.e.y && x <= sel.e.x))
-			|| (y == sel.b.y && x >= sel.b.x
-				&& (x <= sel.e.x || sel.b.y != sel.e.y));
-	case SEL_RECTANGULAR:
+	if(sel.type == SEL_RECTANGULAR) {
 		return ((sel.b.y <= y && y <= sel.e.y)
 			&& (sel.b.x <= x && x <= sel.e.x));
-	};
+	}
+	return ((sel.b.y < y && y < sel.e.y)
+		|| (y == sel.e.y && x <= sel.e.x))
+		|| (y == sel.b.y && x >= sel.b.x
+			&& (x <= sel.e.x || sel.b.y != sel.e.y));
 }
 
 void
@@ -1254,8 +1252,12 @@ selscroll(int orig, int n) {
 			sel.bx = -1;
 			return;
 		}
-		switch(sel.type) {
-		case SEL_REGULAR:
+		if(sel.type == SEL_RECTANGULAR) {
+			if(sel.by < term.top)
+				sel.by = term.top;
+			if(sel.ey > term.bot)
+				sel.ey = term.bot;
+		} else {
 			if(sel.by < term.top) {
 				sel.by = term.top;
 				sel.bx = 0;
@@ -1264,14 +1266,7 @@ selscroll(int orig, int n) {
 				sel.ey = term.bot;
 				sel.ex = term.col;
 			}
-			break;
-		case SEL_RECTANGULAR:
-			if(sel.by < term.top)
-				sel.by = term.top;
-			if(sel.ey > term.bot)
-				sel.ey = term.bot;
-			break;
-		};
+		}
 		sel.b.y = sel.by, sel.b.x = sel.bx;
 		sel.e.y = sel.ey, sel.e.x = sel.ex;
 	}

From f876810626773828747f48675a6d1f33dc163662 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 29 Mar 2013 18:43:32 +0100
Subject: [PATCH 0493/1146] Adding PgUp and PgDown + Ctrl to config.def.h

Thanks stargrave@stargrave.org!
---
 config.def.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/config.def.h b/config.def.h
index 34884c0..4114f4b 100644
--- a/config.def.h
+++ b/config.def.h
@@ -215,7 +215,9 @@ static Key key[] = {
 	{ XK_End,           ShiftMask,      "\033[K",       -1,    0,    0},
 	{ XK_End,           ShiftMask,      "\033[1;2F",    +1,    0,    0},
 	{ XK_End,           XK_ANY_MOD,     "\033[4~",       0,    0,    0},
+	{ XK_Prior,         ControlMask,    "\033[5;5~",     0,    0,    0},
 	{ XK_Prior,         XK_NO_MOD,      "\033[5~",       0,    0,    0},
+	{ XK_Next,          ControlMask,    "\033[6;5~",     0,    0,    0},
 	{ XK_Next,          ShiftMask,      "\033[6;2~",     0,    0,    0},
 	{ XK_Next,          XK_ANY_MOD,     "\033[6~",       0,    0,    0},
 	{ XK_F1,            XK_NO_MOD,      "\033OP" ,       0,    0,    0},

From adde5c6d9dec3a0ab4d78b9d6e70b970ffb33a05 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 29 Mar 2013 18:45:09 +0100
Subject: [PATCH 0494/1146] Adding PgUp + Ctrl.

Thanks stargrave@stargrave.org!
---
 config.def.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/config.def.h b/config.def.h
index 4114f4b..75abefb 100644
--- a/config.def.h
+++ b/config.def.h
@@ -216,6 +216,7 @@ static Key key[] = {
 	{ XK_End,           ShiftMask,      "\033[1;2F",    +1,    0,    0},
 	{ XK_End,           XK_ANY_MOD,     "\033[4~",       0,    0,    0},
 	{ XK_Prior,         ControlMask,    "\033[5;5~",     0,    0,    0},
+	{ XK_Prior,         ShiftMask,      "\033[5;2~",     0,    0,    0},
 	{ XK_Prior,         XK_NO_MOD,      "\033[5~",       0,    0,    0},
 	{ XK_Next,          ControlMask,    "\033[6;5~",     0,    0,    0},
 	{ XK_Next,          ShiftMask,      "\033[6;2~",     0,    0,    0},

From 7e7760c2ed1a6fc9d500da51bd8dc499fb36e1b0 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 29 Mar 2013 19:01:24 +0100
Subject: [PATCH 0495/1146] Add the possibility to have default highlight
 colors.

Thanks to stargrave@stargrave.org for the suggestion!
---
 config.def.h |  8 ++++++++
 st.c         | 32 +++++++++++++++++++-------------
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/config.def.h b/config.def.h
index 75abefb..693bdbd 100644
--- a/config.def.h
+++ b/config.def.h
@@ -62,6 +62,14 @@ static unsigned int defaultbg = 0;
 static unsigned int defaultcs = 256;
 static unsigned int defaultucs = 257;
 
+/*
+ * Colors used, when the specific fg == defaultfg. So in reverse mode this
+ * will reverse too. Another logic would only make the simple feature too
+ * complex.
+ */
+static unsigned int defaultitalic = 11;
+static unsigned int defaultunderline = 7;
+
 /* Internal shortcuts. */
 #define MODKEY Mod1Mask
 
diff --git a/st.c b/st.c
index 599685c..8b1fc56 100644
--- a/st.c
+++ b/st.c
@@ -2711,12 +2711,28 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	FcPattern *fcpattern, *fontpattern;
 	FcFontSet *fcsets[] = { NULL };
 	FcCharSet *fccharset;
-	Colour *fg = &dc.col[base.fg], *bg = &dc.col[base.bg],
-		 *temp, revfg, revbg;
+	Colour *fg, *bg, *temp, revfg, revbg;
 	XRenderColor colfg, colbg;
 
 	frcflags = FRC_NORMAL;
 
+	if(base.mode & ATTR_ITALIC) {
+		if(base.fg == defaultfg)
+			base.fg = defaultitalic;
+		font = &dc.ifont;
+		frcflags = FRC_ITALIC;
+	} else if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) {
+		if(base.fg == defaultfg)
+			base.fg = defaultitalic;
+		font = &dc.ibfont;
+		frcflags = FRC_ITALICBOLD;
+	} else if(base.mode & ATTR_UNDERLINE) {
+		if(base.fg == defaultfg)
+			base.fg = defaultunderline;
+	}
+	fg = &dc.col[base.fg];
+	bg = &dc.col[base.bg];
+
 	if(base.mode & ATTR_BOLD) {
 		if(BETWEEN(base.fg, 0, 7)) {
 			/* basic system colors */
@@ -2738,15 +2754,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		frcflags = FRC_BOLD;
 	}
 
-	if(base.mode & ATTR_ITALIC) {
-		font = &dc.ifont;
-		frcflags = FRC_ITALIC;
-	}
-	if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) {
-		font = &dc.ibfont;
-		frcflags = FRC_ITALICBOLD;
-	}
-
 	if(IS_SET(MODE_REVERSE)) {
 		if(fg == &dc.col[defaultfg]) {
 			fg = &dc.col[defaultbg];
@@ -2873,8 +2880,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 					FcTrue, fcpattern, &fcres);
 
 			/*
-			 * Overwrite or create the new cache entry
-			 * entry.
+			 * Overwrite or create the new cache entry.
 			 */
 			frccur++;
 			frclen++;

From a3a5b8e15e2b32337959cb87f821b053cc08c3ac Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 29 Mar 2013 19:13:26 +0100
Subject: [PATCH 0496/1146] Releasing 0.4.

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 4d10df4..88355c7 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.3
+VERSION = 0.4
 
 # Customize below to fit your system
 

From 502911e55442a89602bd5681763f68250bff330b Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 29 Mar 2013 19:44:37 +0100
Subject: [PATCH 0497/1146] Updating the TODO file for after 0.4.

---
 TODO | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/TODO b/TODO
index 67615f8..afd6401 100644
--- a/TODO
+++ b/TODO
@@ -1,18 +1,23 @@
 vt emulation
 ------------
 
-* color definition in CSI
-	* implement CSI parsing
 * wide-character support in conjunction with fallback xft code 
-* mouse selection support
+* double-height support
 
 code & interface
 ----------------
 
 * clean and complete terminfo entry
-* add fallback fonts for the restricted xft code
 * add a simple way to do multiplexing
 
+drawing
+-------
+* add diacritics support to xdraws()
+* add kerning configuration
+* make the font cache simpler
+* add hard width handling
+	* xft is reporting wrong width and height for characters
+
 bugs
 ----
 
@@ -21,8 +26,6 @@ bugs
 * fix rows and column definition in fixed geometry
 * fix -e handling
 * remove DEC test sequence when appropriate
-* reverse cursor when drawin light on light background
-	* text should be readable
 * When some application outputting long text is run in the shell init scripts,
   then this text might be stripped to the standard 80x25 due to st running the
   virtual terminal at first priority. Maybe the vt initialisation could be

From 580c8bbd4691218849c9a809acaa4c95f65cb846 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 3 Apr 2013 20:42:27 +0200
Subject: [PATCH 0498/1146] Add an option to disable alternative screens.

---
 config.def.h |  3 +++
 st.1         |  4 ++++
 st.c         | 13 +++++++++----
 3 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index 693bdbd..2c97266 100644
--- a/config.def.h
+++ b/config.def.h
@@ -13,6 +13,9 @@ static char shell[] = "/bin/sh";
 static unsigned int doubleclicktimeout = 300;
 static unsigned int tripleclicktimeout = 600;
 
+/* alt screens */
+static bool allowaltscreen = true;
+
 /* frames per second st should at maximum draw to the screen */
 static unsigned int xfps = 60;
 static unsigned int actionfps = 30;
diff --git a/st.1 b/st.1
index 1c100c0..fc7703d 100644
--- a/st.1
+++ b/st.1
@@ -3,6 +3,7 @@
 st \- simple terminal
 .SH SYNOPSIS
 .B st
+.RB [ \-a ]
 .RB [ \-c
 .IR class ]
 .RB [ \-f
@@ -23,6 +24,9 @@ st \- simple terminal
 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
diff --git a/st.c b/st.c
index 8b1fc56..18935d4 100644
--- a/st.c
+++ b/st.c
@@ -43,7 +43,7 @@
 
 #define USAGE \
 	"st " VERSION " (c) 2010-2013 st engineers\n" \
-	"usage: st [-v] [-c class] [-f font] [-g geometry] [-o file]" \
+	"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]" \
 	" [-t title] [-w windowid] [-e command ...]\n"
 
 /* XEMBED messages */
@@ -1615,7 +1615,10 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				break;
 			case 1049: /* = 1047 and 1048 */
 			case 47:
-			case 1047: {
+			case 1047:
+				if (!allowaltscreen)
+					break;
+
 				alt = IS_SET(MODE_ALTSCREEN);
 				if(alt) {
 					tclearregion(0, 0, term.col-1,
@@ -1625,8 +1628,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 					tswapscreen();
 				if(*args != 1049)
 					break;
-			}
-				/* pass through */
+				/* FALLTRU */
 			case 1048:
 				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
 				break;
@@ -3316,6 +3318,9 @@ main(int argc, char *argv[]) {
 
 	for(i = 1; i < argc; i++) {
 		switch(argv[i][0] != '-' || argv[i][2] ? -1 : argv[i][1]) {
+		case 'a':
+			allowaltscreen = false;
+			break;
 		case 'c':
 			if(++i < argc)
 				opt_class = argv[i];

From b1813b14d956978ae8af37166b3cccc3a7b4b720 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 3 Apr 2013 21:00:38 +0200
Subject: [PATCH 0499/1146] Adopting arg.h with more flexible cmd handling.

---
 arg.h |  55 ++++++++++++++++++++++++++++
 st.c  | 116 ++++++++++++++++++++++++++++------------------------------
 2 files changed, 111 insertions(+), 60 deletions(-)
 create mode 100644 arg.h

diff --git a/arg.h b/arg.h
new file mode 100644
index 0000000..2b189fe
--- /dev/null
+++ b/arg.h
@@ -0,0 +1,55 @@
+/*
+ * Copy me if you can.
+ * by 20h
+ */
+
+#ifndef __ARG_H__
+#define __ARG_H__
+
+extern char *argv0;
+
+#define USED(x)		((void)(x))
+
+/* use main(int argc, char *argv[]) */
+#define ARGBEGIN	for (argv0 = *argv, argv++, argc--;\
+					argv[0] && argv[0][1]\
+					&& argv[0][0] == '-';\
+					argc--, argv++) {\
+				char _argc;\
+				char **_argv;\
+				int brk;\
+				if (argv[0][1] == '-' && argv[0][2] == '\0') {\
+					argv++;\
+					argc--;\
+					break;\
+				}\
+				for (brk = 0, argv[0]++, _argv = argv;\
+						argv[0][0] && !brk;\
+						argv[0]++) {\
+					if (_argv != argv)\
+						break;\
+					_argc = argv[0][0];\
+					switch (_argc)
+
+#define ARGEND			}\
+				USED(_argc);\
+			}\
+			USED(argv);\
+			USED(argc);
+
+#define ARGC()		_argc
+
+#define EARGF(x)	((argv[0][1] == '\0' && argv[1] == NULL)?\
+				((x), abort(), (char *)0) :\
+				(brk = 1, (argv[0][1] != '\0')?\
+					(&argv[0][1]) :\
+					(argc--, argv++, argv[0])))
+
+#define ARGF()		((argv[0][1] == '\0' && argv[1] == NULL)?\
+				(char *)0 :\
+				(brk = 1, (argv[0][1] != '\0')?\
+					(&argv[0][1]) :\
+					(argc--, argv++, argv[0])))
+
+#endif
+
diff --git a/st.c b/st.c
index 18935d4..c938ff4 100644
--- a/st.c
+++ b/st.c
@@ -27,6 +27,10 @@
 #include <X11/Xft/Xft.h>
 #include <fontconfig/fontconfig.h>
 
+#include "arg.h"
+
+char *argv0;
+
 #define Glyph Glyph_
 #define Font Font_
 #define Draw XftDraw *
@@ -41,10 +45,6 @@
  #include <libutil.h>
 #endif
 
-#define USAGE \
-	"st " VERSION " (c) 2010-2013 st engineers\n" \
-	"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]" \
-	" [-t title] [-w windowid] [-e command ...]\n"
 
 /* XEMBED messages */
 #define XEMBED_FOCUS_IN  4
@@ -3308,70 +3308,66 @@ run(void) {
 	}
 }
 
+void
+usage(void) {
+	die("%s " VERSION " (c) 2010-2013 st engineers\n" \
+	"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]" \
+	" [-t title] [-w windowid] [-e command ...]\n", argv0);
+}
+
 int
 main(int argc, char *argv[]) {
-	int i, bitm, xr, yr;
+	int bitm, xr, yr;
 	uint wr, hr;
 
 	xw.fw = xw.fh = xw.fx = xw.fy = 0;
 	xw.isfixed = False;
 
-	for(i = 1; i < argc; i++) {
-		switch(argv[i][0] != '-' || argv[i][2] ? -1 : argv[i][1]) {
-		case 'a':
-			allowaltscreen = false;
-			break;
-		case 'c':
-			if(++i < argc)
-				opt_class = argv[i];
-			break;
-		case 'e':
-			/* eat all remaining arguments */
-			if(++i < argc)
-				opt_cmd = &argv[i];
-			goto run;
-		case 'f':
-			if(++i < argc)
-				opt_font = argv[i];
-			break;
-		case 'g':
-			if(++i >= argc)
-				break;
+	ARGBEGIN {
+	case 'a':
+		allowaltscreen = false;
+		break;
+	case 'c':
+		opt_class = EARGF(usage());
+		break;
+	case 'e':
+		/* eat all remaining arguments */
+		opt_cmd = &argv[1];
+		goto run;
+	case 'f':
+		opt_font = EARGF(usage());
+		break;
+	case 'g':
+		bitm = XParseGeometry(EARGF(usage()), &xr, &yr, &wr, &hr);
+		if(bitm & XValue)
+			xw.fx = xr;
+		if(bitm & YValue)
+			xw.fy = yr;
+		if(bitm & WidthValue)
+			xw.fw = (int)wr;
+		if(bitm & HeightValue)
+			xw.fh = (int)hr;
+		if(bitm & XNegative && xw.fx == 0)
+			xw.fx = -1;
+		if(bitm & XNegative && xw.fy == 0)
+			xw.fy = -1;
 
-			bitm = XParseGeometry(argv[i], &xr, &yr, &wr, &hr);
-			if(bitm & XValue)
-				xw.fx = xr;
-			if(bitm & YValue)
-				xw.fy = yr;
-			if(bitm & WidthValue)
-				xw.fw = (int)wr;
-			if(bitm & HeightValue)
-				xw.fh = (int)hr;
-			if(bitm & XNegative && xw.fx == 0)
-				xw.fx = -1;
-			if(bitm & XNegative && xw.fy == 0)
-				xw.fy = -1;
-
-			if(xw.fh != 0 && xw.fw != 0)
-				xw.isfixed = True;
-			break;
-		case 'o':
-			if(++i < argc)
-				opt_io = argv[i];
-			break;
-		case 't':
-			if(++i < argc)
-				opt_title = argv[i];
-			break;
-		case 'v':
-		default:
-			die(USAGE);
-		case 'w':
-			if(++i < argc)
-				opt_embed = argv[i];
-			break;
-		}
-	}
+		if(xw.fh != 0 && xw.fw != 0)
+			xw.isfixed = True;
+		break;
+	case 'o':
+		opt_io = EARGF(usage());
+		break;
+	case 't':
+		opt_title = EARGF(usage());
+		break;
+	case 'w':
+		opt_embed = EARGF(usage());
+		break;
+	case 'v':
+	default:
+		usage();
+	} ARGEND;
 
 run:
 	setlocale(LC_CTYPE, "");

From 684cf55a0d21da19a6e9e4a490a7c4dd3334638d Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 10 Apr 2013 17:48:32 +0200
Subject: [PATCH 0500/1146] Make st work with a plain -e command.

---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index c938ff4..93058b9 100644
--- a/st.c
+++ b/st.c
@@ -3332,7 +3332,8 @@ main(int argc, char *argv[]) {
 		break;
 	case 'e':
 		/* eat all remaining arguments */
-		opt_cmd = &argv[1];
+		if(argc > 1)
+			opt_cmd = &argv[1];
 		goto run;
 	case 'f':
 		opt_font = EARGF(usage());

From ddd429ea2478beeb7d17d9b548abd9173049dcc6 Mon Sep 17 00:00:00 2001
From: Kai Hendry <hendry@webconverger.com>
Date: Tue, 9 Apr 2013 22:13:54 +0100
Subject: [PATCH 0501/1146] Convert FAQ into Markdown, to make it easier to
 integrate it into http://st.suckless.org/

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 FAQ | 56 +++++++++++++++++++++++---------------------------------
 1 file changed, 23 insertions(+), 33 deletions(-)

diff --git a/FAQ b/FAQ
index 9d29335..8f260c1 100644
--- a/FAQ
+++ b/FAQ
@@ -1,43 +1,35 @@
---
-Why does st not handle utmp entries?
+## Why does st not handle utmp entries?
 
-Use the excellent tool of utmp[0] for this task.
+Use the excellent tool of [utmp](http://git.suckless.org/utmp/) for this task.
 
-[0] http://git.suckless.org/utmp/
---
-Some _random program_ complains that st is unknown/not
-recognised/unsupported/whatever!
+## 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 manualy run tic -s st.info in st dir. It will compile st.info into a
-fully working local terminfo description. You can delete it when you’re done.
---
-Nothing works, and nothing is said about an unknown terminal!
+you did not `make install`. If you just want to test it without installing it,
+you can manualy run `tic -s 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.
---
-I get some weird glitches/visual bug on _random program_!
 
-Try lauching it with a different TERM: $ TERM=xterm myapp. toe(1) will give
-you a list of available terminals, but you’ll most likely switch between
-xterm, st or st-256color. The default value for TERM can be changed in
-config.h (TNAME).
---
-How do I scroll back up?
+## I get some weird glitches/visual bug on _random program_!
 
-Invoke st with a screen multiplexer like GNU screen[0] or tmux[1].
-st -e screen works better for text reflowing. To enter screen’s scroll
-back mode aka “copy mode”, it’s C-a ESC. You probably want defscrollback
-10000 in your ~/.screenrc too.
+Try launching it with a different TERM: $ TERM=xterm myapp. toe(1) will give
+you a list of available terminals, but you’ll most likely switch between xterm,
+st or st-256color. The default value for TERM can be changed in config.h
+(TNAME).
 
-[0] http://en.wikipedia.org/wiki/GNU_Screen
-[1] http://en.wikipedia.org/wiki/Tmux
---
-Why doesn't the Del key work in some programs?
+## How do I scroll back up?
+
+Using a terminal multiplexer.
+
+* `st -e tmux` using C-a [
+* `st -e screen` using C-a ESC
+
+## Why doesn't the Del key work in some programs?
 
 Taken from the terminfo manpage:
 
@@ -49,14 +41,14 @@ Taken from the terminfo manpage:
 	codes as smkx and rmkx. Otherwise the keypad is assumed to
 	always transmit.
 
-In the st case smkx=\E[?1h\E= and rmkx=\E[?1l\E>, so it is mandatory that
+In the st case smkx=E[?1hE= and rmkx=E[?1lE>, so it is mandatory that
 applications which want to test against keypad keys, have to 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
+	$ printf "�33?1h�33=" >/dev/tty
 
 or
 	$ echo $(tput smkx) >/dev/tty
@@ -73,7 +65,7 @@ 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):
+<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
@@ -91,5 +83,3 @@ If you are using zsh, then read the zsh FAQ
 		zle -N zle-line-finish
 
 Putting these lines into your .zshrc will fix the problems.
---
-

From 4018b2c5075c1cab603ca137ef5f6d68b9cee483 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 13 Apr 2013 08:48:17 +0200
Subject: [PATCH 0502/1146] Making the copy and pasting consistent.

The copying and pasting in the terminald and GUI world is flawed. Due to the
discussion on the mailinglist it seems that sending '\n' is what GUIs expect
and '\r' what terminal applications want. St now implements that behaviour.
---
 st.c | 35 +++++++++++++++++++++++++++++++----
 1 file changed, 31 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 93058b9..49a9770 100644
--- a/st.c
+++ b/st.c
@@ -788,9 +788,18 @@ selcopy(void) {
 				memcpy(ptr, p, size);
 				ptr += size;
 			}
-			/* \n at the end of every selected line except for the last one */
+
+			/*
+			 * 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(is_selected && y < sel.e.y)
-				*ptr++ = '\r';
+				*ptr++ = '\n';
 		}
 		*ptr = 0;
 	}
@@ -801,7 +810,7 @@ void
 selnotify(XEvent *e) {
 	ulong nitems, ofs, rem;
 	int format;
-	uchar *data;
+	uchar *data, *last, *repl;
 	Atom type;
 
 	ofs = 0;
@@ -812,7 +821,25 @@ selnotify(XEvent *e) {
 			fprintf(stderr, "Clipboard allocation failed\n");
 			return;
 		}
-		ttywrite((const char *) data, nitems * format / 8);
+
+		/*
+		 * As seen in selcopy:
+		 * 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';
+		}
+
+		last = data + nitems * format / 8;
+		repl = data;
+
+
+		ttywrite((const char *)data, nitems * format / 8);
 		XFree(data);
 		/* number of 32-bit chunks returned */
 		ofs += nitems * format / 32;

From 5984657c001fe5b4690cef5ddffe11acbf7da7f2 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 13 Apr 2013 08:50:38 +0200
Subject: [PATCH 0503/1146] Minor naming issue fixed.

---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 49a9770..b350225 100644
--- a/st.c
+++ b/st.c
@@ -758,7 +758,7 @@ bpress(XEvent *e) {
 void
 selcopy(void) {
 	char *str, *ptr, *p;
-	int x, y, bufsize, is_selected = 0, size;
+	int x, y, bufsize, isselected = 0, size;
 	Glyph *gp, *last;
 
 	if(sel.bx == -1) {
@@ -769,7 +769,7 @@ selcopy(void) {
 
 		/* append every set & selected glyph to the selection */
 		for(y = sel.b.y; y < sel.e.y + 1; y++) {
-			is_selected = 0;
+			isselected = 0;
 			gp = &term.line[y][0];
 			last = gp + term.col;
 
@@ -780,7 +780,7 @@ selcopy(void) {
 				if(!selected(x, y)) {
 					continue;
 				} else {
-					is_selected = 1;
+					isselected = 1;
 				}
 
 				p = (gp->state & GLYPH_SET) ? gp->c : " ";
@@ -798,7 +798,7 @@ selcopy(void) {
 			 * st.
 			 * FIXME: Fix the computer world.
 			 */
-			if(is_selected && y < sel.e.y)
+			if(isselected && y < sel.e.y)
 				*ptr++ = '\n';
 		}
 		*ptr = 0;

From 5dc48af29e9972527767977be3bbc9c072cf1c13 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 13 Apr 2013 08:51:30 +0200
Subject: [PATCH 0504/1146] Patching while not really woken up.

---
 st.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/st.c b/st.c
index b350225..23a43c1 100644
--- a/st.c
+++ b/st.c
@@ -835,10 +835,6 @@ selnotify(XEvent *e) {
 			*repl++ = '\r';
 		}
 
-		last = data + nitems * format / 8;
-		repl = data;
-
-
 		ttywrite((const char *)data, nitems * format / 8);
 		XFree(data);
 		/* number of 32-bit chunks returned */

From 1e7816c2023f48728e15cc4128ad8be163986902 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 13 Apr 2013 09:44:00 +0200
Subject: [PATCH 0505/1146] Drawing a more visible rectangle as cursor on
 unfocus.

To have a more visible cursor on unfocused windows this patch makes st draw a
rectangle around the terminal cell.

Thanks Mark Hills <mark@xwax.org> for the suggestion!
---
 config.def.h |  4 +---
 st.c         | 33 ++++++++++++++++++++++++++-------
 2 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/config.def.h b/config.def.h
index 2c97266..d1c20bd 100644
--- a/config.def.h
+++ b/config.def.h
@@ -52,18 +52,16 @@ static const char *colorname[] = {
 
 	/* more colors can be added after 255 to use with DefaultXX */
 	"#cccccc",
-	"#333333",
 };
 
 
 /*
  * Default colors (colorname index)
- * foreground, background, cursor, unfocused cursor
+ * foreground, background, cursor
  */
 static unsigned int defaultfg = 7;
 static unsigned int defaultbg = 0;
 static unsigned int defaultcs = 256;
-static unsigned int defaultucs = 257;
 
 /*
  * Colors used, when the specific fg == defaultfg. So in reverse mode this
diff --git a/st.c b/st.c
index 23a43c1..c4eafa0 100644
--- a/st.c
+++ b/st.c
@@ -2968,14 +2968,33 @@ xdrawcursor(void) {
 
 	/* draw the new one */
 	if(!(IS_SET(MODE_HIDE))) {
-		if(!(xw.state & WIN_FOCUSED))
-			g.bg = defaultucs;
+		if(xw.state & WIN_FOCUSED) {
+			if(IS_SET(MODE_REVERSE)) {
+				g.mode |= ATTR_REVERSE;
+				g.fg = defaultcs;
+				g.bg = defaultfg;
+			}
 
-		if(IS_SET(MODE_REVERSE))
-			g.mode |= ATTR_REVERSE, g.fg = defaultcs, g.bg = defaultfg;
-
-		sl = utf8size(g.c);
-		xdraws(g.c, g, term.c.x, term.c.y, 1, sl);
+			sl = utf8size(g.c);
+			xdraws(g.c, g, term.c.x, term.c.y, 1, sl);
+		} else {
+			XftDrawRect(xw.draw, &dc.col[defaultcs],
+					borderpx + term.c.x * xw.cw,
+					borderpx + term.c.y * xw.ch,
+					xw.cw - 1, 1);
+			XftDrawRect(xw.draw, &dc.col[defaultcs],
+					borderpx + term.c.x * xw.cw,
+					borderpx + term.c.y * xw.ch,
+					1, xw.ch - 1);
+			XftDrawRect(xw.draw, &dc.col[defaultcs],
+					borderpx + (term.c.x + 1) * xw.cw - 1,
+					borderpx + term.c.y * xw.ch,
+					1, xw.ch - 1);
+			XftDrawRect(xw.draw, &dc.col[defaultcs],
+					borderpx + term.c.x * xw.cw,
+					borderpx + (term.c.y + 1) * xw.ch - 1,
+					xw.cw, 1);
+		}
 		oldx = term.c.x, oldy = term.c.y;
 	}
 }

From de4cd2f6afdf450aaa97abb328f4c4849602c7db Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 13 Apr 2013 09:49:11 +0200
Subject: [PATCH 0506/1146] Resize now uses xclear().

---
 st.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/st.c b/st.c
index c4eafa0..de3d045 100644
--- a/st.c
+++ b/st.c
@@ -2358,10 +2358,8 @@ xresize(int col, int row) {
 	XFreePixmap(xw.dpy, xw.buf);
 	xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
 			DefaultDepth(xw.dpy, xw.scr));
-	XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
-	XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
-
 	XftDrawChange(xw.draw, xw.buf);
+	xclear(0, 0, xw.w, xw.h);
 }
 
 static inline ushort

From 4de64fa4d24fe0164bc59dd853982a43a9c19e56 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 13 Apr 2013 12:26:17 +0200
Subject: [PATCH 0507/1146] \033 should be used in printf in the FAQ.

Never apply patches of Apple users without shouting at them. The basic rule of
nature is that when you apply Appl users patches without shouting at them that
something will go horribly wrong.
---
 FAQ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/FAQ b/FAQ
index 8f260c1..23d557d 100644
--- a/FAQ
+++ b/FAQ
@@ -48,7 +48,7 @@ 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 "�33?1h�33=" >/dev/tty
+	$ printf "\033?1h\033=" >/dev/tty
 
 or
 	$ echo $(tput smkx) >/dev/tty

From 44db38a5f8560564851683f80e1a649836e5885c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 13 Apr 2013 15:24:26 +0200
Subject: [PATCH 0508/1146] Fix the geometry handling.

---
 st.1 | 3 +++
 st.c | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/st.1 b/st.1
index fc7703d..ab90908 100644
--- a/st.1
+++ b/st.1
@@ -37,6 +37,9 @@ to use when st is run.
 .TP
 .BI \-g " geometry"
 defines the X11 geometry string, which will fixate the height and width of st. 
+The form is [=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]. See
+.BR XParseGeometry (3)
+for further details.
 .TP
 .BI \-o " file"
 writes all the I/O to
diff --git a/st.c b/st.c
index de3d045..d7d70e7 100644
--- a/st.c
+++ b/st.c
@@ -3417,6 +3417,8 @@ run:
 	xinit();
 	ttynew();
 	selinit();
+	if(xw.isfixed)
+		cresize(xw.h, xw.w);
 	run();
 
 	return 0;

From c371fe58a36abbfbf684e62d6b4026173dbc79be Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 14 Apr 2013 18:30:10 +0200
Subject: [PATCH 0509/1146] Enable BCE everywhere.

---
 st.c | 53 +++++++++++++++++++++++++----------------------------
 1 file changed, 25 insertions(+), 28 deletions(-)

diff --git a/st.c b/st.c
index d7d70e7..7250da2 100644
--- a/st.c
+++ b/st.c
@@ -310,7 +310,7 @@ static void strhandle(void);
 static void strparse(void);
 static void strreset(void);
 
-static void tclearregion(int, int, int, int, int);
+static void tclearregion(int, int, int, int);
 static void tcursor(int);
 static void tdeletechar(int);
 static void tdeleteline(int);
@@ -1187,7 +1187,7 @@ treset(void) {
 	term.bot = term.row - 1;
 	term.mode = MODE_WRAP;
 
-	tclearregion(0, 0, term.col-1, term.row-1, 0);
+	tclearregion(0, 0, term.col-1, term.row-1);
 	tmoveto(0, 0);
 	tcursor(CURSOR_SAVE);
 }
@@ -1231,7 +1231,7 @@ tscrolldown(int orig, int n) {
 
 	LIMIT(n, 0, term.bot-orig+1);
 
-	tclearregion(0, term.bot-n+1, term.col-1, term.bot, 0);
+	tclearregion(0, term.bot-n+1, term.col-1, term.bot);
 
 	for(i = term.bot; i >= orig+n; i--) {
 		temp = term.line[i];
@@ -1251,7 +1251,7 @@ tscrollup(int orig, int n) {
 	Line temp;
 	LIMIT(n, 0, term.bot-orig+1);
 
-	tclearregion(0, orig, term.col-1, orig+n-1, 0);
+	tclearregion(0, orig, term.col-1, orig+n-1);
 
 	for(i = orig; i <= term.bot-n; i++) {
 		 temp = term.line[i];
@@ -1389,7 +1389,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 }
 
 void
-tclearregion(int x1, int y1, int x2, int y2, int bce) {
+tclearregion(int x1, int y1, int x2, int y2) {
 	int x, y, temp;
 
 	if(x1 > x2)
@@ -1405,13 +1405,9 @@ tclearregion(int x1, int y1, int x2, int y2, int bce) {
 	for(y = y1; y <= y2; y++) {
 		term.dirty[y] = 1;
 		for(x = x1; x <= x2; x++) {
-			if(bce) {
-				term.line[y][x] = term.c.attr;
-				memcpy(term.line[y][x].c, " ", 2);
-				term.line[y][x].state |= GLYPH_SET;
-			} else {
-				term.line[y][x].state = 0;
-			}
+			term.line[y][x] = term.c.attr;
+			memcpy(term.line[y][x].c, " ", 2);
+			term.line[y][x].state |= GLYPH_SET;
 		}
 	}
 }
@@ -1425,13 +1421,13 @@ tdeletechar(int n) {
 	term.dirty[term.c.y] = 1;
 
 	if(src >= term.col) {
-		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 0);
+		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
 		return;
 	}
 
 	memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src],
 			size * sizeof(Glyph));
-	tclearregion(term.col-n, term.c.y, term.col-1, term.c.y, 0);
+	tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
 }
 
 void
@@ -1443,13 +1439,13 @@ tinsertblank(int n) {
 	term.dirty[term.c.y] = 1;
 
 	if(dst >= term.col) {
-		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 0);
+		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
 		return;
 	}
 
 	memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src],
 			size * sizeof(Glyph));
-	tclearregion(src, term.c.y, dst - 1, term.c.y, 0);
+	tclearregion(src, term.c.y, dst - 1, term.c.y);
 }
 
 void
@@ -1475,8 +1471,9 @@ tsetattr(int *attr, int l) {
 	for(i = 0; i < l; i++) {
 		switch(attr[i]) {
 		case 0:
-			term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE | ATTR_BOLD \
-					| ATTR_ITALIC | ATTR_BLINK);
+			term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE \
+					| ATTR_BOLD | ATTR_ITALIC \
+					| ATTR_BLINK);
 			term.c.attr.fg = defaultfg;
 			term.c.attr.bg = defaultbg;
 			break;
@@ -1645,7 +1642,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				alt = IS_SET(MODE_ALTSCREEN);
 				if(alt) {
 					tclearregion(0, 0, term.col-1,
-							term.row-1, 0);
+							term.row-1);
 				}
 				if(set ^ alt)		/* set is always 1 or 0 */
 					tswapscreen();
@@ -1764,19 +1761,19 @@ csihandle(void) {
 		sel.bx = -1;
 		switch(csiescseq.arg[0]) {
 		case 0: /* below */
-			tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1);
+			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, 1);
+						term.row-1);
 			}
 			break;
 		case 1: /* above */
 			if(term.c.y > 1)
-				tclearregion(0, 0, term.col-1, term.c.y-1, 1);
-			tclearregion(0, term.c.y, term.c.x, 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, 1);
+			tclearregion(0, 0, term.col-1, term.row-1);
 			break;
 		default:
 			goto unknown;
@@ -1786,13 +1783,13 @@ csihandle(void) {
 		switch(csiescseq.arg[0]) {
 		case 0: /* right */
 			tclearregion(term.c.x, term.c.y, term.col-1,
-					term.c.y, 1);
+					term.c.y);
 			break;
 		case 1: /* left */
-			tclearregion(0, term.c.y, term.c.x, term.c.y, 1);
+			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, 1);
+			tclearregion(0, term.c.y, term.col-1, term.c.y);
 			break;
 		}
 		break;
@@ -1818,7 +1815,7 @@ csihandle(void) {
 	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, 1);
+				term.c.x + csiescseq.arg[0] - 1, term.c.y);
 		break;
 	case 'P': /* DCH -- Delete <n> char */
 		DEFAULT(csiescseq.arg[0], 1);

From 0ca0dd8b11ec0febc547e485395b7c9ec01e2866 Mon Sep 17 00:00:00 2001
From: Alexander Sedov <alex0player@gmail.com>
Date: Sun, 14 Apr 2013 23:17:44 +0400
Subject: [PATCH 0510/1146] Strip trailing spaces from lines when copying
 selection.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 7250da2..56dc94c 100644
--- a/st.c
+++ b/st.c
@@ -773,7 +773,8 @@ selcopy(void) {
 			gp = &term.line[y][0];
 			last = gp + term.col;
 
-			while(--last >= gp && !(last->state & GLYPH_SET))
+			while(--last >= gp && !((last->state & GLYPH_SET) && \
+						selected(last - gp, y) && strcmp(last->c, " ") != 0))
 				/* nothing */;
 
 			for(x = 0; gp <= last; x++, ++gp) {

From fed9968ba5d3c6874f73517b261968746d36801e Mon Sep 17 00:00:00 2001
From: Alexander Sedov <alex0player@gmail.com>
Date: Mon, 15 Apr 2013 00:12:10 +0400
Subject: [PATCH 0511/1146] Got rid of code duplication in tnew() and
 tresize().

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 18 +++---------------
 1 file changed, 3 insertions(+), 15 deletions(-)

diff --git a/st.c b/st.c
index 56dc94c..fc07a46 100644
--- a/st.c
+++ b/st.c
@@ -1195,22 +1195,10 @@ treset(void) {
 
 void
 tnew(int col, int row) {
-	/* set screen size */
-	term.row = row;
-	term.col = col;
-	term.line = xmalloc(term.row * sizeof(Line));
-	term.alt  = xmalloc(term.row * sizeof(Line));
-	term.dirty = xmalloc(term.row * sizeof(*term.dirty));
-	term.tabs = xmalloc(term.col * sizeof(*term.tabs));
-
-	for(row = 0; row < term.row; row++) {
-		term.line[row] = xmalloc(term.col * sizeof(Glyph));
-		term.alt [row] = xmalloc(term.col * sizeof(Glyph));
-		term.dirty[row] = 0;
-	}
-
+	/* setting "zero" terminal to resize it later */
+	memset(&term, 0, sizeof(Term));
+	tresize(col, row);
 	term.numlock = 1;
-	memset(term.tabs, 0, term.col * sizeof(*term.tabs));
 	/* setup screen */
 	treset();
 }

From 3ae02990648447ec3252b42f5b64e18818c19fd8 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 18 Apr 2013 06:41:54 +0200
Subject: [PATCH 0512/1146] Removing unneeded comments.

---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index fc07a46..9587886 100644
--- a/st.c
+++ b/st.c
@@ -1195,11 +1195,10 @@ treset(void) {
 
 void
 tnew(int col, int row) {
-	/* setting "zero" terminal to resize it later */
 	memset(&term, 0, sizeof(Term));
 	tresize(col, row);
 	term.numlock = 1;
-	/* setup screen */
+
 	treset();
 }
 

From b7e6a5c825a8d786a0cc4dbacc82df1c90ad7020 Mon Sep 17 00:00:00 2001
From: Alexander Sedov <alex0player@gmail.com>
Date: Mon, 15 Apr 2013 17:13:19 +0400
Subject: [PATCH 0513/1146] Got rid of redundant Glyph state.

Now, newly allocated Glyphs are set to spaces and current cursor colors
with tclearregion() routine.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 79 ++++++++++++++++++++++++++----------------------------------
 1 file changed, 34 insertions(+), 45 deletions(-)

diff --git a/st.c b/st.c
index 9587886..53c524f 100644
--- a/st.c
+++ b/st.c
@@ -98,11 +98,6 @@ enum cursor_state {
 	CURSOR_ORIGIN	= 2
 };
 
-enum glyph_state {
-	GLYPH_SET   = 1,
-	GLYPH_DIRTY = 2
-};
-
 enum term_mode {
 	MODE_WRAP	 = 1,
 	MODE_INSERT      = 2,
@@ -154,7 +149,6 @@ typedef struct {
 	uchar mode;  /* attribute flags */
 	ushort fg;   /* foreground  */
 	ushort bg;   /* background  */
-	uchar state; /* state flags    */
 } Glyph;
 
 typedef Glyph *Line;
@@ -757,7 +751,7 @@ bpress(XEvent *e) {
 
 void
 selcopy(void) {
-	char *str, *ptr, *p;
+	char *str, *ptr;
 	int x, y, bufsize, isselected = 0, size;
 	Glyph *gp, *last;
 
@@ -773,8 +767,8 @@ selcopy(void) {
 			gp = &term.line[y][0];
 			last = gp + term.col;
 
-			while(--last >= gp && !((last->state & GLYPH_SET) && \
-						selected(last - gp, y) && strcmp(last->c, " ") != 0))
+			while(--last >= gp && !(selected(last - gp, y) && \
+						strcmp(last->c, " ") != 0))
 				/* nothing */;
 
 			for(x = 0; gp <= last; x++, ++gp) {
@@ -784,9 +778,8 @@ selcopy(void) {
 					isselected = 1;
 				}
 
-				p = (gp->state & GLYPH_SET) ? gp->c : " ";
-				size = utf8size(p);
-				memcpy(ptr, p, size);
+				size = utf8size(gp->c);
+				memcpy(ptr, gp->c, size);
 				ptr += size;
 			}
 
@@ -943,13 +936,11 @@ brelease(XEvent *e) {
 			} else if(TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) {
 				/* double click to select word */
 				sel.bx = sel.ex;
-				while(sel.bx > 0 && term.line[sel.ey][sel.bx-1].state & GLYPH_SET &&
-						term.line[sel.ey][sel.bx-1].c[0] != ' ') {
+				while(sel.bx > 0 && term.line[sel.ey][sel.bx-1].c[0] != ' ') {
 					sel.bx--;
 				}
 				sel.b.x = sel.bx;
-				while(sel.ex < term.col-1 && term.line[sel.ey][sel.ex+1].state & GLYPH_SET &&
-						term.line[sel.ey][sel.ex+1].c[0] != ' ') {
+				while(sel.ex < term.col-1 && term.line[sel.ey][sel.ex+1].c[0] != ' ') {
 					sel.ex++;
 				}
 				sel.e.x = sel.ex;
@@ -1373,7 +1364,6 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 	term.dirty[y] = 1;
 	term.line[y][x] = *attr;
 	memcpy(term.line[y][x].c, c, UTF_SIZ);
-	term.line[y][x].state |= GLYPH_SET;
 }
 
 void
@@ -1395,7 +1385,6 @@ tclearregion(int x1, int y1, int x2, int y2) {
 		for(x = x1; x <= x2; x++) {
 			term.line[y][x] = term.c.attr;
 			memcpy(term.line[y][x].c, " ", 2);
-			term.line[y][x].state |= GLYPH_SET;
 		}
 	}
 }
@@ -2263,11 +2252,12 @@ tputc(char *c, int len) {
 
 int
 tresize(int col, int row) {
-	int i, x;
+	int i;
 	int minrow = MIN(row, term.row);
 	int mincol = MIN(col, term.col);
 	int slide = term.c.y - row + 1;
 	bool *bp;
+	Line *orig;
 
 	if(col < 1 || row < 1)
 		return 0;
@@ -2303,10 +2293,6 @@ tresize(int col, int row) {
 		term.dirty[i] = 1;
 		term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
 		term.alt[i]  = xrealloc(term.alt[i],  col * sizeof(Glyph));
-		for(x = mincol; x < col; x++) {
-			term.line[i][x].state = 0;
-			term.alt[i][x].state = 0;
-		}
 	}
 
 	/* allocate any new rows */
@@ -2331,6 +2317,17 @@ tresize(int col, int row) {
 	tsetscroll(0, row-1);
 	/* make use of the LIMIT in tmoveto */
 	tmoveto(term.c.x, term.c.y);
+	/* Clearing both screens */
+	orig = term.line;
+	do {	
+		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();
+	} while(orig != term.line);
 
 	return (slide > 0);
 }
@@ -2932,22 +2929,17 @@ void
 xdrawcursor(void) {
 	static int oldx = 0, oldy = 0;
 	int sl;
-	Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs, 0};
+	Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs};
 
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
 
-	if(term.line[term.c.y][term.c.x].state & GLYPH_SET)
-		memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
+	memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
 
 	/* remove the old cursor */
-	if(term.line[oldy][oldx].state & GLYPH_SET) {
-		sl = utf8size(term.line[oldy][oldx].c);
-		xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx,
-				oldy, 1, sl);
-	} else {
-		xtermclear(oldx, oldy, oldx, oldy);
-	}
+	sl = utf8size(term.line[oldy][oldx].c);
+	xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx,
+			oldy, 1, sl);
 
 	/* draw the new one */
 	if(!(IS_SET(MODE_HIDE))) {
@@ -3045,23 +3037,20 @@ drawregion(int x1, int y1, int x2, int y2) {
 			new = term.line[y][x];
 			if(ena_sel && *(new.c) && selected(x, y))
 				new.mode ^= ATTR_REVERSE;
-			if(ib > 0 && (!(new.state & GLYPH_SET)
-					|| ATTRCMP(base, new)
+			if(ib > 0 && (ATTRCMP(base, new)
 					|| ib >= DRAW_BUF_SIZ-UTF_SIZ)) {
 				xdraws(buf, base, ox, y, ic, ib);
 				ic = ib = 0;
 			}
-			if(new.state & GLYPH_SET) {
-				if(ib == 0) {
-					ox = x;
-					base = new;
-				}
-
-				sl = utf8size(new.c);
-				memcpy(buf+ib, new.c, sl);
-				ib += sl;
-				++ic;
+			if(ib == 0) {
+				ox = x;
+				base = new;
 			}
+
+			sl = utf8size(new.c);
+			memcpy(buf+ib, new.c, sl);
+			ib += sl;
+			++ic;
 		}
 		if(ib > 0)
 			xdraws(buf, base, ox, y, ic, ib);

From da182612b7c7a6be67b2c7be0c0d85562220f1e4 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 18 Apr 2013 06:51:18 +0200
Subject: [PATCH 0514/1146] Removing trailing whitespace.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 53c524f..8e39ec2 100644
--- a/st.c
+++ b/st.c
@@ -2319,7 +2319,7 @@ tresize(int col, int row) {
 	tmoveto(term.c.x, term.c.y);
 	/* Clearing both screens */
 	orig = term.line;
-	do {	
+	do {
 		if(mincol < col && 0 < minrow) {
 			tclearregion(mincol, 0, col - 1, minrow - 1);
 		}

From e5ff746430725b05e223c454febbde949df2fde2 Mon Sep 17 00:00:00 2001
From: Alexander Sedov <alex0player@gmail.com>
Date: Thu, 18 Apr 2013 12:47:23 +0400
Subject: [PATCH 0515/1146] Selection now handles empty lines less
 counter-intuitively.

Now, when you are selecting a region, you will get all empty lines that happen
to be in it, including trailing ones. Last line terminator is omitted as it previously
was, though.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 8e39ec2..686ed5d 100644
--- a/st.c
+++ b/st.c
@@ -752,7 +752,7 @@ bpress(XEvent *e) {
 void
 selcopy(void) {
 	char *str, *ptr;
-	int x, y, bufsize, isselected = 0, size;
+	int x, y, bufsize, size;
 	Glyph *gp, *last;
 
 	if(sel.bx == -1) {
@@ -763,7 +763,6 @@ selcopy(void) {
 
 		/* append every set & selected glyph to the selection */
 		for(y = sel.b.y; y < sel.e.y + 1; y++) {
-			isselected = 0;
 			gp = &term.line[y][0];
 			last = gp + term.col;
 
@@ -774,8 +773,6 @@ selcopy(void) {
 			for(x = 0; gp <= last; x++, ++gp) {
 				if(!selected(x, y)) {
 					continue;
-				} else {
-					isselected = 1;
 				}
 
 				size = utf8size(gp->c);
@@ -792,7 +789,7 @@ selcopy(void) {
 			 * st.
 			 * FIXME: Fix the computer world.
 			 */
-			if(isselected && y < sel.e.y)
+			if(y < sel.e.y)
 				*ptr++ = '\n';
 		}
 		*ptr = 0;

From 645c1b0afccf14a5bcdf754475516554437599ca Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 19 Apr 2013 21:11:29 +0200
Subject: [PATCH 0516/1146] Making st compile on OpenBSD again.

---
 config.mk | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/config.mk b/config.mk
index 88355c7..4d0a869 100644
--- a/config.mk
+++ b/config.mk
@@ -12,11 +12,11 @@ X11LIB = /usr/X11R6/lib
 
 # includes and libs
 INCS = -I. -I/usr/include -I${X11INC} \
-       $(shell pkg-config --cflags fontconfig) \
-       $(shell pkg-config --cflags freetype2)
+       `pkg-config --cflags fontconfig` \
+       `pkg-config --cflags freetype2`
 LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext -lXft \
-       $(shell pkg-config --libs fontconfig)  \
-       $(shell pkg-config --libs freetype2)
+       `pkg-config --libs fontconfig`  \
+       `pkg-config --libs freetype2`
 
 # flags
 CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_XOPEN_SOURCE=600

From 3c546ae73924804ddc6d29dc3ab2f12a93287009 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 20 Apr 2013 15:29:39 +0200
Subject: [PATCH 0517/1146] 0.4.1 release.

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 4d0a869..9431de2 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.4
+VERSION = 0.4.1
 
 # Customize below to fit your system
 

From 872a7f18eaffd96eefb31e3dcb45fd86bc67029b Mon Sep 17 00:00:00 2001
From: Alexander Sedov <alex0player@gmail.com>
Date: Mon, 15 Apr 2013 10:28:31 +0400
Subject: [PATCH 0518/1146] Added support for double/triple click+dragging.

Now double-click+dragging automatically snaps both ends to word boundaries
(unless on series of spaces), and triple-click selects whole lines.
As a side effect, snapping now occurs on button press, not button release
like it previously was, but I hope that won't be inconvenient for anyone.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 90 ++++++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 63 insertions(+), 27 deletions(-)

diff --git a/st.c b/st.c
index 686ed5d..bca9dc7 100644
--- a/st.c
+++ b/st.c
@@ -135,6 +135,11 @@ enum selection_type {
 	SEL_RECTANGULAR = 2
 };
 
+enum selection_snap {
+	SNAP_WORD = 1,
+	SNAP_LINE = 2
+};
+
 /* bit macro */
 #undef B0
 enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 };
@@ -232,6 +237,7 @@ typedef struct {
 typedef struct {
 	int mode;
 	int type;
+	int snap;
 	int bx, by;
 	int ex, ey;
 	struct {
@@ -372,6 +378,7 @@ static void selinit(void);
 static inline bool selected(int, int);
 static void selcopy(void);
 static void selscroll(int, int);
+static void selsnap(int, int *, int *, int);
 
 static int utf8decode(char *, long *);
 static int utf8encode(long *, char *);
@@ -657,6 +664,25 @@ selected(int x, int y) {
 			&& (x <= sel.e.x || sel.b.y != sel.e.y));
 }
 
+void
+selsnap(int mode, int *x, int *y, int direction) {
+	switch(mode) {
+	case SNAP_WORD:
+		while(*x > 0 && *x < term.col-1 && term.line[*y][*x + direction].c[0] != ' ') {
+			*x += direction;
+		}
+		break;
+
+	case SNAP_LINE:
+		*x = (direction < 0) ? 0 : term.col - 1;
+		break;
+	
+	default:
+		/* do nothing */
+		break;
+	}
+}
+
 void
 getbuttoninfo(XEvent *e) {
 	int type;
@@ -667,6 +693,15 @@ getbuttoninfo(XEvent *e) {
 	sel.ex = x2col(e->xbutton.x);
 	sel.ey = y2row(e->xbutton.y);
 
+	if (sel.by < sel.ey
+			|| (sel.by == sel.ey && sel.bx < sel.ex)) {
+		selsnap(sel.snap, &sel.bx, &sel.by, -1);
+		selsnap(sel.snap, &sel.ex, &sel.ey, +1);
+	} else {
+		selsnap(sel.snap, &sel.ex, &sel.ey, -1);
+		selsnap(sel.snap, &sel.bx, &sel.by, +1);
+	}
+
 	sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex;
 	sel.b.y = MIN(sel.by, sel.ey);
 	sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx;
@@ -730,9 +765,13 @@ mousereport(XEvent *e) {
 
 void
 bpress(XEvent *e) {
+	struct timeval now;
+
 	if(IS_SET(MODE_MOUSE)) {
 		mousereport(e);
 	} else if(e->xbutton.button == Button1) {
+		gettimeofday(&now, NULL);
+		/* Clear previous selection, logically and visually. */
 		if(sel.bx != -1) {
 			sel.bx = -1;
 			tsetdirt(sel.b.y, sel.e.y);
@@ -742,6 +781,30 @@ bpress(XEvent *e) {
 		sel.type = SEL_REGULAR;
 		sel.ex = sel.bx = x2col(e->xbutton.x);
 		sel.ey = sel.by = y2row(e->xbutton.y);
+		/*
+		 * Snap handling.
+		 * If user clicks are fasst enough (e.g. below timeouts),
+		 * we ignore if his hand slipped left or down and accidentally selected more;
+		 * we are just snapping to whatever we're snapping.
+		 */
+		if(TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) {
+			/* Snap to line */
+			sel.snap = SNAP_LINE;
+		} else if(TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) {
+			sel.snap = SNAP_WORD;
+		} else {
+			sel.snap = 0;
+		}
+		selsnap(sel.snap, &sel.bx, &sel.by, -1);
+		selsnap(sel.snap, &sel.ex, &sel.ey, 1);
+		sel.b.x = sel.bx, sel.b.y = sel.by, sel.e.x = sel.ex, sel.e.y = sel.ey;
+		/* Draw selection, unless it's regular and we don't want to make clicks visible */
+		if (sel.snap != 0) {
+			tsetdirt(sel.b.y, sel.e.y);
+			draw();
+		}
+		sel.tclick2 = sel.tclick1;
+		sel.tclick1 = now;
 	} else if(e->xbutton.button == Button4) {
 		ttywrite("\031", 1);
 	} else if(e->xbutton.button == Button5) {
@@ -907,8 +970,6 @@ xsetsel(char *str) {
 
 void
 brelease(XEvent *e) {
-	struct timeval now;
-
 	if(IS_SET(MODE_MOUSE)) {
 		mousereport(e);
 		return;
@@ -922,35 +983,10 @@ brelease(XEvent *e) {
 		term.dirty[sel.ey] = 1;
 		if(sel.bx == sel.ex && sel.by == sel.ey) {
 			sel.bx = -1;
-			gettimeofday(&now, NULL);
-
-			if(TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) {
-				/* triple click on the line */
-				sel.b.x = sel.bx = 0;
-				sel.e.x = sel.ex = term.col;
-				sel.b.y = sel.e.y = sel.ey;
-				selcopy();
-			} else if(TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) {
-				/* double click to select word */
-				sel.bx = sel.ex;
-				while(sel.bx > 0 && term.line[sel.ey][sel.bx-1].c[0] != ' ') {
-					sel.bx--;
-				}
-				sel.b.x = sel.bx;
-				while(sel.ex < term.col-1 && term.line[sel.ey][sel.ex+1].c[0] != ' ') {
-					sel.ex++;
-				}
-				sel.e.x = sel.ex;
-				sel.b.y = sel.e.y = sel.ey;
-				selcopy();
-			}
 		} else {
 			selcopy();
 		}
 	}
-
-	memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval));
-	gettimeofday(&sel.tclick1, NULL);
 }
 
 void

From b596d6ba3c50bc379adc298a4e2ba7c122b116ab Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 21 Apr 2013 13:01:16 +0200
Subject: [PATCH 0519/1146] Adding wrap handling in selection.

---
 st.c | 37 +++++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index bca9dc7..71e5b83 100644
--- a/st.c
+++ b/st.c
@@ -85,6 +85,7 @@ enum glyph_attribute {
 	ATTR_GFX       = 8,
 	ATTR_ITALIC    = 16,
 	ATTR_BLINK     = 32,
+	ATTR_WRAP      = 64,
 };
 
 enum cursor_movement {
@@ -668,17 +669,15 @@ void
 selsnap(int mode, int *x, int *y, int direction) {
 	switch(mode) {
 	case SNAP_WORD:
-		while(*x > 0 && *x < term.col-1 && term.line[*y][*x + direction].c[0] != ' ') {
+		while(*x > 0 && *x < term.col-1
+				&& term.line[*y][*x + direction].c[0] != ' ') {
 			*x += direction;
 		}
 		break;
-
 	case SNAP_LINE:
 		*x = (direction < 0) ? 0 : term.col - 1;
 		break;
-	
 	default:
-		/* do nothing */
 		break;
 	}
 }
@@ -771,6 +770,7 @@ bpress(XEvent *e) {
 		mousereport(e);
 	} else if(e->xbutton.button == Button1) {
 		gettimeofday(&now, NULL);
+
 		/* Clear previous selection, logically and visually. */
 		if(sel.bx != -1) {
 			sel.bx = -1;
@@ -781,14 +781,15 @@ bpress(XEvent *e) {
 		sel.type = SEL_REGULAR;
 		sel.ex = sel.bx = x2col(e->xbutton.x);
 		sel.ey = sel.by = y2row(e->xbutton.y);
+
 		/*
 		 * Snap handling.
 		 * If user clicks are fasst enough (e.g. below timeouts),
-		 * we ignore if his hand slipped left or down and accidentally selected more;
-		 * we are just snapping to whatever we're snapping.
+		 * we ignore if his hand slipped left or down and accidentally
+		 * selected more; we are just snapping to whatever we're
+		 * snapping.
 		 */
 		if(TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) {
-			/* Snap to line */
 			sel.snap = SNAP_LINE;
 		} else if(TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) {
 			sel.snap = SNAP_WORD;
@@ -797,8 +798,15 @@ bpress(XEvent *e) {
 		}
 		selsnap(sel.snap, &sel.bx, &sel.by, -1);
 		selsnap(sel.snap, &sel.ex, &sel.ey, 1);
-		sel.b.x = sel.bx, sel.b.y = sel.by, sel.e.x = sel.ex, sel.e.y = sel.ey;
-		/* Draw selection, unless it's regular and we don't want to make clicks visible */
+		sel.b.x = sel.bx;
+		sel.b.y = sel.by;
+		sel.e.x = sel.ex;
+		sel.e.y = sel.ey;
+
+		/*
+		 * Draw selection, unless it's regular and we don't want to
+		 * make clicks visible
+		 */
 		if (sel.snap != 0) {
 			tsetdirt(sel.b.y, sel.e.y);
 			draw();
@@ -834,9 +842,8 @@ selcopy(void) {
 				/* nothing */;
 
 			for(x = 0; gp <= last; x++, ++gp) {
-				if(!selected(x, y)) {
+				if(!selected(x, y))
 					continue;
-				}
 
 				size = utf8size(gp->c);
 				memcpy(ptr, gp->c, size);
@@ -852,7 +859,7 @@ selcopy(void) {
 			 * st.
 			 * FIXME: Fix the computer world.
 			 */
-			if(y < sel.e.y)
+			if(y < sel.e.y && !((gp-1)->mode & ATTR_WRAP))
 				*ptr++ = '\n';
 		}
 		*ptr = 0;
@@ -2266,8 +2273,10 @@ tputc(char *c, int len) {
 		return;
 	if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey))
 		sel.bx = -1;
-	if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT)
-		tnewline(1); /* always go to first col */
+	if(IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
+		term.line[term.c.y][term.c.x].mode |= ATTR_WRAP;
+		tnewline(1);
+	}
 
 	if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col) {
 		memmove(&term.line[term.c.y][term.c.x+1],

From 2bd6afd1c9eb341d9e2c5d89bc16bb7758691e1f Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 23 Apr 2013 15:22:14 +0200
Subject: [PATCH 0520/1146] Implementing 8 bit mode for meta.

---
 st.c    | 23 +++++++++++++++++++----
 st.info |  3 +++
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 71e5b83..f593302 100644
--- a/st.c
+++ b/st.c
@@ -114,6 +114,7 @@ enum term_mode {
 	MODE_ECHO	 = 1024,
 	MODE_APPCURSOR	 = 2048,
 	MODE_MOUSESGR    = 4096,
+	MODE_8BIT	 = 8192,
 };
 
 enum escape_state {
@@ -1650,6 +1651,9 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 1006:
 				MODBIT(term.mode, set, MODE_MOUSESGR);
 				break;
+			case 1034:
+				MODBIT(term.mode, set, MODE_8BIT);
+				break;
 			case 1049: /* = 1047 and 1048 */
 			case 47:
 			case 1047:
@@ -3228,7 +3232,8 @@ kpress(XEvent *ev) {
 	XKeyEvent *e = &ev->xkey;
 	KeySym ksym;
 	char xstr[31], buf[32], *customkey, *cp = buf;
-	int len;
+	int len, ret;
+	long c;
 	Status status;
 	Shortcut *bp;
 
@@ -3249,13 +3254,23 @@ kpress(XEvent *ev) {
 	if((customkey = kmap(ksym, e->state))) {
 		len = strlen(customkey);
 		memcpy(buf, customkey, len);
-	/* 2. hardcoded (overrides X lookup) */
+	/* 3. hardcoded (overrides X lookup) */
 	} else {
 		if(len == 0)
 			return;
 
-		if(len == 1 && e->state & Mod1Mask)
-			*cp++ = '\033';
+		if(len == 1 && e->state & Mod1Mask) {
+			if(IS_SET(MODE_8BIT)) {
+				if(*xstr < 0177) {
+					c = *xstr | B7;
+					ret = utf8encode(&c, cp);
+					cp += ret;
+					len = 0;
+				}
+			} else {
+				*cp++ = '\033';
+			}
+		}
 
 		memcpy(cp, xstr, len);
 		len = cp - buf + len;
diff --git a/st.info b/st.info
index 1c83dc1..26db8cc 100644
--- a/st.info
+++ b/st.info
@@ -147,6 +147,7 @@ st| simpleterm,
 	kich1=\E[2~,
 	knp=\E[6~,
 	kmous=\E[M,
+	km,
 	kpp=\E[5~,
 	lines#24,
 	mir,
@@ -162,6 +163,7 @@ st| simpleterm,
 	rmcup=\E[?1049l,
 	rmir=\E[4l,
 	rmkx=\E[?1l\E>,
+	rmm=\E[?1034l,
 	rmso=\E[27m,
 	rmul=\E[m,
 	rs1=\Ec,
@@ -178,6 +180,7 @@ st| simpleterm,
 	smcup=\E[?1049h,
 	smir=\E[4h,
 	smkx=\E[?1h\E=,
+	smm=\E[?1034h,
 	smso=\E[7m,
 	smul=\E[4m,
 	tbc=\E[3g,

From 8037dac847b1006f1ba94a9aa2c7ef3ba72690e5 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 23 Apr 2013 15:33:21 +0200
Subject: [PATCH 0521/1146] There is no 8bit by default and reset 8bit too.

---
 st.info | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/st.info b/st.info
index 26db8cc..60855c1 100644
--- a/st.info
+++ b/st.info
@@ -47,7 +47,7 @@ st| simpleterm,
 	ind=^J,
 	indn=\E[%p1%dS,
 	invis=\E[8m,
-	is2=\E[4l\E>,
+	is2=\E[4l\E>\E[?1034l,
 	it#8,
 	kel=\E[1;2F,
 	ked=\E[1;5F,
@@ -147,7 +147,6 @@ st| simpleterm,
 	kich1=\E[2~,
 	knp=\E[6~,
 	kmous=\E[M,
-	km,
 	kpp=\E[5~,
 	lines#24,
 	mir,
@@ -167,7 +166,7 @@ st| simpleterm,
 	rmso=\E[27m,
 	rmul=\E[m,
 	rs1=\Ec,
-	rs2=\E[4l\E>,
+	is2=\E[4l\E>\E[?1034l,
 	sc=\E7,
 	setab=\E[4%p1%dm,
 	setaf=\E[3%p1%dm,

From 7ea68632081e5adc2f0d2681ac89ed5decfac7b9 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 23 Apr 2013 15:38:48 +0200
Subject: [PATCH 0522/1146] Yes, rs2 != is2.

---
 st.info | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.info b/st.info
index 60855c1..79b881f 100644
--- a/st.info
+++ b/st.info
@@ -166,7 +166,7 @@ st| simpleterm,
 	rmso=\E[27m,
 	rmul=\E[m,
 	rs1=\Ec,
-	is2=\E[4l\E>\E[?1034l,
+	rs2=\E[4l\E>\E[?1034l,
 	sc=\E7,
 	setab=\E[4%p1%dm,
 	setaf=\E[3%p1%dm,

From db6f796ecfafcee879613b60a772be3e5d9e355e Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 23 Apr 2013 19:17:50 +0200
Subject: [PATCH 0523/1146] Removing the overdrawing of some fonts.

---
 st.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/st.c b/st.c
index f593302..f2ee12f 100644
--- a/st.c
+++ b/st.c
@@ -36,6 +36,7 @@ char *argv0;
 #define Draw XftDraw *
 #define Colour XftColor
 #define Colourmap Colormap
+#define Rectangle XRectangle
 
 #if   defined(__linux)
  #include <pty.h>
@@ -2764,6 +2765,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	FcCharSet *fccharset;
 	Colour *fg, *bg, *temp, revfg, revbg;
 	XRenderColor colfg, colbg;
+	Rectangle r;
 
 	frcflags = FRC_NORMAL;
 
@@ -2851,6 +2853,11 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 	/* Clean up the region we want to draw to. */
 	XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch);
+	r.x = 0;
+	r.y = 0;
+	r.height = xw.ch;
+	r.width = width;
+	XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
 
 	fcsets[0] = font->set;
 	for(xp = winx; bytelen > 0;) {
@@ -2885,6 +2892,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 							(FcChar8 *)u8fs,
 							u8fblen);
 					xp += font->width * u8fl;
+
 				}
 				break;
 			}
@@ -2969,6 +2977,9 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1,
 				width, 1);
 	}
+
+	/* Reset clip to none. */
+	XftDrawSetClip(xw.draw, 0);
 }
 
 void

From 6b03bb769a105f797bce40aa0258cf035266e7bf Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 23 Apr 2013 19:37:28 +0200
Subject: [PATCH 0524/1146] Now clipping is more clear.

---
 st.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.c b/st.c
index f2ee12f..7f53981 100644
--- a/st.c
+++ b/st.c
@@ -2853,6 +2853,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 	/* Clean up the region we want to draw to. */
 	XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch);
+
+	/* Set the clip region because Xft is sometimes dirty. */
 	r.x = 0;
 	r.y = 0;
 	r.height = xw.ch;

From 048c54fd5b275ac54d7819020485b77e99fcc469 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 23 Apr 2013 20:34:52 +0200
Subject: [PATCH 0525/1146] Fix selecting clearing and BCE

The commit b78c5085f72 changed the st behaviour enabling BCE capability,
that means erase regions using background color. Problem comes when you
clear a region with a selection, because in this case the real mode of the
Glyph is not the value of term.line[y][x], due in drawregion we had enabled
the ATTR_REVERSE bit.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 7f53981..92854b4 100644
--- a/st.c
+++ b/st.c
@@ -1410,7 +1410,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 
 void
 tclearregion(int x1, int y1, int x2, int y2) {
-	int x, y, temp;
+	int x, y, temp, mask;
 
 	if(x1 > x2)
 		temp = x1, x1 = x2, x2 = temp;
@@ -1425,7 +1425,9 @@ tclearregion(int x1, int y1, int x2, int y2) {
 	for(y = y1; y <= y2; y++) {
 		term.dirty[y] = 1;
 		for(x = x1; x <= x2; x++) {
+			mask = selected(x, y) ? ATTR_REVERSE : 0;
 			term.line[y][x] = term.c.attr;
+			term.line[y][x].mode ^= mask;
 			memcpy(term.line[y][x].c, " ", 2);
 		}
 	}

From 011c0f9e5bb87838afa90f2a33ba68920681e3ce Mon Sep 17 00:00:00 2001
From: Alexander Sedov <alex0player@gmail.com>
Date: Wed, 24 Apr 2013 02:34:59 +0400
Subject: [PATCH 0526/1146] Removed redundant check in draw code.

We're now clearing empty areas with spaces, so there is no point to check
if character contains non-empty string.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 92854b4..8e9e895 100644
--- a/st.c
+++ b/st.c
@@ -3096,7 +3096,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 		ic = ib = ox = 0;
 		for(x = x1; x < x2; x++) {
 			new = term.line[y][x];
-			if(ena_sel && *(new.c) && selected(x, y))
+			if(ena_sel && selected(x, y))
 				new.mode ^= ATTR_REVERSE;
 			if(ib > 0 && (ATTRCMP(base, new)
 					|| ib >= DRAW_BUF_SIZ-UTF_SIZ)) {

From 0851f2be2ab48ee3a67ef2287c09bd67622dcd8e Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 24 Apr 2013 21:30:59 +0200
Subject: [PATCH 0527/1146] Fixing the selection issue in altscreens.

---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 8e9e895..c0a4780 100644
--- a/st.c
+++ b/st.c
@@ -1410,7 +1410,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 
 void
 tclearregion(int x1, int y1, int x2, int y2) {
-	int x, y, temp, mask;
+	int x, y, temp;
 
 	if(x1 > x2)
 		temp = x1, x1 = x2, x2 = temp;
@@ -1425,9 +1425,9 @@ tclearregion(int x1, int y1, int x2, int y2) {
 	for(y = y1; y <= y2; y++) {
 		term.dirty[y] = 1;
 		for(x = x1; x <= x2; x++) {
-			mask = selected(x, y) ? ATTR_REVERSE : 0;
+			if(selected(x, y))
+				selclear(NULL);
 			term.line[y][x] = term.c.attr;
-			term.line[y][x].mode ^= mask;
 			memcpy(term.line[y][x].c, " ", 2);
 		}
 	}

From 1b2751f5c24ca06afbb68e41e73fc9fce6c6b521 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 25 Apr 2013 06:28:11 +0200
Subject: [PATCH 0528/1146] Fixing the selection handling to allow one char
 selection.

Thanks Alexander Sedov <alex0player@gmail.com> for suggesting the fix!
---
 st.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/st.c b/st.c
index c0a4780..8d27c94 100644
--- a/st.c
+++ b/st.c
@@ -785,11 +785,8 @@ bpress(XEvent *e) {
 		sel.ey = sel.by = y2row(e->xbutton.y);
 
 		/*
-		 * Snap handling.
-		 * If user clicks are fasst enough (e.g. below timeouts),
-		 * we ignore if his hand slipped left or down and accidentally
-		 * selected more; we are just snapping to whatever we're
-		 * snapping.
+		 * If the user clicks below predefined timeouts specific
+		 * snapping behaviour is exposed.
 		 */
 		if(TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) {
 			sel.snap = SNAP_LINE;
@@ -809,7 +806,8 @@ bpress(XEvent *e) {
 		 * Draw selection, unless it's regular and we don't want to
 		 * make clicks visible
 		 */
-		if (sel.snap != 0) {
+		if(sel.snap != 0) {
+			sel.mode++;
 			tsetdirt(sel.b.y, sel.e.y);
 			draw();
 		}
@@ -987,14 +985,14 @@ brelease(XEvent *e) {
 	if(e->xbutton.button == Button2) {
 		selpaste(NULL);
 	} else if(e->xbutton.button == Button1) {
-		sel.mode = 0;
-		getbuttoninfo(e);
-		term.dirty[sel.ey] = 1;
-		if(sel.bx == sel.ex && sel.by == sel.ey) {
+		if(sel.mode < 2) {
 			sel.bx = -1;
 		} else {
+			getbuttoninfo(e);
 			selcopy();
 		}
+		sel.mode = 0;
+		term.dirty[sel.ey] = 1;
 	}
 }
 
@@ -1010,6 +1008,7 @@ bmotion(XEvent *e) {
 	if(!sel.mode)
 		return;
 
+	sel.mode++;
 	oldey = sel.ey;
 	oldex = sel.ex;
 	oldsby = sel.b.y;

From 1e09726518b84091e80dfaf96632c122f6f446a6 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 26 Apr 2013 18:41:54 +0200
Subject: [PATCH 0529/1146] Enable blinking in st.

---
 config.def.h |  3 ++
 st.c         | 83 ++++++++++++++++++++++++++++++++++++++++++++--------
 st.info      |  2 +-
 3 files changed, 74 insertions(+), 14 deletions(-)

diff --git a/config.def.h b/config.def.h
index d1c20bd..b44fe17 100644
--- a/config.def.h
+++ b/config.def.h
@@ -20,6 +20,9 @@ static bool allowaltscreen = true;
 static unsigned int xfps = 60;
 static unsigned int actionfps = 30;
 
+/* blinking timeout (set to 0 to disable blinking) */
+static unsigned int blinktimeout = 800;
+
 /* TERM value */
 static char termname[] = "st-256color";
 
diff --git a/st.c b/st.c
index 8d27c94..8065ebe 100644
--- a/st.c
+++ b/st.c
@@ -116,6 +116,8 @@ enum term_mode {
 	MODE_APPCURSOR	 = 2048,
 	MODE_MOUSESGR    = 4096,
 	MODE_8BIT	 = 8192,
+	MODE_BLINK	 = 16384,
+	MODE_FBLINK	 = 32768,
 };
 
 enum escape_state {
@@ -313,6 +315,7 @@ static void strhandle(void);
 static void strparse(void);
 static void strreset(void);
 
+static int tattrset(int);
 static void tclearregion(int, int, int, int);
 static void tcursor(int);
 static void tdeletechar(int);
@@ -334,6 +337,7 @@ static void tsetchar(char *, Glyph *, int, int);
 static void tsetscroll(int, int);
 static void tswapscreen(void);
 static void tsetdirt(int, int);
+static void tsetdirtattr(int);
 static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 static void techo(char *, int);
@@ -1175,6 +1179,20 @@ ttyresize(void) {
 		fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
 }
 
+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;
@@ -1186,6 +1204,20 @@ tsetdirt(int top, int bot) {
 		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);
@@ -2838,6 +2870,9 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		bg = temp;
 	}
 
+	if(base.mode & ATTR_BLINK && term.mode & MODE_BLINK)
+		fg = bg;
+
 	/* Intelligent cleaning up of the borders. */
 	if(x == 0) {
 		xclear(0, (y == 0)? 0 : winy, borderpx,
@@ -3345,34 +3380,55 @@ void
 run(void) {
 	XEvent ev;
 	fd_set rfd;
-	int xfd = XConnectionNumber(xw.dpy), xev;
-	struct timeval drawtimeout, *tv = NULL, now, last;
+	int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
+	struct timeval drawtimeout, *tv = NULL, now, last, lastblink;
 
+	gettimeofday(&lastblink, NULL);
 	gettimeofday(&last, NULL);
 
 	for(xev = actionfps;;) {
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);
-		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv) < 0) {
+
+		switch(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv) < 0) {
+		case -1:
 			if(errno == EINTR)
 				continue;
 			die("select failed: %s\n", SERRNO);
-		}
+		default:
+			if(FD_ISSET(cmdfd, &rfd)) {
+				ttyread();
+				if(blinktimeout) {
+					blinkset = tattrset(ATTR_BLINK);
+					if(!blinkset && term.mode & ATTR_BLINK)
+						term.mode &= ~(MODE_BLINK);
+				}
+			}
 
+			if(FD_ISSET(xfd, &rfd))
+				xev = actionfps;
+			break;
+		}
 		gettimeofday(&now, NULL);
 		drawtimeout.tv_sec = 0;
 		drawtimeout.tv_usec = (1000/xfps) * 1000;
 		tv = &drawtimeout;
 
-		if(FD_ISSET(cmdfd, &rfd))
-			ttyread();
+		dodraw = 0;
+		if(blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
+			tsetdirtattr(ATTR_BLINK);
+			term.mode ^= MODE_BLINK;
+			gettimeofday(&lastblink, NULL);
+			dodraw = 1;
+		}
+		if(TIMEDIFF(now, last) \
+				> (xev? (1000/xfps) : (1000/actionfps))) {
+			dodraw = 1;
+			last = now;
+		}
 
-		if(FD_ISSET(xfd, &rfd))
-			xev = actionfps;
-
-		if(TIMEDIFF(now, last) > \
-				(xev ? (1000/xfps) : (1000/actionfps))) {
+		if(dodraw) {
 			while(XPending(xw.dpy)) {
 				XNextEvent(xw.dpy, &ev);
 				if(XFilterEvent(&ev, None))
@@ -3383,12 +3439,13 @@ run(void) {
 
 			draw();
 			XFlush(xw.dpy);
-			last = now;
 
 			if(xev && !FD_ISSET(xfd, &rfd))
 				xev--;
-			if(!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd))
+			if(!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd) \
+					&& !blinkset) {
 				tv = NULL;
+			}
 		}
 	}
 }
diff --git a/st.info b/st.info
index 79b881f..ff01c80 100644
--- a/st.info
+++ b/st.info
@@ -5,7 +5,7 @@ st| simpleterm,
 	am,
 	bce,
 	bel=^G,
-#	blink=\E[5m,
+	blink=\E[5m,
 	bold=\E[1m,
 	cbt=\E[Z,
 	cvvis=\E[?25h,

From a77b01176a34de741485024e5e36002cff3c1124 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 26 Apr 2013 18:55:40 +0200
Subject: [PATCH 0530/1146] Be more efficient in blinking.

---
 st.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 8065ebe..07940d2 100644
--- a/st.c
+++ b/st.c
@@ -3442,9 +3442,13 @@ run(void) {
 
 			if(xev && !FD_ISSET(xfd, &rfd))
 				xev--;
-			if(!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd) \
-					&& !blinkset) {
-				tv = NULL;
+			if(!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
+				if(blinkset) {
+					drawtimeout.tv_usec = 1000 * \
+						blinktimeout;
+				} else {
+					tv = NULL;
+				}
 			}
 		}
 	}

From a53017c8b47f511cf0462ac910cf9223a31ceb2f Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 28 Apr 2013 17:42:30 +0200
Subject: [PATCH 0531/1146] Add a possibility to modify the string sent by
 mouse buttons.

Thanks Alexander Rezinsky <alexrez@gmail.com> for the suggestion!
---
 config.def.h | 10 +++++++++-
 st.c         | 26 +++++++++++++++++++++-----
 2 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/config.def.h b/config.def.h
index b44fe17..b0bc752 100644
--- a/config.def.h
+++ b/config.def.h
@@ -74,7 +74,15 @@ static unsigned int defaultcs = 256;
 static unsigned int defaultitalic = 11;
 static unsigned int defaultunderline = 7;
 
-/* Internal shortcuts. */
+/* Internal mouse shortcuts. */
+/* Beware that overloading Button1 will disable the selection. */
+static Mousekey mshortcuts[] = {
+	/* keysym		mask		string */
+	{ Button4,		XK_ANY_MOD,	"\031"},
+	{ Button5,		XK_ANY_MOD,	"\005"},
+};
+
+/* Internal keyboard shortcuts. */
 #define MODKEY Mod1Mask
 
 static Shortcut shortcuts[] = {
diff --git a/st.c b/st.c
index 07940d2..aa2cd08 100644
--- a/st.c
+++ b/st.c
@@ -228,6 +228,12 @@ typedef struct {
 	char state; /* focus, redraw, visible */
 } XWindow;
 
+typedef struct {
+	int b;
+	uint mask;
+	char s[ESC_BUF_SIZ];
+} Mousekey;
+
 typedef struct {
 	KeySym k;
 	uint mask;
@@ -771,10 +777,24 @@ mousereport(XEvent *e) {
 void
 bpress(XEvent *e) {
 	struct timeval now;
+	Mousekey *mk;
 
 	if(IS_SET(MODE_MOUSE)) {
 		mousereport(e);
-	} else if(e->xbutton.button == Button1) {
+		return;
+	}
+
+	for(mk = mshortcuts; mk < mshortcuts + LEN(mshortcuts); mk++) {
+		if(e->xbutton.button == mk->b
+				&& match(mk->mask, e->xbutton.state)) {
+			ttywrite(mk->s, strlen(mk->s));
+			if(IS_SET(MODE_ECHO))
+				techo(mk->s, strlen(mk->s));
+			return;
+		}
+	}
+
+	if(e->xbutton.button == Button1) {
 		gettimeofday(&now, NULL);
 
 		/* Clear previous selection, logically and visually. */
@@ -817,10 +837,6 @@ bpress(XEvent *e) {
 		}
 		sel.tclick2 = sel.tclick1;
 		sel.tclick1 = now;
-	} else if(e->xbutton.button == Button4) {
-		ttywrite("\031", 1);
-	} else if(e->xbutton.button == Button5) {
-		ttywrite("\005", 1);
 	}
 }
 

From 911ba5674bc4eb53a2ed548856a50032c39ca7f2 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 28 Apr 2013 18:14:15 +0200
Subject: [PATCH 0532/1146] Selection snapping is now considering wrapping.

Thanks Alexander Rezinsky <alexrez@gmail.com> for mentioning this!
---
 st.c | 42 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 39 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index aa2cd08..5095315 100644
--- a/st.c
+++ b/st.c
@@ -681,13 +681,49 @@ void
 selsnap(int mode, int *x, int *y, int direction) {
 	switch(mode) {
 	case SNAP_WORD:
-		while(*x > 0 && *x < term.col-1
-				&& term.line[*y][*x + direction].c[0] != ' ') {
+		for(;;) {
+			if(direction < 0 && *x <= 0) {
+				if(*y > 0 && term.line[*y - 1][term.col-1].mode
+						& ATTR_WRAP) {
+					*y -= 1;
+					*x = term.col-1;
+				} else {
+					break;
+				}
+			}
+			if(direction > 0 && *x >= term.col-1) {
+				if(*y < term.row-1 && term.line[*y][*x].mode
+						& ATTR_WRAP) {
+					*y += 1;
+					*x = 0;
+				} else {
+					break;
+				}
+			}
+
+			if(term.line[*y][*x + direction].c[0] == ' ')
+				break;
+
 			*x += direction;
 		}
 		break;
 	case SNAP_LINE:
 		*x = (direction < 0) ? 0 : term.col - 1;
+		if(direction < 0 && *y > 0) {
+			for(; *y > 0; *y += direction) {
+				if(!(term.line[*y-1][term.col-1].mode
+						& ATTR_WRAP)) {
+					break;
+				}
+			}
+		} else if(direction > 0 && *y < term.row-1) {
+			for(; *y < term.row; *y += direction) {
+				if(!(term.line[*y][term.col-1].mode
+						& ATTR_WRAP)) {
+					break;
+				}
+			}
+		}
 		break;
 	default:
 		break;
@@ -820,7 +856,7 @@ bpress(XEvent *e) {
 			sel.snap = 0;
 		}
 		selsnap(sel.snap, &sel.bx, &sel.by, -1);
-		selsnap(sel.snap, &sel.ex, &sel.ey, 1);
+		selsnap(sel.snap, &sel.ex, &sel.ey, +1);
 		sel.b.x = sel.bx;
 		sel.b.y = sel.by;
 		sel.e.x = sel.ex;

From e1458ef467f1164fa3ca51e64e3c768c8c69b346 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 28 Apr 2013 21:32:42 +0200
Subject: [PATCH 0533/1146] Explaining blinking for the dummies.

---
 config.def.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index b0bc752..d9a0568 100644
--- a/config.def.h
+++ b/config.def.h
@@ -20,7 +20,10 @@ static bool allowaltscreen = true;
 static unsigned int xfps = 60;
 static unsigned int actionfps = 30;
 
-/* blinking timeout (set to 0 to disable blinking) */
+/*
+ * blinking timeout (set to 0 to disable blinking) for the terminal blinking
+ * attribute.
+ */
 static unsigned int blinktimeout = 800;
 
 /* TERM value */

From 8618386de947a1e2d0b449d6f60fde478e931ecb Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 1 May 2013 13:14:46 +0200
Subject: [PATCH 0534/1146] More stable blinking.

---
 st.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 5095315..533fb0a 100644
--- a/st.c
+++ b/st.c
@@ -3496,8 +3496,15 @@ run(void) {
 				xev--;
 			if(!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
 				if(blinkset) {
-					drawtimeout.tv_usec = 1000 * \
-						blinktimeout;
+					if(TIMEDIFF(now, lastblink) \
+							> blinktimeout) {
+						drawtimeout.tv_usec = 1;
+					} else {
+						drawtimeout.tv_usec = (1000 * \
+							(blinktimeout - \
+							TIMEDIFF(now,
+								lastblink)));
+					}
 				} else {
 					tv = NULL;
 				}

From 5938fa9d32379815757a83076069584f29a8d276 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 4 May 2013 08:01:17 +0200
Subject: [PATCH 0535/1146] Better comments for the snapping code.

---
 st.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/st.c b/st.c
index 533fb0a..d73aaa1 100644
--- a/st.c
+++ b/st.c
@@ -681,6 +681,10 @@ void
 selsnap(int mode, int *x, int *y, int direction) {
 	switch(mode) {
 	case SNAP_WORD:
+		/*
+		 * Snap around if the word wraps around at the end or
+		 * beginning of a line.
+		 */
 		for(;;) {
 			if(direction < 0 && *x <= 0) {
 				if(*y > 0 && term.line[*y - 1][term.col-1].mode
@@ -708,6 +712,11 @@ selsnap(int mode, int *x, int *y, int direction) {
 		}
 		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 && *y > 0) {
 			for(; *y > 0; *y += direction) {

From 634c247fa76a5f649cdcc51109970e46ddaf5c32 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 4 May 2013 08:05:11 +0200
Subject: [PATCH 0536/1146] Select to the end of row if end of line is reached.

Thanks Alexander Rezinsky <alexrez@gmail.com>!
---
 st.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/st.c b/st.c
index d73aaa1..e2e6c57 100644
--- a/st.c
+++ b/st.c
@@ -679,6 +679,8 @@ selected(int x, int y) {
 
 void
 selsnap(int mode, int *x, int *y, int direction) {
+	int i;
+
 	switch(mode) {
 	case SNAP_WORD:
 		/*
@@ -735,6 +737,16 @@ selsnap(int mode, int *x, int *y, int direction) {
 		}
 		break;
 	default:
+		/*
+		 * Select the whole line when the end of line is reached.
+		 */
+		if(direction > 0) {
+			i = term.col;
+			while(--i > 0 && term.line[*y][i].c[0] == ' ')
+				/* nothing */;
+			if(i > 0 && i < *x)
+				*x = term.col - 1;
+		}
 		break;
 	}
 }

From 0c2b513d01697aea20bb4a2a144b55e72c625e86 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 4 May 2013 19:00:32 +0200
Subject: [PATCH 0537/1146] Expand the last line with '\n' in case of
 overselection.

Thanks Alexander Rezinsky <alexrez@gmail.com>!
---
 st.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index e2e6c57..0f47d6d 100644
--- a/st.c
+++ b/st.c
@@ -900,7 +900,7 @@ bpress(XEvent *e) {
 void
 selcopy(void) {
 	char *str, *ptr;
-	int x, y, bufsize, size;
+	int x, y, bufsize, size, i, ex;
 	Glyph *gp, *last;
 
 	if(sel.bx == -1) {
@@ -938,6 +938,21 @@ selcopy(void) {
 			 */
 			if(y < sel.e.y && !((gp-1)->mode & ATTR_WRAP))
 				*ptr++ = '\n';
+
+			/*
+			 * If the last selected line expands in the selection
+			 * after the visible text '\n' is appended.
+			 */
+			if(y == sel.e.y) {
+				i = term.col;
+				while(--i > 0 && term.line[y][i].c[0] == ' ')
+					/* nothing */;
+				ex = sel.e.x;
+				if(sel.b.y == sel.e.y && sel.e.x < sel.b.x)
+					ex = sel.b.x;
+				if(i < ex)
+					*ptr++ = '\n';
+			}
 		}
 		*ptr = 0;
 	}

From 8e968739c3cfc4e9f7088a9ea360bc4f37e9ad9f Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 4 May 2013 19:04:20 +0200
Subject: [PATCH 0538/1146] Allow more complex delimiters for word selections.

Thanks Alexander Rezinsky <alexrez@gmail.com>!
---
 config.def.h | 9 ++++++++-
 st.c         | 4 +++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/config.def.h b/config.def.h
index d9a0568..2d854a0 100644
--- a/config.def.h
+++ b/config.def.h
@@ -9,7 +9,14 @@ static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=fals
 static int borderpx = 2;
 static char shell[] = "/bin/sh";
 
-/* timeouts (in milliseconds) */
+/*
+ * word delimiter string
+ *
+ * More advanced example: " `'\"()[]{}"
+ */
+static char worddelimiters[] = " ";
+
+/* selection timeouts (in milliseconds) */
 static unsigned int doubleclicktimeout = 300;
 static unsigned int tripleclicktimeout = 600;
 
diff --git a/st.c b/st.c
index 0f47d6d..5251e70 100644
--- a/st.c
+++ b/st.c
@@ -707,8 +707,10 @@ selsnap(int mode, int *x, int *y, int direction) {
 				}
 			}
 
-			if(term.line[*y][*x + direction].c[0] == ' ')
+			if(strchr(worddelimiters,
+					term.line[*y][*x + direction].c[0])) {
 				break;
+			}
 
 			*x += direction;
 		}

From 678eff6e1882a888deda5e4e429df42c39b604fe Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 6 May 2013 19:50:14 +0200
Subject: [PATCH 0539/1146] Removing an old select() regression.

---
 st.c | 28 +++++++++++++---------------
 1 file changed, 13 insertions(+), 15 deletions(-)

diff --git a/st.c b/st.c
index 5251e70..50090a4 100644
--- a/st.c
+++ b/st.c
@@ -3481,25 +3481,23 @@ run(void) {
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);
 
-		switch(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv) < 0) {
-		case -1:
+		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv) < 0) {
 			if(errno == EINTR)
 				continue;
 			die("select failed: %s\n", SERRNO);
-		default:
-			if(FD_ISSET(cmdfd, &rfd)) {
-				ttyread();
-				if(blinktimeout) {
-					blinkset = tattrset(ATTR_BLINK);
-					if(!blinkset && term.mode & ATTR_BLINK)
-						term.mode &= ~(MODE_BLINK);
-				}
-			}
-
-			if(FD_ISSET(xfd, &rfd))
-				xev = actionfps;
-			break;
 		}
+		if(FD_ISSET(cmdfd, &rfd)) {
+			ttyread();
+			if(blinktimeout) {
+				blinkset = tattrset(ATTR_BLINK);
+				if(!blinkset && term.mode & ATTR_BLINK)
+					term.mode &= ~(MODE_BLINK);
+			}
+		}
+
+		if(FD_ISSET(xfd, &rfd))
+			xev = actionfps;
+
 		gettimeofday(&now, NULL);
 		drawtimeout.tv_sec = 0;
 		drawtimeout.tv_usec = (1000/xfps) * 1000;

From 62502a88e94dd908fdd4418899afdd09a4de3bea Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 11 May 2013 08:54:26 +0200
Subject: [PATCH 0540/1146] Lazy fontset loading.

Thanks Johannes Hofmann <Johannes.Hofmann@gmx.de>!
---
 st.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index 50090a4..56955a3 100644
--- a/st.c
+++ b/st.c
@@ -363,6 +363,7 @@ static void xloadcols(void);
 static int xsetcolorname(int, const char *);
 static int xloadfont(Font *, FcPattern *);
 static void xloadfonts(char *, int);
+static int xloadfontset(Font *);
 static void xsettitle(char *);
 static void xresettitle(void);
 static void xseturgency(int);
@@ -2643,16 +2644,12 @@ xloadfont(Font *f, FcPattern *pattern) {
 	if(!match)
 		return 1;
 
-	if(!(f->set = FcFontSort(0, match, FcTrue, 0, &result))) {
-		FcPatternDestroy(match);
-		return 1;
-	}
-
 	if(!(f->match = XftFontOpenPattern(xw.dpy, match))) {
 		FcPatternDestroy(match);
 		return 1;
 	}
 
+	f->set = NULL;
 	f->pattern = FcPatternDuplicate(pattern);
 
 	f->ascent = f->match->ascent;
@@ -2727,6 +2724,15 @@ xloadfonts(char *fontstr, int fontsize) {
 	FcPatternDestroy(pattern);
 }
 
+int
+xloadfontset(Font *f) {
+	FcResult result;
+
+	if(!(f->set = FcFontSort(0, f->pattern, FcTrue, 0, &result)))
+		return 1;
+	return 0;
+}
+
 void
 xunloadfonts(void) {
 	int i, ip;
@@ -2987,7 +2993,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	r.width = width;
 	XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
 
-	fcsets[0] = font->set;
 	for(xp = winx; bytelen > 0;) {
 		/*
 		 * Search for the range in the to be printed string of glyphs
@@ -3045,6 +3050,10 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 		/* Nothing was found. */
 		if(i >= frclen) {
+			if(!font->set)
+				xloadfontset(font);
+			fcsets[0] = font->set;
+
 			/*
 			 * Nothing was found in the cache. Now use
 			 * some dozen of Fontconfig calls to get the

From 8f47c4a4dea7272d72833d2ae26eacc3896d8f5c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 11 May 2013 21:59:55 +0200
Subject: [PATCH 0541/1146] Lazy font unloading too.

---
 st.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/st.c b/st.c
index 56955a3..8475878 100644
--- a/st.c
+++ b/st.c
@@ -369,6 +369,7 @@ static void xresettitle(void);
 static void xseturgency(int);
 static void xsetsel(char*);
 static void xtermclear(int, int, int, int);
+static void xunloadfont(Font *f);
 static void xunloadfonts(void);
 static void xresize(int, int);
 
@@ -2733,6 +2734,14 @@ xloadfontset(Font *f) {
 	return 0;
 }
 
+void
+xunloadfont(Font *f) {
+	XftFontClose(xw.dpy, f->match);
+	FcPatternDestroy(f->pattern);
+	if(f->set)
+		FcFontSetDestroy(f->set);
+}
+
 void
 xunloadfonts(void) {
 	int i, ip;
@@ -2749,18 +2758,10 @@ xunloadfonts(void) {
 	frccur = -1;
 	frclen = 0;
 
-	XftFontClose(xw.dpy, dc.font.match);
-	FcPatternDestroy(dc.font.pattern);
-	FcFontSetDestroy(dc.font.set);
-	XftFontClose(xw.dpy, dc.bfont.match);
-	FcPatternDestroy(dc.bfont.pattern);
-	FcFontSetDestroy(dc.bfont.set);
-	XftFontClose(xw.dpy, dc.ifont.match);
-	FcPatternDestroy(dc.ifont.pattern);
-	FcFontSetDestroy(dc.ifont.set);
-	XftFontClose(xw.dpy, dc.ibfont.match);
-	FcPatternDestroy(dc.ibfont.pattern);
-	FcFontSetDestroy(dc.ibfont.set);
+	xunloadfont(&dc.font);
+	xunloadfont(&dc.bfont);
+	xunloadfont(&dc.ifont);
+	xunloadfont(&dc.ibfont);
 }
 
 void

From 8f1bef05025c0052603f7ca30552a43395b4c13f Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 26 May 2013 13:07:26 +0200
Subject: [PATCH 0542/1146] Fixing the selection scrolling and the selection
 naming.

Thanks p37sitdu@lavabit.com!
---
 st.c | 174 ++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 89 insertions(+), 85 deletions(-)

diff --git a/st.c b/st.c
index 8475878..826f745 100644
--- a/st.c
+++ b/st.c
@@ -249,11 +249,17 @@ typedef struct {
 	int mode;
 	int type;
 	int snap;
-	int bx, by;
-	int ex, ey;
+	/*
+	 * 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;
-	} b, e;
+	} nb, ne, ob, oe;
+
 	char *clip;
 	Atom xtarget;
 	bool alt;
@@ -390,6 +396,7 @@ static void selclear(XEvent *);
 static void selrequest(XEvent *);
 
 static void selinit(void);
+static void selsort(void);
 static inline bool selected(int, int);
 static void selcopy(void);
 static void selscroll(int, int);
@@ -630,12 +637,12 @@ utf8size(char *s) {
 	}
 }
 
-void
+static void
 selinit(void) {
 	memset(&sel.tclick1, 0, sizeof(sel.tclick1));
 	memset(&sel.tclick2, 0, sizeof(sel.tclick2));
 	sel.mode = 0;
-	sel.bx = -1;
+	sel.ob.x = -1;
 	sel.clip = NULL;
 	sel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
 	if(sel.xtarget == None)
@@ -658,25 +665,28 @@ y2row(int y) {
 	return LIMIT(y, 0, term.row-1);
 }
 
+static void
+selsort(void) {
+	sel.nb.x = sel.ob.y < sel.oe.y ? sel.ob.x : sel.oe.x;
+	sel.nb.y = MIN(sel.ob.y, sel.oe.y);
+	sel.ne.x = sel.ob.y < sel.oe.y ? sel.oe.x : sel.ob.x;
+	sel.ne.y = MAX(sel.ob.y, sel.oe.y);
+}
+
 static inline bool
 selected(int x, int y) {
-	int bx, ex;
-
-	if(sel.ey == y && sel.by == y) {
-		bx = MIN(sel.bx, sel.ex);
-		ex = MAX(sel.bx, sel.ex);
-
-		return BETWEEN(x, bx, ex);
-	}
+	if(sel.ne.y == y && sel.nb.y == y)
+		return BETWEEN(x, sel.nb.x, sel.ne.y);
 
 	if(sel.type == SEL_RECTANGULAR) {
-		return ((sel.b.y <= y && y <= sel.e.y)
-			&& (sel.b.x <= x && x <= sel.e.x));
+		return ((sel.nb.y <= y && y <= sel.ne.y)
+			&& (sel.nb.x <= x && x <= sel.ne.x));
 	}
-	return ((sel.b.y < y && y < sel.e.y)
-		|| (y == sel.e.y && x <= sel.e.x))
-		|| (y == sel.b.y && x >= sel.b.x
-			&& (x <= sel.e.x || sel.b.y != sel.e.y));
+
+	return ((sel.nb.y < y && y < sel.ne.y)
+		|| (y == sel.ne.y && x <= sel.ne.x))
+		|| (y == sel.nb.y && x >= sel.nb.x
+			&& (x <= sel.ne.x || sel.nb.y != sel.ne.y));
 }
 
 void
@@ -762,22 +772,19 @@ getbuttoninfo(XEvent *e) {
 
 	sel.alt = IS_SET(MODE_ALTSCREEN);
 
-	sel.ex = x2col(e->xbutton.x);
-	sel.ey = y2row(e->xbutton.y);
+	sel.oe.x = x2col(e->xbutton.x);
+	sel.oe.y = y2row(e->xbutton.y);
 
-	if (sel.by < sel.ey
-			|| (sel.by == sel.ey && sel.bx < sel.ex)) {
-		selsnap(sel.snap, &sel.bx, &sel.by, -1);
-		selsnap(sel.snap, &sel.ex, &sel.ey, +1);
+	if (sel.ob.y < sel.oe.y
+			|| (sel.ob.y == sel.oe.y && sel.ob.x < sel.oe.x)) {
+		selsnap(sel.snap, &sel.ob.x, &sel.ob.y, -1);
+		selsnap(sel.snap, &sel.oe.x, &sel.oe.y, +1);
 	} else {
-		selsnap(sel.snap, &sel.ex, &sel.ey, -1);
-		selsnap(sel.snap, &sel.bx, &sel.by, +1);
+		selsnap(sel.snap, &sel.oe.x, &sel.oe.y, -1);
+		selsnap(sel.snap, &sel.ob.x, &sel.ob.y, +1);
 	}
 
-	sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex;
-	sel.b.y = MIN(sel.by, sel.ey);
-	sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx;
-	sel.e.y = MAX(sel.by, sel.ey);
+	selsort();
 
 	sel.type = SEL_REGULAR;
 	for(type = 1; type < LEN(selmasks); ++type) {
@@ -801,7 +808,8 @@ mousereport(XEvent *e) {
 		if(!IS_SET(MODE_MOUSEMOTION) || (x == ox && y == oy))
 			return;
 		button = ob + 32;
-		ox = x, oy = y;
+		ox = x;
+		oy = y;
 	} else if(!IS_SET(MODE_MOUSESGR)
 			&& (e->xbutton.type == ButtonRelease
 				|| button == AnyButton)) {
@@ -812,7 +820,8 @@ mousereport(XEvent *e) {
 			button += 64 - 3;
 		if(e->xbutton.type == ButtonPress) {
 			ob = button;
-			ox = x, oy = y;
+			ox = x;
+			oy = y;
 		}
 	}
 
@@ -859,15 +868,15 @@ bpress(XEvent *e) {
 		gettimeofday(&now, NULL);
 
 		/* Clear previous selection, logically and visually. */
-		if(sel.bx != -1) {
-			sel.bx = -1;
-			tsetdirt(sel.b.y, sel.e.y);
+		if(sel.ob.x != -1) {
+			sel.ob.x = -1;
+			tsetdirt(sel.nb.y, sel.ne.y);
 			draw();
 		}
 		sel.mode = 1;
 		sel.type = SEL_REGULAR;
-		sel.ex = sel.bx = x2col(e->xbutton.x);
-		sel.ey = sel.by = y2row(e->xbutton.y);
+		sel.oe.x = sel.ob.x = x2col(e->xbutton.x);
+		sel.oe.y = sel.ob.y = y2row(e->xbutton.y);
 
 		/*
 		 * If the user clicks below predefined timeouts specific
@@ -880,12 +889,9 @@ bpress(XEvent *e) {
 		} else {
 			sel.snap = 0;
 		}
-		selsnap(sel.snap, &sel.bx, &sel.by, -1);
-		selsnap(sel.snap, &sel.ex, &sel.ey, +1);
-		sel.b.x = sel.bx;
-		sel.b.y = sel.by;
-		sel.e.x = sel.ex;
-		sel.e.y = sel.ey;
+		selsnap(sel.snap, &sel.ob.x, &sel.ob.y, -1);
+		selsnap(sel.snap, &sel.oe.x, &sel.oe.y, +1);
+		selsort();
 
 		/*
 		 * Draw selection, unless it's regular and we don't want to
@@ -893,7 +899,7 @@ bpress(XEvent *e) {
 		 */
 		if(sel.snap != 0) {
 			sel.mode++;
-			tsetdirt(sel.b.y, sel.e.y);
+			tsetdirt(sel.nb.y, sel.ne.y);
 			draw();
 		}
 		sel.tclick2 = sel.tclick1;
@@ -907,14 +913,14 @@ selcopy(void) {
 	int x, y, bufsize, size, i, ex;
 	Glyph *gp, *last;
 
-	if(sel.bx == -1) {
+	if(sel.ob.x == -1) {
 		str = NULL;
 	} else {
-		bufsize = (term.col+1) * (sel.e.y-sel.b.y+1) * UTF_SIZ;
+		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.b.y; y < sel.e.y + 1; y++) {
+		for(y = sel.nb.y; y < sel.ne.y + 1; y++) {
 			gp = &term.line[y][0];
 			last = gp + term.col;
 
@@ -940,20 +946,20 @@ selcopy(void) {
 			 * st.
 			 * FIXME: Fix the computer world.
 			 */
-			if(y < sel.e.y && !((gp-1)->mode & ATTR_WRAP))
+			if(y < sel.ne.y && !((gp-1)->mode & ATTR_WRAP))
 				*ptr++ = '\n';
 
 			/*
 			 * If the last selected line expands in the selection
 			 * after the visible text '\n' is appended.
 			 */
-			if(y == sel.e.y) {
+			if(y == sel.ne.y) {
 				i = term.col;
 				while(--i > 0 && term.line[y][i].c[0] == ' ')
 					/* nothing */;
-				ex = sel.e.x;
-				if(sel.b.y == sel.e.y && sel.e.x < sel.b.x)
-					ex = sel.b.x;
+				ex = sel.ne.x;
+				if(sel.nb.y == sel.ne.y && sel.ne.x < sel.nb.x)
+					ex = sel.nb.x;
 				if(i < ex)
 					*ptr++ = '\n';
 			}
@@ -1016,10 +1022,10 @@ clippaste(const Arg *dummy) {
 
 void
 selclear(XEvent *e) {
-	if(sel.bx == -1)
+	if(sel.ob.x == -1)
 		return;
-	sel.bx = -1;
-	tsetdirt(sel.b.y, sel.e.y);
+	sel.ob.x = -1;
+	tsetdirt(sel.nb.y, sel.ne.y);
 }
 
 void
@@ -1082,13 +1088,13 @@ brelease(XEvent *e) {
 		selpaste(NULL);
 	} else if(e->xbutton.button == Button1) {
 		if(sel.mode < 2) {
-			sel.bx = -1;
+			sel.ob.x = -1;
 		} else {
 			getbuttoninfo(e);
 			selcopy();
 		}
 		sel.mode = 0;
-		term.dirty[sel.ey] = 1;
+		term.dirty[sel.oe.y] = 1;
 	}
 }
 
@@ -1105,15 +1111,14 @@ bmotion(XEvent *e) {
 		return;
 
 	sel.mode++;
-	oldey = sel.ey;
-	oldex = sel.ex;
-	oldsby = sel.b.y;
-	oldsey = sel.e.y;
+	oldey = sel.oe.y;
+	oldex = sel.oe.x;
+	oldsby = sel.nb.y;
+	oldsey = sel.ne.y;
 	getbuttoninfo(e);
 
-	if(oldey != sel.ey || oldex != sel.ex) {
-		tsetdirt(MIN(sel.b.y, oldsby), MAX(sel.e.y, oldsey));
-	}
+	if(oldey != sel.oe.y || oldex != sel.oe.x)
+		tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
 }
 
 void
@@ -1411,31 +1416,30 @@ tscrollup(int orig, int n) {
 
 void
 selscroll(int orig, int n) {
-	if(sel.bx == -1)
+	if(sel.ob.x == -1)
 		return;
 
-	if(BETWEEN(sel.by, orig, term.bot) || BETWEEN(sel.ey, orig, term.bot)) {
-		if((sel.by += n) > term.bot || (sel.ey += n) < term.top) {
-			sel.bx = -1;
+	if(BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig, term.bot)) {
+		if((sel.ob.y += n) > term.bot || (sel.oe.y += n) < term.top) {
+			sel.ob.x = -1;
 			return;
 		}
 		if(sel.type == SEL_RECTANGULAR) {
-			if(sel.by < term.top)
-				sel.by = term.top;
-			if(sel.ey > term.bot)
-				sel.ey = term.bot;
+			if(sel.ob.y < term.top)
+				sel.ob.y = term.top;
+			if(sel.oe.y > term.bot)
+				sel.oe.y = term.bot;
 		} else {
-			if(sel.by < term.top) {
-				sel.by = term.top;
-				sel.bx = 0;
+			if(sel.ob.y < term.top) {
+				sel.ob.y = term.top;
+				sel.ob.x = 0;
 			}
-			if(sel.ey > term.bot) {
-				sel.ey = term.bot;
-				sel.ex = term.col;
+			if(sel.oe.y > term.bot) {
+				sel.oe.y = term.bot;
+				sel.oe.x = term.col;
 			}
 		}
-		sel.b.y = sel.by, sel.b.x = sel.bx;
-		sel.e.y = sel.ey, sel.e.x = sel.ex;
+		selsort();
 	}
 }
 
@@ -1905,7 +1909,7 @@ csihandle(void) {
 			tputtab(1);
 		break;
 	case 'J': /* ED -- Clear screen */
-		sel.bx = -1;
+		sel.ob.x = -1;
 		switch(csiescseq.arg[0]) {
 		case 0: /* below */
 			tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
@@ -2401,8 +2405,8 @@ tputc(char *c, int len) {
 	 */
 	if(control && !(term.c.attr.mode & ATTR_GFX))
 		return;
-	if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey))
-		sel.bx = -1;
+	if(sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
+		sel.ob.x = -1;
 	if(IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
 		term.line[term.c.y][term.c.x].mode |= ATTR_WRAP;
 		tnewline(1);
@@ -3212,7 +3216,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 	int ic, ib, x, y, ox, sl;
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
-	bool ena_sel = sel.bx != -1;
+	bool ena_sel = sel.ob.x != -1;
 
 	if(sel.alt ^ IS_SET(MODE_ALTSCREEN))
 		ena_sel = 0;

From b5144100a59956b5bf69614a077bd4d252d7dc6c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 26 May 2013 16:10:22 +0200
Subject: [PATCH 0543/1146] Fixing the selection in a single line again.

Thanks p37sitdu@lavabit.com!
---
 st.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 826f745..2eb007b 100644
--- a/st.c
+++ b/st.c
@@ -667,16 +667,21 @@ y2row(int y) {
 
 static void
 selsort(void) {
-	sel.nb.x = sel.ob.y < sel.oe.y ? sel.ob.x : sel.oe.x;
+	if(sel.ob.y == sel.oe.y) {
+		sel.nb.x = MIN(sel.ob.x, sel.oe.x);
+		sel.ne.x = MAX(sel.ob.x, sel.oe.x);
+	} else {
+		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;
+	}
 	sel.nb.y = MIN(sel.ob.y, sel.oe.y);
-	sel.ne.x = sel.ob.y < sel.oe.y ? sel.oe.x : sel.ob.x;
 	sel.ne.y = MAX(sel.ob.y, sel.oe.y);
 }
 
 static inline bool
 selected(int x, int y) {
 	if(sel.ne.y == y && sel.nb.y == y)
-		return BETWEEN(x, sel.nb.x, sel.ne.y);
+		return BETWEEN(x, sel.nb.x, sel.ne.x);
 
 	if(sel.type == SEL_RECTANGULAR) {
 		return ((sel.nb.y <= y && y <= sel.ne.y)

From 8315dc417982936186837edfac24420d0d0e516e Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 1 Jun 2013 12:23:55 +0200
Subject: [PATCH 0544/1146] Fixing bad highlighting on first SNAP_WORD
 multiline select.

---
 st.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 2eb007b..3fcf543 100644
--- a/st.c
+++ b/st.c
@@ -780,7 +780,7 @@ getbuttoninfo(XEvent *e) {
 	sel.oe.x = x2col(e->xbutton.x);
 	sel.oe.y = y2row(e->xbutton.y);
 
-	if (sel.ob.y < sel.oe.y
+	if(sel.ob.y < sel.oe.y
 			|| (sel.ob.y == sel.oe.y && sel.ob.x < sel.oe.x)) {
 		selsnap(sel.snap, &sel.ob.x, &sel.ob.y, -1);
 		selsnap(sel.snap, &sel.oe.x, &sel.oe.y, +1);
@@ -788,7 +788,6 @@ getbuttoninfo(XEvent *e) {
 		selsnap(sel.snap, &sel.oe.x, &sel.oe.y, -1);
 		selsnap(sel.snap, &sel.ob.x, &sel.ob.y, +1);
 	}
-
 	selsort();
 
 	sel.type = SEL_REGULAR;
@@ -1099,7 +1098,7 @@ brelease(XEvent *e) {
 			selcopy();
 		}
 		sel.mode = 0;
-		term.dirty[sel.oe.y] = 1;
+		tsetdirt(sel.nb.y, sel.ne.y);
 	}
 }
 

From 405fd89ac1d333be79325417c973a07ccad67453 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 1 Jun 2013 13:06:53 +0200
Subject: [PATCH 0545/1146] Implementing mouse focus and all events.

---
 st.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/st.c b/st.c
index 3fcf543..321b58d 100644
--- a/st.c
+++ b/st.c
@@ -118,6 +118,7 @@ enum term_mode {
 	MODE_8BIT	 = 8192,
 	MODE_BLINK	 = 16384,
 	MODE_FBLINK	 = 32768,
+	MODE_FOCUS	 = 65536,
 };
 
 enum escape_state {
@@ -1782,6 +1783,13 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				MODBIT(term.mode, set, MODE_MOUSEMOTION);
 				MODBIT(term.mode, 0, MODE_MOUSEBTN);
 				break;
+			case 1003: /* 1003: enable all mouse reports */
+				MODBIT(term.mode, set, MODE_MOUSEMOTION);
+				MODBIT(term.mode, set, MODE_MOUSEBTN);
+				break;
+			case 1004:
+				MODBIT(term.mode, set, MODE_FOCUS);
+				break;
 			case 1006:
 				MODBIT(term.mode, set, MODE_MOUSESGR);
 				break;
@@ -1807,6 +1815,9 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 1048:
 				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
 				break;
+			case 9: /* X10 compatibility mode */
+			case 1001: /* mouse highlight mode; can hang the
+				      terminal when implemented. */
 			default:
 				fprintf(stderr,
 					"erresc: unknown private set/reset mode %d\n",
@@ -3309,9 +3320,13 @@ focus(XEvent *ev) {
 		XSetICFocus(xw.xic);
 		xw.state |= WIN_FOCUSED;
 		xseturgency(0);
+		if(IS_SET(MODE_FOCUS))
+			ttywrite("\033[I", 3);
 	} else {
 		XUnsetICFocus(xw.xic);
 		xw.state &= ~WIN_FOCUSED;
+		if(IS_SET(MODE_FOCUS))
+			ttywrite("\033[O", 3);
 	}
 }
 

From 317b7859210c187f898ddbc8ec0cc50885f340bc Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 1 Jun 2013 13:13:01 +0200
Subject: [PATCH 0546/1146] Add some comments about the other mouse reporting
 modes.

---
 st.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 321b58d..a032474 100644
--- a/st.c
+++ b/st.c
@@ -1815,9 +1815,16 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 1048:
 				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
 				break;
+			/* Not implemented mouse modes. See comments there. */
 			case 9: /* X10 compatibility mode */
 			case 1001: /* mouse highlight mode; can hang the
-				      terminal when implemented. */
+				      terminal by design when implemented. */
+			case 1005: /* UTF-8 mouse mode; will confuse
+				      applications not supporting UTF-8
+				      and luit. */
+			case 1015: /* urxvt mangled mouse mode; incompatible
+				      and can be mistaken for other control
+				      codes. */
 			default:
 				fprintf(stderr,
 					"erresc: unknown private set/reset mode %d\n",

From d743b93fdaee4900052a94b37c24073008888002 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 1 Jun 2013 13:17:20 +0200
Subject: [PATCH 0547/1146] This is a shorter bit handling in MODE_MOUSE.

---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index a032474..bcb36a2 100644
--- a/st.c
+++ b/st.c
@@ -1784,8 +1784,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				MODBIT(term.mode, 0, MODE_MOUSEBTN);
 				break;
 			case 1003: /* 1003: enable all mouse reports */
-				MODBIT(term.mode, set, MODE_MOUSEMOTION);
-				MODBIT(term.mode, set, MODE_MOUSEBTN);
+				MODBIT(term.mode, set, MODE_MOUSE);
 				break;
 			case 1004:
 				MODBIT(term.mode, set, MODE_FOCUS);

From 7530694987596642b0b83db1c4a61f2794c20397 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 1 Jun 2013 14:37:30 +0200
Subject: [PATCH 0548/1146] Adding true mouse motion support.

---
 st.c | 87 ++++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 55 insertions(+), 32 deletions(-)

diff --git a/st.c b/st.c
index bcb36a2..9a7891e 100644
--- a/st.c
+++ b/st.c
@@ -108,7 +108,6 @@ enum term_mode {
 	MODE_CRLF	 = 16,
 	MODE_MOUSEBTN    = 32,
 	MODE_MOUSEMOTION = 64,
-	MODE_MOUSE       = 32|64,
 	MODE_REVERSE     = 128,
 	MODE_KBDLOCK     = 256,
 	MODE_HIDE	 = 512,
@@ -119,6 +118,10 @@ enum term_mode {
 	MODE_BLINK	 = 16384,
 	MODE_FBLINK	 = 32768,
 	MODE_FOCUS	 = 65536,
+	MODE_MOUSEX10	 = 131072,
+	MODE_MOUSEMANY   = 262144,
+	MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
+			   |MODE_MOUSEMANY,
 };
 
 enum escape_state {
@@ -219,6 +222,7 @@ typedef struct {
 	XIC xic;
 	Draw draw;
 	Visual *vis;
+	XSetWindowAttributes attrs;
 	int scr;
 	bool isfixed; /* is fixed geometry? */
 	int fx, fy, fw, fh; /* fixed geometry */
@@ -245,7 +249,6 @@ typedef struct {
 	signed char crlf;		/* crlf mode          */
 } Key;
 
-/* TODO: use better name for vars... */
 typedef struct {
 	int mode;
 	int type;
@@ -373,6 +376,7 @@ static void xloadfonts(char *, int);
 static int xloadfontset(Font *);
 static void xsettitle(char *);
 static void xresettitle(void);
+static void xsetpointermotion(int);
 static void xseturgency(int);
 static void xsetsel(char*);
 static void xtermclear(int, int, int, int);
@@ -446,6 +450,7 @@ static char *opt_title = NULL;
 static char *opt_embed = NULL;
 static char *opt_class = NULL;
 static char *opt_font = NULL;
+static int oldbutton = 3; /* button event on startup: 3 = release */
 
 static char *usedfont = NULL;
 static int usedfontsize = 0;
@@ -806,13 +811,19 @@ mousereport(XEvent *e) {
 	    button = e->xbutton.button, state = e->xbutton.state,
 	    len;
 	char buf[40];
-	static int ob, ox, oy;
+	static int ox, oy;
 
 	/* from urxvt */
 	if(e->xbutton.type == MotionNotify) {
-		if(!IS_SET(MODE_MOUSEMOTION) || (x == ox && y == oy))
+		if(x == ox && y == oy)
 			return;
-		button = ob + 32;
+		if(!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
+			return;
+		/* MOUSE_MOTION: no reporting if no button is pressed */
+		if(IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
+			return;
+
+		button = oldbutton + 32;
 		ox = x;
 		oy = y;
 	} else if(!IS_SET(MODE_MOUSESGR)
@@ -824,15 +835,17 @@ mousereport(XEvent *e) {
 		if(button >= 3)
 			button += 64 - 3;
 		if(e->xbutton.type == ButtonPress) {
-			ob = button;
+			oldbutton = button;
 			ox = x;
 			oy = y;
 		}
 	}
 
-	button += (state & ShiftMask   ? 4  : 0)
-		+ (state & Mod4Mask    ? 8  : 0)
-		+ (state & ControlMask ? 16 : 0);
+	if(!IS_SET(MODE_MOUSEX10)) {
+		button += (state & ShiftMask   ? 4  : 0)
+			+ (state & Mod4Mask    ? 8  : 0)
+			+ (state & ControlMask ? 16 : 0);
+	}
 
 	len = 0;
 	if(IS_SET(MODE_MOUSESGR)) {
@@ -841,7 +854,8 @@ mousereport(XEvent *e) {
 				e->xbutton.type == ButtonRelease ? 'm' : 'M');
 	} else if(x < 223 && y < 223) {
 		len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
-				32+button, 32+x+1, 32+y+1);
+				IS_SET(MODE_MOUSEX10)? button-1 : 32+button,
+				32+x+1, 32+y+1);
 	} else {
 		return;
 	}
@@ -1775,21 +1789,30 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 25: /* DECTCEM -- Text Cursor Enable Mode */
 				MODBIT(term.mode, !set, MODE_HIDE);
 				break;
-			case 1000: /* 1000,1002: enable xterm mouse report */
+			case 9:    /* X10 mouse compatibility mode */
+				xsetpointermotion(0);
+				MODBIT(term.mode, 0, MODE_MOUSE);
+				MODBIT(term.mode, set, MODE_MOUSEX10);
+				break;
+			case 1000: /* 1000: report button press */
+				xsetpointermotion(0);
+				MODBIT(term.mode, 0, MODE_MOUSE);
 				MODBIT(term.mode, set, MODE_MOUSEBTN);
-				MODBIT(term.mode, 0, MODE_MOUSEMOTION);
 				break;
-			case 1002:
+			case 1002: /* 1002: report motion on button press */
+				xsetpointermotion(0);
+				MODBIT(term.mode, 0, MODE_MOUSE);
 				MODBIT(term.mode, set, MODE_MOUSEMOTION);
-				MODBIT(term.mode, 0, MODE_MOUSEBTN);
 				break;
-			case 1003: /* 1003: enable all mouse reports */
-				MODBIT(term.mode, set, MODE_MOUSE);
+			case 1003: /* 1003: enable all mouse motions */
+				xsetpointermotion(set);
+				MODBIT(term.mode, 0, MODE_MOUSE);
+				MODBIT(term.mode, set, MODE_MOUSEMANY);
 				break;
-			case 1004:
+			case 1004: /* 1004: send focus events to tty */
 				MODBIT(term.mode, set, MODE_FOCUS);
 				break;
-			case 1006:
+			case 1006: /* 1006: extended reporting mode */
 				MODBIT(term.mode, set, MODE_MOUSESGR);
 				break;
 			case 1034:
@@ -1815,7 +1838,6 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
 				break;
 			/* Not implemented mouse modes. See comments there. */
-			case 9: /* X10 compatibility mode */
 			case 1001: /* mouse highlight mode; can hang the
 				      terminal by design when implemented. */
 			case 1005: /* UTF-8 mouse mode; will confuse
@@ -1855,8 +1877,6 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 		}
 	}
 }
-#undef MODBIT
-
 
 void
 csihandle(void) {
@@ -2799,7 +2819,6 @@ xzoom(const Arg *arg) {
 
 void
 xinit(void) {
-	XSetWindowAttributes attrs;
 	XGCValues gcvalues;
 	Cursor cursor;
 	Window parent;
@@ -2841,22 +2860,20 @@ xinit(void) {
 	}
 
 	/* Events */
-	attrs.background_pixel = dc.col[defaultbg].pixel;
-	attrs.border_pixel = dc.col[defaultbg].pixel;
-	attrs.bit_gravity = NorthWestGravity;
-	attrs.event_mask = FocusChangeMask | KeyPressMask
+	xw.attrs.background_pixel = dc.col[defaultbg].pixel;
+	xw.attrs.border_pixel = dc.col[defaultbg].pixel;
+	xw.attrs.bit_gravity = NorthWestGravity;
+	xw.attrs.event_mask = FocusChangeMask | KeyPressMask
 		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
 		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
-	attrs.colormap = xw.cmap;
+	xw.attrs.colormap = xw.cmap;
 
 	parent = opt_embed ? strtol(opt_embed, NULL, 0) : \
 			XRootWindow(xw.dpy, xw.scr);
 	xw.win = XCreateWindow(xw.dpy, parent, xw.fx, xw.fy,
 			xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
-			xw.vis,
-			CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
-			| CWColormap,
-			&attrs);
+			xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
+			| CWEventMask | CWColormap, &xw.attrs);
 
 	memset(&gcvalues, 0, sizeof(gcvalues));
 	gcvalues.graphics_exposures = False;
@@ -2871,7 +2888,7 @@ xinit(void) {
 	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
 
 	/* input methods */
-	if((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+	if((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
 		XSetLocaleModifiers("@im=local");
 		if((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
 			XSetLocaleModifiers("@im=");
@@ -3306,6 +3323,12 @@ unmap(XEvent *ev) {
 	xw.state &= ~WIN_VISIBLE;
 }
 
+void
+xsetpointermotion(int set) {
+	MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
+	XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
+}
+
 void
 xseturgency(int add) {
 	XWMHints *h = XGetWMHints(xw.dpy, xw.win);

From 2cf4f366d615a4e5ed199f90e6cdb7741606a38e Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 1 Jun 2013 14:39:13 +0200
Subject: [PATCH 0549/1146] Bumping up the xfps so mouse motion won't reap the
 CPU.

---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 2d854a0..6b2737e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -24,7 +24,7 @@ static unsigned int tripleclicktimeout = 600;
 static bool allowaltscreen = true;
 
 /* frames per second st should at maximum draw to the screen */
-static unsigned int xfps = 60;
+static unsigned int xfps = 120;
 static unsigned int actionfps = 30;
 
 /*

From 369734c80c6e5049d704a00f436c59ecf4dafae8 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 6 Jun 2013 19:09:18 +0200
Subject: [PATCH 0550/1146] Adding xterm behaviour to setting the title.

Thanks Airwave!
---
 st.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 9a7891e..28c083a 100644
--- a/st.c
+++ b/st.c
@@ -19,6 +19,7 @@
 #include <sys/wait.h>
 #include <time.h>
 #include <unistd.h>
+#include <libgen.h>
 #include <X11/Xatom.h>
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
@@ -3622,6 +3623,7 @@ int
 main(int argc, char *argv[]) {
 	int bitm, xr, yr;
 	uint wr, hr;
+	char *titles;
 
 	xw.fw = xw.fh = xw.fx = xw.fy = 0;
 	xw.isfixed = False;
@@ -3635,8 +3637,13 @@ main(int argc, char *argv[]) {
 		break;
 	case 'e':
 		/* eat all remaining arguments */
-		if(argc > 1)
+		if(argc > 1) {
 			opt_cmd = &argv[1];
+			if(argv[1] != NULL) {
+				titles = strdup(argv[1]);
+				opt_title = basename(titles);
+			}
+		}
 		goto run;
 	case 'f':
 		opt_font = EARGF(usage());

From 5d3318c0c734a1d65e78ed4ce103b4517be8ec3b Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 9 Jun 2013 15:52:35 +0200
Subject: [PATCH 0551/1146] Fixing title setting with the title argument.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 28c083a..2811876 100644
--- a/st.c
+++ b/st.c
@@ -3639,7 +3639,7 @@ main(int argc, char *argv[]) {
 		/* eat all remaining arguments */
 		if(argc > 1) {
 			opt_cmd = &argv[1];
-			if(argv[1] != NULL) {
+			if(argv[1] != NULL && opt_title == NULL) {
 				titles = strdup(argv[1]);
 				opt_title = basename(titles);
 			}

From 7af030c999ba87cad2f3155bb9f58bf2854ad2bb Mon Sep 17 00:00:00 2001
From: Markus Teich <teichm@fs.tum.de>
Date: Sat, 22 Jun 2013 16:22:41 +0200
Subject: [PATCH 0552/1146] fix PageUp Modifier Mask in config.def.h

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 6b2737e..2de9a0a 100644
--- a/config.def.h
+++ b/config.def.h
@@ -247,7 +247,7 @@ static Key key[] = {
 	{ XK_End,           XK_ANY_MOD,     "\033[4~",       0,    0,    0},
 	{ XK_Prior,         ControlMask,    "\033[5;5~",     0,    0,    0},
 	{ XK_Prior,         ShiftMask,      "\033[5;2~",     0,    0,    0},
-	{ XK_Prior,         XK_NO_MOD,      "\033[5~",       0,    0,    0},
+	{ XK_Prior,         XK_ANY_MOD,     "\033[5~",       0,    0,    0},
 	{ XK_Next,          ControlMask,    "\033[6;5~",     0,    0,    0},
 	{ XK_Next,          ShiftMask,      "\033[6;2~",     0,    0,    0},
 	{ XK_Next,          XK_ANY_MOD,     "\033[6~",       0,    0,    0},

From ebbac77d7416d365a2a33f159780ef0f06cc3351 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 23 Jun 2013 12:09:19 +0200
Subject: [PATCH 0553/1146] Fix selection clearing

The way st knows if there is a selection activated is checking if sel.ob.x
is equal to -1. In some parts of the code the way of disabling the selection
was only setting it to -1, but after it you can't be sure if the selection
is clearing from the terminal representation, because it is necessary mark
all the lines affected by the selection as dirty. Already there is a functon
which perform this task, selclear.
---
 st.c | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index 2811876..96111a0 100644
--- a/st.c
+++ b/st.c
@@ -888,11 +888,7 @@ bpress(XEvent *e) {
 		gettimeofday(&now, NULL);
 
 		/* Clear previous selection, logically and visually. */
-		if(sel.ob.x != -1) {
-			sel.ob.x = -1;
-			tsetdirt(sel.nb.y, sel.ne.y);
-			draw();
-		}
+		selclear(NULL);
 		sel.mode = 1;
 		sel.type = SEL_REGULAR;
 		sel.oe.x = sel.ob.x = x2col(e->xbutton.x);
@@ -1108,7 +1104,7 @@ brelease(XEvent *e) {
 		selpaste(NULL);
 	} else if(e->xbutton.button == Button1) {
 		if(sel.mode < 2) {
-			sel.ob.x = -1;
+			selclear(NULL);
 		} else {
 			getbuttoninfo(e);
 			selcopy();
@@ -1441,7 +1437,7 @@ selscroll(int orig, int n) {
 
 	if(BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig, term.bot)) {
 		if((sel.ob.y += n) > term.bot || (sel.oe.y += n) < term.top) {
-			sel.ob.x = -1;
+			selclear(NULL);
 			return;
 		}
 		if(sel.type == SEL_RECTANGULAR) {
@@ -1951,7 +1947,7 @@ csihandle(void) {
 			tputtab(1);
 		break;
 	case 'J': /* ED -- Clear screen */
-		sel.ob.x = -1;
+		selclear(NULL);
 		switch(csiescseq.arg[0]) {
 		case 0: /* below */
 			tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
@@ -2448,7 +2444,7 @@ tputc(char *c, int len) {
 	if(control && !(term.c.attr.mode & ATTR_GFX))
 		return;
 	if(sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
-		sel.ob.x = -1;
+		selclear(NULL);
 	if(IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
 		term.line[term.c.y][term.c.x].mode |= ATTR_WRAP;
 		tnewline(1);

From 90c6f055b637a58da0381a21b4a290ce26f56d8f Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 23 Jun 2013 12:13:26 +0200
Subject: [PATCH 0554/1146] Remove unneded call to draw

draw is the function which update the Xwindow with the information st has,
and it is designed in a way that it must be called once in the main loop
(run function), and calling it in other places it is a waste of time.
---
 st.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.c b/st.c
index 96111a0..2809592 100644
--- a/st.c
+++ b/st.c
@@ -916,7 +916,6 @@ bpress(XEvent *e) {
 		if(sel.snap != 0) {
 			sel.mode++;
 			tsetdirt(sel.nb.y, sel.ne.y);
-			draw();
 		}
 		sel.tclick2 = sel.tclick1;
 		sel.tclick1 = now;

From 6e1c7c8afce3a0e6f896231a3155a27543d261e5 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 23 Jun 2013 10:33:53 +0200
Subject: [PATCH 0555/1146] Fix match function bugs

There were two problems with match denfinition.

1) There was a forward declaration in the form:

	static inline bool match(uint, uint);

but later the function was defined as:

	inline bool
	match(uint mask, uint state) {

This causes that there were two different functions in the code, one local
and inline, and other inline but extern. All was working without problems
due to we were using -Os, and the compiler was using the extern definition
and it was no expanding the static declaration. If you removed the -Os flag,
then you got linker errors due it was no able to find the static definition
of the static declaration.

2) The mask checking was incorrect because we were doing the test:

	(state & mask) != state

and this test only was saying that at least all the enabled bits of state
were enabled also in mask, but no all the possible bits in mask. This was
the origin of the bug reported by Xavier Cartron, where he said it was
possible activated some shortcuts with some of the modifiers defined in the
config.h file.
---
 st.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 2809592..66aca2d 100644
--- a/st.c
+++ b/st.c
@@ -3355,17 +3355,17 @@ focus(XEvent *ev) {
 	}
 }
 
-inline bool
+static inline bool
 match(uint mask, uint state) {
-	state &= ~(ignoremod);
+	state &= ~ignoremod;
 
 	if(mask == XK_NO_MOD && state)
 		return false;
 	if(mask != XK_ANY_MOD && mask != XK_NO_MOD && !state)
 		return false;
-	if((state & mask) != state)
-		return false;
-	return true;
+	if(mask == XK_ANY_MOD)
+		return true;
+	return state == mask;
 }
 
 void

From 8b602a37a65a3c001bd9334d8b1cfc17fc5dd45c Mon Sep 17 00:00:00 2001
From: Markus Teich <markus.teich@stusta.mhn.de>
Date: Sat, 22 Jun 2013 23:05:03 +0200
Subject: [PATCH 0556/1146] fix: do not need an extra variable for a single
 read

---
 st.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 66aca2d..16803ec 100644
--- a/st.c
+++ b/st.c
@@ -3375,7 +3375,6 @@ numlock(const Arg *dummy) {
 
 char*
 kmap(KeySym k, uint state) {
-	uint mask;
 	Key *kp;
 	int i;
 
@@ -3390,12 +3389,10 @@ kmap(KeySym k, uint state) {
 	}
 
 	for(kp = key; kp < key + LEN(key); kp++) {
-		mask = kp->mask;
-
 		if(kp->k != k)
 			continue;
 
-		if(!match(mask, state))
+		if(!match(kp->mask, state))
 			continue;
 
 		if(kp->appkey > 0) {

From 6fc471ccc660b305cf836dcb8d57cdbffb4ed017 Mon Sep 17 00:00:00 2001
From: Markus Teich <markus.teich@stusta.mhn.de>
Date: Sat, 22 Jun 2013 23:06:49 +0200
Subject: [PATCH 0557/1146] fix: consistent usage of bitmask operations on
 unicode functions

---
 st.c | 50 +++++++++++++++++++++++---------------------------
 1 file changed, 23 insertions(+), 27 deletions(-)

diff --git a/st.c b/st.c
index 16803ec..ac1954e 100644
--- a/st.c
+++ b/st.c
@@ -150,10 +150,6 @@ enum selection_snap {
 	SNAP_LINE = 2
 };
 
-/* bit macro */
-#undef B0
-enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 };
-
 typedef unsigned char uchar;
 typedef unsigned int uint;
 typedef unsigned long ulong;
@@ -527,17 +523,17 @@ utf8decode(char *s, long *u) {
 
 	rtn = 1;
 	c = *s;
-	if(~c & B7) { /* 0xxxxxxx */
+	if(~c & 0x80) { /* 0xxxxxxx */
 		*u = c;
 		return rtn;
-	} else if((c & (B7|B6|B5)) == (B7|B6)) { /* 110xxxxx */
-		*u = c&(B4|B3|B2|B1|B0);
+	} else if((c & 0xE0) == 0xC0) { /* 110xxxxx */
+		*u = c & 0x1F;
 		n = 1;
-	} else if((c & (B7|B6|B5|B4)) == (B7|B6|B5)) { /* 1110xxxx */
-		*u = c&(B3|B2|B1|B0);
+	} else if((c & 0xF0) == 0xE0) { /* 1110xxxx */
+		*u = c & 0x0F;
 		n = 2;
-	} else if((c & (B7|B6|B5|B4|B3)) == (B7|B6|B5|B4)) { /* 11110xxx */
-		*u = c & (B2|B1|B0);
+	} else if((c & 0xF8) == 0xF0) { /* 11110xxx */
+		*u = c & 0x07;
 		n = 3;
 	} else {
 		goto invalid;
@@ -545,10 +541,10 @@ utf8decode(char *s, long *u) {
 
 	for(i = n, ++s; i > 0; --i, ++rtn, ++s) {
 		c = *s;
-		if((c & (B7|B6)) != B7) /* 10xxxxxx */
+		if((c & 0xC0) != 0x80) /* 10xxxxxx */
 			goto invalid;
 		*u <<= 6;
-		*u |= c & (B5|B4|B3|B2|B1|B0);
+		*u |= c & 0x3F;
 	}
 
 	if((n == 1 && *u < 0x80) ||
@@ -577,20 +573,20 @@ utf8encode(long *u, char *s) {
 		*sp = uc; /* 0xxxxxxx */
 		return 1;
 	} else if(*u < 0x800) {
-		*sp = (uc >> 6) | (B7|B6); /* 110xxxxx */
+		*sp = (uc >> 6) | 0xC0; /* 110xxxxx */
 		n = 1;
 	} else if(uc < 0x10000) {
-		*sp = (uc >> 12) | (B7|B6|B5); /* 1110xxxx */
+		*sp = (uc >> 12) | 0xE0; /* 1110xxxx */
 		n = 2;
 	} else if(uc <= 0x10FFFF) {
-		*sp = (uc >> 18) | (B7|B6|B5|B4); /* 11110xxx */
+		*sp = (uc >> 18) | 0xF0; /* 11110xxx */
 		n = 3;
 	} else {
 		goto invalid;
 	}
 
 	for(i=n,++sp; i>0; --i,++sp)
-		*sp = ((uc >> 6*(i-1)) & (B5|B4|B3|B2|B1|B0)) | B7; /* 10xxxxxx */
+		*sp = ((uc >> 6*(i-1)) & 0x3F) | 0x80; /* 10xxxxxx */
 
 	return n+1;
 invalid:
@@ -613,16 +609,16 @@ isfullutf8(char *s, int b) {
 	c3 = (uchar *)++s;
 	if(b < 1) {
 		return 0;
-	} else if((*c1&(B7|B6|B5)) == (B7|B6) && b == 1) {
+	} else if((*c1 & 0xE0) == 0xC0 && b == 1) {
 		return 0;
-	} else if((*c1&(B7|B6|B5|B4)) == (B7|B6|B5) &&
+	} else if((*c1 & 0xF0) == 0xE0 &&
 	    ((b == 1) ||
-	    ((b == 2) && (*c2&(B7|B6)) == B7))) {
+	    ((b == 2) && (*c2 & 0xC0) == 0x80))) {
 		return 0;
-	} else if((*c1&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4) &&
+	} else if((*c1 & 0xF8) == 0xF0 &&
 	    ((b == 1) ||
-	    ((b == 2) && (*c2&(B7|B6)) == B7) ||
-	    ((b == 3) && (*c2&(B7|B6)) == B7 && (*c3&(B7|B6)) == B7))) {
+	    ((b == 2) && (*c2 & 0xC0) == 0x80) ||
+	    ((b == 3) && (*c2 & 0xC0) == 0x80 && (*c3 & 0xC0) == 0x80))) {
 		return 0;
 	} else {
 		return 1;
@@ -633,11 +629,11 @@ int
 utf8size(char *s) {
 	uchar c = *s;
 
-	if(~c&B7) {
+	if(~c & 0x80) {
 		return 1;
-	} else if((c&(B7|B6|B5)) == (B7|B6)) {
+	} else if((c & 0xE0) == 0xC0) {
 		return 2;
-	} else if((c&(B7|B6|B5|B4)) == (B7|B6|B5)) {
+	} else if((c & 0xF0) == 0xE0) {
 		return 3;
 	} else {
 		return 4;
@@ -3456,7 +3452,7 @@ kpress(XEvent *ev) {
 		if(len == 1 && e->state & Mod1Mask) {
 			if(IS_SET(MODE_8BIT)) {
 				if(*xstr < 0177) {
-					c = *xstr | B7;
+					c = *xstr | 0x80;
 					ret = utf8encode(&c, cp);
 					cp += ret;
 					len = 0;

From fbc589d50603e8b0de9239e4800e227ab5d0ea69 Mon Sep 17 00:00:00 2001
From: Alexander Sedov <alex0player@gmail.com>
Date: Sun, 23 Jun 2013 21:05:29 +0400
Subject: [PATCH 0558/1146] Remove long text being cropped/wrapped to standard
 80x24 on launch.

To be more specific, now tty creation is delayed until X window is
actually mapped; last ConfigureNotify before mapping determines
initial tty size.
Please report problems if there are any.
---
 TODO |  4 ----
 st.c | 21 ++++++++++++++++++---
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/TODO b/TODO
index afd6401..4fc1346 100644
--- a/TODO
+++ b/TODO
@@ -26,10 +26,6 @@ bugs
 * fix rows and column definition in fixed geometry
 * fix -e handling
 * remove DEC test sequence when appropriate
-* When some application outputting long text is run in the shell init scripts,
-  then this text might be stripped to the standard 80x25 due to st running the
-  virtual terminal at first priority. Maybe the vt initialisation could be
-  moved somewhere after knowing the right window size.
 
 misc
 ----
diff --git a/st.c b/st.c
index ac1954e..0fc724b 100644
--- a/st.c
+++ b/st.c
@@ -3520,10 +3520,28 @@ resize(XEvent *e) {
 void
 run(void) {
 	XEvent ev;
+	int w = xw.w, h = xw.h;
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
 	struct timeval drawtimeout, *tv = NULL, now, last, lastblink;
 
+	/* Waiting for window mapping */
+	while(1) {
+		XNextEvent(xw.dpy, &ev);
+		if(ev.type == ConfigureNotify) {
+			w = ev.xconfigure.width;
+			h = ev.xconfigure.height;
+		} else if(ev.type == MapNotify) {
+			break;
+		}
+	}
+
+	if(!xw.isfixed)
+		cresize(w, h);
+	else
+		cresize(xw.fw, xw.fh);
+	ttynew();
+
 	gettimeofday(&lastblink, NULL);
 	gettimeofday(&last, NULL);
 
@@ -3673,10 +3691,7 @@ run:
 	XSetLocaleModifiers("");
 	tnew(80, 24);
 	xinit();
-	ttynew();
 	selinit();
-	if(xw.isfixed)
-		cresize(xw.h, xw.w);
 	run();
 
 	return 0;

From 40e4d76d227d9c517054036f546acd49431bca42 Mon Sep 17 00:00:00 2001
From: Markus Teich <markus.teich@stusta.mhn.de>
Date: Sat, 22 Jun 2013 23:07:00 +0200
Subject: [PATCH 0559/1146] fix: whitespace

---
 config.def.h |   4 +-
 st.c         | 124 +++++++++++++++++++++++++--------------------------
 2 files changed, 64 insertions(+), 64 deletions(-)

diff --git a/config.def.h b/config.def.h
index 2de9a0a..9a3d2c8 100644
--- a/config.def.h
+++ b/config.def.h
@@ -160,7 +160,7 @@ static Key key[] = {
 	{ XK_KP_Right,      XK_ANY_MOD,     "\033[C",        0,   -1,    0},
 	{ XK_KP_Right,      XK_ANY_MOD,     "\033OC",        0,   +1,    0},
 	{ XK_KP_Prior,      ShiftMask,      "\033[5;2~",     0,    0,    0},
-	{ XK_KP_Prior,      XK_ANY_MOD,     "\033[5~",	     0,    0,    0},
+	{ XK_KP_Prior,      XK_ANY_MOD,     "\033[5~",       0,    0,    0},
 	{ XK_KP_Begin,      XK_ANY_MOD,     "\033[E",        0,    0,    0},
 	{ XK_KP_End,        ControlMask,    "\033[J",       -1,    0,    0},
 	{ XK_KP_End,        ControlMask,    "\033[1;5F",    +1,    0,    0},
@@ -213,7 +213,7 @@ static Key key[] = {
 	{ XK_Left,          ShiftMask,      "\033[1;2D",     0,    0,    0},
 	{ XK_Left,          ControlMask,    "\033[1;5D",     0,    0,    0},
 	{ XK_Left,          Mod1Mask,       "\033[1;3D",     0,    0,    0},
-	{ XK_Left,	    XK_ANY_MOD,     "\033[D",        0,   -1,    0},
+	{ XK_Left,          XK_ANY_MOD,     "\033[D",        0,   -1,    0},
 	{ XK_Left,          XK_ANY_MOD,     "\033OD",        0,   +1,    0},
 	{ XK_Right,         ShiftMask,      "\033[1;2C",     0,    0,    0},
 	{ XK_Right,         ControlMask,    "\033[1;5C",     0,    0,    0},
diff --git a/st.c b/st.c
index 0fc724b..289ecb8 100644
--- a/st.c
+++ b/st.c
@@ -98,37 +98,37 @@ enum cursor_movement {
 enum cursor_state {
 	CURSOR_DEFAULT  = 0,
 	CURSOR_WRAPNEXT = 1,
-	CURSOR_ORIGIN	= 2
+	CURSOR_ORIGIN   = 2
 };
 
 enum term_mode {
-	MODE_WRAP	 = 1,
+	MODE_WRAP        = 1,
 	MODE_INSERT      = 2,
 	MODE_APPKEYPAD   = 4,
 	MODE_ALTSCREEN   = 8,
-	MODE_CRLF	 = 16,
+	MODE_CRLF        = 16,
 	MODE_MOUSEBTN    = 32,
 	MODE_MOUSEMOTION = 64,
 	MODE_REVERSE     = 128,
 	MODE_KBDLOCK     = 256,
-	MODE_HIDE	 = 512,
-	MODE_ECHO	 = 1024,
-	MODE_APPCURSOR	 = 2048,
+	MODE_HIDE        = 512,
+	MODE_ECHO        = 1024,
+	MODE_APPCURSOR   = 2048,
 	MODE_MOUSESGR    = 4096,
-	MODE_8BIT	 = 8192,
-	MODE_BLINK	 = 16384,
-	MODE_FBLINK	 = 32768,
-	MODE_FOCUS	 = 65536,
-	MODE_MOUSEX10	 = 131072,
+	MODE_8BIT        = 8192,
+	MODE_BLINK       = 16384,
+	MODE_FBLINK      = 32768,
+	MODE_FOCUS       = 65536,
+	MODE_MOUSEX10    = 131072,
 	MODE_MOUSEMANY   = 262144,
 	MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
-			   |MODE_MOUSEMANY,
+	                  |MODE_MOUSEMANY,
 };
 
 enum escape_state {
 	ESC_START      = 1,
-	ESC_CSI	= 2,
-	ESC_STR	= 4, /* DSC, OSC, PM, APC */
+	ESC_CSI        = 2,
+	ESC_STR        = 4,  /* DSC, OSC, PM, APC */
 	ESC_ALTCHARSET = 8,
 	ESC_STR_END    = 16, /* a final string was encountered */
 	ESC_TEST       = 32, /* Enter in test mode */
@@ -156,16 +156,16 @@ typedef unsigned long ulong;
 typedef unsigned short ushort;
 
 typedef struct {
-	char c[UTF_SIZ];     /* character code */
-	uchar mode;  /* attribute flags */
-	ushort fg;   /* foreground  */
-	ushort bg;   /* background  */
+	char c[UTF_SIZ]; /* character code */
+	uchar mode;      /* attribute flags */
+	ushort fg;       /* foreground  */
+	ushort bg;       /* background  */
 } Glyph;
 
 typedef Glyph *Line;
 
 typedef struct {
-	Glyph attr;	 /* current char attributes */
+	Glyph attr; /* current char attributes */
 	int x;
 	int y;
 	char state;
@@ -175,36 +175,36 @@ typedef struct {
 /* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
 typedef struct {
 	char buf[ESC_BUF_SIZ]; /* raw string */
-	int len;	       /* raw string length */
+	int len;               /* raw string length */
 	char priv;
 	int arg[ESC_ARG_SIZ];
-	int narg;	       /* nb of args */
+	int narg;              /* nb of args */
 	char mode;
 } CSIEscape;
 
 /* STR Escape sequence structs */
 /* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
 typedef struct {
-	char type;	     /* ESC type ... */
+	char type;             /* ESC type ... */
 	char buf[STR_BUF_SIZ]; /* raw string */
-	int len;	       /* raw string length */
+	int len;               /* raw string length */
 	char *args[STR_ARG_SIZ];
-	int narg;	      /* nb of args */
+	int narg;              /* nb of args */
 } STREscape;
 
 /* Internal representation of the screen */
 typedef struct {
-	int row;	/* nb row */
-	int col;	/* nb col */
-	Line *line;	/* screen */
-	Line *alt;	/* alternate screen */
-	bool *dirty;	/* dirtyness of lines */
-	TCursor c;	/* cursor */
-	int top;	/* top    scroll limit */
-	int bot;	/* bottom scroll limit */
-	int mode;	/* terminal mode flags */
-	int esc;	/* escape state flags */
-	bool numlock;	/* lock numbers in keyboard */
+	int row;      /* nb row */
+	int col;      /* nb col */
+	Line *line;   /* screen */
+	Line *alt;    /* alternate screen */
+	bool *dirty;  /* dirtyness of lines */
+	TCursor c;    /* cursor */
+	int top;      /* top    scroll limit */
+	int bot;      /* bottom scroll limit */
+	int mode;     /* terminal mode flags */
+	int esc;      /* escape state flags */
+	bool numlock; /* lock numbers in keyboard */
 	bool *tabs;
 } Term;
 
@@ -241,9 +241,9 @@ typedef struct {
 	uint mask;
 	char s[ESC_BUF_SIZ];
 	/* three valued logic variables: 0 indifferent, 1 on, -1 off */
-	signed char appkey;		/* application keypad */
-	signed char appcursor;		/* application cursor */
-	signed char crlf;		/* crlf mode          */
+	signed char appkey;    /* application keypad */
+	signed char appcursor; /* application cursor */
+	signed char crlf;      /* crlf mode          */
 } Key;
 
 typedef struct {
@@ -1182,7 +1182,7 @@ sigchld(int a) {
 	int stat = 0;
 
 	if(waitpid(pid, &stat, 0) < 0)
-		die("Waiting for pid %hd failed: %s\n",	pid, SERRNO);
+		die("Waiting for pid %hd failed: %s\n", pid, SERRNO);
 
 	if(WIFEXITED(stat)) {
 		exit(WEXITSTATUS(stat));
@@ -1821,7 +1821,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 					tclearregion(0, 0, term.col-1,
 							term.row-1);
 				}
-				if(set ^ alt)		/* set is always 1 or 0 */
+				if(set ^ alt) /* set is always 1 or 0 */
 					tswapscreen();
 				if(*args != 1049)
 					break;
@@ -2184,10 +2184,10 @@ techo(char *buf, int len) {
 	for(; len > 0; buf++, len--) {
 		char c = *buf;
 
-		if(c == '\033') {		/* escape */
+		if(c == '\033') { /* escape */
 			tputc("^", 1);
 			tputc("[", 1);
-		} else if(c < '\x20') {	/* control code */
+		} else if(c < '\x20') { /* control code */
 			if(c != '\n' && c != '\r' && c != '\t') {
 				c |= '\x40';
 				tputc("^", 1);
@@ -2258,31 +2258,31 @@ tputc(char *c, int len) {
 	 */
 	if(control) {
 		switch(ascii) {
-		case '\t':	/* HT */
+		case '\t':   /* HT */
 			tputtab(1);
 			return;
-		case '\b':	/* BS */
+		case '\b':   /* BS */
 			tmoveto(term.c.x-1, term.c.y);
 			return;
-		case '\r':	/* CR */
+		case '\r':   /* CR */
 			tmoveto(0, term.c.y);
 			return;
-		case '\f':	/* LF */
-		case '\v':	/* VT */
-		case '\n':	/* LF */
+		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 */
+		case '\a':   /* BEL */
 			if(!(xw.state & WIN_FOCUSED))
 				xseturgency(1);
 			return;
-		case '\033':	/* ESC */
+		case '\033': /* ESC */
 			csireset();
 			term.esc = ESC_START;
 			return;
-		case '\016':	/* SO */
-		case '\017':	/* SI */
+		case '\016': /* SO */
+		case '\017': /* SI */
 			/*
 			 * Different charsets are hard to handle. Applications
 			 * should use the right alt charset escapes for the
@@ -2290,15 +2290,15 @@ tputc(char *c, int len) {
 			 * rest is incompatible history st should not support.
 			 */
 			return;
-		case '\032':	/* SUB */
-		case '\030':	/* CAN */
+		case '\032': /* SUB */
+		case '\030': /* CAN */
 			csireset();
 			return;
-		case '\005':	/* ENQ (IGNORED) */
-		case '\000':	/* NUL (IGNORED) */
-		case '\021':	/* XON (IGNORED) */
-		case '\023':	/* XOFF (IGNORED) */
-		case 0177:	/* DEL (IGNORED) */
+		case '\005': /* ENQ (IGNORED) */
+		case '\000': /* NUL (IGNORED) */
+		case '\021': /* XON (IGNORED) */
+		case '\023': /* XOFF (IGNORED) */
+		case 0177:   /* DEL (IGNORED) */
 			return;
 		}
 	} else if(term.esc & ESC_START) {
@@ -2963,9 +2963,9 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		}
 		/*
 		 * Those ranges will not be brightened:
-		 *	8 - 15 – bright system colors
-		 *	196 - 231 – highest 256 color cube
-		 *	252 - 255 – brightest colors in greyscale
+		 *    8 - 15 – bright system colors
+		 *    196 - 231 – highest 256 color cube
+		 *    252 - 255 – brightest colors in greyscale
 		 */
 		font = &dc.bfont;
 		frcflags = FRC_BOLD;

From 33ad83d49213749f4fcec850327f57a33ca8b921 Mon Sep 17 00:00:00 2001
From: "Eon S. Jeon" <esjeon@lavabit.com>
Date: Fri, 19 Jul 2013 01:07:02 -0400
Subject: [PATCH 0560/1146] Improved font caching

I made a patch that improves the performance of font caching mechanism.
This is based on a funny behaviour of FontConfig: it was handling
FcCharSet in a somewhat unexpected way.

So, we are currently adding "a character" to a new FcCharSet, and then
add it to a FcPattern. However, if we toss the FcPattern to FontConfig,
it loads the entire language(charset) that contains the character we
gave. That is, we don't always have to load a new font for each unknown
character. Instead, we can reused cached fonts, and this significantly
reduces the number of calls to extremely slow FontConfig matching
functions.

One more thing. I found that, in libXft, there's a function called
XftCharExists. XftCharIndex internally calls this function, and
does more stuffs if the character does exist. Since the returned index
is never used in st, we should call XftCharExists instead of
XftCharIndex. Please note that I already made this change in the patch.
---
 st.c | 63 +++++++++++++++++++++---------------------------------------
 1 file changed, 22 insertions(+), 41 deletions(-)

diff --git a/st.c b/st.c
index 289ecb8..947373f 100644
--- a/st.c
+++ b/st.c
@@ -462,17 +462,12 @@ enum {
 
 typedef struct {
 	XftFont *font;
-	long c;
 	int flags;
 } Fontcache;
 
-/*
- * Fontcache is a ring buffer, with frccur as current position and frclen as
- * the current length of used elements.
- */
-
-static Fontcache frc[1024];
-static int frccur = -1, frclen = 0;
+/* Fontcache is an array now. A new font will be appended to the array. */
+static Fontcache frc[16];
+static int frclen = 0;
 
 ssize_t
 xwrite(int fd, char *s, size_t len) {
@@ -2781,18 +2776,12 @@ xunloadfont(Font *f) {
 
 void
 xunloadfonts(void) {
-	int i, ip;
+	int i;
 
-	/*
-	 * Free the loaded fonts in the font cache. This is done backwards
-	 * from the frccur.
-	 */
-	for(i = 0, ip = frccur; i < frclen; i++, ip--) {
-		if(ip < 0)
-			ip = LEN(frc) - 1;
-		XftFontClose(xw.dpy, frc[ip].font);
+	/* Free the loaded fonts in the font cache.  */
+	for(i = 0; i < frclen; i++) {
+		XftFontClose(xw.dpy, frc[i].font);
 	}
-	frccur = -1;
 	frclen = 0;
 
 	xunloadfont(&dc.font);
@@ -2918,7 +2907,7 @@ void
 xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
 	    width = charlen * xw.cw, xp, i;
-	int frp, frcflags;
+	int frcflags;
 	int u8fl, u8fblen, u8cblen, doesexist;
 	char *u8c, *u8fs;
 	long u8char;
@@ -3044,7 +3033,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			s += u8cblen;
 			bytelen -= u8cblen;
 
-			doesexist = XftCharIndex(xw.dpy, font->match, u8char);
+			doesexist = XftCharExists(xw.dpy, font->match, u8char);
 			if(!doesexist || bytelen <= 0) {
 				if(bytelen <= 0) {
 					if(doesexist) {
@@ -3071,14 +3060,10 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		if(doesexist)
 			break;
 
-		frp = frccur;
 		/* Search the font cache. */
-		for(i = 0; i < frclen; i++, frp--) {
-			if(frp <= 0)
-				frp = LEN(frc) - 1;
-
-			if(frc[frp].c == u8char
-					&& frc[frp].flags == frcflags) {
+		for(i = 0; i < frclen; i++) {
+			if(XftCharExists(xw.dpy, frc[i].font, u8char)
+					&& frc[i].flags == frcflags) {
 				break;
 			}
 		}
@@ -3113,28 +3098,24 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			/*
 			 * Overwrite or create the new cache entry.
 			 */
-			frccur++;
-			frclen++;
-			if(frccur >= LEN(frc))
-				frccur = 0;
-			if(frclen > LEN(frc)) {
-				frclen = LEN(frc);
-				XftFontClose(xw.dpy, frc[frccur].font);
+			if(frclen >= LEN(frc)) {
+				frclen = LEN(frc) - 1;
+				XftFontClose(xw.dpy, frc[frclen].font);
 			}
 
-			frc[frccur].font = XftFontOpenPattern(xw.dpy,
+			frc[frclen].font = XftFontOpenPattern(xw.dpy,
 					fontpattern);
-			frc[frccur].c = u8char;
-			frc[frccur].flags = frcflags;
+			frc[frclen].flags = frcflags;
+
+			i = frclen;
+			frclen++;
 
 			FcPatternDestroy(fcpattern);
 			FcCharSetDestroy(fccharset);
-
-			frp = frccur;
 		}
 
-		XftDrawStringUtf8(xw.draw, fg, frc[frp].font,
-				xp, winy + frc[frp].font->ascent,
+		XftDrawStringUtf8(xw.draw, fg, frc[i].font,
+				xp, winy + frc[i].font->ascent,
 				(FcChar8 *)u8c, u8cblen);
 
 		xp += font->width;

From 8dde8cde41caa311718d2b990ea3356272ee25ee Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 19 Jul 2013 20:34:36 +0200
Subject: [PATCH 0561/1146] Add RGB color definition

This patch uses the bit 24 in the color descriptor as an indicator
of RGB color, so we can take the values and generating the XftColour
directly in xdraws.
---
 st.c | 119 ++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 85 insertions(+), 34 deletions(-)

diff --git a/st.c b/st.c
index 947373f..097244c 100644
--- a/st.c
+++ b/st.c
@@ -77,6 +77,13 @@ char *argv0;
 #define IS_SET(flag) ((term.mode & (flag)) != 0)
 #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
 
+#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
+#define IS_TRUECOL(x)    (1 << 24 & (x))
+#define TRUERED(x)       (((x) & 0xff0000) >> 8)
+#define TRUEGREEN(x)     (((x) & 0xff00))
+#define TRUEBLUE(x)      (((x) & 0xff) << 8)
+
+
 #define VT102ID "\033[?6c"
 
 enum glyph_attribute {
@@ -158,8 +165,8 @@ typedef unsigned short ushort;
 typedef struct {
 	char c[UTF_SIZ]; /* character code */
 	uchar mode;      /* attribute flags */
-	ushort fg;       /* foreground  */
-	ushort bg;       /* background  */
+	ulong fg;        /* foreground  */
+	ulong bg;        /* background  */
 } Glyph;
 
 typedef Glyph *Line;
@@ -354,7 +361,7 @@ static void tsetdirtattr(int);
 static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 static void techo(char *, int);
-
+static ulong tdefcolor(int *, int *, int);
 static inline bool match(uint, uint);
 static void ttynew(void);
 static void ttyread(void);
@@ -1618,9 +1625,58 @@ tdeleteline(int n) {
 	tscrollup(term.c.y, n);
 }
 
+ulong
+tdefcolor(int *attr, int *npar, int l) {
+	long idx = -1;
+	uint r, g, b;
+
+	switch (attr[*npar + 1]) {
+	case 2: /* direct colour 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 (%d,%d,%d)\n",
+				r, g, b);
+		else
+			idx = TRUECOLOR(r, g, b);
+		break;
+	case 5: /* indexed colour */
+		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 colour in CMY space */
+	case 4: /* direct colour in CMYK space */
+	default:
+		fprintf(stderr,
+		        "erresc(38): gfx attr %d unknown\n", attr[*npar]);
+	}
+
+	return idx;
+}
+
 void
 tsetattr(int *attr, int l) {
 	int i;
+	ulong idx;
 
 	for(i = 0; i < l; i++) {
 		switch(attr[i]) {
@@ -1665,39 +1721,15 @@ tsetattr(int *attr, int l) {
 			term.c.attr.mode &= ~ATTR_REVERSE;
 			break;
 		case 38:
-			if(i + 2 < l && attr[i + 1] == 5) {
-				i += 2;
-				if(BETWEEN(attr[i], 0, 255)) {
-					term.c.attr.fg = attr[i];
-				} else {
-					fprintf(stderr,
-						"erresc: bad fgcolor %d\n",
-						attr[i]);
-				}
-			} else {
-				fprintf(stderr,
-					"erresc(38): gfx attr %d unknown\n",
-					attr[i]);
-			}
+			if ((idx = tdefcolor(attr, &i, l)) >= 0)
+				term.c.attr.fg = idx;
 			break;
 		case 39:
 			term.c.attr.fg = defaultfg;
 			break;
 		case 48:
-			if(i + 2 < l && attr[i + 1] == 5) {
-				i += 2;
-				if(BETWEEN(attr[i], 0, 255)) {
-					term.c.attr.bg = attr[i];
-				} else {
-					fprintf(stderr,
-						"erresc: bad bgcolor %d\n",
-						attr[i]);
-				}
-			} else {
-				fprintf(stderr,
-					"erresc(48): gfx attr %d unknown\n",
-					attr[i]);
-			}
+			if ((idx = tdefcolor(attr, &i, l)) >= 0)
+				term.c.attr.bg = idx;
 			break;
 		case 49:
 			term.c.attr.bg = defaultbg;
@@ -2916,7 +2948,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	FcPattern *fcpattern, *fontpattern;
 	FcFontSet *fcsets[] = { NULL };
 	FcCharSet *fccharset;
-	Colour *fg, *bg, *temp, revfg, revbg;
+	Colour *fg, *bg, *temp, revfg, revbg, truefg, truebg;
 	XRenderColor colfg, colbg;
 	Rectangle r;
 
@@ -2936,8 +2968,27 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		if(base.fg == defaultfg)
 			base.fg = defaultunderline;
 	}
-	fg = &dc.col[base.fg];
-	bg = &dc.col[base.bg];
+	if(IS_TRUECOL(base.fg)) {
+		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.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];
+	}
+
+
 
 	if(base.mode & ATTR_BOLD) {
 		if(BETWEEN(base.fg, 0, 7)) {

From aaee0e8b28a353c215b6d1c8fc06d20038d7b426 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 20 Jul 2013 21:52:40 +0200
Subject: [PATCH 0562/1146] Reload colors in reset

Colors definition can be changed using a OSC sequence, so
we have to reload them if we want be sure all the colors
are the correct.

Could be desirable free the colors allocated due to rgb
colors and inverse colors (XftColorAllocValues in xdraws),
but it is impossible due we use the same structure for all
of them.
---
 st.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/st.c b/st.c
index 097244c..362de23 100644
--- a/st.c
+++ b/st.c
@@ -2428,6 +2428,7 @@ tputc(char *c, int len) {
 				treset();
 				term.esc = 0;
 				xresettitle();
+				xloadcols();
 				break;
 			case '=': /* DECPAM -- Application keypad */
 				term.mode |= MODE_APPKEYPAD;
@@ -2589,6 +2590,13 @@ void
 xloadcols(void) {
 	int i, r, g, b;
 	XRenderColor color = { .alpha = 0xffff };
+	static bool loaded;
+	Colour *cp;
+
+	if(loaded) {
+		for (cp = dc.col; cp < dc.col + LEN(dc.col); ++cp)
+			XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
+	}
 
 	/* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */
 	for(i = 0; i < LEN(colorname); i++) {
@@ -2621,6 +2629,7 @@ xloadcols(void) {
 			die("Could not allocate color %d\n", i);
 		}
 	}
+	loaded = true;
 }
 
 int

From 7e3cff33ffbd69a112fa4071a9f0ed2dc93bfc57 Mon Sep 17 00:00:00 2001
From: Eric Pruitt <eric.pruitt@gmail.com>
Date: Mon, 5 Aug 2013 11:33:37 +0200
Subject: [PATCH 0563/1146] Use character size scaling factors

The bounding boxes for characters can be scaled using "cwscale" and "chscale"
to scale the width and height respectively.
---
 TODO         |  1 -
 config.def.h |  4 ++++
 st.c         | 20 +++++++++++++-------
 3 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/TODO b/TODO
index 4fc1346..794b71b 100644
--- a/TODO
+++ b/TODO
@@ -13,7 +13,6 @@ code & interface
 drawing
 -------
 * add diacritics support to xdraws()
-* add kerning configuration
 * make the font cache simpler
 * add hard width handling
 	* xft is reporting wrong width and height for characters
diff --git a/config.def.h b/config.def.h
index 9a3d2c8..8cb8804 100644
--- a/config.def.h
+++ b/config.def.h
@@ -9,6 +9,10 @@ static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=fals
 static int borderpx = 2;
 static char shell[] = "/bin/sh";
 
+/* Kerning / character bounding-box mutlipliers */
+float cwscale = 1.0;
+float chscale = 1.0;
+
 /*
  * word delimiter string
  *
diff --git a/st.c b/st.c
index 362de23..6756f76 100644
--- a/st.c
+++ b/st.c
@@ -76,6 +76,7 @@ char *argv0;
 #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
 #define IS_SET(flag) ((term.mode & (flag)) != 0)
 #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
+#define CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x))
 
 #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
 #define IS_TRUECOL(x)    (1 << 24 & (x))
@@ -2777,8 +2778,8 @@ xloadfonts(char *fontstr, int fontsize) {
 		die("st: can't open font %s\n", fontstr);
 
 	/* Setting character width and height. */
-	xw.cw = dc.font.width;
-	xw.ch = dc.font.height;
+	xw.cw = CEIL(dc.font.width * cwscale);
+	xw.ch = CEIL(dc.font.height * chscale);
 
 	FcPatternDel(pattern, FC_SLANT);
 	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
@@ -2960,6 +2961,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	Colour *fg, *bg, *temp, revfg, revbg, truefg, truebg;
 	XRenderColor colfg, colbg;
 	Rectangle r;
+	int oneatatime;
 
 	frcflags = FRC_NORMAL;
 
@@ -3087,6 +3089,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		u8fs = s;
 		u8fblen = 0;
 		u8fl = 0;
+		oneatatime = font->width != xw.cw;
 		for(;;) {
 			u8c = s;
 			u8cblen = utf8decode(s, &u8char);
@@ -3094,8 +3097,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			bytelen -= u8cblen;
 
 			doesexist = XftCharExists(xw.dpy, font->match, u8char);
-			if(!doesexist || bytelen <= 0) {
-				if(bytelen <= 0) {
+			if(oneatatime || !doesexist || bytelen <= 0) {
+				if(oneatatime || bytelen <= 0) {
 					if(doesexist) {
 						u8fl++;
 						u8fblen += u8cblen;
@@ -3108,7 +3111,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 							winy + font->ascent,
 							(FcChar8 *)u8fs,
 							u8fblen);
-					xp += font->width * u8fl;
+					xp += CEIL(font->width * cwscale * u8fl);
 
 				}
 				break;
@@ -3117,8 +3120,11 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			u8fl++;
 			u8fblen += u8cblen;
 		}
-		if(doesexist)
+		if(doesexist) {
+			if (oneatatime);
+				continue;
 			break;
+		}
 
 		/* Search the font cache. */
 		for(i = 0; i < frclen; i++) {
@@ -3178,7 +3184,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 				xp, winy + frc[i].font->ascent,
 				(FcChar8 *)u8c, u8cblen);
 
-		xp += font->width;
+		xp += CEIL(font->width * cwscale);
 	}
 
 	/*

From 86c03ddc82d2f9f84f22f79741e13ade0e0b8cd1 Mon Sep 17 00:00:00 2001
From: Michael Forney <mforney@mforney.org>
Date: Thu, 25 Jul 2013 16:24:16 -0700
Subject: [PATCH 0564/1146] Fix blink mode check

ATTR_BLINK is an attribute for a Glyph and will not be set in term.mode.
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 6756f76..b63d865 100644
--- a/st.c
+++ b/st.c
@@ -3606,8 +3606,8 @@ run(void) {
 			ttyread();
 			if(blinktimeout) {
 				blinkset = tattrset(ATTR_BLINK);
-				if(!blinkset && term.mode & ATTR_BLINK)
-					term.mode &= ~(MODE_BLINK);
+				if(!blinkset)
+					MODBIT(term.mode, 0, MODE_BLINK);
 			}
 		}
 

From 22eeda56b7c1532773343811dee1f76c0999d01c Mon Sep 17 00:00:00 2001
From: Alexander Sedov <alex0player@gmail.com>
Date: Mon, 29 Jul 2013 11:50:44 +0400
Subject: [PATCH 0565/1146] Fixed memory leak in xsettitle().

---
 st.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index b63d865..9cdd969 100644
--- a/st.c
+++ b/st.c
@@ -3258,6 +3258,7 @@ xsettitle(char *p) {
 	Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
 			&prop);
 	XSetWMName(xw.dpy, xw.win, &prop);
+	XFree(prop.value);
 }
 
 void

From 347a45c35299c94e97c976b6e1df383dc2b8fbda Mon Sep 17 00:00:00 2001
From: "Eon S. Jeon" <esjeon@lavabit.com>
Date: Mon, 5 Aug 2013 16:37:59 -0400
Subject: [PATCH 0566/1146] Fix signess of tdefcolor

tdefcolor() returns -1 on error, while its return type is
unsigned long. At the same time, line 1724 and 1731 are checking the
positivity of its unsigned return value.
---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 9cdd969..1b01353 100644
--- a/st.c
+++ b/st.c
@@ -362,7 +362,7 @@ static void tsetdirtattr(int);
 static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 static void techo(char *, int);
-static ulong tdefcolor(int *, int *, int);
+static long tdefcolor(int *, int *, int);
 static inline bool match(uint, uint);
 static void ttynew(void);
 static void ttyread(void);
@@ -1626,7 +1626,7 @@ tdeleteline(int n) {
 	tscrollup(term.c.y, n);
 }
 
-ulong
+long
 tdefcolor(int *attr, int *npar, int l) {
 	long idx = -1;
 	uint r, g, b;
@@ -1677,7 +1677,7 @@ tdefcolor(int *attr, int *npar, int l) {
 void
 tsetattr(int *attr, int l) {
 	int i;
-	ulong idx;
+	long idx;
 
 	for(i = 0; i < l; i++) {
 		switch(attr[i]) {

From 457969381869f9f3ecbb462bf40f053f2a748a02 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 12 Aug 2013 15:25:18 +0200
Subject: [PATCH 0567/1146] Add terminfo definitions for terminals with meta
 key

Some programs don't check the value of km and use smm and rmm
capabilites, and they cause the terminal change to meta enabled
mode even in cases where is not desirable.

Allmost all people is using the terminal waiting that meta sends
escape, so rmm and smm are not needed. If someone needs meta
sets 8 bit he can use the correct terminfo definition in TERM.
---
 FAQ     |  6 ++++++
 st.info | 20 ++++++++++++++++----
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/FAQ b/FAQ
index 23d557d..9f30ca3 100644
--- a/FAQ
+++ b/FAQ
@@ -83,3 +83,9 @@ If you are using zsh, then read the zsh FAQ
 		zle -N zle-line-finish
 
 Putting these lines into your .zshrc will fix the problems.
+
+## How can use meta in 8bit mode?
+
+ St support meta in 8bit mode, but the default terminfo entry doesn't
+ use this capability. If you want it, you have to use st-meta value
+ in TERM.
diff --git a/st.info b/st.info
index ff01c80..94fce22 100644
--- a/st.info
+++ b/st.info
@@ -1,5 +1,3 @@
-# unsupported xterm caps are (getting) commented. 
-# as soon as they work, uncomment them.
 st| simpleterm,
 	acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
 	am,
@@ -162,7 +160,6 @@ st| simpleterm,
 	rmcup=\E[?1049l,
 	rmir=\E[4l,
 	rmkx=\E[?1l\E>,
-	rmm=\E[?1034l,
 	rmso=\E[27m,
 	rmul=\E[m,
 	rs1=\Ec,
@@ -179,7 +176,6 @@ st| simpleterm,
 	smcup=\E[?1049h,
 	smir=\E[4h,
 	smkx=\E[?1h\E=,
-	smm=\E[?1034h,
 	smso=\E[7m,
 	smul=\E[4m,
 	tbc=\E[3g,
@@ -196,3 +192,19 @@ st-256color| simpleterm with 256 colors,
 #	Nicked from xterm-256color
 	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,

From 8d21ced08527e79489f37b7a4ad19355bca2207c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 20 Aug 2013 18:18:48 +0200
Subject: [PATCH 0568/1146] Correcting the bitmask value check.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 1b01353..9733a9b 100644
--- a/st.c
+++ b/st.c
@@ -3714,7 +3714,7 @@ main(int argc, char *argv[]) {
 			xw.fh = (int)hr;
 		if(bitm & XNegative && xw.fx == 0)
 			xw.fx = -1;
-		if(bitm & XNegative && xw.fy == 0)
+		if(bitm & YNegative && xw.fy == 0)
 			xw.fy = -1;
 
 		if(xw.fh != 0 && xw.fw != 0)

From 587bc939f63b49c6155c4f1fdf97e73380207446 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 22 Aug 2013 19:32:49 +0200
Subject: [PATCH 0569/1146] Tmux is using C-b by default.

Thanks for noticing Fidel Barrera Cruz!
---
 FAQ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/FAQ b/FAQ
index 9f30ca3..bb2bde4 100644
--- a/FAQ
+++ b/FAQ
@@ -26,7 +26,7 @@ st or st-256color. The default value for TERM can be changed in config.h
 
 Using a terminal multiplexer.
 
-* `st -e tmux` using C-a [
+* `st -e tmux` using C-b [
 * `st -e screen` using C-a ESC
 
 ## Why doesn't the Del key work in some programs?

From f3d438b1015a031bc543bb2d65c81cc2329787d4 Mon Sep 17 00:00:00 2001
From: "Eon S. Jeon" <esjeon@hyunmu.am>
Date: Sun, 11 Aug 2013 06:42:30 -0400
Subject: [PATCH 0570/1146] Regarding commit 7e3cff3

Hello.

I reviewed and tested commit 7e3cff3, and made a patch that fixes some
problems in it.

1. There's a semicolon after an if statement, which is obviously a
typo.

2. The current way of calculating text position in "xdraws" yields
inconsistent results in some cases. This is due to the use of
"font->width", which varies. Instead, "xw.cw" has to be used as the
character width.

Sincerely,
Eon
---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 9733a9b..c751aa1 100644
--- a/st.c
+++ b/st.c
@@ -3111,7 +3111,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 							winy + font->ascent,
 							(FcChar8 *)u8fs,
 							u8fblen);
-					xp += CEIL(font->width * cwscale * u8fl);
+					xp += xw.cw * u8fl;
 
 				}
 				break;
@@ -3121,7 +3121,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			u8fblen += u8cblen;
 		}
 		if(doesexist) {
-			if (oneatatime);
+			if (oneatatime)
 				continue;
 			break;
 		}
@@ -3184,7 +3184,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 				xp, winy + frc[i].font->ascent,
 				(FcChar8 *)u8c, u8cblen);
 
-		xp += CEIL(font->width * cwscale);
+		xp += xw.cw;
 	}
 
 	/*

From 4245ba0d12a330b3e54c6498e88024d90956ae34 Mon Sep 17 00:00:00 2001
From: Mark Edgar <medgar123@gmail.com>
Date: Mon, 26 Aug 2013 00:10:47 +0200
Subject: [PATCH 0571/1146] Correctly initialize altscreen when defaultbg is
 not 0.

The alternate screen is not properly initialized when st starts. To see
this, set defaultbg in config.h to anything other than 0 (for example, swap
defaultfg and defaultbg), and run:

./st -e sh -c 'tput smcup; read'

You should see that the top-left 80x24 rectangle is black (or whatever
colorname[0] is), while the rest of the screen (if any) has the desired
colorname[defaultbg] color.

The attached patch fixes this by initializing term.c.attr in tnew() before
calling tresize(). It also removes the unnecessary xcalloc() calls, which
misled me on this bug hunt since it is really tclearregion() which
initializes term.lines and term.alt in tresize().
---
 config.def.h |  6 +++---
 st.c         | 17 +++--------------
 2 files changed, 6 insertions(+), 17 deletions(-)

diff --git a/config.def.h b/config.def.h
index 8cb8804..24aeb19 100644
--- a/config.def.h
+++ b/config.def.h
@@ -129,13 +129,13 @@ static Shortcut shortcuts[] = {
  * * < 0: crlf mode is disabled
  *
  * Be careful with the order of the definitons because st searchs in
- * this table sequencially, so any XK_ANY_MOD must be in the last
+ * this table sequentially, so any XK_ANY_MOD must be in the last
  * position for a key.
  */
 
 /*
- * If you want something else but the function keys of X11 (0xFF00 - 0xFFFF)
- * mapped below, add them to this array.
+ * 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 };
 
diff --git a/st.c b/st.c
index c751aa1..0fa0c86 100644
--- a/st.c
+++ b/st.c
@@ -420,7 +420,6 @@ static int isfullutf8(char *, int);
 static ssize_t xwrite(int, char *, size_t);
 static void *xmalloc(size_t);
 static void *xrealloc(void *, size_t);
-static void *xcalloc(size_t, size_t);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
@@ -509,16 +508,6 @@ xrealloc(void *p, size_t len) {
 	return p;
 }
 
-void *
-xcalloc(size_t nmemb, size_t size) {
-	void *p = calloc(nmemb, size);
-
-	if(!p)
-		die("Out of memory\n");
-
-	return p;
-}
-
 int
 utf8decode(char *s, long *u) {
 	uchar c;
@@ -1370,7 +1359,7 @@ treset(void) {
 
 void
 tnew(int col, int row) {
-	memset(&term, 0, sizeof(Term));
+	term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
 	tresize(col, row);
 	term.numlock = 1;
 
@@ -2536,8 +2525,8 @@ tresize(int col, int row) {
 	/* allocate any new rows */
 	for(/* i == minrow */; i < row; i++) {
 		term.dirty[i] = 1;
-		term.line[i] = xcalloc(col, sizeof(Glyph));
-		term.alt [i] = xcalloc(col, sizeof(Glyph));
+		term.line[i] = xmalloc(col * sizeof(Glyph));
+		term.alt[i] = xmalloc(col * sizeof(Glyph));
 	}
 	if(col > term.col) {
 		bp = term.tabs + term.col;

From a4358a1fbd1c71269129404c9af4f539b2d7627c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 7 Sep 2013 12:29:44 +0200
Subject: [PATCH 0572/1146] Adding some contributors. Thanks to you all!

---
 LICENSE | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/LICENSE b/LICENSE
index 66f4b1b..910bec9 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,9 +1,15 @@
 MIT/X Consortium License
 
 © 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com> 
+© 2009 Anselm R Garbe <garbeam at gmail dot com>
 © 2012 Roberto E. Vargas Caballero <k0ga at shike2 dot com>
 © 2012 Christoph Lohmann <20h at r-36 dot net>
-© 2009 Anselm R Garbe <garbeam at gmail dot com>
+© 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 Eric Pruitt <eric.pruitt at gmail dot com>
+© 2013 Michael Forney <mforney at mforney dot org>
+© 2013 Markus Teich <markus dot teich at stusta dot mhn dot de>
 
 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and associated documentation files (the "Software"),

From 210dda9570095443bac887c2bfcd75f2bcc23780 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 7 Sep 2013 12:41:36 +0200
Subject: [PATCH 0573/1146] Wide character support.

Thanks "Eon S. Jeon" <esjeon@hyunmu.am>!
---
 TODO |  1 -
 st.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 68 insertions(+), 17 deletions(-)

diff --git a/TODO b/TODO
index 794b71b..0c538e5 100644
--- a/TODO
+++ b/TODO
@@ -1,7 +1,6 @@
 vt emulation
 ------------
 
-* wide-character support in conjunction with fallback xft code 
 * double-height support
 
 code & interface
diff --git a/st.c b/st.c
index 0fa0c86..96d45bf 100644
--- a/st.c
+++ b/st.c
@@ -27,6 +27,7 @@
 #include <X11/keysym.h>
 #include <X11/Xft/Xft.h>
 #include <fontconfig/fontconfig.h>
+#include <wchar.h>
 
 #include "arg.h"
 
@@ -96,6 +97,8 @@ enum glyph_attribute {
 	ATTR_ITALIC    = 16,
 	ATTR_BLINK     = 32,
 	ATTR_WRAP      = 64,
+	ATTR_WIDE      = 128,
+	ATTR_WDUMMY    = 256,
 };
 
 enum cursor_movement {
@@ -165,7 +168,7 @@ typedef unsigned short ushort;
 
 typedef struct {
 	char c[UTF_SIZ]; /* character code */
-	uchar mode;      /* attribute flags */
+	ushort mode;      /* attribute flags */
 	ulong fg;        /* foreground  */
 	ulong bg;        /* background  */
 } Glyph;
@@ -719,8 +722,13 @@ selsnap(int mode, int *x, int *y, int direction) {
 				}
 			}
 
+			if(term.line[*y][*x+direction].mode & ATTR_WDUMMY) {
+				*x += direction;
+				continue;
+			}
+
 			if(strchr(worddelimiters,
-					term.line[*y][*x + direction].c[0])) {
+					term.line[*y][*x+direction].c[0])) {
 				break;
 			}
 
@@ -932,7 +940,7 @@ selcopy(void) {
 				/* nothing */;
 
 			for(x = 0; gp <= last; x++, ++gp) {
-				if(!selected(x, y))
+				if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))
 					continue;
 
 				size = utf8size(gp->c);
@@ -1533,6 +1541,16 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 		}
 	}
 
+	if(term.line[y][x].mode & ATTR_WIDE) {
+		if(x+1 < term.col) {
+			term.line[y][x+1].c[0] = ' ';
+			term.line[y][x+1].mode &= ~ATTR_WDUMMY;
+		}
+	} else if(term.line[y][x].mode & ATTR_WDUMMY) {
+		term.line[y][x-1].c[0] = ' ';
+		term.line[y][x-1].mode &= ~ATTR_WIDE;
+	}
+
 	term.dirty[y] = 1;
 	term.line[y][x] = *attr;
 	memcpy(term.line[y][x].c, c, UTF_SIZ);
@@ -2222,6 +2240,15 @@ void
 tputc(char *c, int len) {
 	uchar ascii = *c;
 	bool control = ascii < '\x20' || ascii == 0177;
+	long u8char;
+	int width;
+
+	if(len == 1) {
+		width = 1;
+	} else {
+		utf8decode(c, &u8char);
+		width = wcwidth(u8char);
+	}
 
 	if(iofd != -1) {
 		if(xwrite(iofd, c, len) < 0) {
@@ -2469,9 +2496,20 @@ tputc(char *c, int len) {
 			(term.col - term.c.x - 1) * sizeof(Glyph));
 	}
 
+	if(term.c.x+width > term.col)
+		tnewline(1);
+
 	tsetchar(c, &term.c.attr, term.c.x, term.c.y);
-	if(term.c.x+1 < term.col) {
-		tmoveto(term.c.x+1, term.c.y);
+
+	if(width == 2) {
+		term.line[term.c.y][term.c.x].mode |= ATTR_WIDE;
+		if(term.c.x+1 < term.col) {
+			term.line[term.c.y][term.c.x+1].c[0] = '\0';
+			term.line[term.c.y][term.c.x+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;
 	}
@@ -3173,7 +3211,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 				xp, winy + frc[i].font->ascent,
 				(FcChar8 *)u8c, u8cblen);
 
-		xp += xw.cw;
+		xp += xw.cw * wcwidth(u8char);
 	}
 
 	/*
@@ -3193,18 +3231,27 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 void
 xdrawcursor(void) {
 	static int oldx = 0, oldy = 0;
-	int sl;
+	int sl, width, curx;
 	Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs};
 
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
 
+	curx = term.c.x;
+
+	/* adjust position if in dummy */
+	if(term.line[oldy][oldx].mode & ATTR_WDUMMY)
+		oldx--;
+	if(term.line[term.c.y][curx].mode & ATTR_WDUMMY)
+		curx--;
+
 	memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
 
 	/* remove the old cursor */
 	sl = utf8size(term.line[oldy][oldx].c);
+	width = (term.line[oldy][oldx].mode & ATTR_WIDE)? 2 : 1;
 	xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx,
-			oldy, 1, sl);
+			oldy, width, sl);
 
 	/* draw the new one */
 	if(!(IS_SET(MODE_HIDE))) {
@@ -3216,26 +3263,28 @@ xdrawcursor(void) {
 			}
 
 			sl = utf8size(g.c);
-			xdraws(g.c, g, term.c.x, term.c.y, 1, sl);
+			width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\
+				? 2 : 1;
+			xdraws(g.c, g, term.c.x, term.c.y, width, sl);
 		} else {
 			XftDrawRect(xw.draw, &dc.col[defaultcs],
-					borderpx + term.c.x * xw.cw,
+					borderpx + curx * xw.cw,
 					borderpx + term.c.y * xw.ch,
 					xw.cw - 1, 1);
 			XftDrawRect(xw.draw, &dc.col[defaultcs],
-					borderpx + term.c.x * xw.cw,
+					borderpx + curx * xw.cw,
 					borderpx + term.c.y * xw.ch,
 					1, xw.ch - 1);
 			XftDrawRect(xw.draw, &dc.col[defaultcs],
-					borderpx + (term.c.x + 1) * xw.cw - 1,
+					borderpx + (curx + 1) * xw.cw - 1,
 					borderpx + term.c.y * xw.ch,
 					1, xw.ch - 1);
 			XftDrawRect(xw.draw, &dc.col[defaultcs],
-					borderpx + term.c.x * xw.cw,
+					borderpx + curx * xw.cw,
 					borderpx + (term.c.y + 1) * xw.ch - 1,
 					xw.cw, 1);
 		}
-		oldx = term.c.x, oldy = term.c.y;
+		oldx = curx, oldy = term.c.y;
 	}
 }
 
@@ -3284,6 +3333,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
 	bool ena_sel = sel.ob.x != -1;
+	long u8char;
 
 	if(sel.alt ^ IS_SET(MODE_ALTSCREEN))
 		ena_sel = 0;
@@ -3301,6 +3351,8 @@ drawregion(int x1, int y1, int x2, int y2) {
 		ic = ib = ox = 0;
 		for(x = x1; x < x2; x++) {
 			new = term.line[y][x];
+			if(new.mode == ATTR_WDUMMY)
+				continue;
 			if(ena_sel && selected(x, y))
 				new.mode ^= ATTR_REVERSE;
 			if(ib > 0 && (ATTRCMP(base, new)
@@ -3313,10 +3365,10 @@ drawregion(int x1, int y1, int x2, int y2) {
 				base = new;
 			}
 
-			sl = utf8size(new.c);
+			sl = utf8decode(new.c, &u8char);
 			memcpy(buf+ib, new.c, sl);
 			ib += sl;
-			++ic;
+			ic += (new.mode & ATTR_WIDE)? 2 : 1;
 		}
 		if(ib > 0)
 			xdraws(buf, base, ox, y, ic, ib);

From bef599bb279e6c9b08853ceebefade066e362c48 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <rvargas@bsccs347.bsc.es>
Date: Thu, 12 Sep 2013 20:41:34 +0200
Subject: [PATCH 0574/1146] Add audible bell

\a is the character for bell, and st is only marking the window as urgent
if it is not active. This patch adds an audible bell which can be disable
with bellvolume variable.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 config.def.h | 6 ++++++
 st.c         | 2 ++
 2 files changed, 8 insertions(+)

diff --git a/config.def.h b/config.def.h
index 24aeb19..6487406 100644
--- a/config.def.h
+++ b/config.def.h
@@ -37,6 +37,12 @@ static unsigned int actionfps = 30;
  */
 static unsigned int blinktimeout = 800;
 
+/*
+ * bell volume. It must be a value between -100 and 100. Use 0 for disabling
+ * it
+ */
+static int bellvolume = 1;
+
 /* TERM value */
 static char termname[] = "st-256color";
 
diff --git a/st.c b/st.c
index 96d45bf..4a91073 100644
--- a/st.c
+++ b/st.c
@@ -2320,6 +2320,8 @@ tputc(char *c, int len) {
 		case '\a':   /* BEL */
 			if(!(xw.state & WIN_FOCUSED))
 				xseturgency(1);
+			if (bellvolume)
+				XBell(xw.dpy, bellvolume);
 			return;
 		case '\033': /* ESC */
 			csireset();

From cc2ea3147accc342f4d411b42c8cae5b883b1224 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 12 Sep 2013 20:52:10 +0200
Subject: [PATCH 0575/1146] Default volume of the bell is 0.

---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 6487406..def6c9e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -41,7 +41,7 @@ static unsigned int blinktimeout = 800;
  * bell volume. It must be a value between -100 and 100. Use 0 for disabling
  * it
  */
-static int bellvolume = 1;
+static int bellvolume = 0;
 
 /* TERM value */
 static char termname[] = "st-256color";

From eae31a532e1c3249abe3fe0dbce286cac263832f Mon Sep 17 00:00:00 2001
From: Michael Forney <mforney@mforney.org>
Date: Thu, 25 Jul 2013 16:19:19 -0700
Subject: [PATCH 0576/1146] Fix some bugs in mouse tracking logic

* Button number in X10 mode:

  I believe the button - 1 came from "C b is button - 1" from [0].
  However, above this section, it states

    "Normally, parameters (such as pointer poisition and button number)
     for all mouse tracking escape sequences generated by xterm encode
     numeric parameters in a single character as value+32. For example, !
     specifies the value 1."

  Also, from the description of SGR,

    "The encoded button value in this case does not add 32 since that
     was useful only in the X10 scheme for ensuring that the byte
     containing the button value is a printable code."

  This suggests that we should still add 32 to the button value when in
  MODE_MOUSEX10.

* No button release reporting in X10 mode:

    "X10 compatibility mode sends an escape sequence only on button press,
     encoding the location and the mouse button pressed."

* Fix MODE_MOUSEMOTION:

  Currently, motion reporting is skipped when oldbutton == 3
  (corresponding to no button being pressed). However, oldbutton is
  only set on a button press, which will never be 3.

[0]: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
---
 st.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index 4a91073..3321c31 100644
--- a/st.c
+++ b/st.c
@@ -823,18 +823,23 @@ mousereport(XEvent *e) {
 		button = oldbutton + 32;
 		ox = x;
 		oy = y;
-	} else if(!IS_SET(MODE_MOUSESGR)
-			&& (e->xbutton.type == ButtonRelease
-				|| button == AnyButton)) {
-		button = 3;
 	} else {
-		button -= Button1;
-		if(button >= 3)
-			button += 64 - 3;
+		if(!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
+			button = 3;
+		} else {
+			button -= Button1;
+			if(button >= 3)
+				button += 64 - 3;
+		}
 		if(e->xbutton.type == ButtonPress) {
 			oldbutton = button;
 			ox = x;
 			oy = y;
+		} else if(e->xbutton.type == ButtonRelease) {
+			oldbutton = 3;
+			/* MODE_MOUSEX10: no button release reporting */
+			if(IS_SET(MODE_MOUSEX10))
+				return;
 		}
 	}
 
@@ -851,8 +856,7 @@ mousereport(XEvent *e) {
 				e->xbutton.type == ButtonRelease ? 'm' : 'M');
 	} else if(x < 223 && y < 223) {
 		len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
-				IS_SET(MODE_MOUSEX10)? button-1 : 32+button,
-				32+x+1, 32+y+1);
+				32+button, 32+x+1, 32+y+1);
 	} else {
 		return;
 	}

From 8ac0a5f872b0024bab161fa020126013724758ba Mon Sep 17 00:00:00 2001
From: Egmont Koblinger <egmont@gmail.com>
Date: Mon, 23 Sep 2013 09:22:47 +0200
Subject: [PATCH 0577/1146] Add bracketed paste mode

This patch enables bracketed paste mode (
http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Bracketed%20Paste%20Mode
).

It's mainly useful for text editors to disable line wrapping and auto
indentation when text is being pasted, rather than typed from keyboard.

On the emulator side, it is supported by at least xterm, urxvt,
gnome-terminal, putty, iterm2; and I have a patch for konsole.

On the application side, vim can be configured easily to handle this, and
I have pending patches for mcedit and joe. Probably many others also
support it.
---
 st.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/st.c b/st.c
index 3321c31..df58e9e 100644
--- a/st.c
+++ b/st.c
@@ -132,6 +132,7 @@ enum term_mode {
 	MODE_FOCUS       = 65536,
 	MODE_MOUSEX10    = 131072,
 	MODE_MOUSEMANY   = 262144,
+	MODE_BRCKTPASTE  = 524288,
 	MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
 	                  |MODE_MOUSEMANY,
 };
@@ -1013,7 +1014,11 @@ selnotify(XEvent *e) {
 			*repl++ = '\r';
 		}
 
+		if(IS_SET(MODE_BRCKTPASTE))
+			ttywrite("\033[200~", 6);
 		ttywrite((const char *)data, nitems * format / 8);
+		if(IS_SET(MODE_BRCKTPASTE))
+			ttywrite("\033[201~", 6);
 		XFree(data);
 		/* number of 32-bit chunks returned */
 		ofs += nitems * format / 32;
@@ -1868,6 +1873,9 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 1048:
 				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
 				break;
+			case 2004: /* 2004: bracketed paste mode */
+				MODBIT(term.mode, set, MODE_BRCKTPASTE);
+				break;
 			/* Not implemented mouse modes. See comments there. */
 			case 1001: /* mouse highlight mode; can hang the
 				      terminal by design when implemented. */

From eeae9b0ceef9e2fec4cb4f1132748c302e5ac702 Mon Sep 17 00:00:00 2001
From: Maurice Quennet <mjq@gmx.net>
Date: Sat, 21 Sep 2013 23:33:56 +0200
Subject: [PATCH 0578/1146] Fix core in multi-line selection on OpenBSD

OpenBSD 5.3 amd64 release version with the most current st
version from git, crash and dump core when selecting multiple
lines whith the cursor.  This happens, because on line 964
of st.c (gp-1)->mode is accessed, although gp is still
pointing at the beginning of the array term.line[y] (see
line 939 for initialization of gp).
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index df58e9e..c3a04c5 100644
--- a/st.c
+++ b/st.c
@@ -962,7 +962,7 @@ selcopy(void) {
 			 * st.
 			 * FIXME: Fix the computer world.
 			 */
-			if(y < sel.ne.y && !((gp-1)->mode & ATTR_WRAP))
+			if(y < sel.ne.y && x > 0 && !((gp-1)->mode & ATTR_WRAP))
 				*ptr++ = '\n';
 
 			/*

From 2b1bc8087f232a7b0ba4c7233e76be7abae25a88 Mon Sep 17 00:00:00 2001
From: Mihail Zenkov <mihail.zenkov@gmail.com>
Date: Tue, 1 Oct 2013 20:01:15 +0200
Subject: [PATCH 0579/1146] Add DSR cursor position sequence

---
 st.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/st.c b/st.c
index c3a04c5..05e285c 100644
--- a/st.c
+++ b/st.c
@@ -2067,6 +2067,13 @@ csihandle(void) {
 	case 'm': /* SGR -- Terminal attribute (color) */
 		tsetattr(csiescseq.arg, csiescseq.narg);
 		break;
+	case 'n': /* DSR – Device Status Report (cursor position) */
+		if (csiescseq.arg[0] == 6) {
+			char buf[40];
+			int len = snprintf(buf, sizeof(buf),"\033[%i;%iR", term.c.y+1, term.c.x+1);
+			ttywrite(buf, len);
+			break;
+		}
 	case 'r': /* DECSTBM -- Set Scrolling Region */
 		if(csiescseq.priv) {
 			goto unknown;

From 62ab938965f2673e029ae2e2a4244788e673bd70 Mon Sep 17 00:00:00 2001
From: Mihail Zenkov <mihail.zenkov@gmail.com>
Date: Tue, 1 Oct 2013 20:02:24 +0200
Subject: [PATCH 0580/1146] Fix save/restore cursor

st was assuming that save/restore cursor position was independent
of the screen that was shown in each moment, but it is not true,
because each screen has a different save/restore buffer. This
patch fixes it.
---
 st.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index 05e285c..12fcc90 100644
--- a/st.c
+++ b/st.c
@@ -1342,13 +1342,14 @@ tfulldirt(void) {
 
 void
 tcursor(int mode) {
-	static TCursor c;
+	static TCursor c[2];
+	bool alt = IS_SET(MODE_ALTSCREEN);
 
 	if(mode == CURSOR_SAVE) {
-		c = term.c;
+		c[alt] = term.c;
 	} else if(mode == CURSOR_LOAD) {
-		term.c = c;
-		tmoveto(c.x, c.y);
+		term.c = c[alt];
+		tmoveto(c[alt].x, c[alt].y);
 	}
 }
 
@@ -1854,12 +1855,12 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 			case 1034:
 				MODBIT(term.mode, set, MODE_8BIT);
 				break;
-			case 1049: /* = 1047 and 1048 */
-			case 47:
+			case 1049: /* swap screen & set/restore cursor as xterm */
+				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
+			case 47: /* swap screen */
 			case 1047:
 				if (!allowaltscreen)
 					break;
-
 				alt = IS_SET(MODE_ALTSCREEN);
 				if(alt) {
 					tclearregion(0, 0, term.col-1,

From c5c2365ab7c7ac2671b6e7d31cc9b0d41636393c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 2 Oct 2013 21:06:50 +0200
Subject: [PATCH 0581/1146] People, learn to keep to styles. Thanks.

---
 st.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 12fcc90..84f9abb 100644
--- a/st.c
+++ b/st.c
@@ -1920,6 +1920,9 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 
 void
 csihandle(void) {
+	char buf[40];
+	int len;
+
 	switch(csiescseq.mode) {
 	default:
 	unknown:
@@ -2070,8 +2073,8 @@ csihandle(void) {
 		break;
 	case 'n': /* DSR – Device Status Report (cursor position) */
 		if (csiescseq.arg[0] == 6) {
-			char buf[40];
-			int len = snprintf(buf, sizeof(buf),"\033[%i;%iR", term.c.y+1, term.c.x+1);
+			len = snprintf(buf, sizeof(buf),"\033[%i;%iR",
+					term.c.y+1, term.c.x+1);
 			ttywrite(buf, len);
 			break;
 		}

From 7a4eefe87cb7661c8a77286d05b6c3afb467f806 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 1 Oct 2013 21:23:11 +0200
Subject: [PATCH 0582/1146] Add support for multiple charset definitions

vt100 has support for two defined charset, G0 and G1. Each charset
can be defined, but in each moment is selected only one of both
charset. This is usually used selecting a national charset in G0
and graphic charset in G1, so you can switch between graphic
charset and text charset without losing the national charset
already defined.

st hasn't support for national charsets, because it is an utf8
based terminal emulator, but it has support for graphic
charset because it is heavily used, but it only supports G0,
without understanding G1 selection sequences, which causes some
programs in some moments can print some garbage in the screen.

This patch adds a fake support for multiple charset definitions,
where we only support graphic charset and us-ascii charset, but
we allow more of one charset definition.

This patch allow define G0 until G3 charsets, but only accepts
select G0 or G1, and it accepts some national charset definitions
but all of them are mapped to us-ascii.
---
 st.c | 82 ++++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 55 insertions(+), 27 deletions(-)

diff --git a/st.c b/st.c
index 84f9abb..77ea0c8 100644
--- a/st.c
+++ b/st.c
@@ -137,6 +137,16 @@ enum term_mode {
 	                  |MODE_MOUSEMANY,
 };
 
+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,
@@ -216,6 +226,9 @@ typedef struct {
 	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 */
 	bool numlock; /* lock numbers in keyboard */
 	bool *tabs;
 } Term;
@@ -367,6 +380,8 @@ static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 static void techo(char *, int);
 static long tdefcolor(int *, int *, int);
+static void tselcs(void);
+static void tdeftran(char);
 static inline bool match(uint, uint);
 static void ttynew(void);
 static void ttyread(void);
@@ -1369,6 +1384,8 @@ treset(void) {
 	term.top = 0;
 	term.bot = term.row - 1;
 	term.mode = MODE_WRAP;
+	memset(term.trantbl, sizeof(term.trantbl), CS_USA);
+	term.charset = 0;
 
 	tclearregion(0, 0, term.col-1, term.row-1);
 	tmoveto(0, 0);
@@ -2259,6 +2276,33 @@ techo(char *buf, int len) {
 		tputc(buf, len);
 }
 
+void
+tdeftran(char ascii) {
+	char c, (*bp)[2];
+	static char tbl[][2] = {
+		{'0', CS_GRAPHIC0}, {'1', CS_GRAPHIC1}, {'A', CS_UK},
+		{'B', CS_USA},      {'<', CS_MULTI},    {'K', CS_GER},
+		{'5', CS_FIN},      {'C', CS_FIN},
+		{0, 0}
+	};
+
+	for (bp = &tbl[0]; (c = (*bp)[0]) && c != ascii; ++bp)
+		/* nothing */;
+
+	if (c == 0)
+		fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
+	else
+		term.trantbl[term.icharset] = (*bp)[1];
+}
+
+void
+tselcs(void) {
+	if (term.trantbl[term.charset] == CS_GRAPHIC0)
+		term.c.attr.mode |= ATTR_GFX;
+	else
+		term.c.attr.mode &= ~ATTR_GFX;
+}
+
 void
 tputc(char *c, int len) {
 	uchar ascii = *c;
@@ -2351,13 +2395,12 @@ tputc(char *c, int len) {
 			term.esc = ESC_START;
 			return;
 		case '\016': /* SO */
+			term.charset = 0;
+			tselcs();
+			return;
 		case '\017': /* SI */
-			/*
-			 * Different charsets are hard to handle. Applications
-			 * should use the right alt charset escapes for the
-			 * only reason they still exist: line drawing. The
-			 * rest is incompatible history st should not support.
-			 */
+			term.charset = 1;
+			tselcs();
 			return;
 		case '\032': /* SUB */
 		case '\030': /* CAN */
@@ -2385,22 +2428,8 @@ tputc(char *c, int len) {
 			if(ascii == '\\')
 				strhandle();
 		} else if(term.esc & ESC_ALTCHARSET) {
-			switch(ascii) {
-			case '0': /* Line drawing set */
-				term.c.attr.mode |= ATTR_GFX;
-				break;
-			case 'B': /* USASCII */
-				term.c.attr.mode &= ~ATTR_GFX;
-				break;
-			case 'A': /* UK (IGNORED) */
-			case '<': /* multinational charset (IGNORED) */
-			case '5': /* Finnish (IGNORED) */
-			case 'C': /* Finnish (IGNORED) */
-			case 'K': /* German (IGNORED) */
-				break;
-			default:
-				fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
-			}
+			tdeftran(ascii);
+			tselcs();
 			term.esc = 0;
 		} else if(term.esc & ESC_TEST) {
 			if(ascii == '8') { /* DEC screen alignment test. */
@@ -2431,13 +2460,12 @@ tputc(char *c, int len) {
 				term.esc |= ESC_STR;
 				break;
 			case '(': /* set primary charset G0 */
+			case ')': /* set secondary charset G1 */
+			case '*': /* set tertiary charset G2 */
+			case '+': /* set quaternary charset G3 */
+				term.icharset = ascii - '(';
 				term.esc |= ESC_ALTCHARSET;
 				break;
-			case ')': /* set secondary charset G1 (IGNORED) */
-			case '*': /* set tertiary charset G2 (IGNORED) */
-			case '+': /* set quaternary charset G3 (IGNORED) */
-				term.esc = 0;
-				break;
 			case 'D': /* IND -- Linefeed */
 				if(term.c.y == term.bot) {
 					tscrollup(term.top, 1);

From 02ae3ce6fdc178ca6eb9b10b6447bb56a6513a27 Mon Sep 17 00:00:00 2001
From: Mark Edgar <medgar123@gmail.com>
Date: Sat, 5 Oct 2013 11:45:17 +0200
Subject: [PATCH 0583/1146] Simplify Mod1 logic in kpress(), eliminating locals
 and a memcpy.

---
 st.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/st.c b/st.c
index 77ea0c8..331509f 100644
--- a/st.c
+++ b/st.c
@@ -3563,8 +3563,8 @@ void
 kpress(XEvent *ev) {
 	XKeyEvent *e = &ev->xkey;
 	KeySym ksym;
-	char xstr[31], buf[32], *customkey, *cp = buf;
-	int len, ret;
+	char buf[32], *customkey;
+	int len;
 	long c;
 	Status status;
 	Shortcut *bp;
@@ -3572,7 +3572,7 @@ kpress(XEvent *ev) {
 	if(IS_SET(MODE_KBDLOCK))
 		return;
 
-	len = XmbLookupString(xw.xic, e, xstr, sizeof(xstr), &ksym, &status);
+	len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
 	e->state &= ~Mod2Mask;
 	/* 1. shortcuts */
 	for(bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
@@ -3586,26 +3586,23 @@ kpress(XEvent *ev) {
 	if((customkey = kmap(ksym, e->state))) {
 		len = strlen(customkey);
 		memcpy(buf, customkey, len);
-	/* 3. hardcoded (overrides X lookup) */
+	/* 3. composed string from input method */
 	} else {
 		if(len == 0)
 			return;
 
 		if(len == 1 && e->state & Mod1Mask) {
 			if(IS_SET(MODE_8BIT)) {
-				if(*xstr < 0177) {
-					c = *xstr | 0x80;
-					ret = utf8encode(&c, cp);
-					cp += ret;
-					len = 0;
+				if(*buf < 0177) {
+					c = *buf | 0x80;
+					len = utf8encode(&c, buf);
 				}
 			} else {
-				*cp++ = '\033';
+				buf[1] = buf[0];
+				buf[0] = '\033';
+				len = 2;
 			}
 		}
-
-		memcpy(cp, xstr, len);
-		len = cp - buf + len;
 	}
 
 	ttywrite(buf, len);

From 939e149544e4da958c333f3b6d00991d459c2e34 Mon Sep 17 00:00:00 2001
From: Mark Edgar <medgar123@gmail.com>
Date: Sat, 5 Oct 2013 11:45:44 +0200
Subject: [PATCH 0584/1146] Avoid buffer overrun in kpress() and remove limit
 on shortcut strings.

---
 st.c | 39 ++++++++++++++++++++-------------------
 1 file changed, 20 insertions(+), 19 deletions(-)

diff --git a/st.c b/st.c
index 331509f..16bf68b 100644
--- a/st.c
+++ b/st.c
@@ -264,7 +264,7 @@ typedef struct {
 typedef struct {
 	KeySym k;
 	uint mask;
-	char s[ESC_BUF_SIZ];
+	char *s;
 	/* three valued logic variables: 0 indifferent, 1 on, -1 off */
 	signed char appkey;    /* application keypad */
 	signed char appcursor; /* application cursor */
@@ -3585,26 +3585,27 @@ kpress(XEvent *ev) {
 	/* 2. custom keys from config.h */
 	if((customkey = kmap(ksym, e->state))) {
 		len = strlen(customkey);
-		memcpy(buf, customkey, len);
-	/* 3. composed string from input method */
-	} else {
-		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(customkey, len);
+		if(IS_SET(MODE_ECHO))
+			techo(customkey, len);
+		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);
 	if(IS_SET(MODE_ECHO))
 		techo(buf, len);

From 8e577322a3a55abf2f8226218ec87a7eec7fc3b1 Mon Sep 17 00:00:00 2001
From: Mark Edgar <medgar123@gmail.com>
Date: Sat, 5 Oct 2013 11:49:35 +0200
Subject: [PATCH 0585/1146] New ttysend() function calls ttywrite() and
 techo(). Honor MODE_ECHO when pasting in selnotify().

---
 st.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/st.c b/st.c
index 16bf68b..9df6707 100644
--- a/st.c
+++ b/st.c
@@ -386,6 +386,7 @@ static inline bool match(uint, uint);
 static void ttynew(void);
 static void ttyread(void);
 static void ttyresize(void);
+static void ttysend(char *, size_t);
 static void ttywrite(const char *, size_t);
 
 static void xdraws(char *, Glyph, int, int, int, int);
@@ -893,9 +894,7 @@ bpress(XEvent *e) {
 	for(mk = mshortcuts; mk < mshortcuts + LEN(mshortcuts); mk++) {
 		if(e->xbutton.button == mk->b
 				&& match(mk->mask, e->xbutton.state)) {
-			ttywrite(mk->s, strlen(mk->s));
-			if(IS_SET(MODE_ECHO))
-				techo(mk->s, strlen(mk->s));
+			ttysend(mk->s, strlen(mk->s));
 			return;
 		}
 	}
@@ -1031,7 +1030,7 @@ selnotify(XEvent *e) {
 
 		if(IS_SET(MODE_BRCKTPASTE))
 			ttywrite("\033[200~", 6);
-		ttywrite((const char *)data, nitems * format / 8);
+		ttysend((char *)data, nitems * format / 8);
 		if(IS_SET(MODE_BRCKTPASTE))
 			ttywrite("\033[201~", 6);
 		XFree(data);
@@ -1299,6 +1298,13 @@ ttywrite(const char *s, size_t n) {
 		die("write error on tty: %s\n", SERRNO);
 }
 
+void
+ttysend(char *s, size_t n) {
+	ttywrite(s, n);
+	if(IS_SET(MODE_ECHO))
+		techo(s, n);
+}
+
 void
 ttyresize(void) {
 	struct winsize w;
@@ -3584,10 +3590,7 @@ kpress(XEvent *ev) {
 
 	/* 2. custom keys from config.h */
 	if((customkey = kmap(ksym, e->state))) {
-		len = strlen(customkey);
-		ttywrite(customkey, len);
-		if(IS_SET(MODE_ECHO))
-			techo(customkey, len);
+		ttysend(customkey, strlen(customkey));
 		return;
 	}
 
@@ -3606,9 +3609,7 @@ kpress(XEvent *ev) {
 			len = 2;
 		}
 	}
-	ttywrite(buf, len);
-	if(IS_SET(MODE_ECHO))
-		techo(buf, len);
+	ttysend(buf, len);
 }
 
 

From 0f6942cdf6f8220f1ecd06e4b398e95c43833d44 Mon Sep 17 00:00:00 2001
From: Mark Edgar <medgar123@gmail.com>
Date: Sun, 6 Oct 2013 12:19:12 +0200
Subject: [PATCH 0586/1146] Avoid buffer overrun in bpress()

Use correct type for Mousekey.b (XButtonEvent.button).
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 9df6707..50b58a7 100644
--- a/st.c
+++ b/st.c
@@ -256,9 +256,9 @@ typedef struct {
 } XWindow;
 
 typedef struct {
-	int b;
+	uint b;
 	uint mask;
-	char s[ESC_BUF_SIZ];
+	char *s;
 } Mousekey;
 
 typedef struct {

From 297c886b72f4e9093973aaa14b66d392f6196634 Mon Sep 17 00:00:00 2001
From: Mark Edgar <medgar123@gmail.com>
Date: Sun, 22 Sep 2013 00:07:49 +0200
Subject: [PATCH 0587/1146] Ignore numlock (Mod2Mask) for button events too.

Conflicts:
	config.def.h
	st.c
---
 config.def.h | 6 +++---
 st.c         | 1 -
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index def6c9e..2a7e098 100644
--- a/config.def.h
+++ b/config.def.h
@@ -146,10 +146,10 @@ static Shortcut shortcuts[] = {
 static KeySym mappedkeys[] = { -1 };
 
 /*
- * Which bits of the state should be ignored. By default the state bit for the
- * keyboard layout (XK_SWITCH_MOD) is ignored.
+ * State bits to ignore when matching key or button events.  By default,
+ * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored.
  */
-uint ignoremod = XK_SWITCH_MOD;
+static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
 
 /* key, mask, output, keypad, cursor, crlf */
 static Key key[] = {
diff --git a/st.c b/st.c
index 50b58a7..12e1e1f 100644
--- a/st.c
+++ b/st.c
@@ -3579,7 +3579,6 @@ kpress(XEvent *ev) {
 		return;
 
 	len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
-	e->state &= ~Mod2Mask;
 	/* 1. shortcuts */
 	for(bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
 		if(ksym == bp->keysym && match(bp->mod, e->state)) {

From 489982d4b8442af25a380f8c22be542055cda81f Mon Sep 17 00:00:00 2001
From: Rob Pilling <rob@egbert>
Date: Wed, 19 Jun 2013 21:24:01 +0100
Subject: [PATCH 0588/1146] Fixed lock up when system time jumps backwards

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 50b58a7..d0a6218 100644
--- a/st.c
+++ b/st.c
@@ -3687,6 +3687,8 @@ run(void) {
 	gettimeofday(&last, NULL);
 
 	for(xev = actionfps;;) {
+		long deltatime;
+
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);
@@ -3720,8 +3722,9 @@ run(void) {
 			gettimeofday(&lastblink, NULL);
 			dodraw = 1;
 		}
-		if(TIMEDIFF(now, last) \
-				> (xev? (1000/xfps) : (1000/actionfps))) {
+		deltatime = TIMEDIFF(now, last);
+		if(deltatime > (xev? (1000/xfps) : (1000/actionfps))
+				|| deltatime < 0) {
 			dodraw = 1;
 			last = now;
 		}

From 1fa27b93f9a78ee78a35a5449bb8c4d0c3ef0f1b Mon Sep 17 00:00:00 2001
From: Mark Edgar <medgar123@gmail.com>
Date: Sat, 19 Oct 2013 14:56:40 +0200
Subject: [PATCH 0589/1146] Simplify logic in match().

---
 st.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/st.c b/st.c
index 8cfa2f7..da2ce3f 100644
--- a/st.c
+++ b/st.c
@@ -3501,15 +3501,7 @@ focus(XEvent *ev) {
 
 static inline bool
 match(uint mask, uint state) {
-	state &= ~ignoremod;
-
-	if(mask == XK_NO_MOD && state)
-		return false;
-	if(mask != XK_ANY_MOD && mask != XK_NO_MOD && !state)
-		return false;
-	if(mask == XK_ANY_MOD)
-		return true;
-	return state == mask;
+	return mask == XK_ANY_MOD || mask == (state & ~ignoremod);
 }
 
 void

From 7263820759aa914b27ab3097613bdf22432ed736 Mon Sep 17 00:00:00 2001
From: Mark Edgar <medgar123@gmail.com>
Date: Sat, 19 Oct 2013 15:13:13 +0200
Subject: [PATCH 0590/1146] Simplify logic in kmap().

---
 st.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index da2ce3f..fda7044 100644
--- a/st.c
+++ b/st.c
@@ -3531,25 +3531,16 @@ kmap(KeySym k, uint state) {
 		if(!match(kp->mask, state))
 			continue;
 
-		if(kp->appkey > 0) {
-			if(!IS_SET(MODE_APPKEYPAD))
-				continue;
-			if(term.numlock && kp->appkey == 2)
-				continue;
-		} else if(kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) {
+		if(IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0)
+			continue;
+		if(term.numlock && kp->appkey == 2)
 			continue;
-		}
 
-		if((kp->appcursor < 0 && IS_SET(MODE_APPCURSOR)) ||
-				(kp->appcursor > 0
-				 && !IS_SET(MODE_APPCURSOR))) {
+		if(IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0)
 			continue;
-		}
 
-		if((kp->crlf < 0 && IS_SET(MODE_CRLF)) ||
-				(kp->crlf > 0 && !IS_SET(MODE_CRLF))) {
+		if(IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0)
 			continue;
-		}
 
 		return kp->s;
 	}

From 4435e0ee6791136e641d58ce6cf00f8665fe3065 Mon Sep 17 00:00:00 2001
From: "Carlos J. Torres" <vlaadbrain@gmail.com>
Date: Fri, 22 Nov 2013 10:45:48 -0500
Subject: [PATCH 0591/1146] add _NET_WM_NAME

---
 st.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index fda7044..ee8dc94 100644
--- a/st.c
+++ b/st.c
@@ -239,7 +239,7 @@ typedef struct {
 	Colourmap cmap;
 	Window win;
 	Drawable buf;
-	Atom xembed, wmdeletewin;
+	Atom xembed, wmdeletewin, netwmname;
 	XIM xim;
 	XIC xic;
 	Draw draw;
@@ -3023,6 +3023,7 @@ xinit(void) {
 
 	xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
 	xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
+	xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False);
 	XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
 
 	xresettitle();
@@ -3355,6 +3356,7 @@ xsettitle(char *p) {
 	Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
 			&prop);
 	XSetWMName(xw.dpy, xw.win, &prop);
+	XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
 	XFree(prop.value);
 }
 

From 1fe0a5f39a8755da4cd16e92f2ea00676d9ee3ca Mon Sep 17 00:00:00 2001
From: Johannes Hofmann <johannes.hofmann@gmx.de>
Date: Sun, 24 Nov 2013 10:20:45 +0100
Subject: [PATCH 0592/1146] Use int instead of long for color

This patch replaces long by int32_t. It saves
some memory on 64bit systems.
---
 st.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index ee8dc94..fb084b1 100644
--- a/st.c
+++ b/st.c
@@ -180,8 +180,8 @@ typedef unsigned short ushort;
 typedef struct {
 	char c[UTF_SIZ]; /* character code */
 	ushort mode;      /* attribute flags */
-	ulong fg;        /* foreground  */
-	ulong bg;        /* background  */
+	uint32_t fg;      /* foreground  */
+	uint32_t bg;      /* background  */
 } Glyph;
 
 typedef Glyph *Line;
@@ -379,7 +379,7 @@ static void tsetdirtattr(int);
 static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 static void techo(char *, int);
-static long tdefcolor(int *, int *, int);
+static uint32_t tdefcolor(int *, int *, int);
 static void tselcs(void);
 static void tdeftran(char);
 static inline bool match(uint, uint);
@@ -1666,9 +1666,9 @@ tdeleteline(int n) {
 	tscrollup(term.c.y, n);
 }
 
-long
+uint32_t
 tdefcolor(int *attr, int *npar, int l) {
-	long idx = -1;
+	int32_t idx = -1;
 	uint r, g, b;
 
 	switch (attr[*npar + 1]) {
@@ -1717,7 +1717,7 @@ tdefcolor(int *attr, int *npar, int l) {
 void
 tsetattr(int *attr, int l) {
 	int i;
-	long idx;
+	int32_t idx;
 
 	for(i = 0; i < l; i++) {
 		switch(attr[i]) {

From 53474391bcf2122921d27356a70e6da3c78d058e Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 25 Nov 2013 14:09:53 +0100
Subject: [PATCH 0593/1146] Fix stupid bug in tdefcolor returning -1 in
 unsigned function

k0ga misktook applying patch of others. Sorry guys!!!!
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index fb084b1..8f1b8d8 100644
--- a/st.c
+++ b/st.c
@@ -379,7 +379,7 @@ static void tsetdirtattr(int);
 static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 static void techo(char *, int);
-static uint32_t tdefcolor(int *, int *, int);
+static int32_t tdefcolor(int *, int *, int);
 static void tselcs(void);
 static void tdeftran(char);
 static inline bool match(uint, uint);
@@ -1666,7 +1666,7 @@ tdeleteline(int n) {
 	tscrollup(term.c.y, n);
 }
 
-uint32_t
+int32_t
 tdefcolor(int *attr, int *npar, int l) {
 	int32_t idx = -1;
 	uint r, g, b;

From 08a3eea571f8e81b6820c18d30f9264b6ee6e08b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Rietz?= <rrietz@informatik.tu-cottbus.de>
Date: Mon, 25 Nov 2013 16:06:22 +0100
Subject: [PATCH 0594/1146] Add stdint include

Since st is using now int32_t and uint32_t the inclusion of
stdint or inttype is mandatory, because in other case the
definition of these new types will not be known by the
compiler.
---
 st.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index 8f1b8d8..91eb2cc 100644
--- a/st.c
+++ b/st.c
@@ -11,6 +11,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
+#include <stdint.h>
 #include <sys/ioctl.h>
 #include <sys/select.h>
 #include <sys/stat.h>

From 2738592de6d1b53e1f5aa896c8fd3bb5a4204749 Mon Sep 17 00:00:00 2001
From: Eric Pruitt <eric.pruitt@gmail.com>
Date: Fri, 6 Dec 2013 09:22:37 -0600
Subject: [PATCH 0595/1146] Fix rmul definition

rmul means "exit underline mode", so a full reset of all
the attributes is not the correct way of exiting from
underline mode, because it is going to modify also another
attributes not related.
---
 st.info | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.info b/st.info
index 94fce22..7526141 100644
--- a/st.info
+++ b/st.info
@@ -161,7 +161,7 @@ st| simpleterm,
 	rmir=\E[4l,
 	rmkx=\E[?1l\E>,
 	rmso=\E[27m,
-	rmul=\E[m,
+	rmul=\E[24m,
 	rs1=\Ec,
 	rs2=\E[4l\E>\E[?1034l,
 	sc=\E7,

From 39f28b18b76b9dc8353ae399cb8a99f13f9de2c2 Mon Sep 17 00:00:00 2001
From: Eric Pruitt <eric.pruitt@gmail.com>
Date: Wed, 11 Dec 2013 07:10:08 -0600
Subject: [PATCH 0596/1146] Set _NET_WM_PID attribute

---
 st.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 91eb2cc..f883ac1 100644
--- a/st.c
+++ b/st.c
@@ -240,7 +240,7 @@ typedef struct {
 	Colourmap cmap;
 	Window win;
 	Drawable buf;
-	Atom xembed, wmdeletewin, netwmname;
+	Atom xembed, wmdeletewin, netwmname, netwmpid;
 	XIM xim;
 	XIC xic;
 	Draw draw;
@@ -2933,6 +2933,7 @@ xinit(void) {
 	Cursor cursor;
 	Window parent;
 	int sw, sh;
+	pid_t thispid = getpid();
 
 	if(!(xw.dpy = XOpenDisplay(NULL)))
 		die("Can't open display\n");
@@ -3027,6 +3028,10 @@ xinit(void) {
 	xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False);
 	XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
 
+	xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False);
+	XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
+			PropModeReplace, (unsigned char *)&thispid, 1);
+
 	xresettitle();
 	XMapWindow(xw.dpy, xw.win);
 	xhints();

From fb8e3f67f7ca86e8118c731ed510345112a6d9d8 Mon Sep 17 00:00:00 2001
From: Mark Edgar <medgar123@gmail.com>
Date: Sun, 15 Dec 2013 16:45:51 +0100
Subject: [PATCH 0597/1146] Fix definition of F28 key.

Shitf modifier adds 12 to the function number of the function keys,
while Control adds 24, so Control + F4 generates F28
---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 2a7e098..ca49afd 100644
--- a/config.def.h
+++ b/config.def.h
@@ -281,7 +281,7 @@ static Key key[] = {
 	{ XK_F3, /* F63 */  Mod3Mask,       "\033[1;4R",     0,    0,    0},
 	{ XK_F4,            XK_NO_MOD,      "\033OS" ,       0,    0,    0},
 	{ XK_F4, /* F16 */  ShiftMask,      "\033[1;2S",     0,    0,    0},
-	{ XK_F4, /* F28 */  ShiftMask,      "\033[1;5S",     0,    0,    0},
+	{ XK_F4, /* F28 */  ControlMask,    "\033[1;5S",     0,    0,    0},
 	{ XK_F4, /* F40 */  Mod4Mask,       "\033[1;6S",     0,    0,    0},
 	{ XK_F4, /* F52 */  Mod1Mask,       "\033[1;3S",     0,    0,    0},
 	{ XK_F5,            XK_NO_MOD,      "\033[15~",      0,    0,    0},

From 6162d631517c892ec76663f6ac2b8e4d109fe2d4 Mon Sep 17 00:00:00 2001
From: Mark Edgar <medgar123@gmail.com>
Date: Sun, 20 Oct 2013 18:18:00 +0200
Subject: [PATCH 0598/1146] Fix comments in config.def.h to match field names.

---
 config.def.h | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/config.def.h b/config.def.h
index ca49afd..4c26ef5 100644
--- a/config.def.h
+++ b/config.def.h
@@ -97,7 +97,7 @@ static unsigned int defaultunderline = 7;
 /* Internal mouse shortcuts. */
 /* Beware that overloading Button1 will disable the selection. */
 static Mousekey mshortcuts[] = {
-	/* keysym		mask		string */
+	/* button		mask		string */
 	{ Button4,		XK_ANY_MOD,	"\031"},
 	{ Button5,		XK_ANY_MOD,	"\005"},
 };
@@ -106,7 +106,7 @@ static Mousekey mshortcuts[] = {
 #define MODKEY Mod1Mask
 
 static Shortcut shortcuts[] = {
-	/* modifier		key		function	argument */
+	/* mask			keysym		function	argument */
 	{ MODKEY|ShiftMask,	XK_Prior,	xzoom,		{.i = +1} },
 	{ MODKEY|ShiftMask,	XK_Next,	xzoom,		{.i = -1} },
 	{ ShiftMask,		XK_Insert,	selpaste,	{.i =  0} },
@@ -120,12 +120,12 @@ static Shortcut shortcuts[] = {
  * 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)
- * keypad value:
+ * appkey value:
  * * 0: no value
  * * > 0: keypad application mode enabled
  * *   = 2: term.numlock = 1
  * * < 0: keypad application mode disabled
- * cursor value:
+ * appcursor value:
  * * 0: no value
  * * > 0: cursor application mode enabled
  * * < 0: cursor application mode disabled
@@ -151,9 +151,8 @@ static KeySym mappedkeys[] = { -1 };
  */
 static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
 
-/* key, mask, output, keypad, cursor, crlf */
 static Key key[] = {
-	/* keysym             mask         string         keypad cursor crlf */
+	/* keysym           mask            string      appkey appcursor crlf */
 	{ XK_KP_Home,       ShiftMask,      "\033[1;2H",     0,    0,    0},
 	{ XK_KP_Home,       XK_ANY_MOD,     "\033[H",        0,   -1,    0},
 	{ XK_KP_Home,       XK_ANY_MOD,     "\033[1~",       0,   +1,    0},

From ef1dc9fc4bdfcd944b054c329bb5d51b8c52eb5c Mon Sep 17 00:00:00 2001
From: Mark Edgar <medgar123@gmail.com>
Date: Sun, 20 Oct 2013 19:16:33 +0200
Subject: [PATCH 0599/1146] Replace alignment tabs with spaces.

---
 config.def.h | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/config.def.h b/config.def.h
index 4c26ef5..986f6e2 100644
--- a/config.def.h
+++ b/config.def.h
@@ -97,21 +97,21 @@ static unsigned int defaultunderline = 7;
 /* Internal mouse shortcuts. */
 /* Beware that overloading Button1 will disable the selection. */
 static Mousekey mshortcuts[] = {
-	/* button		mask		string */
-	{ Button4,		XK_ANY_MOD,	"\031"},
-	{ Button5,		XK_ANY_MOD,	"\005"},
+	/* button               mask            string */
+	{ Button4,              XK_ANY_MOD,     "\031" },
+	{ Button5,              XK_ANY_MOD,     "\005" },
 };
 
 /* Internal keyboard shortcuts. */
 #define MODKEY Mod1Mask
 
 static Shortcut shortcuts[] = {
-	/* mask			keysym		function	argument */
-	{ MODKEY|ShiftMask,	XK_Prior,	xzoom,		{.i = +1} },
-	{ MODKEY|ShiftMask,	XK_Next,	xzoom,		{.i = -1} },
-	{ ShiftMask,		XK_Insert,	selpaste,	{.i =  0} },
-	{ MODKEY|ShiftMask,	XK_Insert,	clippaste,	{.i =  0} },
-	{ MODKEY,		XK_Num_Lock,	numlock,	{.i =  0} },
+	/* mask                 keysym          function        argument */
+	{ MODKEY|ShiftMask,     XK_Prior,       xzoom,          {.i = +1} },
+	{ MODKEY|ShiftMask,     XK_Next,        xzoom,          {.i = -1} },
+	{ ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
+	{ MODKEY|ShiftMask,     XK_Insert,      clippaste,      {.i =  0} },
+	{ MODKEY,               XK_Num_Lock,    numlock,        {.i =  0} },
 };
 
 /*

From d60ee7337b5f378d8858ef3774c5552d2c8e54fa Mon Sep 17 00:00:00 2001
From: "Eon S. Jeon" <esjeon@hyunmu.am>
Date: Tue, 17 Dec 2013 12:45:38 -0500
Subject: [PATCH 0600/1146] Prevent resizing stdin

This fixes a bug that the parent tty gets resized whenever you launch
st through command line.

The problem was that ioctl was resizing cmdfd before it gets
initialized in ttynew. Since cmdfd is a global variable, its initial
value is 0, and consequently stdin was being resized.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index f883ac1..4fb3311 100644
--- a/st.c
+++ b/st.c
@@ -3667,11 +3667,11 @@ run(void) {
 		}
 	}
 
+	ttynew();
 	if(!xw.isfixed)
 		cresize(w, h);
 	else
 		cresize(xw.fw, xw.fh);
-	ttynew();
 
 	gettimeofday(&lastblink, NULL);
 	gettimeofday(&last, NULL);

From 33da67dac035b0d592f984bce90aec8d815b38a8 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 18 Dec 2013 08:29:28 +0100
Subject: [PATCH 0601/1146] Update arg.h from sbase

sbase did some interesting modifications to arg.h (basically it
was fixed an incorrect use of the _ namespace), and this commit
take this last version for st.
---
 arg.h | 48 ++++++++++++++++++++++++++++--------------------
 1 file changed, 28 insertions(+), 20 deletions(-)

diff --git a/arg.h b/arg.h
index 2b189fe..4df77a7 100644
--- a/arg.h
+++ b/arg.h
@@ -3,53 +3,61 @@
  * by 20h
  */
 
-#ifndef __ARG_H__
-#define __ARG_H__
+#ifndef ARG_H__
+#define ARG_H__
 
 extern char *argv0;
 
-#define USED(x)		((void)(x))
-
 /* use main(int argc, char *argv[]) */
 #define ARGBEGIN	for (argv0 = *argv, argv++, argc--;\
 					argv[0] && argv[0][1]\
 					&& argv[0][0] == '-';\
 					argc--, argv++) {\
-				char _argc;\
-				char **_argv;\
-				int brk;\
+				char argc_;\
+				char **argv_;\
+				int brk_;\
 				if (argv[0][1] == '-' && argv[0][2] == '\0') {\
 					argv++;\
 					argc--;\
 					break;\
 				}\
-				for (brk = 0, argv[0]++, _argv = argv;\
-						argv[0][0] && !brk;\
+				for (brk_ = 0, argv[0]++, argv_ = argv;\
+						argv[0][0] && !brk_;\
 						argv[0]++) {\
-					if (_argv != argv)\
+					if (argv_ != argv)\
 						break;\
-					_argc = argv[0][0];\
-					switch (_argc)
+					argc_ = argv[0][0];\
+					switch (argc_)
+
+/* Handles obsolete -NUM syntax */
+#define ARGNUM				case '0':\
+					case '1':\
+					case '2':\
+					case '3':\
+					case '4':\
+					case '5':\
+					case '6':\
+					case '7':\
+					case '8':\
+					case '9'
 
 #define ARGEND			}\
-				USED(_argc);\
-			}\
-			USED(argv);\
-			USED(argc);
+			}
 
-#define ARGC()		_argc
+#define ARGC()		argc_
+
+#define ARGNUMF(base)	(brk_ = 1, estrtol(argv[0], (base)))
 
 #define EARGF(x)	((argv[0][1] == '\0' && argv[1] == NULL)?\
 				((x), abort(), (char *)0) :\
-				(brk = 1, (argv[0][1] != '\0')?\
+				(brk_ = 1, (argv[0][1] != '\0')?\
 					(&argv[0][1]) :\
 					(argc--, argv++, argv[0])))
 
 #define ARGF()		((argv[0][1] == '\0' && argv[1] == NULL)?\
 				(char *)0 :\
-				(brk = 1, (argv[0][1] != '\0')?\
+				(brk_ = 1, (argv[0][1] != '\0')?\
 					(&argv[0][1]) :\
 					(argc--, argv++, argv[0])))
 
 #endif
-

From e8dba89164fe70647a413b8568b545ff2d887a78 Mon Sep 17 00:00:00 2001
From: "Eon S. Jeon" <esjeon@hyunmu.am>
Date: Tue, 17 Dec 2013 15:14:19 -0500
Subject: [PATCH 0602/1146] query pixel size from matched font

Sorry for another duplicated mail. I found the patch is malformed
significantly. I've been away from my laptop for a while, so I'm quite
unfamiliar with the settings on this system...
---
 st.c | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index 4fb3311..82bfd3d 100644
--- a/st.c
+++ b/st.c
@@ -398,7 +398,7 @@ static void xinit(void);
 static void xloadcols(void);
 static int xsetcolorname(int, const char *);
 static int xloadfont(Font *, FcPattern *);
-static void xloadfonts(char *, int);
+static void xloadfonts(char *, double);
 static int xloadfontset(Font *);
 static void xsettitle(char *);
 static void xresettitle(void);
@@ -478,7 +478,7 @@ static char *opt_font = NULL;
 static int oldbutton = 3; /* button event on startup: 3 = release */
 
 static char *usedfont = NULL;
-static int usedfontsize = 0;
+static double usedfontsize = 0;
 
 /* Font Ring Cache */
 enum {
@@ -2826,9 +2826,9 @@ xloadfont(Font *f, FcPattern *pattern) {
 }
 
 void
-xloadfonts(char *fontstr, int fontsize) {
+xloadfonts(char *fontstr, double fontsize) {
 	FcPattern *pattern;
-	FcResult result;
+	FcResult r_sz, r_psz;
 	double fontval;
 
 	if(fontstr[0] == '-') {
@@ -2842,12 +2842,16 @@ xloadfonts(char *fontstr, int fontsize) {
 
 	if(fontsize > 0) {
 		FcPatternDel(pattern, FC_PIXEL_SIZE);
+		FcPatternDel(pattern, FC_SIZE);
 		FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize);
 		usedfontsize = fontsize;
 	} else {
-		result = FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval);
-		if(result == FcResultMatch) {
-			usedfontsize = (int)fontval;
+		r_psz = FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval);
+		r_sz = FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval);
+		if(r_psz == FcResultMatch) {
+			usedfontsize = fontval;
+		} else if(r_sz == FcResultMatch) {
+			usedfontsize = -1;
 		} else {
 			/*
 			 * Default font size is 12, if none given. This is to
@@ -2864,6 +2868,12 @@ xloadfonts(char *fontstr, int fontsize) {
 	if(xloadfont(&dc.font, pattern))
 		die("st: can't open font %s\n", fontstr);
 
+	if(usedfontsize < 0) {
+		FcPatternGetDouble(dc.font.match->pattern,
+		                   FC_PIXEL_SIZE, 0, &fontval);
+		usedfontsize = fontval;
+	}
+
 	/* Setting character width and height. */
 	xw.cw = CEIL(dc.font.width * cwscale);
 	xw.ch = CEIL(dc.font.height * chscale);

From 9df9a4723dedf4f5e12c954376c4931a6976b918 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= <amade@asmblr.net>
Date: Fri, 3 Jan 2014 15:24:24 +0100
Subject: [PATCH 0603/1146] Fix truecolor escapes, when both bg and fg are set
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

for example
echo -e "\e[48;2;255;0;0m\e[38;2;0;0;255m test "
should render on red bg with blue fg

also now elinks works correctly when using 'truecolor' option
in preferences

Signed-off-by: Amadeusz Sławiński <amade@asmblr.net>
---
 st.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.c b/st.c
index 82bfd3d..4d543d1 100644
--- a/st.c
+++ b/st.c
@@ -3083,6 +3083,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			base.fg = defaultunderline;
 	}
 	if(IS_TRUECOL(base.fg)) {
+		colfg.alpha = 0xffff;
 		colfg.red = TRUERED(base.fg);
 		colfg.green = TRUEGREEN(base.fg);
 		colfg.blue = TRUEBLUE(base.fg);
@@ -3093,6 +3094,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	}
 
 	if(IS_TRUECOL(base.bg)) {
+		colbg.alpha = 0xffff;
 		colbg.green = TRUEGREEN(base.bg);
 		colbg.red = TRUERED(base.bg);
 		colbg.blue = TRUEBLUE(base.bg);

From c0a56ef4be2a0f84360f41b2d45964e7ef297746 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= <amade@asmblr.net>
Date: Sat, 11 Jan 2014 12:54:36 +0100
Subject: [PATCH 0604/1146] Make w3mimgdisplay work with st
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Before this patch draw() calls drawregion which calls xdraws and then
updates whole window in one call thus overdrawing anything drawn by
w3mimgdisplay. After moving XCopyArea to xdraws it only updates the
regions which are being updated by XftDraw* functions. It may do a few
more calls to XCopyArea with this patch.

Signed-off-by: Amadeusz Sławiński <amade@asmblr.net>
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 4d543d1..48c81a2 100644
--- a/st.c
+++ b/st.c
@@ -3301,6 +3301,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1,
 				width, 1);
 	}
+	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, winx, winy, width,
+			font->ascent + font->descent, winx, winy);
 
 	/* Reset clip to none. */
 	XftDrawSetClip(xw.draw, 0);
@@ -3399,8 +3401,6 @@ redraw(int timeout) {
 void
 draw(void) {
 	drawregion(0, 0, term.col, term.row);
-	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
-			xw.h, 0, 0);
 	XSetForeground(xw.dpy, dc.gc,
 			dc.col[IS_SET(MODE_REVERSE)?
 				defaultfg : defaultbg].pixel);

From 95591001306dc5c6b57f46155bd3e2b919114ea6 Mon Sep 17 00:00:00 2001
From: Eric Pruitt <eric.pruitt@gmail.com>
Date: Sun, 19 Jan 2014 10:48:35 -0600
Subject: [PATCH 0605/1146] Use character scaling in XCopyArea

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 48c81a2..21afb52 100644
--- a/st.c
+++ b/st.c
@@ -3302,7 +3302,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 				width, 1);
 	}
 	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, winx, winy, width,
-			font->ascent + font->descent, winx, winy);
+			CEIL((font->ascent + font->descent) * chscale), winx, winy);
 
 	/* Reset clip to none. */
 	XftDrawSetClip(xw.draw, 0);

From d2173cd7162f89df4acaf9da8a30b5e5c0f2b9ab Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 31 Jan 2014 12:23:53 +0100
Subject: [PATCH 0606/1146] Fix SHIFT+DEL definition

The AppMode and AsciiMode were inverted in the definition of this
combination.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 config.def.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index 986f6e2..4664416 100644
--- a/config.def.h
+++ b/config.def.h
@@ -186,8 +186,8 @@ static Key key[] = {
 	{ XK_KP_Insert,     XK_ANY_MOD,     "\033[2~",      +1,    0,    0},
 	{ XK_KP_Delete,     ControlMask,    "\033[2J",      -1,    0,    0},
 	{ XK_KP_Delete,     ControlMask,    "\033[3;5~",    +1,    0,    0},
-	{ XK_KP_Delete,     ShiftMask,      "\033[2K",      +1,    0,    0},
-	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",    -1,    0,    0},
+	{ XK_KP_Delete,     ShiftMask,      "\033[2K",      -1,    0,    0},
+	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",    +1,    0,    0},
 	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[P",       -1,    0,    0},
 	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
 	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +2,    0,    0},
@@ -242,8 +242,8 @@ static Key key[] = {
 	{ XK_Insert,        XK_ANY_MOD,     "\033[2~",      +1,    0,    0},
 	{ XK_Delete,        ControlMask,    "\033[2J",      -1,    0,    0},
 	{ XK_Delete,        ControlMask,    "\033[3;5~",    +1,    0,    0},
-	{ XK_Delete,        ShiftMask,      "\033[2K",      +1,    0,    0},
-	{ XK_Delete,        ShiftMask,      "\033[3;2~",    -1,    0,    0},
+	{ XK_Delete,        ShiftMask,      "\033[2K",      -1,    0,    0},
+	{ XK_Delete,        ShiftMask,      "\033[3;2~",    +1,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,    0,    0},

From 9523233e257f72d07abdf3b07e5fd9ce0c7f31d0 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 31 Jan 2014 14:18:25 +0100
Subject: [PATCH 0607/1146] Make CONTROL + DELETE delete a line

If CONTROL + INSERT inserts a line then it seems natural CONTROL + DELETE
removes a line.
---
 config.def.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config.def.h b/config.def.h
index 4664416..d0fc186 100644
--- a/config.def.h
+++ b/config.def.h
@@ -184,7 +184,7 @@ static Key key[] = {
 	{ XK_KP_Insert,     ControlMask,    "\033[2;5~",    +1,    0,    0},
 	{ XK_KP_Insert,     XK_ANY_MOD,     "\033[4h",      -1,    0,    0},
 	{ XK_KP_Insert,     XK_ANY_MOD,     "\033[2~",      +1,    0,    0},
-	{ XK_KP_Delete,     ControlMask,    "\033[2J",      -1,    0,    0},
+	{ XK_KP_Delete,     ControlMask,    "\033[M",       -1,    0,    0},
 	{ XK_KP_Delete,     ControlMask,    "\033[3;5~",    +1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[2K",      -1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",    +1,    0,    0},
@@ -240,7 +240,7 @@ static Key key[] = {
 	{ XK_Insert,        ControlMask,    "\033[2;5~",    +1,    0,    0},
 	{ XK_Insert,        XK_ANY_MOD,     "\033[4h",      -1,    0,    0},
 	{ XK_Insert,        XK_ANY_MOD,     "\033[2~",      +1,    0,    0},
-	{ XK_Delete,        ControlMask,    "\033[2J",      -1,    0,    0},
+	{ XK_Delete,        ControlMask,    "\033[M",       -1,    0,    0},
 	{ XK_Delete,        ControlMask,    "\033[3;5~",    +1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[2K",      -1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",    +1,    0,    0},

From 21d905c076735783b41eec55f31d933129fd9f22 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 31 Jan 2014 16:54:58 +0100
Subject: [PATCH 0608/1146] Make Shift+Home equal to CLS in ascii mode

---
 config.def.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/config.def.h b/config.def.h
index d0fc186..b31d7d6 100644
--- a/config.def.h
+++ b/config.def.h
@@ -153,7 +153,8 @@ static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
 
 static Key key[] = {
 	/* keysym           mask            string      appkey appcursor crlf */
-	{ XK_KP_Home,       ShiftMask,      "\033[1;2H",     0,    0,    0},
+	{ XK_KP_Home,       ShiftMask,      "\033[2J",       0,   -1,    0},
+	{ XK_KP_Home,       ShiftMask,      "\033[1;2H",     0,   +1,    0},
 	{ XK_KP_Home,       XK_ANY_MOD,     "\033[H",        0,   -1,    0},
 	{ XK_KP_Home,       XK_ANY_MOD,     "\033[1~",       0,   +1,    0},
 	{ XK_KP_Up,         XK_ANY_MOD,     "\033Ox",       +1,    0,    0},
@@ -246,7 +247,8 @@ static Key key[] = {
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",    +1,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
-	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,    0,    0},
+	{ XK_Home,          ShiftMask,      "\033[2J",       0,   -1,    0},
+	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,   +1,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[1~",       0,   +1,    0},
 	{ XK_End,           ControlMask,    "\033[J",       -1,    0,    0},

From a8d5870073af14aa08032ab8520c5fe17bb8a1e8 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 31 Jan 2014 17:04:18 +0100
Subject: [PATCH 0609/1146] Remove duplicated code in strhandle

The error condition was duplicated in two different switches.
This new version centralized the error handling in only one place.
---
 st.c | 24 ++++++++++--------------
 1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index 21afb52..c59bf1d 100644
--- a/st.c
+++ b/st.c
@@ -2152,20 +2152,21 @@ csireset(void) {
 void
 strhandle(void) {
 	char *p = NULL;
-	int i, j, narg;
+	int j, narg, par;
 
 	strparse();
 	narg = strescseq.narg;
+	par = atoi(strescseq.args[0]);
 
 	switch(strescseq.type) {
 	case ']': /* OSC -- Operating System Command */
-		switch(i = atoi(strescseq.args[0])) {
+		switch(par) {
 		case 0:
 		case 1:
 		case 2:
 			if(narg > 1)
 				xsettitle(strescseq.args[1]);
-			break;
+			return;
 		case 4: /* color set */
 			if(narg < 3)
 				break;
@@ -2182,25 +2183,20 @@ strhandle(void) {
 				 */
 				redraw(0);
 			}
-			break;
-		default:
-			fprintf(stderr, "erresc: unknown str ");
-			strdump();
-			break;
+			return;
 		}
 		break;
 	case 'k': /* old title set compatibility */
 		xsettitle(strescseq.args[0]);
-		break;
+		return;
 	case 'P': /* DSC -- Device Control String */
 	case '_': /* APC -- Application Program Command */
 	case '^': /* PM -- Privacy Message */
-	default:
-		fprintf(stderr, "erresc: unknown str ");
-		strdump();
-		/* die(""); */
-		break;
+		return;
 	}
+
+	fprintf(stderr, "erresc: unknown str ");
+	strdump();
 }
 
 void

From 6521b5dc32d9bdc4d8826324cb7b2877910cc633 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 31 Jan 2014 17:30:00 +0100
Subject: [PATCH 0610/1146] Remove non defined behaviour in selcopy

It is not defined when lateral effects of expressions are
calculated, so an expression as:

	--last >= gp && !(selected(last - gp, y)

is non portable.
---
 st.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index c59bf1d..6e7077a 100644
--- a/st.c
+++ b/st.c
@@ -953,11 +953,12 @@ selcopy(void) {
 		/* append every set & selected glyph to the selection */
 		for(y = sel.nb.y; y < sel.ne.y + 1; y++) {
 			gp = &term.line[y][0];
-			last = gp + term.col;
+			last = &gp[term.col-1];
 
-			while(--last >= gp && !(selected(last - gp, y) && \
-						strcmp(last->c, " ") != 0))
-				/* nothing */;
+			while(last >= gp && !(selected(last - gp, y) &&
+			                      strcmp(last->c, " ") != 0)) {
+				--last;
+			}
 
 			for(x = 0; gp <= last; x++, ++gp) {
 				if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))

From c2026a495097a7e3bcfe4b58e1b9e393433cf150 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 3 Feb 2014 20:54:25 +0100
Subject: [PATCH 0611/1146] Removing the w3img support.

The patch to add w3img support destroys our way to handle fps and so stop
wasting resources on fast scrolling. Due to w3img being a hack to display
images in an ugly way, is there no need to support this. Use some real way to
display images.
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 21afb52..4d543d1 100644
--- a/st.c
+++ b/st.c
@@ -3301,8 +3301,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1,
 				width, 1);
 	}
-	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, winx, winy, width,
-			CEIL((font->ascent + font->descent) * chscale), winx, winy);
 
 	/* Reset clip to none. */
 	XftDrawSetClip(xw.draw, 0);
@@ -3401,6 +3399,8 @@ redraw(int timeout) {
 void
 draw(void) {
 	drawregion(0, 0, term.col, term.row);
+	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
+			xw.h, 0, 0);
 	XSetForeground(xw.dpy, dc.gc,
 			dc.col[IS_SET(MODE_REVERSE)?
 				defaultfg : defaultbg].pixel);

From cdb3b1892af40110660da8c3f6fc06b1b054fd12 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 1 Feb 2014 11:12:47 +0100
Subject: [PATCH 0612/1146] Add xstrdup function

Since we are using xmalloc, xrealloc ..., then it is not logical
call directly to strdup.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 37bec70..cad61bf 100644
--- a/st.c
+++ b/st.c
@@ -441,6 +441,7 @@ static int isfullutf8(char *, int);
 static ssize_t xwrite(int, char *, size_t);
 static void *xmalloc(size_t);
 static void *xrealloc(void *, size_t);
+static char *xstrdup(char *s);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
@@ -529,6 +530,16 @@ xrealloc(void *p, size_t len) {
 	return p;
 }
 
+char *
+xstrdup(char *s) {
+	char *p = strdup(s);
+
+	if (!p)
+		die("Out of memory\n");
+
+	return p;
+}
+
 int
 utf8decode(char *s, long *u) {
 	uchar c;
@@ -3789,7 +3800,7 @@ main(int argc, char *argv[]) {
 		if(argc > 1) {
 			opt_cmd = &argv[1];
 			if(argv[1] != NULL && opt_title == NULL) {
-				titles = strdup(argv[1]);
+				titles = xstrdup(argv[1]);
 				opt_title = basename(titles);
 			}
 		}

From 1f0d981bd7a1450ddfae3591c6e457253b3a6842 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 31 Jan 2014 20:57:09 +0100
Subject: [PATCH 0613/1146] Add MC sequence

This sequence control when the printer is enabled or disabled. This
sequence control the behaviour of the -o option.
---
 st.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index cad61bf..314bf3f 100644
--- a/st.c
+++ b/st.c
@@ -134,6 +134,7 @@ enum term_mode {
 	MODE_MOUSEX10    = 131072,
 	MODE_MOUSEMANY   = 262144,
 	MODE_BRCKTPASTE  = 524288,
+	MODE_PRINT       = 1048576,
 	MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
 	                  |MODE_MOUSEMANY,
 };
@@ -469,7 +470,7 @@ static STREscape strescseq;
 static int cmdfd;
 static pid_t pid;
 static Selection sel;
-static int iofd = -1;
+static int iofd;
 static char **opt_cmd = NULL;
 static char *opt_io = NULL;
 static char *opt_title = NULL;
@@ -1256,6 +1257,7 @@ ttynew(void) {
 		cmdfd = m;
 		signal(SIGCHLD, sigchld);
 		if(opt_io) {
+			term.mode |= MODE_PRINT;
 			iofd = (!strcmp(opt_io, "-")) ?
 				  STDOUT_FILENO :
 				  open(opt_io, O_WRONLY | O_CREAT, 0666);
@@ -1979,6 +1981,18 @@ csihandle(void) {
 		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:
+		case 1:
+		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(VT102ID, sizeof(VT102ID) - 1);
@@ -2332,7 +2346,7 @@ tputc(char *c, int len) {
 		width = wcwidth(u8char);
 	}
 
-	if(iofd != -1) {
+	if(IS_SET(MODE_PRINT) && iofd != -1) {
 		if(xwrite(iofd, c, len) < 0) {
 			fprintf(stderr, "Error writing in %s:%s\n",
 				opt_io, strerror(errno));

From d2ec39f0ef4b9d7f291aeba548a56144fce8a42f Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 1 Mar 2014 09:22:57 +0100
Subject: [PATCH 0614/1146] Style matters.

---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index cad61bf..9371b62 100644
--- a/st.c
+++ b/st.c
@@ -2801,7 +2801,8 @@ xhints(void) {
 		sizeh->min_height = sizeh->max_height = xw.fh;
 	}
 
-	XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, &class);
+	XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm,
+			&class);
 	XFree(sizeh);
 }
 

From 1584956a60f7739e46c5a0cd0e0e8295aa26071c Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 1 Mar 2014 11:04:03 +0100
Subject: [PATCH 0615/1146] Style cleanup.

Add some note about the main reason why st is still that big.
---
 st.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 9371b62..c16e45d 100644
--- a/st.c
+++ b/st.c
@@ -3091,6 +3091,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		if(base.fg == defaultfg)
 			base.fg = defaultunderline;
 	}
+
 	if(IS_TRUECOL(base.fg)) {
 		colfg.alpha = 0xffff;
 		colfg.red = TRUERED(base.fg);
@@ -3113,8 +3114,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		bg = &dc.col[base.bg];
 	}
 
-
-
 	if(base.mode & ATTR_BOLD) {
 		if(BETWEEN(base.fg, 0, 7)) {
 			/* basic system colors */
@@ -3144,7 +3143,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			colfg.green = ~fg->color.green;
 			colfg.blue = ~fg->color.blue;
 			colfg.alpha = fg->color.alpha;
-			XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg);
+			XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg,
+					&revfg);
 			fg = &revfg;
 		}
 
@@ -3155,7 +3155,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			colbg.green = ~bg->color.green;
 			colbg.blue = ~bg->color.blue;
 			colbg.alpha = bg->color.alpha;
-			XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &revbg);
+			XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg,
+					&revbg);
 			bg = &revbg;
 		}
 	}
@@ -3235,7 +3236,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			u8fblen += u8cblen;
 		}
 		if(doesexist) {
-			if (oneatatime)
+			if(oneatatime)
 				continue;
 			break;
 		}
@@ -3258,6 +3259,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			 * 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();
@@ -3301,6 +3304,12 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		xp += xw.cw * wcwidth(u8char);
 	}
 
+	/*
+	 * This is how the loop above actually should be. Why does the
+	 * application have to care about font details?
+	 *
+	 * I have to repeat: Xft and Fontconfig are design failures.
+	 */
 	/*
 	XftDrawStringUtf8(xw.draw, fg, font->set, winx,
 			winy + font->ascent, (FcChar8 *)s, bytelen);

From cf332a325dafe7e9ed6d87df9dcec29149c5042c Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 31 Jan 2014 21:53:53 +0100
Subject: [PATCH 0616/1146] Add MC for a single line

This sequence print the current line. It is different to the
'printer on' sequence, where all the characters that arrive to the
terminal are printer. Here only the ascii characters are printed.
---
 st.c | 41 ++++++++++++++++++++++++++++++++---------
 1 file changed, 32 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index 314bf3f..e60643c 100644
--- a/st.c
+++ b/st.c
@@ -356,6 +356,8 @@ static void strparse(void);
 static void strreset(void);
 
 static int tattrset(int);
+static void tprinter(char *s, size_t len);
+static void tdumpline(int);
 static void tclearregion(int, int, int, int);
 static void tcursor(int);
 static void tdeletechar(int);
@@ -470,7 +472,7 @@ static STREscape strescseq;
 static int cmdfd;
 static pid_t pid;
 static Selection sel;
-static int iofd;
+static int iofd = STDOUT_FILENO;
 static char **opt_cmd = NULL;
 static char *opt_io = NULL;
 static char *opt_title = NULL;
@@ -1985,6 +1987,8 @@ csihandle(void) {
 		switch(csiescseq.arg[0]) {
 		case 0:
 		case 1:
+			tdumpline(term.c.y);
+			break;
 		case 4:
 			term.mode &= ~MODE_PRINT;
 			break;
@@ -2265,6 +2269,31 @@ strreset(void) {
 	memset(&strescseq, 0, sizeof(strescseq));
 }
 
+void
+tprinter(char *s, size_t len) {
+	if(iofd != -1 && xwrite(iofd, s, len) < 0) {
+		fprintf(stderr, "Error writing in %s:%s\n",
+			opt_io, strerror(errno));
+		close(iofd);
+		iofd = -1;
+	}
+}
+
+void
+tdumpline(int n) {
+	Glyph *bp, *end;
+
+	bp = &term.line[n][0];
+	end = &bp[term.col-1];
+	while(end > bp && !strcmp(" ", end->c))
+		--end;
+	if(bp != end || strcmp(bp->c, " ")) {
+		for( ;bp <= end; ++bp)
+			tprinter(bp->c, strlen(bp->c));
+	}
+	tprinter("\n", 1);
+}
+
 void
 tputtab(bool forward) {
 	uint x = term.c.x;
@@ -2346,14 +2375,8 @@ tputc(char *c, int len) {
 		width = wcwidth(u8char);
 	}
 
-	if(IS_SET(MODE_PRINT) && iofd != -1) {
-		if(xwrite(iofd, c, len) < 0) {
-			fprintf(stderr, "Error writing in %s:%s\n",
-				opt_io, strerror(errno));
-			close(iofd);
-			iofd = -1;
-		}
-	}
+	if(IS_SET(MODE_PRINT))
+		tprinter(c, len);
 
 	/*
 	 * STR sequences must be checked before anything else

From 6166a1afc8c7875ce9ba62e5001040014269a26d Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 31 Jan 2014 22:25:51 +0100
Subject: [PATCH 0617/1146] Add MC for the full screen

This sequence is very useful because allows comunicate the content
of the terminal to another program.
---
 st.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/st.c b/st.c
index e60643c..1711842 100644
--- a/st.c
+++ b/st.c
@@ -358,6 +358,7 @@ static void strreset(void);
 static int tattrset(int);
 static void tprinter(char *s, size_t len);
 static void tdumpline(int);
+static void tdump(void);
 static void tclearregion(int, int, int, int);
 static void tcursor(int);
 static void tdeletechar(int);
@@ -1986,6 +1987,8 @@ csihandle(void) {
 	case 'i': /* MC -- Media Copy */
 		switch(csiescseq.arg[0]) {
 		case 0:
+			tdump();
+			break;
 		case 1:
 			tdumpline(term.c.y);
 			break;
@@ -2294,6 +2297,14 @@ tdumpline(int n) {
 	tprinter("\n", 1);
 }
 
+void
+tdump(void) {
+	int i;
+
+	for(i = 0; i < term.row; ++i)
+		tdumpline(i);
+}
+
 void
 tputtab(bool forward) {
 	uint x = term.c.x;

From 96c230e476a4fb446a8fa8d651c88fda32cd5427 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 31 Jan 2014 23:05:42 +0100
Subject: [PATCH 0618/1146] Add key definition for printer sequences

These new combinations generate the same behaviour (basically) of
vt102. It is a good way of communicating st with other programs.

[0] http://www.vt100.net/docs/vt102-ug/chapter2.html
---
 config.def.h |  2 ++
 st.c         | 12 ++++++++++++
 2 files changed, 14 insertions(+)

diff --git a/config.def.h b/config.def.h
index b31d7d6..47018a3 100644
--- a/config.def.h
+++ b/config.def.h
@@ -107,6 +107,8 @@ static Mousekey mshortcuts[] = {
 
 static Shortcut shortcuts[] = {
 	/* mask                 keysym          function        argument */
+	{ ControlMask,          XK_Print,       toggleprinter,  {.i =  0} },
+	{ ShiftMask,            XK_Print,       printscreen,    {.i =  0} },
 	{ MODKEY|ShiftMask,     XK_Prior,       xzoom,          {.i = +1} },
 	{ MODKEY|ShiftMask,     XK_Next,        xzoom,          {.i = -1} },
 	{ ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
diff --git a/st.c b/st.c
index 1711842..9f9c161 100644
--- a/st.c
+++ b/st.c
@@ -314,6 +314,8 @@ static void clippaste(const Arg *);
 static void numlock(const Arg *);
 static void selpaste(const Arg *);
 static void xzoom(const Arg *);
+static void printscreen(const Arg *) ;
+static void toggleprinter(const Arg *);
 
 /* Config.h for applying patches and the configuration. */
 #include "config.h"
@@ -2282,6 +2284,16 @@ tprinter(char *s, size_t len) {
 	}
 }
 
+void
+toggleprinter(const Arg *arg) {
+	term.mode ^= MODE_PRINT;
+}
+
+void
+printscreen(const Arg *arg) {
+	tdump();
+}
+
 void
 tdumpline(int n) {
 	Glyph *bp, *end;

From 78f8843bc7d6dc731f23d5ff3a8536fdcc5e4be6 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 1 Feb 2014 13:41:58 +0100
Subject: [PATCH 0619/1146] Add sequence for printing the current selection

This is very usefull in order to can select what is sent
to the plumber.
---
 config.def.h |  1 +
 st.c         | 32 +++++++++++++++++++++++++++++---
 2 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/config.def.h b/config.def.h
index 47018a3..58b470e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -109,6 +109,7 @@ static Shortcut shortcuts[] = {
 	/* mask                 keysym          function        argument */
 	{ ControlMask,          XK_Print,       toggleprinter,  {.i =  0} },
 	{ ShiftMask,            XK_Print,       printscreen,    {.i =  0} },
+	{ XK_ANY_MOD,           XK_Print,       printsel,       {.i =  0} },
 	{ MODKEY|ShiftMask,     XK_Prior,       xzoom,          {.i = +1} },
 	{ MODKEY|ShiftMask,     XK_Next,        xzoom,          {.i = -1} },
 	{ ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
diff --git a/st.c b/st.c
index 9f9c161..c97712c 100644
--- a/st.c
+++ b/st.c
@@ -314,6 +314,7 @@ static void clippaste(const Arg *);
 static void numlock(const Arg *);
 static void selpaste(const Arg *);
 static void xzoom(const Arg *);
+static void printsel(const Arg *);
 static void printscreen(const Arg *) ;
 static void toggleprinter(const Arg *);
 
@@ -359,6 +360,7 @@ static void strreset(void);
 
 static int tattrset(int);
 static void tprinter(char *s, size_t len);
+static void tdumpsel(void);
 static void tdumpline(int);
 static void tdump(void);
 static void tclearregion(int, int, int, int);
@@ -435,6 +437,7 @@ static void selrequest(XEvent *);
 static void selinit(void);
 static void selsort(void);
 static inline bool selected(int, int);
+static char *getsel(void);
 static void selcopy(void);
 static void selscroll(int, int);
 static void selsnap(int, int *, int *, int);
@@ -955,8 +958,8 @@ bpress(XEvent *e) {
 	}
 }
 
-void
-selcopy(void) {
+char *
+getsel(void) {
 	char *str, *ptr;
 	int x, y, bufsize, size, i, ex;
 	Glyph *gp, *last;
@@ -1015,7 +1018,12 @@ selcopy(void) {
 		}
 		*ptr = 0;
 	}
-	xsetsel(str);
+	return str;
+}
+
+void
+selcopy(void) {
+	xsetsel(getsel());
 }
 
 void
@@ -1994,6 +2002,9 @@ csihandle(void) {
 		case 1:
 			tdumpline(term.c.y);
 			break;
+		case 2:
+			tdumpsel();
+			break;
 		case 4:
 			term.mode &= ~MODE_PRINT;
 			break;
@@ -2294,6 +2305,21 @@ printscreen(const Arg *arg) {
 	tdump();
 }
 
+void
+printsel(const Arg *arg) {
+	tdumpsel();
+}
+
+void
+tdumpsel(void)
+{
+	char *ptr;
+
+	ptr = getsel();
+	tprinter(ptr, strlen(ptr));
+	free(ptr);
+}
+
 void
 tdumpline(int n) {
 	Glyph *bp, *end;

From 85f8a414be21ed4d7df153763a1cf679814c72cd Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 1 Feb 2014 11:11:11 +0100
Subject: [PATCH 0620/1146] Add terminfo entries for printer

These capabilities inform to programs how print in local printer
of the terminal.
---
 st.info | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.info b/st.info
index 7526141..4e60a89 100644
--- a/st.info
+++ b/st.info
@@ -152,6 +152,9 @@ st| simpleterm,
 	ncv#3,
 	op=\E[39;49m,
 	pairs#64,
+	mc0=\E[i,
+	mc4=\E[4i,
+	mc5=\E[5i,
 	rc=\E8,
 	rev=\E[7m,
 	ri=\EM,

From 45b808b88ee63f21a188800ba3473a24a3c4b987 Mon Sep 17 00:00:00 2001
From: Damian Okrasa <dokrasa@gmail.com>
Date: Tue, 25 Mar 2014 20:20:26 +0100
Subject: [PATCH 0621/1146] new utf decoder

This patch replaces current utf decoder with a new one, which is ~50
lines shorter and should be easier to understand. Parsing 5 and 6
sequences, if necessary, requires trivial modification of UTF_SIZ
constant and utfbyte, utfmask, utfmin, utfmax arrays.
---
 st.c | 214 ++++++++++++++++++++++-------------------------------------
 1 file changed, 81 insertions(+), 133 deletions(-)

diff --git a/st.c b/st.c
index 69b2491..e20a1e0 100644
--- a/st.c
+++ b/st.c
@@ -55,6 +55,7 @@ char *argv0;
 #define XEMBED_FOCUS_OUT 5
 
 /* Arbitrary sizes */
+#define UTF_INVALID   0xFFFD
 #define UTF_SIZ       4
 #define ESC_BUF_SIZ   (128*UTF_SIZ)
 #define ESC_ARG_SIZ   16
@@ -442,10 +443,12 @@ static void selcopy(void);
 static void selscroll(int, int);
 static void selsnap(int, int *, int *, int);
 
-static int utf8decode(char *, long *);
-static int utf8encode(long *, char *);
-static int utf8size(char *);
-static int isfullutf8(char *, int);
+static size_t utf8decode(char *, long *, size_t);
+static long utf8decodebyte(char, size_t *);
+static size_t utf8encode(long, char *, size_t);
+static char utf8encodebyte(long, size_t);
+static size_t utf8len(char *);
+static size_t utf8validate(long *, size_t);
 
 static ssize_t xwrite(int, char *, size_t);
 static void *xmalloc(size_t);
@@ -490,6 +493,11 @@ static int oldbutton = 3; /* button event on startup: 3 = release */
 static char *usedfont = NULL;
 static double usedfontsize = 0;
 
+static uchar utfbyte[UTF_SIZ + 1] = {0x80,    0, 0xC0, 0xE0, 0xF0};
+static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
+static long utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  0x10000};
+static long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
+
 /* Font Ring Cache */
 enum {
 	FRC_NORMAL,
@@ -549,128 +557,69 @@ xstrdup(char *s) {
 	return p;
 }
 
-int
-utf8decode(char *s, long *u) {
-	uchar c;
-	int i, n, rtn;
+size_t
+utf8decode(char *c, long *u, size_t clen) {
+	size_t i, j, len, type;
+	long udecoded;
 
-	rtn = 1;
-	c = *s;
-	if(~c & 0x80) { /* 0xxxxxxx */
-		*u = c;
-		return rtn;
-	} else if((c & 0xE0) == 0xC0) { /* 110xxxxx */
-		*u = c & 0x1F;
-		n = 1;
-	} else if((c & 0xF0) == 0xE0) { /* 1110xxxx */
-		*u = c & 0x0F;
-		n = 2;
-	} else if((c & 0xF8) == 0xF0) { /* 11110xxx */
-		*u = c & 0x07;
-		n = 3;
-	} else {
-		goto invalid;
+	*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;
 	}
-
-	for(i = n, ++s; i > 0; --i, ++rtn, ++s) {
-		c = *s;
-		if((c & 0xC0) != 0x80) /* 10xxxxxx */
-			goto invalid;
-		*u <<= 6;
-		*u |= c & 0x3F;
-	}
-
-	if((n == 1 && *u < 0x80) ||
-	   (n == 2 && *u < 0x800) ||
-	   (n == 3 && *u < 0x10000) ||
-	   (*u >= 0xD800 && *u <= 0xDFFF)) {
-		goto invalid;
-	}
-
-	return rtn;
-invalid:
-	*u = 0xFFFD;
-
-	return rtn;
+	if(j < len)
+		return 0;
+	*u = udecoded;
+	utf8validate(u, len);
+	return len;
 }
 
-int
-utf8encode(long *u, char *s) {
-	uchar *sp;
-	ulong uc;
-	int i, n;
-
-	sp = (uchar *)s;
-	uc = *u;
-	if(uc < 0x80) {
-		*sp = uc; /* 0xxxxxxx */
-		return 1;
-	} else if(*u < 0x800) {
-		*sp = (uc >> 6) | 0xC0; /* 110xxxxx */
-		n = 1;
-	} else if(uc < 0x10000) {
-		*sp = (uc >> 12) | 0xE0; /* 1110xxxx */
-		n = 2;
-	} else if(uc <= 0x10FFFF) {
-		*sp = (uc >> 18) | 0xF0; /* 11110xxx */
-		n = 3;
-	} else {
-		goto invalid;
-	}
-
-	for(i=n,++sp; i>0; --i,++sp)
-		*sp = ((uc >> 6*(i-1)) & 0x3F) | 0x80; /* 10xxxxxx */
-
-	return n+1;
-invalid:
-	/* U+FFFD */
-	*s++ = '\xEF';
-	*s++ = '\xBF';
-	*s = '\xBD';
-
-	return 3;
+long
+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;
 }
 
-/* use this if your buffer is less than UTF_SIZ, it returns 1 if you can decode
-   UTF-8 otherwise return 0 */
-int
-isfullutf8(char *s, int b) {
-	uchar *c1, *c2, *c3;
+size_t
+utf8encode(long u, char *c, size_t clen) {
+	size_t len, i;
 
-	c1 = (uchar *)s;
-	c2 = (uchar *)++s;
-	c3 = (uchar *)++s;
-	if(b < 1) {
+	len = utf8validate(&u, 0);
+	if(clen < len)
 		return 0;
-	} else if((*c1 & 0xE0) == 0xC0 && b == 1) {
-		return 0;
-	} else if((*c1 & 0xF0) == 0xE0 &&
-	    ((b == 1) ||
-	    ((b == 2) && (*c2 & 0xC0) == 0x80))) {
-		return 0;
-	} else if((*c1 & 0xF8) == 0xF0 &&
-	    ((b == 1) ||
-	    ((b == 2) && (*c2 & 0xC0) == 0x80) ||
-	    ((b == 3) && (*c2 & 0xC0) == 0x80 && (*c3 & 0xC0) == 0x80))) {
-		return 0;
-	} else {
-		return 1;
+	for(i = len - 1; i != 0; --i) {
+		c[i] = utf8encodebyte(u, 0);
+		u >>= 6;
 	}
+	c[0] = utf8encodebyte(u, len);
+	return len;
 }
 
-int
-utf8size(char *s) {
-	uchar c = *s;
+char
+utf8encodebyte(long u, size_t i) {
+	return utfbyte[i] | (u & ~utfmask[i]);
+}
 
-	if(~c & 0x80) {
-		return 1;
-	} else if((c & 0xE0) == 0xC0) {
-		return 2;
-	} else if((c & 0xF0) == 0xE0) {
-		return 3;
-	} else {
-		return 4;
-	}
+size_t
+utf8len(char *c) {
+	return utf8decode(c, &(long){0}, UTF_SIZ);
+}
+
+size_t
+utf8validate(long *u, size_t i) {
+	if(!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
+		*u = UTF_INVALID;
+	for(i = 1; *u > utfmax[i]; ++i)
+		;
+	return i;
 }
 
 static void
@@ -984,7 +933,7 @@ getsel(void) {
 				if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))
 					continue;
 
-				size = utf8size(gp->c);
+				size = utf8len(gp->c);
 				memcpy(ptr, gp->c, size);
 				ptr += size;
 			}
@@ -1298,7 +1247,7 @@ ttyread(void) {
 	char *ptr;
 	char s[UTF_SIZ];
 	int charsize; /* size of utf8 char in bytes */
-	long utf8c;
+	long unicodep;
 	int ret;
 
 	/* append read bytes to unprocessed bytes */
@@ -1308,9 +1257,8 @@ ttyread(void) {
 	/* process every complete utf8 char */
 	buflen += ret;
 	ptr = buf;
-	while(buflen >= UTF_SIZ || isfullutf8(ptr,buflen)) {
-		charsize = utf8decode(ptr, &utf8c);
-		utf8encode(&utf8c, s);
+	while(charsize = utf8decode(ptr, &unicodep, buflen)) {
+		utf8encode(unicodep, s, UTF_SIZ);
 		tputc(s, charsize);
 		ptr += charsize;
 		buflen -= charsize;
@@ -2414,14 +2362,14 @@ void
 tputc(char *c, int len) {
 	uchar ascii = *c;
 	bool control = ascii < '\x20' || ascii == 0177;
-	long u8char;
+	long unicodep;
 	int width;
 
 	if(len == 1) {
 		width = 1;
 	} else {
-		utf8decode(c, &u8char);
-		width = wcwidth(u8char);
+		utf8decode(c, &unicodep, UTF_SIZ);
+		width = wcwidth(unicodep);
 	}
 
 	if(IS_SET(MODE_PRINT))
@@ -3150,7 +3098,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	int frcflags;
 	int u8fl, u8fblen, u8cblen, doesexist;
 	char *u8c, *u8fs;
-	long u8char;
+	long unicodep;
 	Font *font = &dc.font;
 	FcResult fcres;
 	FcPattern *fcpattern, *fontpattern;
@@ -3293,11 +3241,11 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		oneatatime = font->width != xw.cw;
 		for(;;) {
 			u8c = s;
-			u8cblen = utf8decode(s, &u8char);
+			u8cblen = utf8decode(s, &unicodep, UTF_SIZ);
 			s += u8cblen;
 			bytelen -= u8cblen;
 
-			doesexist = XftCharExists(xw.dpy, font->match, u8char);
+			doesexist = XftCharExists(xw.dpy, font->match, unicodep);
 			if(oneatatime || !doesexist || bytelen <= 0) {
 				if(oneatatime || bytelen <= 0) {
 					if(doesexist) {
@@ -3329,7 +3277,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 		/* Search the font cache. */
 		for(i = 0; i < frclen; i++) {
-			if(XftCharExists(xw.dpy, frc[i].font, u8char)
+			if(XftCharExists(xw.dpy, frc[i].font, unicodep)
 					&& frc[i].flags == frcflags) {
 				break;
 			}
@@ -3351,7 +3299,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			fcpattern = FcPatternDuplicate(font->pattern);
 			fccharset = FcCharSetCreate();
 
-			FcCharSetAddChar(fccharset, u8char);
+			FcCharSetAddChar(fccharset, unicodep);
 			FcPatternAddCharSet(fcpattern, FC_CHARSET,
 					fccharset);
 			FcPatternAddBool(fcpattern, FC_SCALABLE,
@@ -3387,7 +3335,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 				xp, winy + frc[i].font->ascent,
 				(FcChar8 *)u8c, u8cblen);
 
-		xp += xw.cw * wcwidth(u8char);
+		xp += xw.cw * wcwidth(unicodep);
 	}
 
 	/*
@@ -3430,7 +3378,7 @@ xdrawcursor(void) {
 	memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
 
 	/* remove the old cursor */
-	sl = utf8size(term.line[oldy][oldx].c);
+	sl = utf8len(term.line[oldy][oldx].c);
 	width = (term.line[oldy][oldx].mode & ATTR_WIDE)? 2 : 1;
 	xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx,
 			oldy, width, sl);
@@ -3444,7 +3392,7 @@ xdrawcursor(void) {
 				g.bg = defaultfg;
 			}
 
-			sl = utf8size(g.c);
+			sl = utf8len(g.c);
 			width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\
 				? 2 : 1;
 			xdraws(g.c, g, term.c.x, term.c.y, width, sl);
@@ -3516,7 +3464,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
 	bool ena_sel = sel.ob.x != -1;
-	long u8char;
+	long unicodep;
 
 	if(sel.alt ^ IS_SET(MODE_ALTSCREEN))
 		ena_sel = 0;
@@ -3548,7 +3496,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 				base = new;
 			}
 
-			sl = utf8decode(new.c, &u8char);
+			sl = utf8decode(new.c, &unicodep, UTF_SIZ);
 			memcpy(buf+ib, new.c, sl);
 			ib += sl;
 			ic += (new.mode & ATTR_WIDE)? 2 : 1;
@@ -3707,7 +3655,7 @@ kpress(XEvent *ev) {
 		if(IS_SET(MODE_8BIT)) {
 			if(*buf < 0177) {
 				c = *buf | 0x80;
-				len = utf8encode(&c, buf);
+				len = utf8encode(c, buf, UTF_SIZ);
 			}
 		} else {
 			buf[1] = buf[0];

From 672e4e4b03d8987103020d399b2c05c95a9ea2f8 Mon Sep 17 00:00:00 2001
From: Rafa Garcia Gallego <rafael.garcia.gallego@gmail.com>
Date: Wed, 26 Mar 2014 23:58:27 +0100
Subject: [PATCH 0622/1146] Fix segfault when pressing PrintScr without a
 selection

---
 st.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index e20a1e0..d58af7d 100644
--- a/st.c
+++ b/st.c
@@ -2263,9 +2263,10 @@ tdumpsel(void)
 {
 	char *ptr;
 
-	ptr = getsel();
-	tprinter(ptr, strlen(ptr));
-	free(ptr);
+	if((ptr = getsel())) {
+		tprinter(ptr, strlen(ptr));
+		free(ptr);
+	}
 }
 
 void

From 6f4cfa5136d354f3901871b71e460ba9f0f182a3 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 2 Apr 2014 09:26:28 +0200
Subject: [PATCH 0623/1146] Fixing a compiler warning with the assignment.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index d58af7d..a4f467d 100644
--- a/st.c
+++ b/st.c
@@ -1257,7 +1257,7 @@ ttyread(void) {
 	/* process every complete utf8 char */
 	buflen += ret;
 	ptr = buf;
-	while(charsize = utf8decode(ptr, &unicodep, buflen)) {
+	while((charsize = utf8decode(ptr, &unicodep, buflen))) {
 		utf8encode(unicodep, s, UTF_SIZ);
 		tputc(s, charsize);
 		ptr += charsize;

From a495fce128a887275d455c09c37b3882e909f962 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 5 Apr 2014 20:34:57 +0200
Subject: [PATCH 0624/1146] There is no need for a full dirt redraw.

---
 st.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.c b/st.c
index a4f467d..392f12d 100644
--- a/st.c
+++ b/st.c
@@ -3440,7 +3440,6 @@ void
 redraw(int timeout) {
 	struct timespec tv = {0, timeout * 1000};
 
-	tfulldirt();
 	draw();
 
 	if(timeout > 0) {

From 62f9142478d58185fee74f41055978f708bffa46 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 5 Apr 2014 20:39:46 +0200
Subject: [PATCH 0625/1146] Updating the TODO in preparating for 0.5.

---
 TODO | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/TODO b/TODO
index 0c538e5..3866f64 100644
--- a/TODO
+++ b/TODO
@@ -6,22 +6,17 @@ vt emulation
 code & interface
 ----------------
 
-* clean and complete terminfo entry
 * add a simple way to do multiplexing
 
 drawing
 -------
 * add diacritics support to xdraws()
 * make the font cache simpler
-* add hard width handling
-	* xft is reporting wrong width and height for characters
 
 bugs
 ----
 
 * fix shift up/down (shift selection in emacs)
-* fix selection paste for xatom STRING
-* fix rows and column definition in fixed geometry
 * fix -e handling
 * remove DEC test sequence when appropriate
 

From 0baf2d8be57d93a86973c8363df4ea3f3e641925 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 5 Apr 2014 20:40:11 +0200
Subject: [PATCH 0626/1146] 0.5 release.

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 9431de2..97afa2c 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.4.1
+VERSION = 0.5
 
 # Customize below to fit your system
 

From c46d929fe18e4a3c9c41101eafa7a9668c8c8830 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 11 Apr 2014 15:08:37 +0200
Subject: [PATCH 0627/1146] Fix Backspace and Delete characters

Backspace key must generate the backspace character (\010) and
Delete key must generate the delete character (\0177). In
some systems the kernel configuration for erasing previous character
is \0177, so some programs (for example cat, ed, mail, ...), can not
understand the correct meaning of backspace. In this cases it is only
needed this command:

	stty erase 
---
 config.def.h | 3 ---
 st.info      | 2 +-
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index 58b470e..d69c9ba 100644
--- a/config.def.h
+++ b/config.def.h
@@ -192,7 +192,6 @@ static Key key[] = {
 	{ XK_KP_Delete,     ControlMask,    "\033[3;5~",    +1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[2K",      -1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",    +1,    0,    0},
-	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[P",       -1,    0,    0},
 	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
 	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +2,    0,    0},
 	{ XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +2,    0,    0},
@@ -212,7 +211,6 @@ static Key key[] = {
 	{ XK_KP_7,          XK_ANY_MOD,     "\033Ow",       +2,    0,    0},
 	{ XK_KP_8,          XK_ANY_MOD,     "\033Ox",       +2,    0,    0},
 	{ XK_KP_9,          XK_ANY_MOD,     "\033Oy",       +2,    0,    0},
-	{ XK_BackSpace,     XK_NO_MOD,      "\177",          0,    0,    0},
 	{ XK_Up,            ShiftMask,      "\033[1;2A",     0,    0,    0},
 	{ XK_Up,            ControlMask,    "\033[1;5A",     0,    0,    0},
 	{ XK_Up,            Mod1Mask,       "\033[1;3A",     0,    0,    0},
@@ -248,7 +246,6 @@ static Key key[] = {
 	{ XK_Delete,        ControlMask,    "\033[3;5~",    +1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[2K",      -1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",    +1,    0,    0},
-	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[2J",       0,   -1,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,   +1,    0},
diff --git a/st.info b/st.info
index 4e60a89..3a01a08 100644
--- a/st.info
+++ b/st.info
@@ -53,7 +53,7 @@ st| simpleterm,
 	ka3=\E[5~,
 	kc1=\E[4~,
 	kc3=\E[6~,
-	kbs=\177,
+	kbs=\010,
 	kcbt=\E[Z,
 	kb2=\EOu,
 	kcub1=\EOD,

From 3cb80840dbf9add2b5f9c26da9650da39e34906d Mon Sep 17 00:00:00 2001
From: Toaster Toaster <toaster23456@gmail.com>
Date: Mon, 7 Apr 2014 10:53:59 -0700
Subject: [PATCH 0628/1146] Increment XSync consistency

This patch cleans up a style inconsistency.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 392f12d..6fef7f3 100644
--- a/st.c
+++ b/st.c
@@ -3089,7 +3089,7 @@ xinit(void) {
 	xresettitle();
 	XMapWindow(xw.dpy, xw.win);
 	xhints();
-	XSync(xw.dpy, 0);
+	XSync(xw.dpy, False);
 }
 
 void

From f27b44b7c271bda4ad3a0c4043bb709e0a4e4fbb Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 11 Apr 2014 18:11:25 +0200
Subject: [PATCH 0629/1146] Removing two unnecessary gettimeofday().

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 392f12d..a104a50 100644
--- a/st.c
+++ b/st.c
@@ -3737,8 +3737,8 @@ run(void) {
 	else
 		cresize(xw.fw, xw.fh);
 
-	gettimeofday(&lastblink, NULL);
 	gettimeofday(&last, NULL);
+	lastblink = last;
 
 	for(xev = actionfps;;) {
 		long deltatime;
@@ -3773,7 +3773,7 @@ run(void) {
 		if(blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
 			tsetdirtattr(ATTR_BLINK);
 			term.mode ^= MODE_BLINK;
-			gettimeofday(&lastblink, NULL);
+			lastblink = now;
 			dodraw = 1;
 		}
 		deltatime = TIMEDIFF(now, last);

From b8d6171cb00c28e4c90e58e101554097003b59d3 Mon Sep 17 00:00:00 2001
From: "q@c9x.me" <q@c9x.me>
Date: Wed, 9 Apr 2014 20:37:23 +0200
Subject: [PATCH 0630/1146] fix cursor handling when alt screen is disabled

I don't like this alt screen thing, but when
allowaltscreen == 0, the cursor is still saved
and restored after calling 'less' (or 'man').

This patch makes allowaltscreen == 0 usable.
---
 st.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.c b/st.c
index ced72ff..70caf82 100644
--- a/st.c
+++ b/st.c
@@ -1855,7 +1855,10 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				MODBIT(term.mode, set, MODE_8BIT);
 				break;
 			case 1049: /* swap screen & set/restore cursor as xterm */
+				if (!allowaltscreen)
+					break;
 				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
+				/* FALLTHRU */
 			case 47: /* swap screen */
 			case 1047:
 				if (!allowaltscreen)

From dc74c4f729a4350267f269c767aa6e377d8d4fbc Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sat, 5 Apr 2014 20:54:01 +0400
Subject: [PATCH 0631/1146] typedefs instead of #defines

Replaced #defines with typedefs where possible, patch attached.
---
 st.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 70caf82..df660ff 100644
--- a/st.c
+++ b/st.c
@@ -36,10 +36,6 @@ char *argv0;
 
 #define Glyph Glyph_
 #define Font Font_
-#define Draw XftDraw *
-#define Colour XftColor
-#define Colourmap Colormap
-#define Rectangle XRectangle
 
 #if   defined(__linux)
  #include <pty.h>
@@ -180,6 +176,10 @@ typedef unsigned int uint;
 typedef unsigned long ulong;
 typedef unsigned short ushort;
 
+typedef XftDraw *Draw;
+typedef XftColor Colour;
+typedef Colormap Colourmap;
+
 typedef struct {
 	char c[UTF_SIZ]; /* character code */
 	ushort mode;      /* attribute flags */
@@ -3110,7 +3110,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	FcCharSet *fccharset;
 	Colour *fg, *bg, *temp, revfg, revbg, truefg, truebg;
 	XRenderColor colfg, colbg;
-	Rectangle r;
+	XRectangle r;
 	int oneatatime;
 
 	frcflags = FRC_NORMAL;

From 4ad2fc7f18c8a58d9f88d9a91fb4972849cfd964 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sun, 13 Apr 2014 20:21:32 +0400
Subject: [PATCH 0632/1146] Simplify techo

Remove special case for \e because it is handled well by "control code"
case.
---
 st.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/st.c b/st.c
index df660ff..e510565 100644
--- a/st.c
+++ b/st.c
@@ -2318,10 +2318,7 @@ techo(char *buf, int len) {
 	for(; len > 0; buf++, len--) {
 		char c = *buf;
 
-		if(c == '\033') { /* escape */
-			tputc("^", 1);
-			tputc("[", 1);
-		} else if(c < '\x20') { /* control code */
+		if(c < '\x20') { /* control code */
 			if(c != '\n' && c != '\r' && c != '\t') {
 				c |= '\x40';
 				tputc("^", 1);

From 3269bf213d8fdbfb78e9eb1cc9eb677114508e57 Mon Sep 17 00:00:00 2001
From: Markus Teich <markus.teich@stusta.mhn.de>
Date: Sun, 20 Apr 2014 13:15:40 +0200
Subject: [PATCH 0633/1146] remove confusing SERRNO macro

I found the SERRNO Macro slightly confusing, since you have to look
it up, if you don't know it already. A web search showed it does
not seem to be any kind of standard. Also there was no reason in
the commit log when it was introduced in 2009. As you can see it
also leads to new patches, which don't use this macro (probably the
author did not know about it).
---
 st.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/st.c b/st.c
index e510565..e017940 100644
--- a/st.c
+++ b/st.c
@@ -65,7 +65,6 @@ char *argv0;
 #define REDRAW_TIMEOUT (80*1000) /* 80 ms */
 
 /* macros */
-#define SERRNO strerror(errno)
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
 #define MAX(a, b)  ((a) < (b) ? (b) : (a))
 #define LEN(a)     (sizeof(a) / sizeof(a[0]))
@@ -1181,7 +1180,7 @@ sigchld(int a) {
 	int stat = 0;
 
 	if(waitpid(pid, &stat, 0) < 0)
-		die("Waiting for pid %hd failed: %s\n", pid, SERRNO);
+		die("Waiting for pid %hd failed: %s\n", pid, strerror(errno));
 
 	if(WIFEXITED(stat)) {
 		exit(WEXITSTATUS(stat));
@@ -1197,7 +1196,7 @@ ttynew(void) {
 
 	/* seems to work fine on linux, openbsd and freebsd */
 	if(openpty(&m, &s, NULL, NULL, &w) < 0)
-		die("openpty failed: %s\n", SERRNO);
+		die("openpty failed: %s\n", strerror(errno));
 
 	switch(pid = fork()) {
 	case -1:
@@ -1209,7 +1208,7 @@ ttynew(void) {
 		dup2(s, STDOUT_FILENO);
 		dup2(s, STDERR_FILENO);
 		if(ioctl(s, TIOCSCTTY, NULL) < 0)
-			die("ioctl TIOCSCTTY failed: %s\n", SERRNO);
+			die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
 		close(s);
 		close(m);
 		execsh();
@@ -1252,7 +1251,7 @@ ttyread(void) {
 
 	/* append read bytes to unprocessed bytes */
 	if((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
-		die("Couldn't read from shell: %s\n", SERRNO);
+		die("Couldn't read from shell: %s\n", strerror(errno));
 
 	/* process every complete utf8 char */
 	buflen += ret;
@@ -1271,7 +1270,7 @@ ttyread(void) {
 void
 ttywrite(const char *s, size_t n) {
 	if(write(cmdfd, s, n) == -1)
-		die("write error on tty: %s\n", SERRNO);
+		die("write error on tty: %s\n", strerror(errno));
 }
 
 void
@@ -1290,7 +1289,7 @@ ttyresize(void) {
 	w.ws_xpixel = xw.tw;
 	w.ws_ypixel = xw.th;
 	if(ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
-		fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
+		fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno));
 }
 
 int
@@ -3750,7 +3749,7 @@ run(void) {
 		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv) < 0) {
 			if(errno == EINTR)
 				continue;
-			die("select failed: %s\n", SERRNO);
+			die("select failed: %s\n", strerror(errno));
 		}
 		if(FD_ISSET(cmdfd, &rfd)) {
 			ttyread();

From 6b56cbf9cc597b529f244ee8fcb1cbbcc338c7b7 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sun, 20 Apr 2014 15:41:40 +0400
Subject: [PATCH 0634/1146] misplaced parenthesis in LEN macro

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index e017940..4ccef9c 100644
--- a/st.c
+++ b/st.c
@@ -67,7 +67,7 @@ char *argv0;
 /* 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 LEN(a)     (sizeof(a) / sizeof(a)[0])
 #define DEFAULT(a, b)     (a) = (a) ? (a) : (b)
 #define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (b))
 #define LIMIT(x, a, b)    (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)

From 138887033193389854a2cb748b8940793a7bfb6f Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sun, 20 Apr 2014 13:08:09 +0400
Subject: [PATCH 0635/1146] move MODBIT to Macros section

Patch moves MODBIT to macros section and uses it in tselcs.
---
 st.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index 4ccef9c..7ffe59a 100644
--- a/st.c
+++ b/st.c
@@ -75,6 +75,7 @@ char *argv0;
 #define IS_SET(flag) ((term.mode & (flag)) != 0)
 #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
 #define CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x))
+#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))
@@ -1784,8 +1785,6 @@ tsetscroll(int t, int b) {
 	term.bot = b;
 }
 
-#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
-
 void
 tsetmode(bool priv, bool set, int *args, int narg) {
 	int *lim, mode;
@@ -2352,10 +2351,9 @@ tdeftran(char ascii) {
 
 void
 tselcs(void) {
-	if (term.trantbl[term.charset] == CS_GRAPHIC0)
-		term.c.attr.mode |= ATTR_GFX;
-	else
-		term.c.attr.mode &= ~ATTR_GFX;
+	MODBIT(term.c.attr.mode,
+	       term.trantbl[term.charset] == CS_GRAPHIC0,
+	       ATTR_GFX);
 }
 
 void

From 87abc7cd596ca34a2e664f1c762f8b69b82eba40 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 22 Apr 2014 19:22:58 +0200
Subject: [PATCH 0636/1146] It's 2014 now.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 7ffe59a..019f53c 100644
--- a/st.c
+++ b/st.c
@@ -3815,7 +3815,7 @@ run(void) {
 
 void
 usage(void) {
-	die("%s " VERSION " (c) 2010-2013 st engineers\n" \
+	die("%s " VERSION " (c) 2010-2014 st engineers\n" \
 	"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]" \
 	" [-t title] [-w windowid] [-e command ...]\n", argv0);
 }

From f21e47f44a11b9a24a5d5081fea46f5b5f02eadf Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Tue, 22 Apr 2014 21:59:01 +0400
Subject: [PATCH 0637/1146] Use BETWEEN in tinsertblankline and tdeleteline.

---
 st.c | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/st.c b/st.c
index 019f53c..92fd7da 100644
--- a/st.c
+++ b/st.c
@@ -1628,18 +1628,14 @@ tinsertblank(int n) {
 
 void
 tinsertblankline(int n) {
-	if(term.c.y < term.top || term.c.y > term.bot)
-		return;
-
-	tscrolldown(term.c.y, n);
+	if(BETWEEN(term.c.y, term.top, term.bot))
+		tscrolldown(term.c.y, n);
 }
 
 void
 tdeleteline(int n) {
-	if(term.c.y < term.top || term.c.y > term.bot)
-		return;
-
-	tscrollup(term.c.y, n);
+	if(BETWEEN(term.c.y, term.top, term.bot))
+		tscrollup(term.c.y, n);
 }
 
 int32_t

From 49672dac7b40d27e140f5b6d6b3829c9c5f728ba Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Tue, 22 Apr 2014 21:59:14 +0400
Subject: [PATCH 0638/1146] Style fix in tdumpsel.

---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 92fd7da..6da4827 100644
--- a/st.c
+++ b/st.c
@@ -2256,8 +2256,7 @@ printsel(const Arg *arg) {
 }
 
 void
-tdumpsel(void)
-{
+tdumpsel(void) {
 	char *ptr;
 
 	if((ptr = getsel())) {

From 68d97457ecf044bda62a37dd6158bbba4e28d7fe Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Tue, 22 Apr 2014 21:59:21 +0400
Subject: [PATCH 0639/1146] Remove argument names from function prototypes.

---
 st.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index 6da4827..64384cd 100644
--- a/st.c
+++ b/st.c
@@ -360,7 +360,7 @@ static void strparse(void);
 static void strreset(void);
 
 static int tattrset(int);
-static void tprinter(char *s, size_t len);
+static void tprinter(char *, size_t);
 static void tdumpsel(void);
 static void tdumpline(int);
 static void tdump(void);
@@ -371,7 +371,7 @@ static void tdeleteline(int);
 static void tinsertblank(int);
 static void tinsertblankline(int);
 static void tmoveto(int, int);
-static void tmoveato(int x, int y);
+static void tmoveato(int, int);
 static void tnew(int, int);
 static void tnewline(int);
 static void tputtab(bool);
@@ -380,7 +380,7 @@ static void treset(void);
 static int tresize(int, int);
 static void tscrollup(int, int);
 static void tscrolldown(int, int);
-static void tsetattr(int*, int);
+static void tsetattr(int *, int);
 static void tsetchar(char *, Glyph *, int, int);
 static void tsetscroll(int, int);
 static void tswapscreen(void);
@@ -413,9 +413,9 @@ static void xsettitle(char *);
 static void xresettitle(void);
 static void xsetpointermotion(int);
 static void xseturgency(int);
-static void xsetsel(char*);
+static void xsetsel(char *);
 static void xtermclear(int, int, int, int);
-static void xunloadfont(Font *f);
+static void xunloadfont(Font *);
 static void xunloadfonts(void);
 static void xresize(int, int);
 
@@ -453,7 +453,7 @@ static size_t utf8validate(long *, size_t);
 static ssize_t xwrite(int, char *, size_t);
 static void *xmalloc(size_t);
 static void *xrealloc(void *, size_t);
-static char *xstrdup(char *s);
+static char *xstrdup(char *);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,

From ed855ea432156cea5ca3c6c942392f97d4c3ab1d Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Tue, 22 Apr 2014 21:59:32 +0400
Subject: [PATCH 0640/1146] Use uint and uchar instead of unsigned int and
 unsigned char.

---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 64384cd..b8bf84b 100644
--- a/st.c
+++ b/st.c
@@ -298,13 +298,13 @@ typedef struct {
 
 typedef union {
 	int i;
-	unsigned int ui;
+	uint ui;
 	float f;
 	const void *v;
 } Arg;
 
 typedef struct {
-	unsigned int mod;
+	uint mod;
 	KeySym keysym;
 	void (*func)(const Arg *);
 	const Arg arg;
@@ -3076,7 +3076,7 @@ xinit(void) {
 
 	xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False);
 	XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
-			PropModeReplace, (unsigned char *)&thispid, 1);
+			PropModeReplace, (uchar *)&thispid, 1);
 
 	xresettitle();
 	XMapWindow(xw.dpy, xw.win);

From df1810dd8fcb7a14f4cd2ff2ec3ce8780591f87f Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Tue, 22 Apr 2014 21:59:39 +0400
Subject: [PATCH 0641/1146] Use BETWEEN in tsetchar.

---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index b8bf84b..bb3e687 100644
--- a/st.c
+++ b/st.c
@@ -1544,8 +1544,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 	 * The table is proudly stolen from rxvt.
 	 */
 	if(attr->mode & ATTR_GFX) {
-		if(c[0] >= 0x41 && c[0] <= 0x7e
-				&& vt100_0[c[0] - 0x41]) {
+		if(BETWEEN(c[0], 0x41, 0x7e) && vt100_0[c[0] - 0x41]) {
 			c = vt100_0[c[0] - 0x41];
 		}
 	}

From fa19f241a34deddf6e089ab462cbd9cb02f61b3d Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Tue, 22 Apr 2014 21:59:48 +0400
Subject: [PATCH 0642/1146] Make xrealloc and xstrdup style consistent.

---
 st.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index bb3e687..aba034f 100644
--- a/st.c
+++ b/st.c
@@ -549,12 +549,10 @@ xrealloc(void *p, size_t len) {
 
 char *
 xstrdup(char *s) {
-	char *p = strdup(s);
-
-	if (!p)
+	if((s = strdup(s)) == NULL)
 		die("Out of memory\n");
 
-	return p;
+	return s;
 }
 
 size_t

From f9dc374ea01c2921ec3bd1214f292a7036d069ae Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Wed, 23 Apr 2014 00:26:07 +0400
Subject: [PATCH 0643/1146] Fix techo handling of control and multibyte
 characters.

techo compares signed char to '\x20'. Any character with code less then
'\x20' is treated as control character.  This way characters with MSB
set to 1 are considered control characters too.

Also this patch makes techo display DEL character as ^?.

To reprocuce the bug, enable echo mode using printf '\e[12l',
then type DEL character or any non-ASCII character.
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index aba034f..b66791a 100644
--- a/st.c
+++ b/st.c
@@ -2308,9 +2308,9 @@ techo(char *buf, int len) {
 	for(; len > 0; buf++, len--) {
 		char c = *buf;
 
-		if(c < '\x20') { /* control code */
+		if(c < 0x20 || c == 0177) { /* control code */
 			if(c != '\n' && c != '\r' && c != '\t') {
-				c |= '\x40';
+				c ^= '\x40';
 				tputc("^", 1);
 			}
 			tputc(&c, 1);

From 3afdb4ff04b45a5e4209a56d5073341c9d506b38 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sun, 20 Apr 2014 17:26:13 +0400
Subject: [PATCH 0644/1146] Use tsetdirt in tscrollup and tscrolldown.

tscrollup and tscrolldown do not use tsetdirt, but their code is
equivalent to

        tsetdirt(orig, term.bot-n);
        tsetdirt(orig+n, term.bot);

tclearregion also marks cleared lines as dirty.
In tscrolldown it sets lines from term.bot-n+1 to term.bot dirty, and in
tscrollup it sets lines from orig to orig+n-1 dirty.

In both functions all lines from orig to term.bot are effectively set
dirty, but in tscrolldown lines from orig+n to term.bot are set dirty
twice, and in tscrollup lines from orig to term.bot-n are set dirty
twice.

These patches make it clear which lines are set dirty and sets them
dirty once in each funciton.
---
 st.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index b66791a..d188b35 100644
--- a/st.c
+++ b/st.c
@@ -1399,14 +1399,13 @@ tscrolldown(int orig, int n) {
 	LIMIT(n, 0, term.bot-orig+1);
 
 	tclearregion(0, term.bot-n+1, term.col-1, term.bot);
+	tsetdirt(orig, term.bot-n);
+	tsetdirt(orig+n, 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;
-
-		term.dirty[i] = 1;
-		term.dirty[i-n] = 1;
 	}
 
 	selscroll(orig, n);
@@ -1419,14 +1418,13 @@ tscrollup(int orig, int n) {
 	LIMIT(n, 0, term.bot-orig+1);
 
 	tclearregion(0, orig, term.col-1, orig+n-1);
+	tsetdirt(orig, term.bot-n);
+	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;
-
-		 term.dirty[i] = 1;
-		 term.dirty[i+n] = 1;
 	}
 
 	selscroll(orig, -n);

From fe527aa508851d83f166b8f50ae4c2ed5f1e4ec8 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sun, 20 Apr 2014 17:26:50 +0400
Subject: [PATCH 0645/1146] Do not set dirty flag twice in tscrollup and
 tscrolldown.

---
 st.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/st.c b/st.c
index d188b35..dffa84e 100644
--- a/st.c
+++ b/st.c
@@ -1398,9 +1398,8 @@ tscrolldown(int orig, int n) {
 
 	LIMIT(n, 0, term.bot-orig+1);
 
-	tclearregion(0, term.bot-n+1, term.col-1, term.bot);
 	tsetdirt(orig, term.bot-n);
-	tsetdirt(orig+n, term.bot);
+	tclearregion(0, term.bot-n+1, term.col-1, term.bot);
 
 	for(i = term.bot; i >= orig+n; i--) {
 		temp = term.line[i];
@@ -1418,7 +1417,6 @@ tscrollup(int orig, int n) {
 	LIMIT(n, 0, term.bot-orig+1);
 
 	tclearregion(0, orig, term.col-1, orig+n-1);
-	tsetdirt(orig, term.bot-n);
 	tsetdirt(orig+n, term.bot);
 
 	for(i = orig; i <= term.bot-n; i++) {

From 16ac85bf5422a7e925743f6134572d3ac1a25188 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sun, 20 Apr 2014 17:26:39 +0400
Subject: [PATCH 0646/1146] Style fixes in tscrollup.

---
 st.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index dffa84e..60243a7 100644
--- a/st.c
+++ b/st.c
@@ -1414,15 +1414,16 @@ 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;
+		temp = term.line[i];
+		term.line[i] = term.line[i+n];
+		term.line[i+n] = temp;
 	}
 
 	selscroll(orig, -n);

From 80b32af794b659cb15745cfb2a19fce0829c42c7 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Wed, 23 Apr 2014 02:08:13 +0400
Subject: [PATCH 0647/1146] Simplify tdeletechar and tinsertblank and fix
 memory corruption.

Current CSI parsing code uses strtol to parse arguments and allows them
to be negative. Negative argument is not properly handled in tdeletechar
and tinsertblank and results in memory corruption in memmove.

Reproduce with printf '\e[-500@'

Patch also removes special handling for corner case and simplifies
the code.

Removed
	term.dirty[term.c.y] = 1
because tclearregion sets dirty flag.
---
 st.c | 30 ++++++++++++------------------
 1 file changed, 12 insertions(+), 18 deletions(-)

diff --git a/st.c b/st.c
index 60243a7..263abaa 100644
--- a/st.c
+++ b/st.c
@@ -1586,37 +1586,31 @@ tclearregion(int x1, int y1, int x2, int y2) {
 
 void
 tdeletechar(int n) {
-	int src = term.c.x + n;
-	int dst = term.c.x;
-	int size = term.col - src;
+	int dst, src, size;
 
-	term.dirty[term.c.y] = 1;
+	LIMIT(n, 0, term.col - term.c.x);
 
-	if(src >= term.col) {
-		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
-		return;
-	}
+	dst = term.c.x;
+	src = term.c.x + n;
+	size = term.col - src;
 
 	memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src],
-			size * sizeof(Glyph));
+	        size * sizeof(Glyph));
 	tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
 }
 
 void
 tinsertblank(int n) {
-	int src = term.c.x;
-	int dst = src + n;
-	int size = term.col - dst;
+	int dst, src, size;
 
-	term.dirty[term.c.y] = 1;
+	LIMIT(n, 0, term.col - term.c.x);
 
-	if(dst >= term.col) {
-		tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
-		return;
-	}
+	dst = term.c.x + n;
+	src = term.c.x;
+	size = term.col - dst;
 
 	memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src],
-			size * sizeof(Glyph));
+	        size * sizeof(Glyph));
 	tclearregion(src, term.c.y, dst - 1, term.c.y);
 }
 

From 6b7f63bac597ca03e18fe63ad522b4d1bded08d1 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 25 Apr 2014 17:24:12 +0200
Subject: [PATCH 0648/1146] Simplify a bit more tdeletechar and tinsertblank

The large and repeated expression used in memmove to indirect
the line can be simplified using a pointer, that makes more
clear where begins and where ends the movement.
---
 st.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 263abaa..e468d73 100644
--- a/st.c
+++ b/st.c
@@ -1587,30 +1587,32 @@ tclearregion(int x1, int y1, int x2, int y2) {
 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(&term.line[term.c.y][dst], &term.line[term.c.y][src],
-	        size * sizeof(Glyph));
+	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(&term.line[term.c.y][dst], &term.line[term.c.y][src],
-	        size * sizeof(Glyph));
+	memmove(&line[dst], &line[src], size * sizeof(Glyph));
 	tclearregion(src, term.c.y, dst - 1, term.c.y);
 }
 

From fe31a3f6344b0a1dbe72540aad63812f1edb6c12 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 25 Apr 2014 22:34:24 +0200
Subject: [PATCH 0649/1146] Conformity in the -g geometry handling.

Thanks to Yuri Karaban for suggesting this!

These changes make -g correspond to <cols>x<rows> and honor it so non-tiling
window managers can work with the size hints afterwards. It also adds a -i
flag to force the window size. This is needed so -g keeps being useful in dwm.
---
 st.1 |   8 +++--
 st.c | 106 ++++++++++++++++++++++++++++-------------------------------
 2 files changed, 56 insertions(+), 58 deletions(-)

diff --git a/st.1 b/st.1
index ab90908..7174da2 100644
--- a/st.1
+++ b/st.1
@@ -10,6 +10,7 @@ st \- simple terminal
 .IR font ]
 .RB [ \-g
 .IR geometry ]
+.RB [ \-i ]
 .RB [ \-o
 .IR file ]
 .RB [ \-t 
@@ -36,11 +37,14 @@ defines the
 to use when st is run.
 .TP
 .BI \-g " geometry"
-defines the X11 geometry string, which will fixate the height and width of st. 
-The form is [=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]. See
+defines the X11 geometry string.
+The form is [=][<cols>{xX}<rows>][{+-}<xoffset>{+-}<yoffset>]. See
 .BR XParseGeometry (3)
 for further details.
 .TP
+.B \-f
+will fixate the position given with the -g option.
+.TP
 .BI \-o " file"
 writes all the I/O to
 .I file.
diff --git a/st.c b/st.c
index e468d73..2741ef8 100644
--- a/st.c
+++ b/st.c
@@ -250,7 +250,8 @@ typedef struct {
 	XSetWindowAttributes attrs;
 	int scr;
 	bool isfixed; /* is fixed geometry? */
-	int fx, fy, fw, fh; /* fixed geometry */
+	int l, t; /* left and top offset */
+	int gm; /* geometry mask */
 	int tw, th; /* tty width and height */
 	int w, h; /* window width and height */
 	int ch; /* char height */
@@ -406,6 +407,7 @@ static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
 static int xsetcolorname(int, const char *);
+static int xgeommasktogravity(int);
 static int xloadfont(Font *, FcPattern *);
 static void xloadfonts(char *, double);
 static int xloadfontset(Font *);
@@ -2804,18 +2806,24 @@ xhints(void) {
 	XSizeHints *sizeh = NULL;
 
 	sizeh = XAllocSizeHints();
-	if(xw.isfixed == False) {
-		sizeh->flags = PSize | PResizeInc | PBaseSize;
-		sizeh->height = xw.h;
-		sizeh->width = xw.w;
-		sizeh->height_inc = xw.ch;
-		sizeh->width_inc = xw.cw;
-		sizeh->base_height = 2 * borderpx;
-		sizeh->base_width = 2 * borderpx;
-	} else {
-		sizeh->flags = PMaxSize | PMinSize;
-		sizeh->min_width = sizeh->max_width = xw.fw;
-		sizeh->min_height = sizeh->max_height = xw.fh;
+
+	sizeh->flags = PSize | PResizeInc | PBaseSize;
+	sizeh->height = xw.h;
+	sizeh->width = xw.w;
+	sizeh->height_inc = xw.ch;
+	sizeh->width_inc = xw.cw;
+	sizeh->base_height = 2 * borderpx;
+	sizeh->base_width = 2 * borderpx;
+	if(xw.isfixed == True) {
+		sizeh->flags |= PMaxSize | PMinSize;
+		sizeh->min_width = sizeh->max_width = xw.w;
+		sizeh->min_height = sizeh->max_height = xw.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,
@@ -2823,6 +2831,19 @@ xhints(void) {
 	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 *match;
@@ -2968,7 +2989,6 @@ xinit(void) {
 	XGCValues gcvalues;
 	Cursor cursor;
 	Window parent;
-	int sw, sh;
 	pid_t thispid = getpid();
 
 	if(!(xw.dpy = XOpenDisplay(NULL)))
@@ -2988,23 +3008,12 @@ xinit(void) {
 	xloadcols();
 
 	/* adjust fixed window geometry */
-	if(xw.isfixed) {
-		sw = DisplayWidth(xw.dpy, xw.scr);
-		sh = DisplayHeight(xw.dpy, xw.scr);
-		if(xw.fx < 0)
-			xw.fx = sw + xw.fx - xw.fw - 1;
-		if(xw.fy < 0)
-			xw.fy = sh + xw.fy - xw.fh - 1;
-
-		xw.h = xw.fh;
-		xw.w = xw.fw;
-	} else {
-		/* window - default size */
-		xw.h = 2 * borderpx + term.row * xw.ch;
-		xw.w = 2 * borderpx + term.col * xw.cw;
-		xw.fx = 0;
-		xw.fy = 0;
-	}
+	xw.w = 2 * borderpx + term.col * xw.cw;
+	xw.h = 2 * borderpx + term.row * xw.ch;
+	if(xw.gm & XNegative)
+		xw.l += DisplayWidth(xw.dpy, xw.scr) - xw.w - 2;
+	if(xw.gm & YNegative)
+		xw.t += DisplayWidth(xw.dpy, xw.scr) - xw.h - 2;
 
 	/* Events */
 	xw.attrs.background_pixel = dc.col[defaultbg].pixel;
@@ -3017,7 +3026,7 @@ xinit(void) {
 
 	parent = opt_embed ? strtol(opt_embed, NULL, 0) : \
 			XRootWindow(xw.dpy, xw.scr);
-	xw.win = XCreateWindow(xw.dpy, parent, xw.fx, xw.fy,
+	xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
 			xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
 			xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
 			| CWEventMask | CWColormap, &xw.attrs);
@@ -3714,10 +3723,7 @@ run(void) {
 	}
 
 	ttynew();
-	if(!xw.isfixed)
-		cresize(w, h);
-	else
-		cresize(xw.fw, xw.fh);
+	cresize(w, h);
 
 	gettimeofday(&last, NULL);
 	lastblink = last;
@@ -3807,11 +3813,10 @@ usage(void) {
 
 int
 main(int argc, char *argv[]) {
-	int bitm, xr, yr;
-	uint wr, hr;
 	char *titles;
+	uint cols = 80, rows = 24;
 
-	xw.fw = xw.fh = xw.fx = xw.fy = 0;
+	xw.l = xw.t = 0;
 	xw.isfixed = False;
 
 	ARGBEGIN {
@@ -3835,22 +3840,11 @@ main(int argc, char *argv[]) {
 		opt_font = EARGF(usage());
 		break;
 	case 'g':
-		bitm = XParseGeometry(EARGF(usage()), &xr, &yr, &wr, &hr);
-		if(bitm & XValue)
-			xw.fx = xr;
-		if(bitm & YValue)
-			xw.fy = yr;
-		if(bitm & WidthValue)
-			xw.fw = (int)wr;
-		if(bitm & HeightValue)
-			xw.fh = (int)hr;
-		if(bitm & XNegative && xw.fx == 0)
-			xw.fx = -1;
-		if(bitm & YNegative && xw.fy == 0)
-			xw.fy = -1;
-
-		if(xw.fh != 0 && xw.fw != 0)
-			xw.isfixed = True;
+		xw.gm = XParseGeometry(EARGF(usage()),
+				&xw.l, &xw.t, &cols, &rows);
+		break;
+	case 'i':
+		xw.isfixed = True;
 		break;
 	case 'o':
 		opt_io = EARGF(usage());
@@ -3869,7 +3863,7 @@ main(int argc, char *argv[]) {
 run:
 	setlocale(LC_CTYPE, "");
 	XSetLocaleModifiers("");
-	tnew(80, 24);
+	tnew(cols? cols : 1, rows? rows : 1);
 	xinit();
 	selinit();
 	run();

From 99d2d6007ace1d5558ee349224af275722fcc701 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Wed, 23 Apr 2014 23:12:29 +0400
Subject: [PATCH 0650/1146] Use BETWEEN macro in xsetcolorname and fix style.

---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 2741ef8..1a2b1dd 100644
--- a/st.c
+++ b/st.c
@@ -2751,10 +2751,10 @@ int
 xsetcolorname(int x, const char *name) {
 	XRenderColor color = { .alpha = 0xffff };
 	Colour colour;
-	if (x < 0 || x > LEN(colorname))
+	if(!BETWEEN(x, 0, LEN(colorname)))
 		return -1;
 	if(!name) {
-		if(16 <= x && x < 16 + 216) {
+		if(BETWEEN(x, 16, 16 + 215)) {
 			int r = (x - 16) / 36, g = ((x - 16) % 36) / 6, b = (x - 16) % 6;
 			color.red = sixd_to_16bit(r);
 			color.green = sixd_to_16bit(g);
@@ -2763,7 +2763,7 @@ xsetcolorname(int x, const char *name) {
 				return 0; /* something went wrong */
 			dc.col[x] = colour;
 			return 1;
-		} else if (16 + 216 <= x && x < 256) {
+		} else if(BETWEEN(x, 16 + 216, 255)) {
 			color.red = color.green = color.blue = 0x0808 + 0x0a0a * (x - (16 + 216));
 			if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour))
 				return 0; /* something went wrong */

From 1b0b9759dca9739da04f5c8a206b2f8ee5ed8b25 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Wed, 23 Apr 2014 23:12:36 +0400
Subject: [PATCH 0651/1146] Use != instead of ^ for logical values.

sel.alt is only changed by
	sel.alt = IS_SET(MODE_ALTSCREEN);
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 1a2b1dd..ff9bdd8 100644
--- a/st.c
+++ b/st.c
@@ -3457,7 +3457,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 	bool ena_sel = sel.ob.x != -1;
 	long unicodep;
 
-	if(sel.alt ^ IS_SET(MODE_ALTSCREEN))
+	if(sel.alt != IS_SET(MODE_ALTSCREEN))
 		ena_sel = 0;
 
 	if(!(xw.state & WIN_VISIBLE))

From 844c503c800e5e1db1e409f5db729431ee2e5c00 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Wed, 23 Apr 2014 23:12:45 +0400
Subject: [PATCH 0652/1146] Optimize tputtab.

Before this patch executing
	printf '\e[10000000000I'
or
	printf '\e[10000000000Z'
resulted in long delay.
---
 st.c | 28 ++++++++++++----------------
 1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/st.c b/st.c
index ff9bdd8..c9ef574 100644
--- a/st.c
+++ b/st.c
@@ -375,7 +375,7 @@ static void tmoveto(int, int);
 static void tmoveato(int, int);
 static void tnew(int, int);
 static void tnewline(int);
-static void tputtab(bool);
+static void tputtab(int);
 static void tputc(char *, int);
 static void treset(void);
 static int tresize(int, int);
@@ -1996,8 +1996,7 @@ csihandle(void) {
 		break;
 	case 'I': /* CHT -- Cursor Forward Tabulation <n> tab stops */
 		DEFAULT(csiescseq.arg[0], 1);
-		while(csiescseq.arg[0]--)
-			tputtab(1);
+		tputtab(csiescseq.arg[0]);
 		break;
 	case 'J': /* ED -- Clear screen */
 		selclear(NULL);
@@ -2065,8 +2064,7 @@ csihandle(void) {
 		break;
 	case 'Z': /* CBT -- Cursor Backward Tabulation <n> tab stops */
 		DEFAULT(csiescseq.arg[0], 1);
-		while(csiescseq.arg[0]--)
-			tputtab(0);
+		tputtab(-csiescseq.arg[0]);
 		break;
 	case 'd': /* VPA -- Move to <row> */
 		DEFAULT(csiescseq.arg[0], 1);
@@ -2281,19 +2279,17 @@ tdump(void) {
 }
 
 void
-tputtab(bool forward) {
+tputtab(int n) {
 	uint x = term.c.x;
 
-	if(forward) {
-		if(x == term.col)
-			return;
-		for(++x; x < term.col && !term.tabs[x]; ++x)
-			/* nothing */ ;
-	} else {
-		if(x == 0)
-			return;
-		for(--x; x > 0 && !term.tabs[x]; --x)
-			/* nothing */ ;
+	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 */ ;
 	}
 	tmoveto(x, term.c.y);
 }

From 8f11e1cd034ff28ca47bb4955505db7fa8016ba8 Mon Sep 17 00:00:00 2001
From: Colona <colona@ycc.fr>
Date: Thu, 24 Apr 2014 20:35:41 +0200
Subject: [PATCH 0653/1146] On terminal resize, clear the alt screen with its
 own cursor.

Currently the alternate screen get messed up on resize if it has
different colors or mode.
---
 st.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.c b/st.c
index c9ef574..b37069c 100644
--- a/st.c
+++ b/st.c
@@ -2674,7 +2674,9 @@ tresize(int col, int row) {
 		if(0 < col && minrow < row) {
 			tclearregion(0, minrow, col - 1, row - 1);
 		}
+		tcursor(CURSOR_SAVE);
 		tswapscreen();
+		tcursor(CURSOR_LOAD);
 	} while(orig != term.line);
 
 	return (slide > 0);

From 4a8574b439e2118bd4cb40374185fba861903620 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Fri, 25 Apr 2014 18:26:43 +0400
Subject: [PATCH 0654/1146] Comment fix.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index b37069c..653cd49 100644
--- a/st.c
+++ b/st.c
@@ -992,7 +992,7 @@ selnotify(XEvent *e) {
 		}
 
 		/*
-		 * As seen in selcopy:
+		 * 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'.

From 2d67f99d286b7c00b298d0f0908035ca49cd4909 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Fri, 25 Apr 2014 18:27:15 +0400
Subject: [PATCH 0655/1146] Remove unnecessary break

---
 st.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.c b/st.c
index 653cd49..7dd5e04 100644
--- a/st.c
+++ b/st.c
@@ -1781,7 +1781,6 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 	for(lim = args + narg; args < lim; ++args) {
 		if(priv) {
 			switch(*args) {
-				break;
 			case 1: /* DECCKM -- Cursor key */
 				MODBIT(term.mode, set, MODE_APPCURSOR);
 				break;

From 84f6dbffa5a26e1a2f94f844844d76f80dd6c5a0 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Fri, 25 Apr 2014 18:27:26 +0400
Subject: [PATCH 0656/1146] Use xwrite instead of write.

---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 7dd5e04..f91eb8d 100644
--- a/st.c
+++ b/st.c
@@ -452,7 +452,7 @@ static char utf8encodebyte(long, size_t);
 static size_t utf8len(char *);
 static size_t utf8validate(long *, size_t);
 
-static ssize_t xwrite(int, char *, size_t);
+static ssize_t xwrite(int, const char *, size_t);
 static void *xmalloc(size_t);
 static void *xrealloc(void *, size_t);
 static char *xstrdup(char *);
@@ -518,7 +518,7 @@ static Fontcache frc[16];
 static int frclen = 0;
 
 ssize_t
-xwrite(int fd, char *s, size_t len) {
+xwrite(int fd, const char *s, size_t len) {
 	size_t aux = len;
 
 	while(len > 0) {
@@ -1270,7 +1270,7 @@ ttyread(void) {
 
 void
 ttywrite(const char *s, size_t n) {
-	if(write(cmdfd, s, n) == -1)
+	if(xwrite(cmdfd, s, n) == -1)
 		die("write error on tty: %s\n", strerror(errno));
 }
 

From 7f1e02e4dbb6e6f033797a09a7deea4fe29f2ca6 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Fri, 25 Apr 2014 18:27:48 +0400
Subject: [PATCH 0657/1146] s/DSC/DCS/ DCS stands for DEVICE CONTROL STRING

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index f91eb8d..297eb3f 100644
--- a/st.c
+++ b/st.c
@@ -149,7 +149,7 @@ enum charset {
 enum escape_state {
 	ESC_START      = 1,
 	ESC_CSI        = 2,
-	ESC_STR        = 4,  /* DSC, OSC, PM, APC */
+	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 */
@@ -2169,7 +2169,7 @@ strhandle(void) {
 	case 'k': /* old title set compatibility */
 		xsettitle(strescseq.args[0]);
 		return;
-	case 'P': /* DSC -- Device Control String */
+	case 'P': /* DCS -- Device Control String */
 	case '_': /* APC -- Application Program Command */
 	case '^': /* PM -- Privacy Message */
 		return;

From c4b79b055df9ef0126f05dd6dbd2bbf935dcb980 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Fri, 25 Apr 2014 18:28:00 +0400
Subject: [PATCH 0658/1146] Fix for multibyte characters in techo.

Works for both signed and unsigned char.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 297eb3f..cacbe20 100644
--- a/st.c
+++ b/st.c
@@ -2298,7 +2298,7 @@ techo(char *buf, int len) {
 	for(; len > 0; buf++, len--) {
 		char c = *buf;
 
-		if(c < 0x20 || c == 0177) { /* control code */
+		if(BETWEEN(c, 0x00, 0x1f) || c == 0x7f) { /* control code */
 			if(c != '\n' && c != '\r' && c != '\t') {
 				c ^= '\x40';
 				tputc("^", 1);

From 02d2df5790d186f16e0e22becd8107a85f328c2f Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sat, 26 Apr 2014 00:12:41 +0200
Subject: [PATCH 0659/1146] Do not eat ESC character if control string is not
 properly terminated.

Currently tputc handles the case of too long control string waiting for
the end of control string.

Another case is when there is ESC character is encountered but is not
followed by '\\'.  In this case st stops processing control string,
but ESC character is ignored.

After this patch st processes ESC characters in control strings properly.

Test case:
printf '\e]0;abc\e[1mBOLD\e[0m'

Also ^[\ is actually processed in the code that handles ST.
According to ECMA-048 ST stands for STRING TERMINATOR and is used to
close control strings.
---
 st.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index cacbe20..d2261e2 100644
--- a/st.c
+++ b/st.c
@@ -2452,10 +2452,6 @@ tputc(char *c, int len) {
 				csiparse();
 				csihandle();
 			}
-		} else if(term.esc & ESC_STR_END) {
-			term.esc = 0;
-			if(ascii == '\\')
-				strhandle();
 		} else if(term.esc & ESC_ALTCHARSET) {
 			tdeftran(ascii);
 			tselcs();
@@ -2545,7 +2541,9 @@ tputc(char *c, int len) {
 				tcursor(CURSOR_LOAD);
 				term.esc = 0;
 				break;
-			case '\\': /* ST -- Stop */
+			case '\\': /* ST -- String Terminator */
+				if(term.esc & ESC_STR_END)
+					strhandle();
 				term.esc = 0;
 				break;
 			default:

From 704d12442e85ded011f71c95e90534ebacc81692 Mon Sep 17 00:00:00 2001
From: Markus Teich <markus.teich@stusta.mhn.de>
Date: Sat, 26 Apr 2014 23:50:37 +0200
Subject: [PATCH 0660/1146] add break;s for last cases in switch statements

---
 st.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/st.c b/st.c
index d2261e2..49df792 100644
--- a/st.c
+++ b/st.c
@@ -1228,6 +1228,7 @@ ttynew(void) {
 					opt_io, strerror(errno));
 			}
 		}
+		break;
 	}
 }
 
@@ -1673,6 +1674,7 @@ tdefcolor(int *attr, int *npar, int l) {
 	default:
 		fprintf(stderr,
 		        "erresc(38): gfx attr %d unknown\n", attr[*npar]);
+		break;
 	}
 
 	return idx;
@@ -2387,6 +2389,7 @@ tputc(char *c, int len) {
 			 * strhandle();
 			 */
 			}
+			break;
 		}
 		return;
 	}
@@ -2550,6 +2553,7 @@ tputc(char *c, int len) {
 				fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
 					(uchar) ascii, isprint(ascii)? ascii:'.');
 				term.esc = 0;
+				break;
 			}
 		}
 		/*

From aa35bbd7a16c6c210a7574a8c45bbe939d5b2922 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 26 Apr 2014 01:34:46 +0200
Subject: [PATCH 0661/1146] Cancel DCS with SUB, CAN, ESC or any CC1 code

From http://www.vt100.net/docs/vt510-rm/chapter4:

	*The VT510 ignores all following characters until it receives a
	 SUB, ST, or any other C1 control character.

So OSC, PM and APC sequence ends with a SUB (it cancels the sequence
and show a question mark as error), ST or any another C1 (8 bits)
code, or their C0 (7 bits) equivalent sequences (at this moment we
do not handle C1 codes, but we should). But it is also said that:

	Cancel  CAN
	1/8     Immediately cancels an escape sequence, control sequence,
		or device control string in progress. In this case, the
		VT510 does not display any error character.

	Escape  ESC
	1/11    Introduces an escape sequence. ESC also cancels any escape
		sequence, control sequence, or device control string in
		progress.
---
 st.c | 206 ++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 127 insertions(+), 79 deletions(-)

diff --git a/st.c b/st.c
index 49df792..124c047 100644
--- a/st.c
+++ b/st.c
@@ -70,6 +70,8 @@ char *argv0;
 #define LEN(a)     (sizeof(a) / sizeof(a)[0])
 #define DEFAULT(a, b)     (a) = (a) ? (a) : (b)
 #define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (b))
+#define ISCONTROLC0(c) (BETWEEN((uchar) (c), 0, 0x1f))
+#define ISCONTROLC1(c) (BETWEEN((uchar) (c), 0x80, 0x9f))
 #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 IS_SET(flag) ((term.mode & (flag)) != 0)
@@ -390,6 +392,7 @@ static void tsetdirtattr(int);
 static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 static void techo(char *, int);
+static bool tcontrolcode(uchar );
 static int32_t tdefcolor(int *, int *, int);
 static void tselcs(void);
 static void tdeftran(char);
@@ -399,6 +402,7 @@ static void ttyread(void);
 static void ttyresize(void);
 static void ttysend(char *, size_t);
 static void ttywrite(const char *, size_t);
+static inline bool iscontrol(char);
 
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
@@ -2136,6 +2140,7 @@ strhandle(void) {
 	char *p = NULL;
 	int j, narg, par;
 
+	term.esc &= ~(ESC_STR_END|ESC_STR);
 	strparse();
 	narg = strescseq.narg;
 	par = atoi(strescseq.args[0]);
@@ -2295,13 +2300,22 @@ tputtab(int n) {
 	tmoveto(x, term.c.y);
 }
 
+static inline bool
+iscontrol(char c) {
+	return ISCONTROLC0(c) || ISCONTROLC1(c);
+}
+
 void
 techo(char *buf, int len) {
 	for(; len > 0; buf++, len--) {
 		char c = *buf;
 
-		if(BETWEEN(c, 0x00, 0x1f) || c == 0x7f) { /* control code */
-			if(c != '\n' && c != '\r' && c != '\t') {
+		if(iscontrol(c)) { /* control code */
+			if(c & 0x80) {
+				c &= 0x7f;
+				tputc("^", 1);
+				tputc("[", 1);
+			} else if(c != '\n' && c != '\r' && c != '\t') {
 				c ^= '\x40';
 				tputc("^", 1);
 			}
@@ -2340,58 +2354,135 @@ tselcs(void) {
 	       ATTR_GFX);
 }
 
+bool
+tcontrolcode(uchar ascii) {
+	static char question[UTF_SIZ] = "?";
+
+	switch(ascii) {
+	case '\t':   /* HT */
+		tputtab(1);
+		break;
+	case '\b':   /* BS */
+		tmoveto(term.c.x-1, term.c.y);
+		break;
+	case '\r':   /* CR */
+		tmoveto(0, term.c.y);
+		break;
+	case '\f':   /* LF */
+	case '\v':   /* VT */
+	case '\n':   /* LF */
+		/* go to first col if the mode is set */
+		tnewline(IS_SET(MODE_CRLF));
+		break;
+	case '\a':   /* BEL */
+		if(term.esc & ESC_STR_END) {
+			/* backwards compatibility to xterm */
+			strhandle();
+		} else {
+			if(!(xw.state & WIN_FOCUSED))
+				xseturgency(1);
+			if (bellvolume)
+				XBell(xw.dpy, bellvolume);
+		}
+		break;
+	case '\033': /* ESC */
+		csireset();
+		term.esc &= ~(ESC_CSI|ESC_ALTCHARSET|ESC_TEST);
+		term.esc |= ESC_START;
+		return 1;
+	case '\016': /* SO */
+		term.charset = 0;
+		tselcs();
+		break;
+	case '\017': /* SI */
+		term.charset = 1;
+		tselcs();
+		break;
+	case '\032': /* SUB */
+		tsetchar(question, &term.c.attr, term.c.x, term.c.y);
+	case '\030': /* CAN */
+		csireset();
+		break;
+	case '\005': /* ENQ (IGNORED) */
+	case '\000': /* NUL (IGNORED) */
+	case '\021': /* XON (IGNORED) */
+	case '\023': /* XOFF (IGNORED) */
+	case 0177:   /* DEL (IGNORED) */
+	case 0x84:   /* TODO: IND */
+	case 0x85:   /* TODO: NEL */
+	case 0x88:   /* TODO: HTS */
+	case 0x8d:   /* TODO: RI */
+	case 0x8e:   /* TODO: SS2 */
+	case 0x8f:   /* TODO: SS3 */
+	case 0x90:   /* TODO: DCS */
+	case 0x98:   /* TODO: SOS */
+	case 0x9a:   /* TODO: DECID */
+	case 0x9b:   /* TODO: CSI */
+	case 0x9c:   /* TODO: ST */
+	case 0x9d:   /* TODO: OSC */
+	case 0x9e:   /* TODO: PM */
+	case 0x9f:   /* TODO: APC */
+		break;
+	default:
+		return 0;
+	}
+	term.esc &= ~(ESC_STR_END|ESC_STR);
+	return 1;
+}
+
 void
 tputc(char *c, int len) {
-	uchar ascii = *c;
-	bool control = ascii < '\x20' || ascii == 0177;
+	uchar ascii;
+	bool control;
 	long unicodep;
 	int width;
 
 	if(len == 1) {
 		width = 1;
+		ascii = *c;
 	} else {
 		utf8decode(c, &unicodep, UTF_SIZ);
 		width = wcwidth(unicodep);
+		ascii = unicodep;
 	}
 
+	control = iscontrol(ascii) && width == 1;
 	if(IS_SET(MODE_PRINT))
 		tprinter(c, len);
 
 	/*
-	 * STR sequences must be checked before anything else
-	 * because it can use some control codes as part of the sequence.
+	 * 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) {
-		switch(ascii) {
-		case '\033':
-			term.esc = ESC_START | ESC_STR_END;
-			break;
-		case '\a': /* backwards compatibility to xterm */
-			term.esc = 0;
-			strhandle();
-			break;
-		default:
-			if(strescseq.len + len < sizeof(strescseq.buf) - 1) {
-				memmove(&strescseq.buf[strescseq.len], c, len);
-				strescseq.len += len;
-			} else {
-			/*
-			 * 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();
-			 */
-			}
-			break;
+		if(width == 1 &&
+		   (ascii == '\a' || ascii == 030 ||
+		    ascii == 032  || ascii == 033 ||
+		    ISCONTROLC1(ascii))) {
+			term.esc &= ~ESC_STR;
+			term.esc |= ESC_STR_END;
+		} else if(strescseq.len + len < sizeof(strescseq.buf) - 1) {
+			memmove(&strescseq.buf[strescseq.len], c, len);
+			strescseq.len += len;
+			return;
+		} else {
+		/*
+		 * Here is a bug in terminals. If the user never sends
+		 * some code to stop the str or esc command, then st
+		 * will stop responding. But this is better than
+		 * silently failing with unknown characters. At least
+		 * then users will report back.
+		 *
+		 * In the case users ever get fixed, here is the code:
+		 */
+		/*
+		 * term.esc = 0;
+		 * strhandle();
+		 */
+			return;
 		}
-		return;
 	}
 
 	/*
@@ -2400,51 +2491,8 @@ tputc(char *c, int len) {
 	 * they must not cause conflicts with sequences.
 	 */
 	if(control) {
-		switch(ascii) {
-		case '\t':   /* HT */
-			tputtab(1);
+		if (tcontrolcode(ascii))
 			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(!(xw.state & WIN_FOCUSED))
-				xseturgency(1);
-			if (bellvolume)
-				XBell(xw.dpy, bellvolume);
-			return;
-		case '\033': /* ESC */
-			csireset();
-			term.esc = ESC_START;
-			return;
-		case '\016': /* SO */
-			term.charset = 0;
-			tselcs();
-			return;
-		case '\017': /* SI */
-			term.charset = 1;
-			tselcs();
-			return;
-		case '\032': /* SUB */
-		case '\030': /* CAN */
-			csireset();
-			return;
-		case '\005': /* ENQ (IGNORED) */
-		case '\000': /* NUL (IGNORED) */
-		case '\021': /* XON (IGNORED) */
-		case '\023': /* XOFF (IGNORED) */
-		case 0177:   /* DEL (IGNORED) */
-			return;
-		}
 	} else if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {
 			csiescseq.buf[csiescseq.len++] = ascii;

From 53105cf74fde46229912275c073f8c0f219b05bb Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 26 Apr 2014 01:45:10 +0200
Subject: [PATCH 0662/1146] Remove repeated initialisation of term.esc

Once a sequence is completed term.esc must return to 0, so
instead of repeating this expression in all the cases is
better put it at the end of the block.
---
 st.c | 24 ++++++------------------
 1 file changed, 6 insertions(+), 18 deletions(-)

diff --git a/st.c b/st.c
index 124c047..0425c72 100644
--- a/st.c
+++ b/st.c
@@ -2503,10 +2503,10 @@ tputc(char *c, int len) {
 				csiparse();
 				csihandle();
 			}
+			return;
 		} else if(term.esc & ESC_ALTCHARSET) {
 			tdeftran(ascii);
 			tselcs();
-			term.esc = 0;
 		} else if(term.esc & ESC_TEST) {
 			if(ascii == '8') { /* DEC screen alignment test. */
 				char E[UTF_SIZ] = "E";
@@ -2517,15 +2517,14 @@ tputc(char *c, int len) {
 						tsetchar(E, &term.c.attr, x, y);
 				}
 			}
-			term.esc = 0;
 		} else {
 			switch(ascii) {
 			case '[':
 				term.esc |= ESC_CSI;
-				break;
+				return;
 			case '#':
 				term.esc |= ESC_TEST;
-				break;
+				return;
 			case 'P': /* DCS -- Device Control String */
 			case '_': /* APC -- Application Program Command */
 			case '^': /* PM -- Privacy Message */
@@ -2534,29 +2533,26 @@ tputc(char *c, int len) {
 				strreset();
 				strescseq.type = ascii;
 				term.esc |= ESC_STR;
-				break;
+				return;
 			case '(': /* set primary charset G0 */
 			case ')': /* set secondary charset G1 */
 			case '*': /* set tertiary charset G2 */
 			case '+': /* set quaternary charset G3 */
 				term.icharset = ascii - '(';
 				term.esc |= ESC_ALTCHARSET;
-				break;
+				return;
 			case 'D': /* IND -- Linefeed */
 				if(term.c.y == term.bot) {
 					tscrollup(term.top, 1);
 				} else {
 					tmoveto(term.c.x, term.c.y+1);
 				}
-				term.esc = 0;
 				break;
 			case 'E': /* NEL -- Next line */
 				tnewline(1); /* always go to first col */
-				term.esc = 0;
 				break;
 			case 'H': /* HTS -- Horizontal tab stop */
 				term.tabs[term.c.x] = 1;
-				term.esc = 0;
 				break;
 			case 'M': /* RI -- Reverse index */
 				if(term.c.y == term.top) {
@@ -2564,46 +2560,38 @@ tputc(char *c, int len) {
 				} else {
 					tmoveto(term.c.x, term.c.y-1);
 				}
-				term.esc = 0;
 				break;
 			case 'Z': /* DECID -- Identify Terminal */
 				ttywrite(VT102ID, sizeof(VT102ID) - 1);
-				term.esc = 0;
 				break;
 			case 'c': /* RIS -- Reset to inital state */
 				treset();
-				term.esc = 0;
 				xresettitle();
 				xloadcols();
 				break;
 			case '=': /* DECPAM -- Application keypad */
 				term.mode |= MODE_APPKEYPAD;
-				term.esc = 0;
 				break;
 			case '>': /* DECPNM -- Normal keypad */
 				term.mode &= ~MODE_APPKEYPAD;
-				term.esc = 0;
 				break;
 			case '7': /* DECSC -- Save Cursor */
 				tcursor(CURSOR_SAVE);
-				term.esc = 0;
 				break;
 			case '8': /* DECRC -- Restore Cursor */
 				tcursor(CURSOR_LOAD);
-				term.esc = 0;
 				break;
 			case '\\': /* ST -- String Terminator */
 				if(term.esc & ESC_STR_END)
 					strhandle();
-				term.esc = 0;
 				break;
 			default:
 				fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
 					(uchar) ascii, isprint(ascii)? ascii:'.');
-				term.esc = 0;
 				break;
 			}
 		}
+		term.esc = 0;
 		/*
 		 * All characters which form part of a sequence are not
 		 * printed

From 3764f38fc805a8846bd18f1d555a10227fd14e29 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 28 Apr 2014 18:32:09 +0200
Subject: [PATCH 0663/1146] Fix tputc control code handling

The patch 53105cf modified how control codes were detected, because
it tried to handle also C1 control codes (0x80-0x9f), that have
upper bit to 1, so they are multi byte character in utf8.
Code was checking the value of width in order to known that after
decoding the unicode point had a width of 1 byte, but it as incorrect
because this width is the columnb width.
---
 st.c | 20 ++++++++------------
 1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/st.c b/st.c
index 0425c72..9a979ea 100644
--- a/st.c
+++ b/st.c
@@ -70,8 +70,9 @@ char *argv0;
 #define LEN(a)     (sizeof(a) / sizeof(a)[0])
 #define DEFAULT(a, b)     (a) = (a) ? (a) : (b)
 #define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (b))
-#define ISCONTROLC0(c) (BETWEEN((uchar) (c), 0, 0x1f))
-#define ISCONTROLC1(c) (BETWEEN((uchar) (c), 0x80, 0x9f))
+#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f))
+#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
+#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
 #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 IS_SET(flag) ((term.mode & (flag)) != 0)
@@ -402,7 +403,6 @@ static void ttyread(void);
 static void ttyresize(void);
 static void ttysend(char *, size_t);
 static void ttywrite(const char *, size_t);
-static inline bool iscontrol(char);
 
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
@@ -2300,17 +2300,12 @@ tputtab(int n) {
 	tmoveto(x, term.c.y);
 }
 
-static inline bool
-iscontrol(char c) {
-	return ISCONTROLC0(c) || ISCONTROLC1(c);
-}
-
 void
 techo(char *buf, int len) {
 	for(; len > 0; buf++, len--) {
 		char c = *buf;
 
-		if(iscontrol(c)) { /* control code */
+		if(ISCONTROL(c)) { /* control code */
 			if(c & 0x80) {
 				c &= 0x7f;
 				tputc("^", 1);
@@ -2439,16 +2434,17 @@ tputc(char *c, int len) {
 
 	if(len == 1) {
 		width = 1;
-		ascii = *c;
+		unicodep = ascii = *c;
 	} else {
 		utf8decode(c, &unicodep, UTF_SIZ);
 		width = wcwidth(unicodep);
+		control = ISCONTROLC1(unicodep);
 		ascii = unicodep;
 	}
 
-	control = iscontrol(ascii) && width == 1;
 	if(IS_SET(MODE_PRINT))
 		tprinter(c, len);
+	control = ISCONTROL(unicodep);
 
 	/*
 	 * STR sequence must be checked before anything else
@@ -2460,7 +2456,7 @@ tputc(char *c, int len) {
 		if(width == 1 &&
 		   (ascii == '\a' || ascii == 030 ||
 		    ascii == 032  || ascii == 033 ||
-		    ISCONTROLC1(ascii))) {
+		    ISCONTROLC1(unicodep))) {
 			term.esc &= ~ESC_STR;
 			term.esc |= ESC_STR_END;
 		} else if(strescseq.len + len < sizeof(strescseq.buf) - 1) {

From 43d74ef362b7dc5da3232cdc9412981ea6386df6 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 26 Apr 2014 09:24:04 +0200
Subject: [PATCH 0664/1146] Create a function for DEC test

Almost of the sequences execute their action in a separate function,
which is good because helps to read the full set of sequences
faster.
---
 st.c | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index 9a979ea..2945c1b 100644
--- a/st.c
+++ b/st.c
@@ -394,6 +394,7 @@ static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 static void techo(char *, int);
 static bool tcontrolcode(uchar );
+static void tdectest(char );
 static int32_t tdefcolor(int *, int *, int);
 static void tselcs(void);
 static void tdeftran(char);
@@ -2425,6 +2426,19 @@ tcontrolcode(uchar ascii) {
 	return 1;
 }
 
+void
+tdectest(char c) {
+	static char E[UTF_SIZ] = "E";
+	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
 tputc(char *c, int len) {
 	uchar ascii;
@@ -2504,15 +2518,7 @@ tputc(char *c, int len) {
 			tdeftran(ascii);
 			tselcs();
 		} else if(term.esc & ESC_TEST) {
-			if(ascii == '8') { /* DEC screen alignment test. */
-				char E[UTF_SIZ] = "E";
-				int x, y;
-
-				for(x = 0; x < term.col; ++x) {
-					for(y = 0; y < term.row; ++y)
-						tsetchar(E, &term.c.attr, x, y);
-				}
-			}
+			tdectest(ascii);
 		} else {
 			switch(ascii) {
 			case '[':

From 17290f493b3701f57f1e8a1f2d26fc12ab968928 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 26 Apr 2014 09:30:53 +0200
Subject: [PATCH 0665/1146] Fix misplaced break

This misplaced break was causing an incorrect fall through
from DSR to DECSTBM.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 2945c1b..bd0c59e 100644
--- a/st.c
+++ b/st.c
@@ -2087,8 +2087,8 @@ csihandle(void) {
 			len = snprintf(buf, sizeof(buf),"\033[%i;%iR",
 					term.c.y+1, term.c.x+1);
 			ttywrite(buf, len);
-			break;
 		}
+		break;
 	case 'r': /* DECSTBM -- Set Scrolling Region */
 		if(csiescseq.priv) {
 			goto unknown;

From a8a9e66a7d481c66bd9680ff0670c322bedd7ca7 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 27 Apr 2014 10:25:15 +0200
Subject: [PATCH 0666/1146] Simplify expressions in tputc()

---
 st.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index bd0c59e..548e0c2 100644
--- a/st.c
+++ b/st.c
@@ -2445,6 +2445,7 @@ tputc(char *c, int len) {
 	bool control;
 	long unicodep;
 	int width;
+	Glyph *gp;
 
 	if(len == 1) {
 		width = 1;
@@ -2607,16 +2608,15 @@ tputc(char *c, int len) {
 		return;
 	if(sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
 		selclear(NULL);
+
+	gp = &term.line[term.c.y][term.c.x];
 	if(IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
-		term.line[term.c.y][term.c.x].mode |= ATTR_WRAP;
+		gp->mode |= ATTR_WRAP;
 		tnewline(1);
 	}
 
-	if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col) {
-		memmove(&term.line[term.c.y][term.c.x+1],
-			&term.line[term.c.y][term.c.x],
-			(term.col - term.c.x - 1) * sizeof(Glyph));
-	}
+	if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col)
+		memmove(gp+1, gp, (term.col - term.c.x - 1) * sizeof(Glyph));
 
 	if(term.c.x+width > term.col)
 		tnewline(1);
@@ -2624,10 +2624,10 @@ tputc(char *c, int len) {
 	tsetchar(c, &term.c.attr, term.c.x, term.c.y);
 
 	if(width == 2) {
-		term.line[term.c.y][term.c.x].mode |= ATTR_WIDE;
+		gp->mode |= ATTR_WIDE;
 		if(term.c.x+1 < term.col) {
-			term.line[term.c.y][term.c.x+1].c[0] = '\0';
-			term.line[term.c.y][term.c.x+1].mode = ATTR_WDUMMY;
+			gp[1].c[0] = '\0';
+			gp[1].mode = ATTR_WDUMMY;
 		}
 	}
 	if(term.c.x+width < term.col) {

From 17fa1493ee0d8c53c63b3c8d1325ee38fd3192e1 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sun, 27 Apr 2014 15:39:29 +0400
Subject: [PATCH 0667/1146] Compute ena_sel as one expression.

---
 st.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 548e0c2..fb206a3 100644
--- a/st.c
+++ b/st.c
@@ -3491,12 +3491,9 @@ drawregion(int x1, int y1, int x2, int y2) {
 	int ic, ib, x, y, ox, sl;
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
-	bool ena_sel = sel.ob.x != -1;
+	bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 	long unicodep;
 
-	if(sel.alt != IS_SET(MODE_ALTSCREEN))
-		ena_sel = 0;
-
 	if(!(xw.state & WIN_VISIBLE))
 		return;
 

From a48f2be7f537cb1655c6b550d9346a17459a94bd Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sun, 27 Apr 2014 15:39:39 +0400
Subject: [PATCH 0668/1146] Use MODBIT in xseturgency.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index fb206a3..d5a8257 100644
--- a/st.c
+++ b/st.c
@@ -3570,7 +3570,7 @@ void
 xseturgency(int add) {
 	XWMHints *h = XGetWMHints(xw.dpy, xw.win);
 
-	h->flags = add ? (h->flags | XUrgencyHint) : (h->flags & ~XUrgencyHint);
+	MODBIT(h->flags, add, XUrgencyHint);
 	XSetWMHints(xw.dpy, xw.win, h);
 	XFree(h);
 }

From 1ae2745fd160bbc25bab56be31d04a9d7f8ef4d4 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sun, 27 Apr 2014 15:39:47 +0400
Subject: [PATCH 0669/1146] Add missing function prototypes.

---
 st.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/st.c b/st.c
index d5a8257..7afff39 100644
--- a/st.c
+++ b/st.c
@@ -399,6 +399,7 @@ static int32_t tdefcolor(int *, int *, int);
 static void tselcs(void);
 static void tdeftran(char);
 static inline bool match(uint, uint);
+static void dump(char c);
 static void ttynew(void);
 static void ttyread(void);
 static void ttyresize(void);
@@ -449,6 +450,8 @@ static char *getsel(void);
 static void selcopy(void);
 static void selscroll(int, int);
 static void selsnap(int, int *, int *, int);
+static void getbuttoninfo(XEvent *);
+static void mousereport(XEvent *);
 
 static size_t utf8decode(char *, long *, size_t);
 static long utf8decodebyte(char, size_t *);
@@ -462,6 +465,8 @@ static void *xmalloc(size_t);
 static void *xrealloc(void *, size_t);
 static char *xstrdup(char *);
 
+static void usage(void);
+
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
 	[ClientMessage] = cmessage,

From 6681af165b06c32cf65bf970a295600d46cb7025 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sun, 27 Apr 2014 15:40:01 +0400
Subject: [PATCH 0670/1146] Remove unused dump() function.

---
 st.c | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/st.c b/st.c
index 7afff39..4c4a0c3 100644
--- a/st.c
+++ b/st.c
@@ -399,7 +399,6 @@ static int32_t tdefcolor(int *, int *, int);
 static void tselcs(void);
 static void tdeftran(char);
 static inline bool match(uint, uint);
-static void dump(char c);
 static void ttynew(void);
 static void ttyread(void);
 static void ttyresize(void);
@@ -1242,15 +1241,6 @@ ttynew(void) {
 	}
 }
 
-void
-dump(char c) {
-	static int col;
-
-	fprintf(stderr, " %02x '%c' ", c, isprint(c)?c:'.');
-	if(++col % 10 == 0)
-		fprintf(stderr, "\n");
-}
-
 void
 ttyread(void) {
 	static char buf[BUFSIZ];

From 74962bf56636e608f0ee35f2076bc6b48923119d Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sun, 27 Apr 2014 15:40:23 +0400
Subject: [PATCH 0671/1146] Remove one indentation level in getsel().

---
 st.c | 97 ++++++++++++++++++++++++++++++------------------------------
 1 file changed, 48 insertions(+), 49 deletions(-)

diff --git a/st.c b/st.c
index 4c4a0c3..9079834 100644
--- a/st.c
+++ b/st.c
@@ -922,60 +922,59 @@ getsel(void) {
 	int x, y, bufsize, size, i, ex;
 	Glyph *gp, *last;
 
-	if(sel.ob.x == -1) {
-		str = NULL;
-	} else {
-		bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
-		ptr = str = xmalloc(bufsize);
+	if(sel.ob.x == -1)
+		return NULL;
 
-		/* append every set & selected glyph to the selection */
-		for(y = sel.nb.y; y < sel.ne.y + 1; y++) {
-			gp = &term.line[y][0];
-			last = &gp[term.col-1];
+	bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
+	ptr = str = xmalloc(bufsize);
 
-			while(last >= gp && !(selected(last - gp, y) &&
-			                      strcmp(last->c, " ") != 0)) {
-				--last;
-			}
+	/* append every set & selected glyph to the selection */
+	for(y = sel.nb.y; y < sel.ne.y + 1; y++) {
+		gp = &term.line[y][0];
+		last = &gp[term.col-1];
 
-			for(x = 0; gp <= last; x++, ++gp) {
-				if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))
-					continue;
-
-				size = utf8len(gp->c);
-				memcpy(ptr, gp->c, size);
-				ptr += size;
-			}
-
-			/*
-			 * 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 && x > 0 && !((gp-1)->mode & ATTR_WRAP))
-				*ptr++ = '\n';
-
-			/*
-			 * If the last selected line expands in the selection
-			 * after the visible text '\n' is appended.
-			 */
-			if(y == sel.ne.y) {
-				i = term.col;
-				while(--i > 0 && term.line[y][i].c[0] == ' ')
-					/* nothing */;
-				ex = sel.ne.x;
-				if(sel.nb.y == sel.ne.y && sel.ne.x < sel.nb.x)
-					ex = sel.nb.x;
-				if(i < ex)
-					*ptr++ = '\n';
-			}
+		while(last >= gp && !(selected(last - gp, y) &&
+				      strcmp(last->c, " ") != 0)) {
+			--last;
+		}
+
+		for(x = 0; gp <= last; x++, ++gp) {
+			if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))
+				continue;
+
+			size = utf8len(gp->c);
+			memcpy(ptr, gp->c, size);
+			ptr += size;
+		}
+
+		/*
+		 * 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 && x > 0 && !((gp-1)->mode & ATTR_WRAP))
+			*ptr++ = '\n';
+
+		/*
+		 * If the last selected line expands in the selection
+		 * after the visible text '\n' is appended.
+		 */
+		if(y == sel.ne.y) {
+			i = term.col;
+			while(--i > 0 && term.line[y][i].c[0] == ' ')
+				/* nothing */;
+			ex = sel.ne.x;
+			if(sel.nb.y == sel.ne.y && sel.ne.x < sel.nb.x)
+				ex = sel.nb.x;
+			if(i < ex)
+				*ptr++ = '\n';
 		}
-		*ptr = 0;
 	}
+	*ptr = 0;
 	return str;
 }
 

From 0e439e5624113233525266c2a104792f2c33b7e3 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Mon, 28 Apr 2014 02:41:17 +0400
Subject: [PATCH 0672/1146] Simplify xunloadfonts.

---
 st.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index 9079834..672c47a 100644
--- a/st.c
+++ b/st.c
@@ -2993,13 +2993,9 @@ xunloadfont(Font *f) {
 
 void
 xunloadfonts(void) {
-	int i;
-
 	/* Free the loaded fonts in the font cache.  */
-	for(i = 0; i < frclen; i++) {
-		XftFontClose(xw.dpy, frc[i].font);
-	}
-	frclen = 0;
+	while(frclen > 0)
+		XftFontClose(xw.dpy, frc[--frclen].font);
 
 	xunloadfont(&dc.font);
 	xunloadfont(&dc.bfont);

From 9e3e8ce4661d31629f9d4862467b2fb21c628e38 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sun, 27 Apr 2014 15:39:53 +0400
Subject: [PATCH 0673/1146] Do not export chscale and cwscale.

---
 config.def.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config.def.h b/config.def.h
index d69c9ba..646a88a 100644
--- a/config.def.h
+++ b/config.def.h
@@ -10,8 +10,8 @@ static int borderpx = 2;
 static char shell[] = "/bin/sh";
 
 /* Kerning / character bounding-box mutlipliers */
-float cwscale = 1.0;
-float chscale = 1.0;
+static float cwscale = 1.0;
+static float chscale = 1.0;
 
 /*
  * word delimiter string

From 5f91983541014d34274087dbf723b48551f90fc0 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sun, 27 Apr 2014 15:16:41 +0400
Subject: [PATCH 0674/1146] Simplify selected().

---
 st.c | 17 ++++++-----------
 1 file changed, 6 insertions(+), 11 deletions(-)

diff --git a/st.c b/st.c
index 672c47a..5198749 100644
--- a/st.c
+++ b/st.c
@@ -674,18 +674,13 @@ selsort(void) {
 
 static inline bool
 selected(int x, int y) {
-	if(sel.ne.y == y && sel.nb.y == y)
-		return BETWEEN(x, sel.nb.x, sel.ne.x);
+	if(sel.type == SEL_RECTANGULAR)
+		return BETWEEN(y, sel.nb.y, sel.ne.y)
+		    && BETWEEN(x, sel.nb.x, sel.ne.x);
 
-	if(sel.type == SEL_RECTANGULAR) {
-		return ((sel.nb.y <= y && y <= sel.ne.y)
-			&& (sel.nb.x <= x && x <= sel.ne.x));
-	}
-
-	return ((sel.nb.y < y && y < sel.ne.y)
-		|| (y == sel.ne.y && x <= sel.ne.x))
-		|| (y == sel.nb.y && x >= sel.nb.x
-			&& (x <= sel.ne.x || sel.nb.y != sel.ne.y));
+	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

From 6b315558f8095b91988d5b305ed06e082da48889 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Tue, 29 Apr 2014 02:35:22 +0400
Subject: [PATCH 0675/1146] Do not save cursor in tresize.

This patch fixes the bug introduced in
8f11e1cd034ff28ca47bb4955505db7fa8016ba8

To reproduce the bug:
1. Save cursor: printf '\e[s'
2. Load cursor: printf '\e[u'
3. Resize st window.
4. Load cursor again: printf '\e[u'
---
 st.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 5198749..c50a202 100644
--- a/st.c
+++ b/st.c
@@ -2634,6 +2634,7 @@ tresize(int col, int row) {
 	int slide = term.c.y - row + 1;
 	bool *bp;
 	Line *orig;
+	TCursor c;
 
 	if(col < 1 || row < 1)
 		return 0;
@@ -2695,6 +2696,7 @@ tresize(int col, int row) {
 	tmoveto(term.c.x, term.c.y);
 	/* Clearing both screens */
 	orig = term.line;
+	c = term.c;
 	do {
 		if(mincol < col && 0 < minrow) {
 			tclearregion(mincol, 0, col - 1, minrow - 1);
@@ -2702,10 +2704,10 @@ tresize(int col, int row) {
 		if(0 < col && minrow < row) {
 			tclearregion(0, minrow, col - 1, row - 1);
 		}
-		tcursor(CURSOR_SAVE);
 		tswapscreen();
 		tcursor(CURSOR_LOAD);
 	} while(orig != term.line);
+	term.c = c;
 
 	return (slide > 0);
 }

From 1629363f2d009a0c0d61209e4126ff09fa0e11a4 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 29 Apr 2014 08:58:10 +0200
Subject: [PATCH 0676/1146] Remove ATTR_GFX and tselcs

ATTR_GFX was used long time ago to detect when terminal was in
graphic mode. Today graphic mode is implemented using a charset
pointer, so ATTR_GFX is not needed anymore because graphic
condition can be detected directly checking if current charset
is GRAPHICS C0.
---
 st.c | 30 ++++++++----------------------
 1 file changed, 8 insertions(+), 22 deletions(-)

diff --git a/st.c b/st.c
index c50a202..3ed77e1 100644
--- a/st.c
+++ b/st.c
@@ -94,12 +94,11 @@ enum glyph_attribute {
 	ATTR_REVERSE   = 1,
 	ATTR_UNDERLINE = 2,
 	ATTR_BOLD      = 4,
-	ATTR_GFX       = 8,
-	ATTR_ITALIC    = 16,
-	ATTR_BLINK     = 32,
-	ATTR_WRAP      = 64,
-	ATTR_WIDE      = 128,
-	ATTR_WDUMMY    = 256,
+	ATTR_ITALIC    = 8,
+	ATTR_BLINK     = 16,
+	ATTR_WRAP      = 32,
+	ATTR_WIDE      = 64,
+	ATTR_WDUMMY    = 128,
 };
 
 enum cursor_movement {
@@ -396,7 +395,6 @@ static void techo(char *, int);
 static bool tcontrolcode(uchar );
 static void tdectest(char );
 static int32_t tdefcolor(int *, int *, int);
-static void tselcs(void);
 static void tdeftran(char);
 static inline bool match(uint, uint);
 static void ttynew(void);
@@ -1535,7 +1533,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 	/*
 	 * The table is proudly stolen from rxvt.
 	 */
-	if(attr->mode & ATTR_GFX) {
+	if(term.trantbl[term.charset] == CS_GRAPHIC0) {
 		if(BETWEEN(c[0], 0x41, 0x7e) && vt100_0[c[0] - 0x41]) {
 			c = vt100_0[c[0] - 0x41];
 		}
@@ -2317,9 +2315,7 @@ void
 tdeftran(char ascii) {
 	char c, (*bp)[2];
 	static char tbl[][2] = {
-		{'0', CS_GRAPHIC0}, {'1', CS_GRAPHIC1}, {'A', CS_UK},
-		{'B', CS_USA},      {'<', CS_MULTI},    {'K', CS_GER},
-		{'5', CS_FIN},      {'C', CS_FIN},
+		{'0', CS_GRAPHIC0}, {'B', CS_USA},
 		{0, 0}
 	};
 
@@ -2332,13 +2328,6 @@ tdeftran(char ascii) {
 		term.trantbl[term.icharset] = (*bp)[1];
 }
 
-void
-tselcs(void) {
-	MODBIT(term.c.attr.mode,
-	       term.trantbl[term.charset] == CS_GRAPHIC0,
-	       ATTR_GFX);
-}
-
 bool
 tcontrolcode(uchar ascii) {
 	static char question[UTF_SIZ] = "?";
@@ -2377,11 +2366,9 @@ tcontrolcode(uchar ascii) {
 		return 1;
 	case '\016': /* SO */
 		term.charset = 0;
-		tselcs();
 		break;
 	case '\017': /* SI */
 		term.charset = 1;
-		tselcs();
 		break;
 	case '\032': /* SUB */
 		tsetchar(question, &term.c.attr, term.c.x, term.c.y);
@@ -2506,7 +2493,6 @@ tputc(char *c, int len) {
 			return;
 		} else if(term.esc & ESC_ALTCHARSET) {
 			tdeftran(ascii);
-			tselcs();
 		} else if(term.esc & ESC_TEST) {
 			tdectest(ascii);
 		} else {
@@ -2593,7 +2579,7 @@ tputc(char *c, int len) {
 	/*
 	 * Display control codes only if we are in graphic mode
 	 */
-	if(control && !(term.c.attr.mode & ATTR_GFX))
+	if(control && term.trantbl[term.charset] != CS_GRAPHIC0)
 		return;
 	if(sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
 		selclear(NULL);

From 870f961c49d3f9dfea8d78666e73fcdd0f90cc57 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 29 Apr 2014 09:58:55 +0200
Subject: [PATCH 0677/1146] Fix displaying control code

Control code are never displayed. It is not important if graphic
charset is displayed or not.
---
 st.c | 22 +++++++++-------------
 1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/st.c b/st.c
index 3ed77e1..7474256 100644
--- a/st.c
+++ b/st.c
@@ -392,7 +392,7 @@ static void tsetdirtattr(int);
 static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 static void techo(char *, int);
-static bool tcontrolcode(uchar );
+static void tcontrolcode(uchar );
 static void tdectest(char );
 static int32_t tdefcolor(int *, int *, int);
 static void tdeftran(char);
@@ -2328,7 +2328,7 @@ tdeftran(char ascii) {
 		term.trantbl[term.icharset] = (*bp)[1];
 }
 
-bool
+void
 tcontrolcode(uchar ascii) {
 	static char question[UTF_SIZ] = "?";
 
@@ -2363,7 +2363,7 @@ tcontrolcode(uchar ascii) {
 		csireset();
 		term.esc &= ~(ESC_CSI|ESC_ALTCHARSET|ESC_TEST);
 		term.esc |= ESC_START;
-		return 1;
+		return;
 	case '\016': /* SO */
 		term.charset = 0;
 		break;
@@ -2395,11 +2395,9 @@ tcontrolcode(uchar ascii) {
 	case 0x9e:   /* TODO: PM */
 	case 0x9f:   /* TODO: APC */
 		break;
-	default:
-		return 0;
 	}
 	term.esc &= ~(ESC_STR_END|ESC_STR);
-	return 1;
+	return;
 }
 
 void
@@ -2478,8 +2476,11 @@ tputc(char *c, int len) {
 	 * they must not cause conflicts with sequences.
 	 */
 	if(control) {
-		if (tcontrolcode(ascii))
-			return;
+		tcontrolcode(ascii);
+		/*
+		 * control codes are not shown ever
+		 */
+		return;
 	} else if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {
 			csiescseq.buf[csiescseq.len++] = ascii;
@@ -2576,11 +2577,6 @@ tputc(char *c, int len) {
 		 */
 		return;
 	}
-	/*
-	 * Display control codes only if we are in graphic mode
-	 */
-	if(control && term.trantbl[term.charset] != CS_GRAPHIC0)
-		return;
 	if(sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
 		selclear(NULL);
 

From 99fb365aa30e6d9f8fa035f4d2adbc3145fafb00 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Fri, 25 Apr 2014 18:26:54 +0400
Subject: [PATCH 0678/1146] Consistent FALLTHROUGH comments.

---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 7474256..fe44608 100644
--- a/st.c
+++ b/st.c
@@ -1837,7 +1837,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				if (!allowaltscreen)
 					break;
 				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
-				/* FALLTHRU */
+				/* FALLTHROUGH */
 			case 47: /* swap screen */
 			case 1047:
 				if (!allowaltscreen)
@@ -1851,7 +1851,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 					tswapscreen();
 				if(*args != 1049)
 					break;
-				/* FALLTRU */
+				/* FALLTHROUGH */
 			case 1048:
 				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
 				break;
@@ -2146,7 +2146,7 @@ strhandle(void) {
 			if(narg < 3)
 				break;
 			p = strescseq.args[2];
-			/* fall through */
+			/* FALLTHROUGH */
 		case 104: /* color reset, here p = NULL */
 			j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
 			if (!xsetcolorname(j, p)) {

From 5e917ab2874de556de12ce43e9a97300c9c722a2 Mon Sep 17 00:00:00 2001
From: Colona <colona@ycc.fr>
Date: Wed, 7 May 2014 10:05:27 +0200
Subject: [PATCH 0679/1146] Also clears ESC_START on interrupt characters
 during sequences.

Otherwise, the rest of the input is interpreted as a new escape
sequence.
For the ESC character, ESC_START is re-set in tcontrolcode.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index fe44608..baab589 100644
--- a/st.c
+++ b/st.c
@@ -2446,7 +2446,7 @@ tputc(char *c, int len) {
 		   (ascii == '\a' || ascii == 030 ||
 		    ascii == 032  || ascii == 033 ||
 		    ISCONTROLC1(unicodep))) {
-			term.esc &= ~ESC_STR;
+			term.esc &= ~(ESC_START|ESC_STR);
 			term.esc |= ESC_STR_END;
 		} else if(strescseq.len + len < sizeof(strescseq.buf) - 1) {
 			memmove(&strescseq.buf[strescseq.len], c, len);

From e31829f659a818e438bf2fe45708abb2983f8765 Mon Sep 17 00:00:00 2001
From: Colona <colona@ycc.fr>
Date: Fri, 9 May 2014 10:23:53 +0200
Subject: [PATCH 0680/1146] End a sequence only on CAN, SUB, \a and C1s.

---
 st.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index baab589..fd872c1 100644
--- a/st.c
+++ b/st.c
@@ -2335,19 +2335,19 @@ tcontrolcode(uchar ascii) {
 	switch(ascii) {
 	case '\t':   /* HT */
 		tputtab(1);
-		break;
+		return;
 	case '\b':   /* BS */
 		tmoveto(term.c.x-1, term.c.y);
-		break;
+		return;
 	case '\r':   /* CR */
 		tmoveto(0, term.c.y);
-		break;
+		return;
 	case '\f':   /* LF */
 	case '\v':   /* VT */
 	case '\n':   /* LF */
 		/* go to first col if the mode is set */
 		tnewline(IS_SET(MODE_CRLF));
-		break;
+		return;
 	case '\a':   /* BEL */
 		if(term.esc & ESC_STR_END) {
 			/* backwards compatibility to xterm */
@@ -2366,10 +2366,10 @@ tcontrolcode(uchar ascii) {
 		return;
 	case '\016': /* SO */
 		term.charset = 0;
-		break;
+		return;
 	case '\017': /* SI */
 		term.charset = 1;
-		break;
+		return;
 	case '\032': /* SUB */
 		tsetchar(question, &term.c.attr, term.c.x, term.c.y);
 	case '\030': /* CAN */
@@ -2380,6 +2380,7 @@ tcontrolcode(uchar ascii) {
 	case '\021': /* XON (IGNORED) */
 	case '\023': /* XOFF (IGNORED) */
 	case 0177:   /* DEL (IGNORED) */
+		return;
 	case 0x84:   /* TODO: IND */
 	case 0x85:   /* TODO: NEL */
 	case 0x88:   /* TODO: HTS */
@@ -2396,6 +2397,7 @@ tcontrolcode(uchar ascii) {
 	case 0x9f:   /* TODO: APC */
 		break;
 	}
+	/* only CAN, SUB, \a and C1 chars interrupt a sequence */
 	term.esc &= ~(ESC_STR_END|ESC_STR);
 	return;
 }

From bdb850a16a6d7a2d12b2bd5500a3b7d70290a74a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 9 May 2014 17:12:58 +0200
Subject: [PATCH 0681/1146] Redraw needs all dirty lines to have flash etc.
 work.

---
 st.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index fd872c1..5946c7c 100644
--- a/st.c
+++ b/st.c
@@ -3439,6 +3439,7 @@ void
 redraw(int timeout) {
 	struct timespec tv = {0, timeout * 1000};
 
+	tfulldirt();
 	draw();
 
 	if(timeout > 0) {

From cf890e5bf06a65a35fe195aa1ef8ae3e1eb55f51 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Mon, 12 May 2014 14:39:37 +0200
Subject: [PATCH 0682/1146] Allow mouse selection override using ShiftMask

Similar to xterm or urxvt holding shift before selecting text with the mouse
allows to override copying text. For example in tmux with "mode-mouse on" or
vim (compiled with --with-x), mc, htop, etc.

forceselmod in config.h sets the modifier to use this mode, by default
ShiftMask.

Signed-off-by: Hiltjo Posthuma <hiltjo@codemadness.org>
---
 config.def.h | 6 +++++-
 st.c         | 8 ++++----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/config.def.h b/config.def.h
index 646a88a..6e2be9a 100644
--- a/config.def.h
+++ b/config.def.h
@@ -154,6 +154,11 @@ static KeySym mappedkeys[] = { -1 };
  */
 static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
 
+/* Override mouse-select while mask is active (when MODE_MOUSE is set).
+ * Note that if you want to use ShiftMask with selmasks, set this to an other
+ * modifier, set to 0 to not use it. */
+static uint forceselmod = ShiftMask;
+
 static Key key[] = {
 	/* keysym           mask            string      appkey appcursor crlf */
 	{ XK_KP_Home,       ShiftMask,      "\033[2J",       0,   -1,    0},
@@ -357,7 +362,6 @@ static Key key[] = {
  * ButtonRelease and MotionNotify.
  * If no match is found, regular selection is used.
  */
-
 static uint selmasks[] = {
 	[SEL_RECTANGULAR] = Mod1Mask,
 };
diff --git a/st.c b/st.c
index 5946c7c..78d8a01 100644
--- a/st.c
+++ b/st.c
@@ -765,7 +765,7 @@ selsnap(int mode, int *x, int *y, int direction) {
 void
 getbuttoninfo(XEvent *e) {
 	int type;
-	uint state = e->xbutton.state &~Button1Mask;
+	uint state = e->xbutton.state & ~(Button1Mask | forceselmod);
 
 	sel.alt = IS_SET(MODE_ALTSCREEN);
 
@@ -858,7 +858,7 @@ bpress(XEvent *e) {
 	struct timeval now;
 	Mousekey *mk;
 
-	if(IS_SET(MODE_MOUSE)) {
+	if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);
 		return;
 	}
@@ -1090,7 +1090,7 @@ xsetsel(char *str) {
 
 void
 brelease(XEvent *e) {
-	if(IS_SET(MODE_MOUSE)) {
+	if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);
 		return;
 	}
@@ -1113,7 +1113,7 @@ void
 bmotion(XEvent *e) {
 	int oldey, oldex, oldsby, oldsey;
 
-	if(IS_SET(MODE_MOUSE)) {
+	if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);
 		return;
 	}

From 3544e354b2dcdfcced1a2f4aeedb4d479abd543c Mon Sep 17 00:00:00 2001
From: FRIGN <dev@frign.de>
Date: Thu, 22 May 2014 15:00:33 +0200
Subject: [PATCH 0683/1146] Fix colour-model and simplify xloadcols()

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 58 +++++++++++++++++++++-------------------------------------
 1 file changed, 21 insertions(+), 37 deletions(-)

diff --git a/st.c b/st.c
index 78d8a01..a6b4ada 100644
--- a/st.c
+++ b/st.c
@@ -340,7 +340,7 @@ typedef struct {
 
 /* Drawing Context */
 typedef struct {
-	Colour col[LEN(colorname) < 256 ? 256 : LEN(colorname)];
+	Colour col[MAX(LEN(colorname), 256)];
 	Font font, bfont, ifont, ibfont;
 	GC gc;
 } DC;
@@ -2715,7 +2715,7 @@ sixd_to_16bit(int x) {
 
 void
 xloadcols(void) {
-	int i, r, g, b;
+	int i;
 	XRenderColor color = { .alpha = 0xffff };
 	static bool loaded;
 	Colour *cp;
@@ -2725,7 +2725,7 @@ xloadcols(void) {
 			XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
 	}
 
-	/* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */
+	/* load colours [0-15] and [256-LEN(colorname)] (config.h) */
 	for(i = 0; i < LEN(colorname); i++) {
 		if(!colorname[i])
 			continue;
@@ -2734,27 +2734,20 @@ xloadcols(void) {
 		}
 	}
 
-	/* load colors [16-255] ; same colors as xterm */
-	for(i = 16, r = 0; r < 6; r++) {
-		for(g = 0; g < 6; g++) {
-			for(b = 0; b < 6; b++) {
-				color.red = sixd_to_16bit(r);
-				color.green = sixd_to_16bit(g);
-				color.blue = sixd_to_16bit(b);
-				if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i])) {
-					die("Could not allocate color %d\n", i);
-				}
-				i++;
-			}
-		}
-	}
-
-	for(r = 0; r < 24; r++, i++) {
-		color.red = color.green = color.blue = 0x0808 + 0x0a0a * r;
-		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color,
-					&dc.col[i])) {
+	/* load colours [16-231] ; same colours as xterm */
+	for(i = 16; i < 6*6*6+16; i++) {
+		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 );
+		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i]))
+			die("Could not allocate color %d\n", i);
+	}
+	
+	/* load colours [232-255] ; grayscale */
+	for(; i < 256; i++) {
+		color.red = color.green = color.blue = 0x0808 + 0x0a0a * (i-(6*6*6+16));
+		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i]))
 			die("Could not allocate color %d\n", i);
-		}
 	}
 	loaded = true;
 }
@@ -3149,22 +3142,13 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	}
 
 	if(base.mode & ATTR_BOLD) {
-		if(BETWEEN(base.fg, 0, 7)) {
-			/* basic system colors */
-			fg = &dc.col[base.fg + 8];
-		} else if(BETWEEN(base.fg, 16, 195)) {
-			/* 256 colors */
-			fg = &dc.col[base.fg + 36];
-		} else if(BETWEEN(base.fg, 232, 251)) {
-			/* greyscale */
-			fg = &dc.col[base.fg + 4];
-		}
 		/*
-		 * Those ranges will not be brightened:
-		 *    8 - 15 – bright system colors
-		 *    196 - 231 – highest 256 color cube
-		 *    252 - 255 – brightest colors in greyscale
+		 * change basic system colours [0-7] 
+		 * to bright system colours [8-15]
 		 */
+		if(BETWEEN(base.fg, 0, 7))
+			fg = &dc.col[base.fg + 8];
+		
 		font = &dc.bfont;
 		frcflags = FRC_BOLD;
 	}

From f4ebb3180f9f03bc35034348a5aff8745eac9ebf Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 24 May 2014 13:48:44 +0200
Subject: [PATCH 0684/1146] Fixing trailing whitespaces.

---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index a6b4ada..6424b54 100644
--- a/st.c
+++ b/st.c
@@ -2742,7 +2742,7 @@ xloadcols(void) {
 		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i]))
 			die("Could not allocate color %d\n", i);
 	}
-	
+
 	/* load colours [232-255] ; grayscale */
 	for(; i < 256; i++) {
 		color.red = color.green = color.blue = 0x0808 + 0x0a0a * (i-(6*6*6+16));
@@ -3143,12 +3143,12 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 	if(base.mode & ATTR_BOLD) {
 		/*
-		 * change basic system colours [0-7] 
+		 * change basic system colours [0-7]
 		 * to bright system colours [8-15]
 		 */
 		if(BETWEEN(base.fg, 0, 7))
 			fg = &dc.col[base.fg + 8];
-		
+
 		font = &dc.bfont;
 		frcflags = FRC_BOLD;
 	}

From 488977c8efd0b3ad5bcc7a76f35e737f56381f45 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 24 May 2014 13:52:24 +0200
Subject: [PATCH 0685/1146] Brightening is again on the TODO list.

---
 TODO | 1 +
 1 file changed, 1 insertion(+)

diff --git a/TODO b/TODO
index 3866f64..00cfdac 100644
--- a/TODO
+++ b/TODO
@@ -12,6 +12,7 @@ drawing
 -------
 * add diacritics support to xdraws()
 * make the font cache simpler
+* add better support for brightening of the upper colors
 
 bugs
 ----

From 80d80512690c0ecb2627b31e1e0296256b27c896 Mon Sep 17 00:00:00 2001
From: FRIGN <dev@frign.de>
Date: Sat, 24 May 2014 21:07:53 +0200
Subject: [PATCH 0686/1146] Add FRIGN to License, remove trailing whitespace

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 LICENSE | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/LICENSE b/LICENSE
index 910bec9..64dc414 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 MIT/X Consortium License
 
-© 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com> 
+© 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>
 © 2009 Anselm R Garbe <garbeam at gmail dot com>
 © 2012 Roberto E. Vargas Caballero <k0ga at shike2 dot com>
 © 2012 Christoph Lohmann <20h at r-36 dot net>
@@ -10,6 +10,7 @@ MIT/X Consortium License
 © 2013 Eric Pruitt <eric.pruitt at gmail dot com>
 © 2013 Michael Forney <mforney at mforney dot org>
 © 2013 Markus Teich <markus dot teich at stusta dot mhn dot de>
+© 2014 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"),

From d03aa8d20bcc8a94a7737331a9ec0bf11df3e572 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 24 May 2014 21:27:54 +0200
Subject: [PATCH 0687/1146] Fix some more LICENSE changes.

---
 LICENSE | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/LICENSE b/LICENSE
index 64dc414..0180b49 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2,14 +2,14 @@ MIT/X Consortium License
 
 © 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>
 © 2009 Anselm R Garbe <garbeam at gmail dot com>
-© 2012 Roberto E. Vargas Caballero <k0ga at shike2 dot com>
-© 2012 Christoph Lohmann <20h at r-36 dot net>
+© 2012-2014 Roberto E. Vargas Caballero <k0ga at shike2 dot com>
+© 2012-2014 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 Eric Pruitt <eric.pruitt at gmail dot com>
 © 2013 Michael Forney <mforney at mforney dot org>
-© 2013 Markus Teich <markus dot teich at stusta dot mhn dot de>
+© 2013-2014 Markus Teich <markus dot teich at stusta dot mhn dot de>
 © 2014 Laslo Hunhold <dev at frign dot de>
 
 Permission is hereby granted, free of charge, to any person obtaining a

From 2411308bd24c4db97a3bb06d38f183a679aec1ea Mon Sep 17 00:00:00 2001
From: Alexander <alex0player@gmail.com>
Date: Mon, 26 May 2014 09:23:56 +0400
Subject: [PATCH 0688/1146] Fixed copying empty lines inside selection.

The code was assuming that empty lines have implicit wrap-around attribute.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 6424b54..506be0f 100644
--- a/st.c
+++ b/st.c
@@ -949,7 +949,7 @@ getsel(void) {
 		 * st.
 		 * FIXME: Fix the computer world.
 		 */
-		if(y < sel.ne.y && x > 0 && !((gp-1)->mode & ATTR_WRAP))
+		if(y < sel.ne.y && !(x > 0 && (gp-1)->mode & ATTR_WRAP))
 			*ptr++ = '\n';
 
 		/*

From ede83bd08b922f2f53264876f6500b564d3c5ef0 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 1 Jun 2014 15:54:28 +0200
Subject: [PATCH 0689/1146] Fixing italic bold.

Thanks Felipe Spychalski <spychalski@gmail.com> for the patch!
---
 st.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 506be0f..f48dab4 100644
--- a/st.c
+++ b/st.c
@@ -3149,8 +3149,13 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		if(BETWEEN(base.fg, 0, 7))
 			fg = &dc.col[base.fg + 8];
 
-		font = &dc.bfont;
-		frcflags = FRC_BOLD;
+		if(base.mode & ATTR_ITALIC) {
+			font = &dc.ibfont;
+			frcflags = FRC_ITALICBOLD;
+		} else {
+			font = &dc.bfont;
+			frcflags = FRC_BOLD;
+		}
 	}
 
 	if(IS_SET(MODE_REVERSE)) {

From ba36d1394b3add5b9d4c174f1443cc312bcc7e09 Mon Sep 17 00:00:00 2001
From: Balazs Kezes <rlblaster@gmail.com>
Date: Sat, 31 May 2014 22:24:58 +0100
Subject: [PATCH 0690/1146] Don't report release events for mouse wheel

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.c b/st.c
index f48dab4..79a4e0a 100644
--- a/st.c
+++ b/st.c
@@ -829,6 +829,8 @@ mousereport(XEvent *e) {
 			/* MODE_MOUSEX10: no button release reporting */
 			if(IS_SET(MODE_MOUSEX10))
 				return;
+			if (button == 64 || button == 65)
+				return;
 		}
 	}
 

From a32c5f5726f514b49bd396f27aab0e78c40126d3 Mon Sep 17 00:00:00 2001
From: FRIGN <dev@frign.de>
Date: Sun, 25 May 2014 12:13:22 +0200
Subject: [PATCH 0691/1146] Refactor xsetcolorname()

I mainly improved the slightly off algorithm used to load colours in the 256-colour-space and
removed unnecessary local values (r,g,b,colour).
"colour" is not necessary as a punchbag for XftColorAlloc[Value,Name], as they don't mess with
the result-adress until they are absolutely sure everything worked out[0].

Being at it, I changed the error-returns for AllocValue to dies (just like in xloadcols()), as
a failure is most likely an OOM-situation you better catch early.
In case of an invalid name everything stays the same.

[0]: http://www.opensource.apple.com/source/X11libs/X11libs-40/libXft/libXft-2.1.13/src/xftcolor.c

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 32 ++++++++++++++------------------
 1 file changed, 14 insertions(+), 18 deletions(-)

diff --git a/st.c b/st.c
index 79a4e0a..beae9bc 100644
--- a/st.c
+++ b/st.c
@@ -2757,32 +2757,28 @@ xloadcols(void) {
 int
 xsetcolorname(int x, const char *name) {
 	XRenderColor color = { .alpha = 0xffff };
-	Colour colour;
+
 	if(!BETWEEN(x, 0, LEN(colorname)))
 		return -1;
 	if(!name) {
-		if(BETWEEN(x, 16, 16 + 215)) {
-			int r = (x - 16) / 36, g = ((x - 16) % 36) / 6, b = (x - 16) % 6;
-			color.red = sixd_to_16bit(r);
-			color.green = sixd_to_16bit(g);
-			color.blue = sixd_to_16bit(b);
-			if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour))
-				return 0; /* something went wrong */
-			dc.col[x] = colour;
+		if(BETWEEN(x, 16, 6*6*6+16)) { /* 256 colour */
+			color.red   = sixd_to_16bit( ((x-16)/36)%6 );
+			color.green = sixd_to_16bit( ((x-16)/6) %6 );
+			color.blue  = sixd_to_16bit( ((x-16)/1) %6 );
+			if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[x]))
+				die("Could not allocate color %d\n", x);
 			return 1;
-		} else if(BETWEEN(x, 16 + 216, 255)) {
-			color.red = color.green = color.blue = 0x0808 + 0x0a0a * (x - (16 + 216));
-			if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour))
-				return 0; /* something went wrong */
-			dc.col[x] = colour;
+		} else if(BETWEEN(x, 6*6*6+16, 255)) { /* grayscale */
+			color.red = color.green = color.blue = 0x0808 + 0x0a0a * (x-(6*6*6+16));
+			if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[x]))
+				die("Could not allocate color %d\n", x);
 			return 1;
-		} else {
+		} else { /* system colours */
 			name = colorname[x];
 		}
 	}
-	if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &colour))
-		return 0;
-	dc.col[x] = colour;
+	if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &dc.col[x]))
+		return 0; /* invalid name */
 	return 1;
 }
 

From 8b4cfcea73a37ab6d67c06c69e9af3de304185e3 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 1 Jun 2014 16:52:19 +0200
Subject: [PATCH 0692/1146] Revert "Refactor xsetcolorname()"

This reverts commit a32c5f5726f514b49bd396f27aab0e78c40126d3.
---
 st.c | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index beae9bc..79a4e0a 100644
--- a/st.c
+++ b/st.c
@@ -2757,28 +2757,32 @@ xloadcols(void) {
 int
 xsetcolorname(int x, const char *name) {
 	XRenderColor color = { .alpha = 0xffff };
-
+	Colour colour;
 	if(!BETWEEN(x, 0, LEN(colorname)))
 		return -1;
 	if(!name) {
-		if(BETWEEN(x, 16, 6*6*6+16)) { /* 256 colour */
-			color.red   = sixd_to_16bit( ((x-16)/36)%6 );
-			color.green = sixd_to_16bit( ((x-16)/6) %6 );
-			color.blue  = sixd_to_16bit( ((x-16)/1) %6 );
-			if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[x]))
-				die("Could not allocate color %d\n", x);
+		if(BETWEEN(x, 16, 16 + 215)) {
+			int r = (x - 16) / 36, g = ((x - 16) % 36) / 6, b = (x - 16) % 6;
+			color.red = sixd_to_16bit(r);
+			color.green = sixd_to_16bit(g);
+			color.blue = sixd_to_16bit(b);
+			if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour))
+				return 0; /* something went wrong */
+			dc.col[x] = colour;
 			return 1;
-		} else if(BETWEEN(x, 6*6*6+16, 255)) { /* grayscale */
-			color.red = color.green = color.blue = 0x0808 + 0x0a0a * (x-(6*6*6+16));
-			if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[x]))
-				die("Could not allocate color %d\n", x);
+		} else if(BETWEEN(x, 16 + 216, 255)) {
+			color.red = color.green = color.blue = 0x0808 + 0x0a0a * (x - (16 + 216));
+			if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour))
+				return 0; /* something went wrong */
+			dc.col[x] = colour;
 			return 1;
-		} else { /* system colours */
+		} else {
 			name = colorname[x];
 		}
 	}
-	if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &dc.col[x]))
-		return 0; /* invalid name */
+	if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &colour))
+		return 0;
+	dc.col[x] = colour;
 	return 1;
 }
 

From c6fcb78b3a9a73b691875048848430c18870a0fc Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 1 Jun 2014 17:08:16 +0200
Subject: [PATCH 0693/1146] Fixing color and refactor xsetcolorname.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

By  the recommendation of FRIGN I refactored xsetcolorname to remove the
unnecessary r, g, b variables when allocating a new  color.  Colors  are
now freed and set to the new color. A die() should not happen here. Oth‐
erwise it is easy for applications to kill st. St should be resilent  to
malicious input.

Second  this  patch  standardises  the  naming  of  »color«. There is no
»colour« here. Maybe in some parts of the world.
---
 st.c | 88 ++++++++++++++++++++++++++++++++++--------------------------
 1 file changed, 50 insertions(+), 38 deletions(-)

diff --git a/st.c b/st.c
index 79a4e0a..11d01df 100644
--- a/st.c
+++ b/st.c
@@ -179,8 +179,8 @@ typedef unsigned long ulong;
 typedef unsigned short ushort;
 
 typedef XftDraw *Draw;
-typedef XftColor Colour;
-typedef Colormap Colourmap;
+typedef XftColor Color;
+typedef Colormap Colormap;
 
 typedef struct {
 	char c[UTF_SIZ]; /* character code */
@@ -241,7 +241,7 @@ typedef struct {
 /* Purely graphic info */
 typedef struct {
 	Display *dpy;
-	Colourmap cmap;
+	Colormap cmap;
 	Window win;
 	Drawable buf;
 	Atom xembed, wmdeletewin, netwmname, netwmpid;
@@ -340,7 +340,7 @@ typedef struct {
 
 /* Drawing Context */
 typedef struct {
-	Colour col[MAX(LEN(colorname), 256)];
+	Color col[MAX(LEN(colorname), 256)];
 	Font font, bfont, ifont, ibfont;
 	GC gc;
 } DC;
@@ -1631,7 +1631,7 @@ tdefcolor(int *attr, int *npar, int l) {
 	uint r, g, b;
 
 	switch (attr[*npar + 1]) {
-	case 2: /* direct colour in RGB space */
+	case 2: /* direct color in RGB space */
 		if (*npar + 4 >= l) {
 			fprintf(stderr,
 				"erresc(38): Incorrect number of parameters (%d)\n",
@@ -1648,7 +1648,7 @@ tdefcolor(int *attr, int *npar, int l) {
 		else
 			idx = TRUECOLOR(r, g, b);
 		break;
-	case 5: /* indexed colour */
+	case 5: /* indexed color */
 		if (*npar + 2 >= l) {
 			fprintf(stderr,
 				"erresc(38): Incorrect number of parameters (%d)\n",
@@ -1663,8 +1663,8 @@ tdefcolor(int *attr, int *npar, int l) {
 		break;
 	case 0: /* implemented defined (only foreground) */
 	case 1: /* transparent */
-	case 3: /* direct colour in CMY space */
-	case 4: /* direct colour in CMYK space */
+	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]);
@@ -2151,7 +2151,7 @@ strhandle(void) {
 			/* FALLTHROUGH */
 		case 104: /* color reset, here p = NULL */
 			j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
-			if (!xsetcolorname(j, p)) {
+			if(xsetcolorname(j, p)) {
 				fprintf(stderr, "erresc: invalid color %s\n", p);
 			} else {
 				/*
@@ -2720,14 +2720,14 @@ xloadcols(void) {
 	int i;
 	XRenderColor color = { .alpha = 0xffff };
 	static bool loaded;
-	Colour *cp;
+	Color *cp;
 
 	if(loaded) {
 		for (cp = dc.col; cp < dc.col + LEN(dc.col); ++cp)
 			XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
 	}
 
-	/* load colours [0-15] and [256-LEN(colorname)] (config.h) */
+	/* load colors [0-15] and [256-LEN(colorname)] (config.h) */
 	for(i = 0; i < LEN(colorname); i++) {
 		if(!colorname[i])
 			continue;
@@ -2736,7 +2736,7 @@ xloadcols(void) {
 		}
 	}
 
-	/* load colours [16-231] ; same colours as xterm */
+	/* load colors [16-231] ; same colors as xterm */
 	for(i = 16; i < 6*6*6+16; i++) {
 		color.red   = sixd_to_16bit( ((i-16)/36)%6 );
 		color.green = sixd_to_16bit( ((i-16)/6) %6 );
@@ -2745,7 +2745,7 @@ xloadcols(void) {
 			die("Could not allocate color %d\n", i);
 	}
 
-	/* load colours [232-255] ; grayscale */
+	/* load colors [232-255] ; grayscale */
 	for(; i < 256; i++) {
 		color.red = color.green = color.blue = 0x0808 + 0x0a0a * (i-(6*6*6+16));
 		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i]))
@@ -2757,33 +2757,45 @@ xloadcols(void) {
 int
 xsetcolorname(int x, const char *name) {
 	XRenderColor color = { .alpha = 0xffff };
-	Colour colour;
+	Color ncolor;
+
 	if(!BETWEEN(x, 0, LEN(colorname)))
-		return -1;
+		return 1;
+
 	if(!name) {
-		if(BETWEEN(x, 16, 16 + 215)) {
-			int r = (x - 16) / 36, g = ((x - 16) % 36) / 6, b = (x - 16) % 6;
-			color.red = sixd_to_16bit(r);
-			color.green = sixd_to_16bit(g);
-			color.blue = sixd_to_16bit(b);
-			if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour))
-				return 0; /* something went wrong */
-			dc.col[x] = colour;
-			return 1;
-		} else if(BETWEEN(x, 16 + 216, 255)) {
-			color.red = color.green = color.blue = 0x0808 + 0x0a0a * (x - (16 + 216));
-			if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour))
-				return 0; /* something went wrong */
-			dc.col[x] = colour;
-			return 1;
-		} else {
+		if(BETWEEN(x, 16, 16 + 215)) { /* 256 color */
+			color.red   = sixd_to_16bit( ((x-16)/36)%6 );
+			color.green = sixd_to_16bit( ((x-16)/6) %6 );
+			color.blue  = sixd_to_16bit( ((x-16)/1) %6 );
+			if(!XftColorAllocValue(xw.dpy, xw.vis,
+						xw.cmap, &color, &ncolor)) {
+				return 1;
+			}
+
+			XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
+			dc.col[x] = ncolor;
+			return 0;
+		} else if(BETWEEN(x, 16 + 216, 255)) { /* greyscale */
+			color.red = color.green = color.blue = \
+				    0x0808 + 0x0a0a * (x - (16 + 216));
+			if(!XftColorAllocValue(xw.dpy, xw.vis,
+						xw.cmap, &color, &ncolor)) {
+				return 1;
+			}
+
+			XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
+			dc.col[x] = ncolor;
+			return 0;
+		} else { /* system colors */
 			name = colorname[x];
 		}
 	}
-	if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &colour))
-		return 0;
-	dc.col[x] = colour;
-	return 1;
+	if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &ncolor))
+		return 1;
+
+	XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
+	dc.col[x] = ncolor;
+	return 0;
 }
 
 void
@@ -3099,7 +3111,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	FcPattern *fcpattern, *fontpattern;
 	FcFontSet *fcsets[] = { NULL };
 	FcCharSet *fccharset;
-	Colour *fg, *bg, *temp, revfg, revbg, truefg, truebg;
+	Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
 	XRenderColor colfg, colbg;
 	XRectangle r;
 	int oneatatime;
@@ -3145,8 +3157,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 	if(base.mode & ATTR_BOLD) {
 		/*
-		 * change basic system colours [0-7]
-		 * to bright system colours [8-15]
+		 * change basic system colors [0-7]
+		 * to bright system colors [8-15]
 		 */
 		if(BETWEEN(base.fg, 0, 7))
 			fg = &dc.col[base.fg + 8];

From 2323e962e6bcddba42fd8be977088fb63ed8844c Mon Sep 17 00:00:00 2001
From: Colona <colona@ycc.fr>
Date: Tue, 3 Jun 2014 04:34:58 +0200
Subject: [PATCH 0694/1146] Make selection consistent over line breaks.

Currently, selection is expanded to the end of the line over line breaks only in
regular selection mode, when the line in not empty and when going down and/or
right. This covers all the cases including word selection mode, with the
exception of rectangular selection because it would make this mode too rigid.
This adjustment is made in selsort so I renamed it to selnormalize to better
reflect what it does now.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 46 ++++++++++++++++++++++++++--------------------
 1 file changed, 26 insertions(+), 20 deletions(-)

diff --git a/st.c b/st.c
index 11d01df..9a41c5b 100644
--- a/st.c
+++ b/st.c
@@ -441,7 +441,7 @@ static void selclear(XEvent *);
 static void selrequest(XEvent *);
 
 static void selinit(void);
-static void selsort(void);
+static void selnormalize(void);
 static inline bool selected(int, int);
 static char *getsel(void);
 static void selcopy(void);
@@ -657,8 +657,19 @@ y2row(int y) {
 	return LIMIT(y, 0, term.row-1);
 }
 
+static int tlinelen(int y) {
+	int i = term.col;
+
+	while (i > 0 && term.line[y][i - 1].c[0] == ' ')
+		--i;
+
+	return i;
+}
+
 static void
-selsort(void) {
+selnormalize(void) {
+	int i;
+
 	if(sel.ob.y == sel.oe.y) {
 		sel.nb.x = MIN(sel.ob.x, sel.oe.x);
 		sel.ne.x = MAX(sel.ob.x, sel.oe.x);
@@ -668,6 +679,15 @@ selsort(void) {
 	}
 	sel.nb.y = MIN(sel.ob.y, sel.oe.y);
 	sel.ne.y = MAX(sel.ob.y, sel.oe.y);
+
+	/* 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;
 }
 
 static inline bool
@@ -683,8 +703,6 @@ selected(int x, int y) {
 
 void
 selsnap(int mode, int *x, int *y, int direction) {
-	int i;
-
 	switch(mode) {
 	case SNAP_WORD:
 		/*
@@ -716,7 +734,7 @@ selsnap(int mode, int *x, int *y, int direction) {
 				continue;
 			}
 
-			if(strchr(worddelimiters,
+			if(*x >= tlinelen(*y) || strchr(worddelimiters,
 					term.line[*y][*x+direction].c[0])) {
 				break;
 			}
@@ -747,18 +765,6 @@ selsnap(int mode, int *x, int *y, int direction) {
 			}
 		}
 		break;
-	default:
-		/*
-		 * Select the whole line when the end of line is reached.
-		 */
-		if(direction > 0) {
-			i = term.col;
-			while(--i > 0 && term.line[*y][i].c[0] == ' ')
-				/* nothing */;
-			if(i > 0 && i < *x)
-				*x = term.col - 1;
-		}
-		break;
 	}
 }
 
@@ -780,7 +786,7 @@ getbuttoninfo(XEvent *e) {
 		selsnap(sel.snap, &sel.oe.x, &sel.oe.y, -1);
 		selsnap(sel.snap, &sel.ob.x, &sel.ob.y, +1);
 	}
-	selsort();
+	selnormalize();
 
 	sel.type = SEL_REGULAR;
 	for(type = 1; type < LEN(selmasks); ++type) {
@@ -896,7 +902,7 @@ bpress(XEvent *e) {
 		}
 		selsnap(sel.snap, &sel.ob.x, &sel.ob.y, -1);
 		selsnap(sel.snap, &sel.oe.x, &sel.oe.y, +1);
-		selsort();
+		selnormalize();
 
 		/*
 		 * Draw selection, unless it's regular and we don't want to
@@ -1451,7 +1457,7 @@ selscroll(int orig, int n) {
 				sel.oe.x = term.col;
 			}
 		}
-		selsort();
+		selnormalize();
 	}
 }
 

From bb6dc332067fddcdcb0940ebc9b5f41c61429c46 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Tue, 3 Jun 2014 17:55:53 +0200
Subject: [PATCH 0695/1146] tiny cleanup

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 9a41c5b..2e55963 100644
--- a/st.c
+++ b/st.c
@@ -920,7 +920,7 @@ bpress(XEvent *e) {
 char *
 getsel(void) {
 	char *str, *ptr;
-	int x, y, bufsize, size, i, ex;
+	int x, y, bufsize, size, ex;
 	Glyph *gp, *last;
 
 	if(sel.ob.x == -1)
@@ -965,13 +965,10 @@ getsel(void) {
 		 * after the visible text '\n' is appended.
 		 */
 		if(y == sel.ne.y) {
-			i = term.col;
-			while(--i > 0 && term.line[y][i].c[0] == ' ')
-				/* nothing */;
 			ex = sel.ne.x;
 			if(sel.nb.y == sel.ne.y && sel.ne.x < sel.nb.x)
 				ex = sel.nb.x;
-			if(i < ex)
+			if(tlinelen(y) < ex)
 				*ptr++ = '\n';
 		}
 	}

From 6fd887077e29efd789499e06193314d7abdcac38 Mon Sep 17 00:00:00 2001
From: Colona <colona@ycc.fr>
Date: Tue, 3 Jun 2014 21:47:55 -0700
Subject: [PATCH 0696/1146] Fix rectangular selection.

selsort computes the wrong normalized coordinates when rectangular
selection is enabled, causing rectangular selection to only work
when going toward either the top left corner, or the bottom right
one.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 2e55963..8b65450 100644
--- a/st.c
+++ b/st.c
@@ -670,7 +670,7 @@ static void
 selnormalize(void) {
 	int i;
 
-	if(sel.ob.y == sel.oe.y) {
+	if(sel.ob.y == sel.oe.y || sel.type == SEL_RECTANGULAR) {
 		sel.nb.x = MIN(sel.ob.x, sel.oe.x);
 		sel.ne.x = MAX(sel.ob.x, sel.oe.x);
 	} else {

From 5159d55c631cd1179bd2f872859d4540668745b9 Mon Sep 17 00:00:00 2001
From: Colona <colona@ycc.fr>
Date: Thu, 5 Jun 2014 06:32:01 +0200
Subject: [PATCH 0697/1146] Refactor selsnap SNAP_WORD.

Refactor the SNAP_WORD part in selsnap, and fix a bug that caused the word
delimiters to be ignored if it was at the very beginning or end of a wrapped
line.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 46 ++++++++++++++++++++++------------------------
 1 file changed, 22 insertions(+), 24 deletions(-)

diff --git a/st.c b/st.c
index 8b65450..13226d8 100644
--- a/st.c
+++ b/st.c
@@ -703,6 +703,9 @@ selected(int x, int y) {
 
 void
 selsnap(int mode, int *x, int *y, int direction) {
+	int newx, newy, xt, yt;
+	Glyph *gp;
+
 	switch(mode) {
 	case SNAP_WORD:
 		/*
@@ -710,36 +713,31 @@ selsnap(int mode, int *x, int *y, int direction) {
 		 * beginning of a line.
 		 */
 		for(;;) {
-			if(direction < 0 && *x <= 0) {
-				if(*y > 0 && term.line[*y - 1][term.col-1].mode
-						& ATTR_WRAP) {
-					*y -= 1;
-					*x = term.col-1;
-				} else {
+			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 && *x >= term.col-1) {
-				if(*y < term.row-1 && term.line[*y][*x].mode
-						& ATTR_WRAP) {
-					*y += 1;
-					*x = 0;
-				} else {
+
+				if(direction > 0)
+					yt = *y, xt = *x;
+				else
+					yt = newy, xt = newx;
+				if(!(term.line[yt][xt].mode & ATTR_WRAP))
 					break;
-				}
 			}
 
-			if(term.line[*y][*x+direction].mode & ATTR_WDUMMY) {
-				*x += direction;
-				continue;
-			}
-
-			if(*x >= tlinelen(*y) || strchr(worddelimiters,
-					term.line[*y][*x+direction].c[0])) {
+			if (newx >= tlinelen(newy))
 				break;
-			}
 
-			*x += direction;
+			gp = &term.line[newy][newx];
+			if (!(gp->mode & ATTR_WDUMMY) && strchr(worddelimiters, gp->c[0]))
+				break;
+
+			*x = newx;
+			*y = newy;
 		}
 		break;
 	case SNAP_LINE:

From 18a05fdf4326ac1c7165de8cad0895b5c44fac83 Mon Sep 17 00:00:00 2001
From: FRIGN <dev@frign.de>
Date: Fri, 6 Jun 2014 14:08:51 +0200
Subject: [PATCH 0698/1146] Remove unnecessary typedef

This should also fix compiling-errors on OpenBSD,
as reported by Nils R. Thanks!

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.c b/st.c
index 13226d8..fde4d2d 100644
--- a/st.c
+++ b/st.c
@@ -180,7 +180,6 @@ typedef unsigned short ushort;
 
 typedef XftDraw *Draw;
 typedef XftColor Color;
-typedef Colormap Colormap;
 
 typedef struct {
 	char c[UTF_SIZ]; /* character code */

From 93661042a2a0cf6f3655360f5c52215c684a4211 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 7 Jun 2014 13:23:45 +0200
Subject: [PATCH 0699/1146] Simplify tdeftrans

---
 st.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/st.c b/st.c
index fde4d2d..b148401 100644
--- a/st.c
+++ b/st.c
@@ -2315,19 +2315,14 @@ techo(char *buf, int len) {
 
 void
 tdeftran(char ascii) {
-	char c, (*bp)[2];
-	static char tbl[][2] = {
-		{'0', CS_GRAPHIC0}, {'B', CS_USA},
-		{0, 0}
-	};
+	static char cs[] = "0B";
+	static int vcs[] = {CS_GRAPHIC0, CS_USA};
+	char *p;
 
-	for (bp = &tbl[0]; (c = (*bp)[0]) && c != ascii; ++bp)
-		/* nothing */;
-
-	if (c == 0)
+	if((p = strchr(cs, ascii)) == NULL)
 		fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
 	else
-		term.trantbl[term.icharset] = (*bp)[1];
+		term.trantbl[term.icharset] = vcs[p - cs];
 }
 
 void

From 587b4435924bab598a904531dc8d01656d1e519a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 7 Jun 2014 13:49:04 +0200
Subject: [PATCH 0700/1146] Style police.

---
 st.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index b148401..3681776 100644
--- a/st.c
+++ b/st.c
@@ -2319,10 +2319,11 @@ tdeftran(char ascii) {
 	static int vcs[] = {CS_GRAPHIC0, CS_USA};
 	char *p;
 
-	if((p = strchr(cs, ascii)) == NULL)
+	if((p = strchr(cs, ascii)) == NULL) {
 		fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
-	else
+	} else {
 		term.trantbl[term.icharset] = vcs[p - cs];
+	}
 }
 
 void

From 27b28f1dc264e9947ea22bd64fd8f00ac98442f5 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Mon, 9 Jun 2014 17:19:15 +0200
Subject: [PATCH 0701/1146] FAQ: update typo and escape code for smkx

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 FAQ | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/FAQ b/FAQ
index bb2bde4..c8e76a5 100644
--- a/FAQ
+++ b/FAQ
@@ -37,7 +37,7 @@ Taken from the terminfo manpage:
 	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, tive these
+	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.
 
@@ -48,7 +48,7 @@ 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
+	$ printf '\033[?1h\033=' >/dev/tty
 
 or
 	$ echo $(tput smkx) >/dev/tty

From c2fd2754ebea6f802e4c71219af269c58b78262e Mon Sep 17 00:00:00 2001
From: Silvan Jegen <s.jegen@gmail.com>
Date: Fri, 6 Jun 2014 22:09:22 +0200
Subject: [PATCH 0702/1146] Refactor the innermost loop of the xdraws function

Signed-off-by: Silvan Jegen <s.jegen@gmail.com>
Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 34 ++++++++++++++--------------------
 1 file changed, 14 insertions(+), 20 deletions(-)

diff --git a/st.c b/st.c
index 3681776..2cf9a26 100644
--- a/st.c
+++ b/st.c
@@ -3245,28 +3245,22 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			bytelen -= u8cblen;
 
 			doesexist = XftCharExists(xw.dpy, font->match, unicodep);
-			if(oneatatime || !doesexist || bytelen <= 0) {
-				if(oneatatime || bytelen <= 0) {
-					if(doesexist) {
-						u8fl++;
-						u8fblen += u8cblen;
-					}
-				}
-
-				if(u8fl > 0) {
-					XftDrawStringUtf8(xw.draw, fg,
-							font->match, xp,
-							winy + font->ascent,
-							(FcChar8 *)u8fs,
-							u8fblen);
-					xp += xw.cw * u8fl;
-
-				}
-				break;
+			if(doesexist) {
+					u8fl++;
+					u8fblen += u8cblen;
+					if(!oneatatime && bytelen > 0)
+							continue;
 			}
 
-			u8fl++;
-			u8fblen += u8cblen;
+			if(u8fl > 0) {
+				XftDrawStringUtf8(xw.draw, fg,
+						font->match, xp,
+						winy + font->ascent,
+						(FcChar8 *)u8fs,
+						u8fblen);
+				xp += xw.cw * u8fl;
+			}
+			break;
 		}
 		if(doesexist) {
 			if(oneatatime)

From 58eaa998b37bc44acbf4356a3bc4116acf570893 Mon Sep 17 00:00:00 2001
From: Troy Sankey <sankeytms@gmail.com>
Date: Wed, 18 Jun 2014 10:41:26 -0700
Subject: [PATCH 0703/1146] update size hints on zoom

On font zooming (i.e. xzoom()), window size hints are not updated.  This
patch does that.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index 2cf9a26..26053b0 100644
--- a/st.c
+++ b/st.c
@@ -2993,6 +2993,7 @@ xzoom(const Arg *arg) {
 	xloadfonts(usedfont, usedfontsize + arg->i);
 	cresize(0, 0);
 	redraw(0);
+	xhints();
 }
 
 void

From 738f555f66e2423678d7f81344131d2e01f7c2e9 Mon Sep 17 00:00:00 2001
From: Eric Pruitt <eric.pruitt@gmail.com>
Date: Wed, 18 Jun 2014 08:39:57 -0500
Subject: [PATCH 0704/1146] Fix typo in config.def.h

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 config.def.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config.def.h b/config.def.h
index 6e2be9a..fadcfa0 100644
--- a/config.def.h
+++ b/config.def.h
@@ -9,7 +9,7 @@ static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=fals
 static int borderpx = 2;
 static char shell[] = "/bin/sh";
 
-/* Kerning / character bounding-box mutlipliers */
+/* Kerning / character bounding-box multipliers */
 static float cwscale = 1.0;
 static float chscale = 1.0;
 
@@ -137,7 +137,7 @@ static Shortcut shortcuts[] = {
  * * > 0: crlf mode is enabled
  * * < 0: crlf mode is disabled
  *
- * Be careful with the order of the definitons because st searchs in
+ * 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.
  */

From 5edeec1b20fcb5900d4f1408594d1e76b6c544f0 Mon Sep 17 00:00:00 2001
From: FRIGN <dev@frign.de>
Date: Mon, 23 Jun 2014 16:51:51 +0200
Subject: [PATCH 0705/1146] Use monotonic clock to prevent timing issues

This patch replaces the gettimeofday()/timeval-system with
uses of clock_gettime() with a monolithic clock and timespec-structs.
gettimeofday() is not accurate and prone to jumps and POSIX.1-2008
marks it as obsolete. Read more here [0].

The patch should speak for itself and decreases the binary
size for me by almost 200K(!).

[0]: http://blog.habets.pp.se/2010/09/gettimeofday-should-never-be-used-to-measure-time

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index 26053b0..17142a4 100644
--- a/st.c
+++ b/st.c
@@ -76,7 +76,7 @@ char *argv0;
 #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 IS_SET(flag) ((term.mode & (flag)) != 0)
-#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
+#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_nsec-t2.tv_nsec)/10E6)
 #define CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x))
 #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
 
@@ -294,8 +294,8 @@ typedef struct {
 	char *clip;
 	Atom xtarget;
 	bool alt;
-	struct timeval tclick1;
-	struct timeval tclick2;
+	struct timespec tclick1;
+	struct timespec tclick2;
 } Selection;
 
 typedef union {
@@ -860,7 +860,7 @@ mousereport(XEvent *e) {
 
 void
 bpress(XEvent *e) {
-	struct timeval now;
+	struct timespec now;
 	Mousekey *mk;
 
 	if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
@@ -877,7 +877,7 @@ bpress(XEvent *e) {
 	}
 
 	if(e->xbutton.button == Button1) {
-		gettimeofday(&now, NULL);
+		clock_gettime(CLOCK_MONOTONIC, &now);
 
 		/* Clear previous selection, logically and visually. */
 		selclear(NULL);
@@ -3709,7 +3709,8 @@ run(void) {
 	int w = xw.w, h = xw.h;
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
-	struct timeval drawtimeout, *tv = NULL, now, last, lastblink;
+	struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
+	long deltatime;
 
 	/* Waiting for window mapping */
 	while(1) {
@@ -3725,17 +3726,15 @@ run(void) {
 	ttynew();
 	cresize(w, h);
 
-	gettimeofday(&last, NULL);
+	clock_gettime(CLOCK_MONOTONIC, &last);
 	lastblink = last;
 
 	for(xev = actionfps;;) {
-		long deltatime;
-
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);
 
-		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv) < 0) {
+		if(pselect(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
 			if(errno == EINTR)
 				continue;
 			die("select failed: %s\n", strerror(errno));
@@ -3752,9 +3751,9 @@ run(void) {
 		if(FD_ISSET(xfd, &rfd))
 			xev = actionfps;
 
-		gettimeofday(&now, NULL);
+		clock_gettime(CLOCK_MONOTONIC, &now);
 		drawtimeout.tv_sec = 0;
-		drawtimeout.tv_usec = (1000/xfps) * 1000;
+		drawtimeout.tv_nsec = (1000/xfps) * 10E6;
 		tv = &drawtimeout;
 
 		dodraw = 0;
@@ -3789,9 +3788,9 @@ run(void) {
 				if(blinkset) {
 					if(TIMEDIFF(now, lastblink) \
 							> blinktimeout) {
-						drawtimeout.tv_usec = 1;
+						drawtimeout.tv_nsec = 1000;
 					} else {
-						drawtimeout.tv_usec = (1000 * \
+						drawtimeout.tv_nsec = (10E6 * \
 							(blinktimeout - \
 							TIMEDIFF(now,
 								lastblink)));

From 19d095717f656d844cd9d696d9c921a0821a5ea7 Mon Sep 17 00:00:00 2001
From: Ivan Delalande <colona@ycc.fr>
Date: Thu, 26 Jun 2014 04:30:43 +0200
Subject: [PATCH 0706/1146] Fixed wrong nanosecond factor 10E6.

Commit 5edeec1 introduced a wrong factor for nanosecond computation, the correct
value is 1E6. Time and timeout values are 10 times less than they should be and
this cause high CPU usage.

Reported by pyroh on IRC. Thanks!

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 17142a4..f9c9f7a 100644
--- a/st.c
+++ b/st.c
@@ -76,7 +76,7 @@ char *argv0;
 #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 IS_SET(flag) ((term.mode & (flag)) != 0)
-#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_nsec-t2.tv_nsec)/10E6)
+#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_nsec-t2.tv_nsec)/1E6)
 #define CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x))
 #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
 
@@ -3753,7 +3753,7 @@ run(void) {
 
 		clock_gettime(CLOCK_MONOTONIC, &now);
 		drawtimeout.tv_sec = 0;
-		drawtimeout.tv_nsec = (1000/xfps) * 10E6;
+		drawtimeout.tv_nsec = (1000/xfps) * 1E6;
 		tv = &drawtimeout;
 
 		dodraw = 0;
@@ -3790,7 +3790,7 @@ run(void) {
 							> blinktimeout) {
 						drawtimeout.tv_nsec = 1000;
 					} else {
-						drawtimeout.tv_nsec = (10E6 * \
+						drawtimeout.tv_nsec = (1E6 * \
 							(blinktimeout - \
 							TIMEDIFF(now,
 								lastblink)));

From 77569526c0166e6364bb635fceb8eeabd58ce683 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 26 Jun 2014 12:37:06 +0200
Subject: [PATCH 0707/1146] Remove CEIL macro

This macro was not correct in some cases, and it was used only in
one place, where we did'nt get any benefit in performance of in size,
so the macro is removed and ceilf is used instead of it. The only
function needed from math.h is ceilf, so this patch defines the
prototype of it instead of including math.h.
---
 config.mk | 2 +-
 st.c      | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/config.mk b/config.mk
index 97afa2c..6d90f86 100644
--- a/config.mk
+++ b/config.mk
@@ -14,7 +14,7 @@ X11LIB = /usr/X11R6/lib
 INCS = -I. -I/usr/include -I${X11INC} \
        `pkg-config --cflags fontconfig` \
        `pkg-config --cflags freetype2`
-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lutil -lXext -lXft \
+LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lX11 -lutil -lXext -lXft \
        `pkg-config --libs fontconfig`  \
        `pkg-config --libs freetype2`
 
diff --git a/st.c b/st.c
index f9c9f7a..2b6b717 100644
--- a/st.c
+++ b/st.c
@@ -77,7 +77,6 @@ char *argv0;
 #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
 #define IS_SET(flag) ((term.mode & (flag)) != 0)
 #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_nsec-t2.tv_nsec)/1E6)
-#define CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x))
 #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
 
 #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
@@ -2892,6 +2891,7 @@ xloadfonts(char *fontstr, double fontsize) {
 	FcPattern *pattern;
 	FcResult r_sz, r_psz;
 	double fontval;
+	float ceilf(float);
 
 	if(fontstr[0] == '-') {
 		pattern = XftXlfdParse(fontstr, False, False);
@@ -2937,8 +2937,8 @@ xloadfonts(char *fontstr, double fontsize) {
 	}
 
 	/* Setting character width and height. */
-	xw.cw = CEIL(dc.font.width * cwscale);
-	xw.ch = CEIL(dc.font.height * chscale);
+	xw.cw = ceilf(dc.font.width * cwscale);
+	xw.ch = ceilf(dc.font.height * chscale);
 
 	FcPatternDel(pattern, FC_SLANT);
 	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);

From 50e6355e0d6c9843b51ac4711980401205ce06c1 Mon Sep 17 00:00:00 2001
From: Anders Eurenius <aes@spotify.com>
Date: Sat, 21 Jun 2014 20:29:36 +0200
Subject: [PATCH 0708/1146] Reorder and extend glyph attributes

Faint, invisible, struck and fast blink are added as glyph attributes.
Since there's an edit here, let's take the opportunity to reorder them
so that they correspond to the two's power of the corresponding escape
code. (just for neatness, let's hope that property never gets used for
anything.)

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 46 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index 2b6b717..9637834 100644
--- a/st.c
+++ b/st.c
@@ -89,15 +89,19 @@ char *argv0;
 #define VT102ID "\033[?6c"
 
 enum glyph_attribute {
-	ATTR_NULL      = 0,
-	ATTR_REVERSE   = 1,
-	ATTR_UNDERLINE = 2,
-	ATTR_BOLD      = 4,
-	ATTR_ITALIC    = 8,
+        ATTR_NULL      = 0,
+	ATTR_BOLD      = 1,
+	ATTR_FAINT     = 2,
+	ATTR_ITALIC    = 4,
+	ATTR_UNDERLINE = 8,
 	ATTR_BLINK     = 16,
-	ATTR_WRAP      = 32,
-	ATTR_WIDE      = 64,
-	ATTR_WDUMMY    = 128,
+	ATTR_FASTBLINK = 32,
+	ATTR_REVERSE   = 64,
+	ATTR_INVISIBLE = 128,
+	ATTR_STRUCK    = 256,
+	ATTR_WRAP      = 512,
+	ATTR_WIDE      = 1024,
+	ATTR_WDUMMY    = 2048,
 };
 
 enum cursor_movement {
@@ -1681,15 +1685,25 @@ tsetattr(int *attr, int l) {
 	for(i = 0; i < l; i++) {
 		switch(attr[i]) {
 		case 0:
-			term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE \
-					| ATTR_BOLD | ATTR_ITALIC \
-					| ATTR_BLINK);
+			term.c.attr.mode &= ~(
+				ATTR_BOLD       |
+				ATTR_FAINT      |
+				ATTR_ITALIC     |
+				ATTR_UNDERLINE  |
+				ATTR_BLINK      |
+				ATTR_FASTBLINK  |
+				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;
@@ -1697,16 +1711,26 @@ tsetattr(int *attr, int l) {
 			term.c.attr.mode |= ATTR_UNDERLINE;
 			break;
 		case 5: /* slow blink */
-		case 6: /* rapid blink */
 			term.c.attr.mode |= ATTR_BLINK;
 			break;
+		case 6: /* rapid blink */
+			term.c.attr.mode |= ATTR_FASTBLINK;
+			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 21:
-		case 22:
 			term.c.attr.mode &= ~ATTR_BOLD;
 			break;
+		case 22:
+			term.c.attr.mode &= ~ATTR_FAINT;
+			break;
 		case 23:
 			term.c.attr.mode &= ~ATTR_ITALIC;
 			break;
@@ -1714,12 +1738,20 @@ tsetattr(int *attr, int l) {
 			term.c.attr.mode &= ~ATTR_UNDERLINE;
 			break;
 		case 25:
-		case 26:
 			term.c.attr.mode &= ~ATTR_BLINK;
 			break;
+		case 26:
+			term.c.attr.mode &= ~ATTR_FASTBLINK;
+			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;

From 21bd4f4f9dce4dd19f218965e5a223c93a5a0fec Mon Sep 17 00:00:00 2001
From: Anders Eurenius <aes@spotify.com>
Date: Sat, 21 Jun 2014 20:30:22 +0200
Subject: [PATCH 0709/1146] Render invisible attribute

Implement invisible mode by setting the foreground color to be the same
as the background color. Not rendering anything would also be an
alternative, but this seems less likely to cause surprises in
conjunction with any hacks.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.c b/st.c
index 9637834..a69cc9e 100644
--- a/st.c
+++ b/st.c
@@ -3236,6 +3236,9 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	if(base.mode & ATTR_BLINK && term.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,

From 1fc4afd1e6609732178369c7f17c917204aad4cc Mon Sep 17 00:00:00 2001
From: Anders Eurenius <aes@spotify.com>
Date: Sat, 21 Jun 2014 20:32:34 +0200
Subject: [PATCH 0710/1146] Render struck-out attribute

Implement crossed-out text with an XftDrawRect call, similar to how
underline is implemented. The line is drawn at 2/3 of the font ascent,
which seems to work nicely in practice.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/st.c b/st.c
index a69cc9e..3aa8539 100644
--- a/st.c
+++ b/st.c
@@ -3383,6 +3383,11 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 				width, 1);
 	}
 
+	if(base.mode & ATTR_STRUCK) {
+		XftDrawRect(xw.draw, fg, winx, winy + 2 * font->ascent / 3,
+				width, 1);
+	}
+
 	/* Reset clip to none. */
 	XftDrawSetClip(xw.draw, 0);
 }

From 0015e198bfceae50a55403ad1339345340f4dcc0 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 30 Jun 2014 17:33:43 +0200
Subject: [PATCH 0711/1146] Making surf compile again with rt.

The clock_gettime patch needs librt to be linked to surf.

Thanks _odie for the hint.
---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 6d90f86..298484e 100644
--- a/config.mk
+++ b/config.mk
@@ -14,7 +14,7 @@ X11LIB = /usr/X11R6/lib
 INCS = -I. -I/usr/include -I${X11INC} \
        `pkg-config --cflags fontconfig` \
        `pkg-config --cflags freetype2`
-LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lX11 -lutil -lXext -lXft \
+LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXext -lXft \
        `pkg-config --libs fontconfig`  \
        `pkg-config --libs freetype2`
 

From 955923b38b1f08f6cb25a706cea2af5966339187 Mon Sep 17 00:00:00 2001
From: Ivan Delalande <colona@ycc.fr>
Date: Fri, 27 Jun 2014 09:15:56 +0200
Subject: [PATCH 0712/1146] Remove all strcmp and strlen calls on Glyph.c[]

There were a few occurrences of strcmp and strlen being called on Glyph.c[],
which is not always null-terminated (this actually depends on the last values in
the buffer s in ttyread()). This patch replace all the calls to strcmp with a
test on c[0] directly or a call to tlinelen, and the one to strlen with utf8len.
I also took the opportunity to refactor getsel and tdumpline.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 42 ++++++++++++++++--------------------------
 1 file changed, 16 insertions(+), 26 deletions(-)

diff --git a/st.c b/st.c
index 3aa8539..61024c8 100644
--- a/st.c
+++ b/st.c
@@ -375,6 +375,7 @@ 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 tnew(int, int);
@@ -920,7 +921,7 @@ bpress(XEvent *e) {
 char *
 getsel(void) {
 	char *str, *ptr;
-	int x, y, bufsize, size, ex;
+	int y, bufsize, size, lastx, linelen;
 	Glyph *gp, *last;
 
 	if(sel.ob.x == -1)
@@ -931,16 +932,19 @@ getsel(void) {
 
 	/* append every set & selected glyph to the selection */
 	for(y = sel.nb.y; y < sel.ne.y + 1; y++) {
-		gp = &term.line[y][0];
-		last = &gp[term.col-1];
+		linelen = tlinelen(y);
 
-		while(last >= gp && !(selected(last - gp, y) &&
-				      strcmp(last->c, " ") != 0)) {
-			--last;
+		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)];
 
-		for(x = 0; gp <= last; x++, ++gp) {
-			if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))
+		for( ; gp <= last; ++gp) {
+			if(gp->mode & ATTR_WDUMMY)
 				continue;
 
 			size = utf8len(gp->c);
@@ -957,20 +961,8 @@ getsel(void) {
 		 * st.
 		 * FIXME: Fix the computer world.
 		 */
-		if(y < sel.ne.y && !(x > 0 && (gp-1)->mode & ATTR_WRAP))
+		if(sel.ne.y > y || lastx >= linelen)
 			*ptr++ = '\n';
-
-		/*
-		 * If the last selected line expands in the selection
-		 * after the visible text '\n' is appended.
-		 */
-		if(y == sel.ne.y) {
-			ex = sel.ne.x;
-			if(sel.nb.y == sel.ne.y && sel.ne.x < sel.nb.x)
-				ex = sel.nb.x;
-			if(tlinelen(y) < ex)
-				*ptr++ = '\n';
-		}
 	}
 	*ptr = 0;
 	return str;
@@ -2287,12 +2279,10 @@ tdumpline(int n) {
 	Glyph *bp, *end;
 
 	bp = &term.line[n][0];
-	end = &bp[term.col-1];
-	while(end > bp && !strcmp(" ", end->c))
-		--end;
-	if(bp != end || strcmp(bp->c, " ")) {
+	end = &bp[MIN(tlinelen(n), term.col) - 1];
+	if(bp != end || bp->c[0] != ' ') {
 		for( ;bp <= end; ++bp)
-			tprinter(bp->c, strlen(bp->c));
+			tprinter(bp->c, utf8len(bp->c));
 	}
 	tprinter("\n", 1);
 }

From f796533b1bab9aa8ea4e70b79d305c9aea47fe6a Mon Sep 17 00:00:00 2001
From: Anders Eurenius <aes@spotify.com>
Date: Sun, 22 Jun 2014 00:10:59 +0200
Subject: [PATCH 0713/1146] Render faint attribute

Faint text is implemented by allocating a new color at one-half
intensity of each of the r, g, b components, or if the text bold at the
same time, it is not made lighter.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 61024c8..69ec122 100644
--- a/st.c
+++ b/st.c
@@ -3179,7 +3179,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		 * change basic system colors [0-7]
 		 * to bright system colors [8-15]
 		 */
-		if(BETWEEN(base.fg, 0, 7))
+		if(BETWEEN(base.fg, 0, 7) && !(base.mode & ATTR_FAINT))
 			fg = &dc.col[base.fg + 8];
 
 		if(base.mode & ATTR_ITALIC) {
@@ -3223,6 +3223,14 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		bg = temp;
 	}
 
+	if(base.mode & ATTR_FAINT && !(base.mode & ATTR_BOLD)) {
+		colfg.red = fg->color.red / 2;
+		colfg.green = fg->color.green / 2;
+		colfg.blue = fg->color.blue / 2;
+		XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg);
+		fg = &revfg;
+	}
+
 	if(base.mode & ATTR_BLINK && term.mode & MODE_BLINK)
 		fg = bg;
 

From bcbaf5d9beb72f29d228d103634d648ca28fb48d Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 20 Jun 2014 09:51:18 +0200
Subject: [PATCH 0714/1146] Add 8 bit version of DECID

DECID version for 7 bits environments already was implemented in st.
This patch adds the 8 bit version of it.
---
 st.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 69ec122..77ae26e 100644
--- a/st.c
+++ b/st.c
@@ -2408,7 +2408,10 @@ tcontrolcode(uchar ascii) {
 	case 0x8f:   /* TODO: SS3 */
 	case 0x90:   /* TODO: DCS */
 	case 0x98:   /* TODO: SOS */
-	case 0x9a:   /* TODO: DECID */
+		break;
+	case 0x9a:   /* DECID -- Identify Terminal */
+		ttywrite(VT102ID, sizeof(VT102ID) - 1);
+		break;
 	case 0x9b:   /* TODO: CSI */
 	case 0x9c:   /* TODO: ST */
 	case 0x9d:   /* TODO: OSC */

From f5356d018505963a72d1a5bb505c69b2cf32792b Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 20 Jun 2014 09:51:18 +0200
Subject: [PATCH 0715/1146] Add 8 bit version of NEL

NEL version for 7 bits environments already was implemented in st.
This patch adds the 8 bit version of it.
---
 st.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 77ae26e..1162700 100644
--- a/st.c
+++ b/st.c
@@ -2401,7 +2401,10 @@ tcontrolcode(uchar ascii) {
 	case 0177:   /* DEL (IGNORED) */
 		return;
 	case 0x84:   /* TODO: IND */
-	case 0x85:   /* TODO: NEL */
+		break;
+	case 0x85:   /* NEL -- Next line */
+		tnewline(1); /* always go to first col */
+		break;
 	case 0x88:   /* TODO: HTS */
 	case 0x8d:   /* TODO: RI */
 	case 0x8e:   /* TODO: SS2 */

From da78629cf5fa234204f002ff2c2b597a2bf7e76f Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 20 Jun 2014 09:51:18 +0200
Subject: [PATCH 0716/1146] Add 8 bit version of HTS

HTS version for 7 bits environments already was implemented in st.
This patch adds the 8 bit version of it.
---
 st.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 1162700..6ec4858 100644
--- a/st.c
+++ b/st.c
@@ -2405,7 +2405,9 @@ tcontrolcode(uchar ascii) {
 	case 0x85:   /* NEL -- Next line */
 		tnewline(1); /* always go to first col */
 		break;
-	case 0x88:   /* TODO: HTS */
+	case 0x88:   /* HTS -- Horizontal tab stop */
+		term.tabs[term.c.x] = 1;
+		break;
 	case 0x8d:   /* TODO: RI */
 	case 0x8e:   /* TODO: SS2 */
 	case 0x8f:   /* TODO: SS3 */

From 984c12d2a67fd19ee69b35152d93de8cb67595e8 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 20 Jun 2014 09:51:18 +0200
Subject: [PATCH 0717/1146] Add 8 bit version of DCS, APC, PM, OSC

DCS, APC, PM, OSC version for 7 bits environments already was implemented
in st.  This patch adds the 8 bit version of it.
---
 st.c | 39 ++++++++++++++++++++++++++++++++-------
 1 file changed, 32 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index 6ec4858..b221f33 100644
--- a/st.c
+++ b/st.c
@@ -405,6 +405,7 @@ static void ttyread(void);
 static void ttyresize(void);
 static void ttysend(char *, size_t);
 static void ttywrite(const char *, size_t);
+static void tstrsequence(uchar c);
 
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
@@ -2347,6 +2348,30 @@ tdeftran(char ascii) {
 	}
 }
 
+void
+tstrsequence(uchar c) {
+	if (c & 0x80) {
+		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;
+	return;
+}
+
 void
 tcontrolcode(uchar ascii) {
 	static char question[UTF_SIZ] = "?";
@@ -2411,7 +2436,6 @@ tcontrolcode(uchar ascii) {
 	case 0x8d:   /* TODO: RI */
 	case 0x8e:   /* TODO: SS2 */
 	case 0x8f:   /* TODO: SS3 */
-	case 0x90:   /* TODO: DCS */
 	case 0x98:   /* TODO: SOS */
 		break;
 	case 0x9a:   /* DECID -- Identify Terminal */
@@ -2419,10 +2443,13 @@ tcontrolcode(uchar ascii) {
 		break;
 	case 0x9b:   /* TODO: CSI */
 	case 0x9c:   /* TODO: ST */
-	case 0x9d:   /* TODO: OSC */
-	case 0x9e:   /* TODO: PM */
-	case 0x9f:   /* TODO: APC */
 		break;
+	case 0x90:   /* DCS -- Device Control String */
+	case 0x9f:   /* APC -- Application Program Command */
+	case 0x9e:   /* PM -- Privacy Message */
+	case 0x9d:   /* OSC -- Operating System Command */
+		tstrsequence(ascii);
+		return;
 	}
 	/* only CAN, SUB, \a and C1 chars interrupt a sequence */
 	term.esc &= ~(ESC_STR_END|ESC_STR);
@@ -2538,9 +2565,7 @@ tputc(char *c, int len) {
 			case '^': /* PM -- Privacy Message */
 			case ']': /* OSC -- Operating System Command */
 			case 'k': /* old title set compatibility */
-				strreset();
-				strescseq.type = ascii;
-				term.esc |= ESC_STR;
+				tstrsequence(ascii);
 				return;
 			case '(': /* set primary charset G0 */
 			case ')': /* set secondary charset G1 */

From b5d0a13c10ab6ba6121c5fa67b9f20c8d41de349 Mon Sep 17 00:00:00 2001
From: Eric Pruitt <eric.pruitt@gmail.com>
Date: Mon, 14 Jul 2014 09:05:07 -0500
Subject: [PATCH 0718/1146] Changed inconsistent indent

- A line was indented using spaces despite the rest of the code using
  tabs.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index b221f33..040638a 100644
--- a/st.c
+++ b/st.c
@@ -89,7 +89,7 @@ char *argv0;
 #define VT102ID "\033[?6c"
 
 enum glyph_attribute {
-        ATTR_NULL      = 0,
+	ATTR_NULL      = 0,
 	ATTR_BOLD      = 1,
 	ATTR_FAINT     = 2,
 	ATTR_ITALIC    = 4,

From 84ceefe0890ee235dd736543fe30479393562fb6 Mon Sep 17 00:00:00 2001
From: Weng Xuetian <wengxt@gmail.com>
Date: Wed, 16 Jul 2014 18:36:46 -0400
Subject: [PATCH 0719/1146] Fix st with input method.

XFilterEvent need to be called against every event, otherwise it would
missing some message in the xim protocol and misbehave on some im server.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.c b/st.c
index 040638a..546db41 100644
--- a/st.c
+++ b/st.c
@@ -3786,6 +3786,8 @@ run(void) {
 	/* Waiting for window mapping */
 	while(1) {
 		XNextEvent(xw.dpy, &ev);
+		if(XFilterEvent(&ev, None))
+			continue;
 		if(ev.type == ConfigureNotify) {
 			w = ev.xconfigure.width;
 			h = ev.xconfigure.height;

From 3949aa7c5db6db76e545f6201b1c49f1b91fb245 Mon Sep 17 00:00:00 2001
From: Wolfgang Corcoran-Mathe <first.lord.of.teal@gmail.com>
Date: Sun, 20 Jul 2014 11:05:39 -0400
Subject: [PATCH 0720/1146] Very minor grammar fixes in FAQ

Self-explanatory.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 FAQ | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/FAQ b/FAQ
index c8e76a5..793680a 100644
--- a/FAQ
+++ b/FAQ
@@ -42,10 +42,10 @@ Taken from the terminfo manpage:
 	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, have to send these
+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
+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
@@ -53,7 +53,7 @@ solution for them is to use the following command:
 or
 	$ echo $(tput smkx) >/dev/tty
 
-In the case of bash readline is used. Readline has a different note in its
+In the case of bash, readline is used. Readline has a different note in its
 manpage about this issue:
 
 	enable-keypad (Off)
@@ -84,8 +84,8 @@ If you are using zsh, then read the zsh FAQ
 
 Putting these lines into your .zshrc will fix the problems.
 
-## How can use meta in 8bit mode?
+## How can I use meta in 8bit mode?
 
- St support meta in 8bit mode, but the default terminfo entry doesn't
- use this capability. If you want it, you have to use st-meta value
+ 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.

From 8c5ba1cfb09edc12d4992df4667c6ea2a476c82f Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 20 Jul 2014 10:31:16 +0200
Subject: [PATCH 0721/1146] Add information about librt and OpenBSD to the FAQ

---
 FAQ | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/FAQ b/FAQ
index 793680a..447577f 100644
--- a/FAQ
+++ b/FAQ
@@ -89,3 +89,10 @@ Putting these lines into your .zshrc will fix the problems.
  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 of librt, but it is mandatory in POSIX
+<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html#tag_20_11_13>.
+If you want compile st for OpenBSD you have to remove -lrt from config.mk.
+

From 844cd7ce17aaad93cfc2ffba6b7511bac855786c Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 20 Jul 2014 10:31:16 +0200
Subject: [PATCH 0722/1146] Add information about librt and OpenBSD to the FAQ

---
 FAQ | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/FAQ b/FAQ
index 447577f..f8a2ec2 100644
--- a/FAQ
+++ b/FAQ
@@ -94,5 +94,7 @@ Putting these lines into your .zshrc will fix the problems.
 
 OpenBSD lacks of librt, but it is mandatory in POSIX
 <http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html#tag_20_11_13>.
-If you want compile st for OpenBSD you have to remove -lrt from config.mk.
+If you want 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.
 

From 8306568bd0b9d082c58ad897b4562ffe6822e585 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 20 Jul 2014 10:31:16 +0200
Subject: [PATCH 0723/1146] Add information about librt and OpenBSD to the FAQ

---
 FAQ | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/FAQ b/FAQ
index f8a2ec2..adac39f 100644
--- a/FAQ
+++ b/FAQ
@@ -92,9 +92,9 @@ Putting these lines into your .zshrc will fix the problems.
 
 ## I cannot compile st in OpenBSD
 
-OpenBSD lacks of librt, but it is mandatory in POSIX
+OpenBSD lacks of librt, despite it begin mandatory in POSIX
 <http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html#tag_20_11_13>.
-If you want 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
+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.
 

From f210ea26c444607980d5de17ed7d4e62bb813631 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 24 Jul 2014 19:56:58 +0200
Subject: [PATCH 0724/1146] Add info about Backspace and Delete to the FAQ

---
 FAQ | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/FAQ b/FAQ
index adac39f..2ee5ec7 100644
--- a/FAQ
+++ b/FAQ
@@ -98,3 +98,61 @@ If you want to compile st for OpenBSD you have to remove -lrt from config.mk, an
 st will compile without any loss of functionality, because all the functions are
 included in libc on this platform.
 
+## Backspace key does not work
+
+This is an issue that was discussed in suckless mailing list
+<http://lists.suckless.org/dev/1404/20697.html>:
+
+	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 were done using punched cards, or hardcopy
+	terminals (basically a typewritter machine connected with
+	the computer using a serial port). Due to this, ascii defines
+	DELETE as 7F, because in the puched cards, it means all the
+	holes of the card punched, so it is a kind of 'phisical
+	delete'. In the same way, BACKSPACE key was a non destructive
+	back space, as in typewriter machines.  So, if you wanted
+	to delete a character, you had to BACKSPACE and then DELETE.
+	Other use of BACKSPACE was 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 BACKSPACE key is located today
+	in common PC keyboards. All the terminal emulators emulated
+	correctly the difference between these keys, and backspace
+	key generated a BACKSPACE (^H) and delete key generated a
+	DELETE (^?).
+
+	But the problem arised when Linus Torvald wrote Linux, and
+	he did that the virtual terminal (the terminal emulator
+	integrated in the kernel) returns a DELETE when backspace
+	was pressed, due to the fact of the key in that position
+	in VT100 was a delete key. This created a lot of problems
+	(you can see it in [1] and [2]), and how Linux became the
+	king, a lot of terminal emulators today generate a DELETE
+	when backspace key is pressed in order to avoid problems
+	with linux. It causes that the only way of generating a
+	BACKSPACE in these systems is using CONTROL + H. I also
+	think that emacs had an important point here because 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 configure the correct value of
+	stty erase for this terminal, but in the case of terminal
+	emulators you don't have any getty that can set the correct
+	value of stty erase, so you always get the default value.
+	So it means that in case of changing the value of the
+	backspace keyboard, you have to add a 'stty erase ^H' into
+	your profile. Of course, other solution can be that st
+	itself modify the value of stty erase.  I have usually the
+	inverse problem, when I connect with non Unix machines, and
+	I have to press control + h to get a BACKSPACE, or the
+	inverse, 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
+

From e8f3513bf4d953176ae932c5d7eb5c374b05a2a0 Mon Sep 17 00:00:00 2001
From: Wolfgang Corcoran-Mathe <first.lord.of.teal@gmail.com>
Date: Fri, 25 Jul 2014 13:32:29 -0400
Subject: [PATCH 0725/1146] Add info about Backspace and Delete to the FAQ

Here is a modest attempt at cleaning it up a little bit. I changed a
few phrases that seemed awkward, but I think the content is the same.

--
Wolfgang Corcoran-Mathe

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 FAQ | 85 ++++++++++++++++++++++++++++++-------------------------------
 1 file changed, 42 insertions(+), 43 deletions(-)

diff --git a/FAQ b/FAQ
index 2ee5ec7..a47c024 100644
--- a/FAQ
+++ b/FAQ
@@ -104,54 +104,53 @@ This is an issue that was discussed in suckless mailing list
 <http://lists.suckless.org/dev/1404/20697.html>:
 
 	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 were done using punched cards, or hardcopy
-	terminals (basically a typewritter machine connected with
-	the computer using a serial port). Due to this, ascii defines
-	DELETE as 7F, because in the puched cards, it means all the
-	holes of the card punched, so it is a kind of 'phisical
-	delete'. In the same way, BACKSPACE key was a non destructive
-	back space, as in typewriter machines.  So, if you wanted
-	to delete a character, you had to BACKSPACE and then DELETE.
-	Other use of BACKSPACE was 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 BACKSPACE key is located today
-	in common PC keyboards. All the terminal emulators emulated
-	correctly the difference between these keys, and backspace
-	key generated a BACKSPACE (^H) and delete key generated a
-	DELETE (^?).
+	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 the problem arised when Linus Torvald wrote Linux, and
-	he did that the virtual terminal (the terminal emulator
-	integrated in the kernel) returns a DELETE when backspace
-	was pressed, due to the fact of the key in that position
-	in VT100 was a delete key. This created a lot of problems
-	(you can see it in [1] and [2]), and how Linux became the
-	king, a lot of terminal emulators today generate a DELETE
-	when backspace key is pressed in order to avoid problems
-	with linux. It causes that the only way of generating a
-	BACKSPACE in these systems is using CONTROL + H. I also
-	think that emacs had an important point here because CONTROL
-	+ H prefix is used in emacs in some commands (help commands).
+	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 configure the correct value of
-	stty erase for this terminal, but in the case of terminal
-	emulators you don't have any getty that can set the correct
+	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.
-	So it means that in case of changing the value of the
-	backspace keyboard, you have to add a 'stty erase ^H' into
-	your profile. Of course, other solution can be that st
-	itself modify the value of stty erase.  I have usually the
-	inverse problem, when I connect with non Unix machines, and
-	I have to press control + h to get a BACKSPACE, or the
-	inverse, when a user connects to my unix machines from a
-	different system with a correct backspace key.
+	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

From b4dfa18124451f9ee29a0719ef36ffd58fae4477 Mon Sep 17 00:00:00 2001
From: Michael Forney <mforney@mforney.org>
Date: Sat, 26 Jul 2014 00:48:15 -0700
Subject: [PATCH 0726/1146] Fix disabling of bold and fastblink
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

According to ECMA-48¹ 8.3.117, an attribute value of 21 is "doubly
underlined", while 22 is "normal colour or normal intensity (neither
bold nor faint)".

Additionally, 25 is "steady (not blinking)", which likely means neither
slow blink nor fast blink.

¹: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/st.c b/st.c
index 546db41..0c917fd 100644
--- a/st.c
+++ b/st.c
@@ -1718,11 +1718,8 @@ tsetattr(int *attr, int l) {
 		case 9:
 			term.c.attr.mode |= ATTR_STRUCK;
 			break;
-		case 21:
-			term.c.attr.mode &= ~ATTR_BOLD;
-			break;
 		case 22:
-			term.c.attr.mode &= ~ATTR_FAINT;
+			term.c.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT);
 			break;
 		case 23:
 			term.c.attr.mode &= ~ATTR_ITALIC;
@@ -1731,10 +1728,7 @@ tsetattr(int *attr, int l) {
 			term.c.attr.mode &= ~ATTR_UNDERLINE;
 			break;
 		case 25:
-			term.c.attr.mode &= ~ATTR_BLINK;
-			break;
-		case 26:
-			term.c.attr.mode &= ~ATTR_FASTBLINK;
+			term.c.attr.mode &= ~(ATTR_BLINK | ATTR_FASTBLINK);
 			break;
 		case 27:
 			term.c.attr.mode &= ~ATTR_REVERSE;

From 769d48180747c3255653360d161c77ec2a2e8d13 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 31 Jul 2014 19:37:59 +0200
Subject: [PATCH 0727/1146] Remove difference between fast and slow blinking

One blinking mode is good enough, and two is too much. The best aproach
is emulate the fast blinking with the slow blinking, that it is more
used.
It is removed the flag ATTR_FASTBLINK because it has not a different
meaning of ATTR_BLINK, so it is not needed.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/st.c b/st.c
index 0c917fd..a2703f4 100644
--- a/st.c
+++ b/st.c
@@ -95,13 +95,12 @@ enum glyph_attribute {
 	ATTR_ITALIC    = 4,
 	ATTR_UNDERLINE = 8,
 	ATTR_BLINK     = 16,
-	ATTR_FASTBLINK = 32,
-	ATTR_REVERSE   = 64,
-	ATTR_INVISIBLE = 128,
-	ATTR_STRUCK    = 256,
-	ATTR_WRAP      = 512,
-	ATTR_WIDE      = 1024,
-	ATTR_WDUMMY    = 2048,
+	ATTR_REVERSE   = 32,
+	ATTR_INVISIBLE = 64,
+	ATTR_STRUCK    = 128,
+	ATTR_WRAP      = 256,
+	ATTR_WIDE      = 512,
+	ATTR_WDUMMY    = 1024,
 };
 
 enum cursor_movement {
@@ -1684,7 +1683,6 @@ tsetattr(int *attr, int l) {
 				ATTR_ITALIC     |
 				ATTR_UNDERLINE  |
 				ATTR_BLINK      |
-				ATTR_FASTBLINK  |
 				ATTR_REVERSE    |
 				ATTR_INVISIBLE  |
 				ATTR_STRUCK     );
@@ -1704,10 +1702,9 @@ tsetattr(int *attr, int l) {
 			term.c.attr.mode |= ATTR_UNDERLINE;
 			break;
 		case 5: /* slow blink */
-			term.c.attr.mode |= ATTR_BLINK;
-			break;
+			/* FALLTHROUGH */
 		case 6: /* rapid blink */
-			term.c.attr.mode |= ATTR_FASTBLINK;
+			term.c.attr.mode |= ATTR_BLINK;
 			break;
 		case 7:
 			term.c.attr.mode |= ATTR_REVERSE;
@@ -1728,7 +1725,7 @@ tsetattr(int *attr, int l) {
 			term.c.attr.mode &= ~ATTR_UNDERLINE;
 			break;
 		case 25:
-			term.c.attr.mode &= ~(ATTR_BLINK | ATTR_FASTBLINK);
+			term.c.attr.mode &= ~ATTR_BLINK;
 			break;
 		case 27:
 			term.c.attr.mode &= ~ATTR_REVERSE;

From ec3268961d1dc4072f6caa6f97db5436da2ff411 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 4 Aug 2014 22:07:04 +0200
Subject: [PATCH 0728/1146] Add error message when child exits whit error

Master proccess was not showing any error message when the child
died with an error, and it was very confusing for the user (for
example with incorrect -e command).
---
 st.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index a2703f4..45bc89d 100644
--- a/st.c
+++ b/st.c
@@ -1176,16 +1176,15 @@ execsh(void) {
 
 void
 sigchld(int a) {
-	int stat = 0;
+	int stat, ret;
 
 	if(waitpid(pid, &stat, 0) < 0)
 		die("Waiting for pid %hd failed: %s\n", pid, strerror(errno));
 
-	if(WIFEXITED(stat)) {
-		exit(WEXITSTATUS(stat));
-	} else {
-		exit(EXIT_FAILURE);
-	}
+	ret = WIFEXITED(stat) ? WEXITSTATUS(stat) : EXIT_FAILURE;
+	if (ret != EXIT_SUCCESS)
+		die("child finished with error '%d'\n", stat);
+	exit(EXIT_SUCCESS);
 }
 
 void

From 8de8ae3923b3b91b034077c8c35acba629588233 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 7 Aug 2014 10:11:38 +0200
Subject: [PATCH 0729/1146] Unset mode when clearing regions

tclearregion() was clearing regions using spaces and the current
attributes of the terminal. It was correct with all the modes excepct
underline, because they didn't affect the space character, but in
the case of underline it was a problem. A easy way of seeing this
problem is writing this in the last line of the terminal:

	tput smul ; echo first; tput rmul; echo second; echo third

Fist was underlined, and second and third were not underlined, but
the spaces at the right of second was underlined becuause in the
previous scrool underline mode was set.
---
 st.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 45bc89d..e0aae9d 100644
--- a/st.c
+++ b/st.c
@@ -1553,6 +1553,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 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;
@@ -1567,10 +1568,13 @@ tclearregion(int x1, int y1, int x2, int y2) {
 	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(NULL);
-			term.line[y][x] = term.c.attr;
-			memcpy(term.line[y][x].c, " ", 2);
+			gp->fg = term.c.attr.fg;
+			gp->bg = term.c.attr.bg;
+			gp->mode = 0;
+			memcpy(gp->c, " ", 2);
 		}
 	}
 }

From 821a6e00a5a9395f40c10c00d19c569bd0f2688e Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 7 Aug 2014 10:19:48 +0200
Subject: [PATCH 0730/1146] Remove ul capability

This capability indicates that underscore '_' overstrike current
letter under the cursor. It means that you can generate a
underline 'b' using 'b^H_', because it writes a 'b' then backward
one characther and then overstrike '_'. St has not such behaviour,
so it is an error to have this capability.
---
 st.info | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.info b/st.info
index 3a01a08..7b4e4f6 100644
--- a/st.info
+++ b/st.info
@@ -183,7 +183,6 @@ st| simpleterm,
 	smul=\E[4m,
 	tbc=\E[3g,
 	tsl=\E]0;,
-	ul,
 	xenl,
 	vpa=\E[%i%p1%dd,
 

From 20c4f122543b67c0cdcefd151eb38b3bee599c10 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Mon, 28 Apr 2014 02:03:04 +0400
Subject: [PATCH 0731/1146] tresize return value is not used

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index e0aae9d..9eebbe4 100644
--- a/st.c
+++ b/st.c
@@ -382,7 +382,7 @@ static void tnewline(int);
 static void tputtab(int);
 static void tputc(char *, int);
 static void treset(void);
-static int tresize(int, int);
+static void tresize(int, int);
 static void tscrollup(int, int);
 static void tscrolldown(int, int);
 static void tsetattr(int *, int);
@@ -2656,7 +2656,7 @@ tputc(char *c, int len) {
 	}
 }
 
-int
+void
 tresize(int col, int row) {
 	int i;
 	int minrow = MIN(row, term.row);
@@ -2666,8 +2666,11 @@ tresize(int col, int row) {
 	Line *orig;
 	TCursor c;
 
-	if(col < 1 || row < 1)
-		return 0;
+	if(col < 1 || row < 1) {
+		fprintf(stderr,
+		        "tresize: error resizing to %dx%d\n", col, row);
+		return;
+	}
 
 	/* free unneeded rows */
 	i = 0;
@@ -2738,8 +2741,6 @@ tresize(int col, int row) {
 		tcursor(CURSOR_LOAD);
 	} while(orig != term.line);
 	term.c = c;
-
-	return (slide > 0);
 }
 
 void

From d4a17316d33f3c5a0017d7fe6e7e174883ccaa97 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Mon, 28 Apr 2014 02:16:21 +0400
Subject: [PATCH 0732/1146] Don't set dirty all lines because tswapcreen do it

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 9eebbe4..814f3f5 100644
--- a/st.c
+++ b/st.c
@@ -2700,14 +2700,12 @@ tresize(int col, int row) {
 
 	/* resize each row to new width, zero-pad if needed */
 	for(i = 0; i < minrow; i++) {
-		term.dirty[i] = 1;
 		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.dirty[i] = 1;
 		term.line[i] = xmalloc(col * sizeof(Glyph));
 		term.alt[i] = xmalloc(col * sizeof(Glyph));
 	}
@@ -2727,7 +2725,7 @@ tresize(int col, int row) {
 	tsetscroll(0, row-1);
 	/* make use of the LIMIT in tmoveto */
 	tmoveto(term.c.x, term.c.y);
-	/* Clearing both screens */
+	/* Clearing both screens (it makes dirty all lines) */
 	orig = term.line;
 	c = term.c;
 	do {

From 6530025bcaf3a65083667a93ae50035bd7137bae Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 15 Aug 2014 14:48:16 +0200
Subject: [PATCH 0733/1146] Fix portability problem in techo()

ISCONTROL chechks if a value is between 0 and 0x1f or
between 0x80 and 0x9f. Char signess depends of architecture
and compiler, so in some environment the second case is
always false (and wrong), Techo() calls ISCONTROL with a
char variable, whose type cannot be changed because tpuc()
expects a pointer to char, so the solution is to insert a
cast in the call to ISCONTROL.
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 814f3f5..d8ff30b 100644
--- a/st.c
+++ b/st.c
@@ -2311,13 +2311,13 @@ techo(char *buf, int len) {
 	for(; len > 0; buf++, len--) {
 		char c = *buf;
 
-		if(ISCONTROL(c)) { /* control code */
+		if(ISCONTROL((uchar) c)) { /* control code */
 			if(c & 0x80) {
 				c &= 0x7f;
 				tputc("^", 1);
 				tputc("[", 1);
 			} else if(c != '\n' && c != '\r' && c != '\t') {
-				c ^= '\x40';
+				c ^= 0x40;
 				tputc("^", 1);
 			}
 			tputc(&c, 1);

From f8b4998b32cbabe2090dc8027720203d6cd2d24d Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 15 Aug 2014 15:00:48 +0200
Subject: [PATCH 0734/1146] Convert VT102ID to a config variable

VT102ID is the sequence that the terminal returns when it is inquired
to identify itself. This value should be configurable in the same
way that another st parameters.
---
 config.def.h | 3 +++
 st.c         | 8 +++-----
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/config.def.h b/config.def.h
index fadcfa0..53e8087 100644
--- a/config.def.h
+++ b/config.def.h
@@ -9,6 +9,9 @@ static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=fals
 static int borderpx = 2;
 static char shell[] = "/bin/sh";
 
+/* identification sequence returned in DA and DECID */
+static char vtiden[] = "\033[?6c";
+
 /* Kerning / character bounding-box multipliers */
 static float cwscale = 1.0;
 static float chscale = 1.0;
diff --git a/st.c b/st.c
index d8ff30b..6e5953a 100644
--- a/st.c
+++ b/st.c
@@ -86,8 +86,6 @@ char *argv0;
 #define TRUEBLUE(x)      (((x) & 0xff) << 8)
 
 
-#define VT102ID "\033[?6c"
-
 enum glyph_attribute {
 	ATTR_NULL      = 0,
 	ATTR_BOLD      = 1,
@@ -1965,7 +1963,7 @@ csihandle(void) {
 		break;
 	case 'c': /* DA -- Device Attributes */
 		if(csiescseq.arg[0] == 0)
-			ttywrite(VT102ID, sizeof(VT102ID) - 1);
+			ttywrite(vtiden, sizeof(vtiden) - 1);
 		break;
 	case 'C': /* CUF -- Cursor <n> Forward */
 	case 'a': /* HPR -- Cursor <n> Forward */
@@ -2433,7 +2431,7 @@ tcontrolcode(uchar ascii) {
 	case 0x98:   /* TODO: SOS */
 		break;
 	case 0x9a:   /* DECID -- Identify Terminal */
-		ttywrite(VT102ID, sizeof(VT102ID) - 1);
+		ttywrite(vtiden, sizeof(vtiden) - 1);
 		break;
 	case 0x9b:   /* TODO: CSI */
 	case 0x9c:   /* TODO: ST */
@@ -2589,7 +2587,7 @@ tputc(char *c, int len) {
 				}
 				break;
 			case 'Z': /* DECID -- Identify Terminal */
-				ttywrite(VT102ID, sizeof(VT102ID) - 1);
+				ttywrite(vtiden, sizeof(vtiden) - 1);
 				break;
 			case 'c': /* RIS -- Reset to inital state */
 				treset();

From 8f3e6a577d0d9733d356c0b691fea7b523d8ade7 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 17 Aug 2014 20:49:33 +0200
Subject: [PATCH 0735/1146] Fix man page and usage()

Man page was repeating -f option, the second time instead of -i,
and this option was lost in usage() message. This patch also indent
the output of usage().
---
 st.1 | 2 +-
 st.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.1 b/st.1
index 7174da2..e655530 100644
--- a/st.1
+++ b/st.1
@@ -42,7 +42,7 @@ The form is [=][<cols>{xX}<rows>][{+-}<xoffset>{+-}<yoffset>]. See
 .BR XParseGeometry (3)
 for further details.
 .TP
-.B \-f
+.B \-i
 will fixate the position given with the -g option.
 .TP
 .BI \-o " file"
diff --git a/st.c b/st.c
index 6e5953a..8f19018 100644
--- a/st.c
+++ b/st.c
@@ -3870,8 +3870,8 @@ run(void) {
 void
 usage(void) {
 	die("%s " VERSION " (c) 2010-2014 st engineers\n" \
-	"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]" \
-	" [-t title] [-w windowid] [-e command ...]\n", argv0);
+	"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
+	"          [-i] [-t title] [-w windowid] [-e command ...]\n", argv0);
 }
 
 int

From 1926305318cf020e20732461293d3e8c1c201734 Mon Sep 17 00:00:00 2001
From: Alexander Huemer <alexander.huemer@xx.vu>
Date: Mon, 18 Aug 2014 01:52:53 +0200
Subject: [PATCH 0736/1146] Simplify README

The term 'virtual terminal emulator' was broken. There is nothing
virtual about it, it's a terminal emulator.

Signed-off-by: Alexander Huemer <alexander.huemer@xx.vu>
Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 README | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README b/README
index 25606a2..b38c88b 100644
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
 st - simple terminal
 --------------------
-st is a simple virtual terminal emulator for X which sucks less.
+st is a simple terminal emulator for X which sucks less.
 
 
 Requirements

From fa04911c91a049f397337d3436c4a5692da558fa Mon Sep 17 00:00:00 2001
From: Quentin Carbonneaux <q@c9x.me>
Date: Mon, 18 Aug 2014 19:19:42 +0200
Subject: [PATCH 0737/1146] simplify loop in tresize

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 8f19018..65473f0 100644
--- a/st.c
+++ b/st.c
@@ -2661,7 +2661,6 @@ tresize(int col, int row) {
 	int mincol = MIN(col, term.col);
 	int slide = term.c.y - row + 1;
 	bool *bp;
-	Line *orig;
 	TCursor c;
 
 	if(col < 1 || row < 1) {
@@ -2724,9 +2723,8 @@ tresize(int col, int row) {
 	/* make use of the LIMIT in tmoveto */
 	tmoveto(term.c.x, term.c.y);
 	/* Clearing both screens (it makes dirty all lines) */
-	orig = term.line;
 	c = term.c;
-	do {
+	for(i = 0; i < 2; i++) {
 		if(mincol < col && 0 < minrow) {
 			tclearregion(mincol, 0, col - 1, minrow - 1);
 		}
@@ -2735,7 +2733,7 @@ tresize(int col, int row) {
 		}
 		tswapscreen();
 		tcursor(CURSOR_LOAD);
-	} while(orig != term.line);
+	}
 	term.c = c;
 }
 

From 177d888dff2fdf987dfa7fc3eb8495fa107879ad Mon Sep 17 00:00:00 2001
From: Quentin Carbonneaux <q@c9x.me>
Date: Mon, 18 Aug 2014 19:20:41 +0200
Subject: [PATCH 0738/1146] reset the alt screen in treset

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 65473f0..0e228a7 100644
--- a/st.c
+++ b/st.c
@@ -1356,9 +1356,12 @@ treset(void) {
 	memset(term.trantbl, sizeof(term.trantbl), CS_USA);
 	term.charset = 0;
 
-	tclearregion(0, 0, term.col-1, term.row-1);
-	tmoveto(0, 0);
-	tcursor(CURSOR_SAVE);
+	for(i = 0; i < 2; i++) {
+		tmoveto(0, 0);
+		tcursor(CURSOR_SAVE);
+		tclearregion(0, 0, term.col-1, term.row-1);
+		tswapscreen();
+	}
 }
 
 void

From 9d9e049eac3dacb2725f9d792f7cdd2230062313 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 18 Aug 2014 23:19:58 +0200
Subject: [PATCH 0739/1146] Make useful DEL in application mode

DEL key has to generate the sequence ^[P in application mode,
because such sequence means delete current character. It implies
that the character sent in keypad mode must be ^? (DEL character).
---
 config.def.h | 6 ++++--
 st.info      | 2 +-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/config.def.h b/config.def.h
index 53e8087..fe81078 100644
--- a/config.def.h
+++ b/config.def.h
@@ -200,7 +200,8 @@ static Key key[] = {
 	{ XK_KP_Delete,     ControlMask,    "\033[3;5~",    +1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[2K",      -1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",    +1,    0,    0},
-	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
+	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[P",       -1,    0,    0},
+	{ XK_KP_Delete,     XK_ANY_MOD,     "\177",         +1,    0,    0},
 	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +2,    0,    0},
 	{ XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +2,    0,    0},
 	{ XK_KP_Enter,      XK_ANY_MOD,     "\033OM",       +2,    0,    0},
@@ -254,7 +255,8 @@ static Key key[] = {
 	{ XK_Delete,        ControlMask,    "\033[3;5~",    +1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[2K",      -1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",    +1,    0,    0},
-	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
+	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
+	{ XK_Delete,        XK_ANY_MOD,     "\177",         +1,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[2J",       0,   -1,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,   +1,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1,    0},
diff --git a/st.info b/st.info
index 7b4e4f6..3b754db 100644
--- a/st.info
+++ b/st.info
@@ -73,7 +73,7 @@ st| simpleterm,
 	kri=\E[1;2A,
 	kclr=\E[3;5~,
 	kdl1=\E[3;2~,
-	kdch1=\E[3~,
+	kdch1=\0177,
 	kich1=\E[2~,
 	kend=\E[4~,
 	kf1=\EOP,

From 8342036f983288046e03a34055c10fc6b6b11017 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 18 Aug 2014 23:23:51 +0200
Subject: [PATCH 0740/1146] Fix definition of CONTROLC0

DEL character is not thecnically talking a C0 control character,
although it has some common properties with them, so it is useful
for us consider it as C0. Before this patch DEL (\177), was not
ignored as it ought to be.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 0e228a7..1c998ec 100644
--- a/st.c
+++ b/st.c
@@ -70,7 +70,7 @@ char *argv0;
 #define LEN(a)     (sizeof(a) / sizeof(a)[0])
 #define DEFAULT(a, b)     (a) = (a) ? (a) : (b)
 #define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (b))
-#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f))
+#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177')
 #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
 #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
 #define LIMIT(x, a, b)    (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)

From a3549c2eecf12b3453e6c86ba1721e7837f23746 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 19 Aug 2014 00:55:02 +0200
Subject: [PATCH 0741/1146] Improve execsh() and don't allow anonymous shells

This patch improves the shell selection on execsh and forbid
shell with users don't registered in the passwd file.
---
 st.c | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/st.c b/st.c
index 1c998ec..009388c 100644
--- a/st.c
+++ b/st.c
@@ -1139,23 +1139,29 @@ die(const char *errstr, ...) {
 
 void
 execsh(void) {
-	char **args;
-	char *envshell = getenv("SHELL");
-	const struct passwd *pass = getpwuid(getuid());
+	char **args, *sh;
+	const struct passwd *pw;
 	char buf[sizeof(long) * 8 + 1];
 
+	errno = 0;
+	if((pw = getpwuid(getuid())) == NULL) {
+		if(errno)
+			die("getpwuid:%s\n", strerror(errno));
+		else
+			die("who are you?\n");
+	}
 	unsetenv("COLUMNS");
 	unsetenv("LINES");
 	unsetenv("TERMCAP");
 
-	if(pass) {
-		setenv("LOGNAME", pass->pw_name, 1);
-		setenv("USER", pass->pw_name, 1);
-		setenv("SHELL", pass->pw_shell, 0);
-		setenv("HOME", pass->pw_dir, 0);
-	}
-
+	sh = (pw->pw_shell[0]) ? pw->pw_shell : shell;
 	snprintf(buf, sizeof(buf), "%lu", xw.win);
+
+	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);
 	setenv("WINDOWID", buf, 1);
 
 	signal(SIGCHLD, SIG_DFL);
@@ -1165,9 +1171,7 @@ execsh(void) {
 	signal(SIGTERM, SIG_DFL);
 	signal(SIGALRM, SIG_DFL);
 
-	DEFAULT(envshell, shell);
-	setenv("TERM", termname, 1);
-	args = opt_cmd ? opt_cmd : (char *[]){envshell, "-i", NULL};
+	args = opt_cmd ? opt_cmd : (char *[]){sh, "-i", NULL};
 	execvp(args[0], args);
 	exit(EXIT_FAILURE);
 }

From e5f6736ee0a0f29a14afec5494a5b3f204cedc1c Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 20 Aug 2014 09:56:24 +0200
Subject: [PATCH 0742/1146] Add eschandle()

We already have a csihandle() function, where is located code about
CSI sequences, so it is logical do the same with ESC sequences.
This change helps to simplify tcontrol(), which has a complex flow
and should be rewritten.
---
 st.c | 169 ++++++++++++++++++++++++++++++++---------------------------
 1 file changed, 91 insertions(+), 78 deletions(-)

diff --git a/st.c b/st.c
index 009388c..f15e868 100644
--- a/st.c
+++ b/st.c
@@ -356,6 +356,7 @@ static void csidump(void);
 static void csihandle(void);
 static void csiparse(void);
 static void csireset(void);
+static int eschandle(uchar ascii);
 static void strdump(void);
 static void strhandle(void);
 static void strparse(void);
@@ -2347,6 +2348,19 @@ tdeftran(char ascii) {
 	}
 }
 
+void
+tdectest(char c) {
+	static char E[UTF_SIZ] = "E";
+	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) {
 	if (c & 0x80) {
@@ -2455,17 +2469,83 @@ tcontrolcode(uchar ascii) {
 	return;
 }
 
-void
-tdectest(char c) {
-	static char E[UTF_SIZ] = "E";
-	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);
+/*
+ * 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 '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 '(': /* set primary charset G0 */
+	case ')': /* set secondary charset G1 */
+	case '*': /* set tertiary charset G2 */
+	case '+': /* 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, sizeof(vtiden) - 1);
+		break;
+	case 'c': /* RIS -- Reset to inital state */
+		treset();
+		xresettitle();
+		xloadcols();
+		break;
+	case '=': /* DECPAM -- Application keypad */
+		term.mode |= MODE_APPKEYPAD;
+		break;
+	case '>': /* DECPNM -- Normal keypad */
+		term.mode &= ~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
@@ -2552,76 +2632,9 @@ tputc(char *c, int len) {
 		} else if(term.esc & ESC_TEST) {
 			tdectest(ascii);
 		} else {
-			switch(ascii) {
-			case '[':
-				term.esc |= ESC_CSI;
+			if (!eschandle(ascii))
 				return;
-			case '#':
-				term.esc |= ESC_TEST;
-				return;
-			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;
-			case '(': /* set primary charset G0 */
-			case ')': /* set secondary charset G1 */
-			case '*': /* set tertiary charset G2 */
-			case '+': /* set quaternary charset G3 */
-				term.icharset = ascii - '(';
-				term.esc |= ESC_ALTCHARSET;
-				return;
-			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, sizeof(vtiden) - 1);
-				break;
-			case 'c': /* RIS -- Reset to inital state */
-				treset();
-				xresettitle();
-				xloadcols();
-				break;
-			case '=': /* DECPAM -- Application keypad */
-				term.mode |= MODE_APPKEYPAD;
-				break;
-			case '>': /* DECPNM -- Normal keypad */
-				term.mode &= ~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;
-			}
+			/* sequence already finished */
 		}
 		term.esc = 0;
 		/*

From 83dea7fd7bb5f6e8a11a7ac8a734d8016d1ed0cb Mon Sep 17 00:00:00 2001
From: Alexander Huemer <alexander.huemer@xx.vu>
Date: Wed, 20 Aug 2014 12:05:12 +0200
Subject: [PATCH 0743/1146] Improve readability of enum members

The 'left shift from one' notation of power of two integers is more
expressive than the result.

Signed-off-by: Alexander Huemer <alexander.huemer@xx.vu>
Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 64 ++++++++++++++++++++++++++++++------------------------------
 1 file changed, 32 insertions(+), 32 deletions(-)

diff --git a/st.c b/st.c
index f15e868..6165119 100644
--- a/st.c
+++ b/st.c
@@ -88,17 +88,17 @@ char *argv0;
 
 enum glyph_attribute {
 	ATTR_NULL      = 0,
-	ATTR_BOLD      = 1,
-	ATTR_FAINT     = 2,
-	ATTR_ITALIC    = 4,
-	ATTR_UNDERLINE = 8,
-	ATTR_BLINK     = 16,
-	ATTR_REVERSE   = 32,
-	ATTR_INVISIBLE = 64,
-	ATTR_STRUCK    = 128,
-	ATTR_WRAP      = 256,
-	ATTR_WIDE      = 512,
-	ATTR_WDUMMY    = 1024,
+	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,
 };
 
 enum cursor_movement {
@@ -113,27 +113,27 @@ enum cursor_state {
 };
 
 enum term_mode {
-	MODE_WRAP        = 1,
-	MODE_INSERT      = 2,
-	MODE_APPKEYPAD   = 4,
-	MODE_ALTSCREEN   = 8,
-	MODE_CRLF        = 16,
-	MODE_MOUSEBTN    = 32,
-	MODE_MOUSEMOTION = 64,
-	MODE_REVERSE     = 128,
-	MODE_KBDLOCK     = 256,
-	MODE_HIDE        = 512,
-	MODE_ECHO        = 1024,
-	MODE_APPCURSOR   = 2048,
-	MODE_MOUSESGR    = 4096,
-	MODE_8BIT        = 8192,
-	MODE_BLINK       = 16384,
-	MODE_FBLINK      = 32768,
-	MODE_FOCUS       = 65536,
-	MODE_MOUSEX10    = 131072,
-	MODE_MOUSEMANY   = 262144,
-	MODE_BRCKTPASTE  = 524288,
-	MODE_PRINT       = 1048576,
+	MODE_WRAP        = 1 << 0,
+	MODE_INSERT      = 1 << 1,
+	MODE_APPKEYPAD   = 1 << 2,
+	MODE_ALTSCREEN   = 1 << 3,
+	MODE_CRLF        = 1 << 4,
+	MODE_MOUSEBTN    = 1 << 5,
+	MODE_MOUSEMOTION = 1 << 6,
+	MODE_REVERSE     = 1 << 7,
+	MODE_KBDLOCK     = 1 << 8,
+	MODE_HIDE        = 1 << 9,
+	MODE_ECHO        = 1 << 10,
+	MODE_APPCURSOR   = 1 << 11,
+	MODE_MOUSESGR    = 1 << 12,
+	MODE_8BIT        = 1 << 13,
+	MODE_BLINK       = 1 << 14,
+	MODE_FBLINK      = 1 << 15,
+	MODE_FOCUS       = 1 << 16,
+	MODE_MOUSEX10    = 1 << 17,
+	MODE_MOUSEMANY   = 1 << 18,
+	MODE_BRCKTPASTE  = 1 << 19,
+	MODE_PRINT       = 1 << 20,
 	MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
 	                  |MODE_MOUSEMANY,
 };

From c490a60b804f467490cd4d8275a181dc37edef9f Mon Sep 17 00:00:00 2001
From: Ivan Delalande <colona@ycc.fr>
Date: Wed, 20 Aug 2014 21:14:08 +0200
Subject: [PATCH 0744/1146] Move calls to selsnap into selnormalize

This simplifies getbuttoninfo() and bpress(), and fixes a bug which made word
snapping behave incorrectly when a delimiter was at the beginning or end of
line.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/st.c b/st.c
index 6165119..01ab962 100644
--- a/st.c
+++ b/st.c
@@ -682,6 +682,9 @@ selnormalize(void) {
 	sel.nb.y = MIN(sel.ob.y, sel.oe.y);
 	sel.ne.y = MAX(sel.ob.y, sel.oe.y);
 
+	selsnap(sel.snap, &sel.nb.x, &sel.nb.y, -1);
+	selsnap(sel.snap, &sel.ne.x, &sel.ne.y, +1);
+
 	/* expand selection over line breaks */
 	if (sel.type == SEL_RECTANGULAR)
 		return;
@@ -777,15 +780,6 @@ getbuttoninfo(XEvent *e) {
 
 	sel.oe.x = x2col(e->xbutton.x);
 	sel.oe.y = y2row(e->xbutton.y);
-
-	if(sel.ob.y < sel.oe.y
-			|| (sel.ob.y == sel.oe.y && sel.ob.x < sel.oe.x)) {
-		selsnap(sel.snap, &sel.ob.x, &sel.ob.y, -1);
-		selsnap(sel.snap, &sel.oe.x, &sel.oe.y, +1);
-	} else {
-		selsnap(sel.snap, &sel.oe.x, &sel.oe.y, -1);
-		selsnap(sel.snap, &sel.ob.x, &sel.ob.y, +1);
-	}
 	selnormalize();
 
 	sel.type = SEL_REGULAR;
@@ -900,8 +894,6 @@ bpress(XEvent *e) {
 		} else {
 			sel.snap = 0;
 		}
-		selsnap(sel.snap, &sel.ob.x, &sel.ob.y, -1);
-		selsnap(sel.snap, &sel.oe.x, &sel.oe.y, +1);
 		selnormalize();
 
 		/*

From 51466e019a67e9319e6c5a7fa4205842ca860b71 Mon Sep 17 00:00:00 2001
From: Ivan Delalande <colona@ycc.fr>
Date: Wed, 20 Aug 2014 21:20:44 +0200
Subject: [PATCH 0745/1146] Change the behavior of word snapping on delimiters

This makes any sequence of identical delimiters be considered a single
word in word-snapping mode. This seems more coherent for this mode and
is similar to what xterm does.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 01ab962..497885b 100644
--- a/st.c
+++ b/st.c
@@ -709,7 +709,8 @@ selected(int x, int y) {
 void
 selsnap(int mode, int *x, int *y, int direction) {
 	int newx, newy, xt, yt;
-	Glyph *gp;
+	bool delim, prevdelim;
+	Glyph *gp, *prevgp;
 
 	switch(mode) {
 	case SNAP_WORD:
@@ -717,6 +718,8 @@ selsnap(int mode, int *x, int *y, int direction) {
 		 * Snap around if the word wraps around at the end or
 		 * beginning of a line.
 		 */
+		prevgp = &term.line[*y][*x];
+		prevdelim = strchr(worddelimiters, prevgp->c[0]) != NULL;
 		for(;;) {
 			newx = *x + direction;
 			newy = *y;
@@ -738,11 +741,15 @@ selsnap(int mode, int *x, int *y, int direction) {
 				break;
 
 			gp = &term.line[newy][newx];
-			if (!(gp->mode & ATTR_WDUMMY) && strchr(worddelimiters, gp->c[0]))
+			delim = strchr(worddelimiters, gp->c[0]) != NULL;
+			if(!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
+					|| (delim && gp->c[0] != prevgp->c[0])))
 				break;
 
 			*x = newx;
 			*y = newy;
+			prevgp = gp;
+			prevdelim = delim;
 		}
 		break;
 	case SNAP_LINE:

From 98a1085d0e7c3d84e19185ba666c4b0c725cd974 Mon Sep 17 00:00:00 2001
From: Ben Hendrickson <ben@1m7.com>
Date: Fri, 22 Aug 2014 09:25:04 -0700
Subject: [PATCH 0746/1146] Removing wrapping newlines from selection

When getting selected text, lines that were wrapped because of length
ought not include the wrapping newline in the selection.

This comes up, for example, when copying a bash command that is long
enough to wrap from the console and pasting it back into the console.
The extra newline breaks it.

Similiarly, changes behavior when trimming whitespace from the end of a
physical line to only do so if the line does not wrap. Otherwise we are
trimming whitespace from the middle of a logical line, which may change
its meaning.

Signed-off-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
---
 st.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 497885b..097775d 100644
--- a/st.c
+++ b/st.c
@@ -662,7 +662,10 @@ y2row(int y) {
 static int tlinelen(int y) {
 	int i = term.col;
 
-	while (i > 0 && term.line[y][i - 1].c[0] == ' ')
+	if(term.line[y][i - 1].mode & ATTR_WRAP)
+		return i;
+
+	while(i > 0 && term.line[y][i - 1].c[0] == ' ')
 		--i;
 
 	return i;
@@ -959,7 +962,7 @@ getsel(void) {
 		 * st.
 		 * FIXME: Fix the computer world.
 		 */
-		if(sel.ne.y > y || lastx >= linelen)
+		if((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP))
 			*ptr++ = '\n';
 	}
 	*ptr = 0;

From 0392d165d07143eec29c730364006bc0613e1198 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 24 Aug 2014 16:27:28 +0200
Subject: [PATCH 0747/1146] Remove indentation level in xdrawcursor

---
 st.c | 61 ++++++++++++++++++++++++++++++------------------------------
 1 file changed, 31 insertions(+), 30 deletions(-)

diff --git a/st.c b/st.c
index 097775d..dd3301b 100644
--- a/st.c
+++ b/st.c
@@ -3459,39 +3459,40 @@ xdrawcursor(void) {
 	xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx,
 			oldy, width, sl);
 
-	/* draw the new one */
-	if(!(IS_SET(MODE_HIDE))) {
-		if(xw.state & WIN_FOCUSED) {
-			if(IS_SET(MODE_REVERSE)) {
-				g.mode |= ATTR_REVERSE;
-				g.fg = defaultcs;
-				g.bg = defaultfg;
-			}
+	if(IS_SET(MODE_HIDE))
+		return;
 
-			sl = utf8len(g.c);
-			width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\
-				? 2 : 1;
-			xdraws(g.c, g, term.c.x, term.c.y, width, sl);
-		} else {
-			XftDrawRect(xw.draw, &dc.col[defaultcs],
-					borderpx + curx * xw.cw,
-					borderpx + term.c.y * xw.ch,
-					xw.cw - 1, 1);
-			XftDrawRect(xw.draw, &dc.col[defaultcs],
-					borderpx + curx * xw.cw,
-					borderpx + term.c.y * xw.ch,
-					1, xw.ch - 1);
-			XftDrawRect(xw.draw, &dc.col[defaultcs],
-					borderpx + (curx + 1) * xw.cw - 1,
-					borderpx + term.c.y * xw.ch,
-					1, xw.ch - 1);
-			XftDrawRect(xw.draw, &dc.col[defaultcs],
-					borderpx + curx * xw.cw,
-					borderpx + (term.c.y + 1) * xw.ch - 1,
-					xw.cw, 1);
+	/* draw the new one */
+	if(xw.state & WIN_FOCUSED) {
+		if(IS_SET(MODE_REVERSE)) {
+			g.mode |= ATTR_REVERSE;
+			g.fg = defaultcs;
+			g.bg = defaultfg;
 		}
-		oldx = curx, oldy = term.c.y;
+
+		sl = utf8len(g.c);
+		width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\
+			? 2 : 1;
+		xdraws(g.c, g, term.c.x, term.c.y, width, sl);
+	} else {
+		XftDrawRect(xw.draw, &dc.col[defaultcs],
+				borderpx + curx * xw.cw,
+				borderpx + term.c.y * xw.ch,
+				xw.cw - 1, 1);
+		XftDrawRect(xw.draw, &dc.col[defaultcs],
+				borderpx + curx * xw.cw,
+				borderpx + term.c.y * xw.ch,
+				1, xw.ch - 1);
+		XftDrawRect(xw.draw, &dc.col[defaultcs],
+				borderpx + (curx + 1) * xw.cw - 1,
+				borderpx + term.c.y * xw.ch,
+				1, xw.ch - 1);
+		XftDrawRect(xw.draw, &dc.col[defaultcs],
+				borderpx + curx * xw.cw,
+				borderpx + (term.c.y + 1) * xw.ch - 1,
+				xw.cw, 1);
 	}
+	oldx = curx, oldy = term.c.y;
 }
 
 

From 5afb3862ba368de8888c0c570098baababc7bc19 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 28 Aug 2014 12:48:29 +0200
Subject: [PATCH 0748/1146] Add support for utmp in st

St runs an interactive shell and not a login shell, and it means
that profile is not loaded. The default terminal configuration
in some system is not the correct for st, but since profile is
not loaded there is no way of getting a script configures the
correct values.

St doesn't update the utmp files, this is the job of another
suckless tool, utmp. Utmp also opens a login shell (it is the
logical behaviour when you create a new user record) it is a
good option execute utmp and then get a correct input in
utmp, wtmp and lastlog file, and execute the content of the
profile.
---
 config.def.h |  1 +
 st.c         | 17 +++++++++++------
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/config.def.h b/config.def.h
index fe81078..cc16f97 100644
--- a/config.def.h
+++ b/config.def.h
@@ -8,6 +8,7 @@
 static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=false";
 static int borderpx = 2;
 static char shell[] = "/bin/sh";
+static char *utmp = NULL;
 
 /* identification sequence returned in DA and DECID */
 static char vtiden[] = "\033[?6c";
diff --git a/st.c b/st.c
index dd3301b..ab3fa6e 100644
--- a/st.c
+++ b/st.c
@@ -1153,16 +1153,22 @@ execsh(void) {
 		else
 			die("who are you?\n");
 	}
+
+	if (utmp)
+		sh = utmp;
+	else if (pw->pw_shell[0])
+		sh = pw->pw_shell;
+	else
+		sh = shell;
+	args = (opt_cmd) ? opt_cmd : (char *[]){sh, NULL};
+	snprintf(buf, sizeof(buf), "%lu", xw.win);
+
 	unsetenv("COLUMNS");
 	unsetenv("LINES");
 	unsetenv("TERMCAP");
-
-	sh = (pw->pw_shell[0]) ? pw->pw_shell : shell;
-	snprintf(buf, sizeof(buf), "%lu", xw.win);
-
 	setenv("LOGNAME", pw->pw_name, 1);
 	setenv("USER", pw->pw_name, 1);
-	setenv("SHELL", sh, 1);
+	setenv("SHELL", args[0], 1);
 	setenv("HOME", pw->pw_dir, 1);
 	setenv("TERM", termname, 1);
 	setenv("WINDOWID", buf, 1);
@@ -1174,7 +1180,6 @@ execsh(void) {
 	signal(SIGTERM, SIG_DFL);
 	signal(SIGALRM, SIG_DFL);
 
-	args = opt_cmd ? opt_cmd : (char *[]){sh, "-i", NULL};
 	execvp(args[0], args);
 	exit(EXIT_FAILURE);
 }

From c7a945c4086ab913cd8a05997bfbc1906645eff4 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 20 Aug 2014 10:41:41 +0200
Subject: [PATCH 0749/1146] Add missed names of charset sequences

---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index ab3fa6e..83293f4 100644
--- a/st.c
+++ b/st.c
@@ -2496,10 +2496,10 @@ eschandle(uchar ascii) {
 	case 'k': /* old title set compatibility */
 		tstrsequence(ascii);
 		return 0;
-	case '(': /* set primary charset G0 */
-	case ')': /* set secondary charset G1 */
-	case '*': /* set tertiary charset G2 */
-	case '+': /* set quaternary charset G3 */
+	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;

From dc8c5c82aa14e75305bd5b0e42b4f8bba45702a8 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 29 Sep 2014 15:38:21 +0200
Subject: [PATCH 0750/1146] Implementing xzoomreset.

Thanks mvdan@mvdan.cc for proposing this.
---
 config.def.h |  1 +
 st.c         | 25 ++++++++++++++++++++++++-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index cc16f97..0a3c3e0 100644
--- a/config.def.h
+++ b/config.def.h
@@ -116,6 +116,7 @@ static Shortcut shortcuts[] = {
 	{ XK_ANY_MOD,           XK_Print,       printsel,       {.i =  0} },
 	{ MODKEY|ShiftMask,     XK_Prior,       xzoom,          {.i = +1} },
 	{ MODKEY|ShiftMask,     XK_Next,        xzoom,          {.i = -1} },
+	{ MODKEY|ShiftMask,     XK_Home,        xzoomreset,     {.i =  0}  },
 	{ ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
 	{ MODKEY|ShiftMask,     XK_Insert,      clippaste,      {.i =  0} },
 	{ MODKEY,               XK_Num_Lock,    numlock,        {.i =  0} },
diff --git a/st.c b/st.c
index 83293f4..2b4d52c 100644
--- a/st.c
+++ b/st.c
@@ -317,6 +317,8 @@ static void clippaste(const Arg *);
 static void numlock(const Arg *);
 static void selpaste(const Arg *);
 static void xzoom(const Arg *);
+static void xzoomabs(const Arg *);
+static void xzoomreset(const Arg *);
 static void printsel(const Arg *);
 static void printscreen(const Arg *) ;
 static void toggleprinter(const Arg *);
@@ -503,6 +505,7 @@ static int oldbutton = 3; /* button event on startup: 3 = release */
 
 static char *usedfont = NULL;
 static double usedfontsize = 0;
+static double defaultfontsize = 0;
 
 static uchar utfbyte[UTF_SIZ + 1] = {0x80,    0, 0xC0, 0xE0, 0xF0};
 static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
@@ -2993,6 +2996,7 @@ xloadfonts(char *fontstr, double fontsize) {
 			FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12);
 			usedfontsize = 12;
 		}
+		defaultfontsize = usedfontsize;
 	}
 
 	FcConfigSubstitute(0, pattern, FcMatchPattern);
@@ -3005,6 +3009,8 @@ xloadfonts(char *fontstr, double fontsize) {
 		FcPatternGetDouble(dc.font.match->pattern,
 		                   FC_PIXEL_SIZE, 0, &fontval);
 		usedfontsize = fontval;
+		if(fontsize == 0)
+			defaultfontsize = fontval;
 	}
 
 	/* Setting character width and height. */
@@ -3058,15 +3064,32 @@ xunloadfonts(void) {
 	xunloadfont(&dc.ibfont);
 }
 
+
 void
 xzoom(const Arg *arg) {
+	Arg larg;
+	larg.i = usedfontsize + arg->i;
+	xzoomabs(&larg);
+}
+
+void
+xzoomabs(const Arg *arg) {
 	xunloadfonts();
-	xloadfonts(usedfont, usedfontsize + arg->i);
+	xloadfonts(usedfont, arg->i);
 	cresize(0, 0);
 	redraw(0);
 	xhints();
 }
 
+void
+xzoomreset(const Arg *arg) {
+	Arg larg;
+	if(defaultfontsize > 0) {
+		larg.i = defaultfontsize;
+		xzoomabs(&larg);
+	}
+}
+
 void
 xinit(void) {
 	XGCValues gcvalues;

From 63a07eb19c908ac86936b6f9857738107326d27a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 29 Sep 2014 15:40:37 +0200
Subject: [PATCH 0751/1146] Minor style changes for the last patch.

---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 2b4d52c..c90bed1 100644
--- a/st.c
+++ b/st.c
@@ -3064,10 +3064,10 @@ xunloadfonts(void) {
 	xunloadfont(&dc.ibfont);
 }
 
-
 void
 xzoom(const Arg *arg) {
 	Arg larg;
+
 	larg.i = usedfontsize + arg->i;
 	xzoomabs(&larg);
 }
@@ -3084,6 +3084,7 @@ xzoomabs(const Arg *arg) {
 void
 xzoomreset(const Arg *arg) {
 	Arg larg;
+
 	if(defaultfontsize > 0) {
 		larg.i = defaultfontsize;
 		xzoomabs(&larg);

From a7eef8f230bcf72a85af68fc9a08ca94e52ca18d Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 29 Sep 2014 15:41:10 +0200
Subject: [PATCH 0752/1146] Removing an extra space.

---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 0a3c3e0..1667ed6 100644
--- a/config.def.h
+++ b/config.def.h
@@ -116,7 +116,7 @@ static Shortcut shortcuts[] = {
 	{ XK_ANY_MOD,           XK_Print,       printsel,       {.i =  0} },
 	{ MODKEY|ShiftMask,     XK_Prior,       xzoom,          {.i = +1} },
 	{ MODKEY|ShiftMask,     XK_Next,        xzoom,          {.i = -1} },
-	{ MODKEY|ShiftMask,     XK_Home,        xzoomreset,     {.i =  0}  },
+	{ MODKEY|ShiftMask,     XK_Home,        xzoomreset,     {.i =  0} },
 	{ ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
 	{ MODKEY|ShiftMask,     XK_Insert,      clippaste,      {.i =  0} },
 	{ MODKEY,               XK_Num_Lock,    numlock,        {.i =  0} },

From 0c8feecbf74674132070169986802c75dd49d688 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 8 Oct 2014 10:30:20 +0200
Subject: [PATCH 0753/1146] Fix SI and SO

SI (0x0F or ^O) means Shift In, and it selects G1 charset definition,
and SO (0x0E or ^N) means Shift Out, and it selects G0 charset
definition, but st was doing just the inverse.
---
 st.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index c90bed1..19e4379 100644
--- a/st.c
+++ b/st.c
@@ -2431,11 +2431,9 @@ tcontrolcode(uchar ascii) {
 		term.esc &= ~(ESC_CSI|ESC_ALTCHARSET|ESC_TEST);
 		term.esc |= ESC_START;
 		return;
-	case '\016': /* SO */
-		term.charset = 0;
-		return;
-	case '\017': /* SI */
-		term.charset = 1;
+	case '\016': /* SO (LS1 -- Locking shift 1) */
+	case '\017': /* SI (LS0 -- Locking shift 0) */
+		term.charset = 1 - (ascii - '\016');
 		return;
 	case '\032': /* SUB */
 		tsetchar(question, &term.c.attr, term.c.x, term.c.y);

From 88429cdcbf937c4042cc315b31fcb8c662bd51fb Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 8 Oct 2014 11:33:36 +0200
Subject: [PATCH 0754/1146] Add LS2 and LS3

These sequences are the equivalents of LS0 and LS1, but for G2 and
G3.
---
 st.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/st.c b/st.c
index 19e4379..22a1ce6 100644
--- a/st.c
+++ b/st.c
@@ -2497,6 +2497,10 @@ eschandle(uchar ascii) {
 	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 */

From dcfe505d3c97506918d5aff24ab62e17e5f58fdb Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 8 Oct 2014 11:35:45 +0200
Subject: [PATCH 0755/1146] Use G1 for alternate charset

St has enacs, which must be printed if a program requires to use
the alternate charset (graphic charset), that in st case was to
select charset graphic for G1, but it was not useful
at all because smacs and rmacs were always redefining the value
of G0.
---
 st.info | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.info b/st.info
index 3b754db..c5a9c2d 100644
--- a/st.info
+++ b/st.info
@@ -159,7 +159,7 @@ st| simpleterm,
 	rev=\E[7m,
 	ri=\EM,
 	ritm=\E[23m,
-	rmacs=\E(B,
+	rmacs=^O,
 	rmcup=\E[?1049l,
 	rmir=\E[4l,
 	rmkx=\E[?1l\E>,
@@ -175,7 +175,7 @@ st| simpleterm,
 	sgr0=\E[0m,
 	sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
 	sitm=\E[3m,
-	smacs=\E(0,
+	smacs=^N,
 	smcup=\E[?1049h,
 	smir=\E[4h,
 	smkx=\E[?1h\E=,

From 86633ada91d1c7d8be1bf0398caff8a62fb1b805 Mon Sep 17 00:00:00 2001
From: CustaiCo <custaico@openmailbox.org>
Date: Fri, 3 Oct 2014 19:25:21 +0000
Subject: [PATCH 0756/1146] patch for bell in st

The XBell() call currently used when a bell is recieved sends a message
to the X server, but if the X server doesn't know how to sound it,
it just gets ignored and I have not been able to find anywhere in x.org's
code a way to configure the action that the server does.

However, if you use XkbBell() then you can have a process listening for
the XkbBellNotifyEvent that is produced and either alert you visually or
play an audio file or whatever you want as your notification. You have
to include one more header file but the function seems to be compiled as
part of Xlib, at least on my installation.

CustaiCo
---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 22a1ce6..c61b90a 100644
--- a/st.c
+++ b/st.c
@@ -27,6 +27,7 @@
 #include <X11/cursorfont.h>
 #include <X11/keysym.h>
 #include <X11/Xft/Xft.h>
+#include <X11/XKBlib.h>
 #include <fontconfig/fontconfig.h>
 #include <wchar.h>
 
@@ -2423,7 +2424,7 @@ tcontrolcode(uchar ascii) {
 			if(!(xw.state & WIN_FOCUSED))
 				xseturgency(1);
 			if (bellvolume)
-				XBell(xw.dpy, bellvolume);
+				XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL);
 		}
 		break;
 	case '\033': /* ESC */

From f9fb620914f7b1e2580a890f23b66e18762788b7 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 15 Oct 2014 19:42:20 +0200
Subject: [PATCH 0757/1146] Do not set SHELL to utmp ever

SHELL must be set to the SHELL of the user, but it was possible set
it to utmp.
---
 st.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index c61b90a..bcf96e9 100644
--- a/st.c
+++ b/st.c
@@ -1146,7 +1146,7 @@ die(const char *errstr, ...) {
 
 void
 execsh(void) {
-	char **args, *sh;
+	char **args, *sh, *prog;
 	const struct passwd *pw;
 	char buf[sizeof(long) * 8 + 1];
 
@@ -1158,13 +1158,15 @@ execsh(void) {
 			die("who are you?\n");
 	}
 
-	if (utmp)
-		sh = utmp;
-	else if (pw->pw_shell[0])
-		sh = pw->pw_shell;
+	sh = (pw->pw_shell[0]) ? pw->pw_shell : shell;
+	if(opt_cmd)
+		prog = opt_cmd[0];
+	else if(utmp)
+		prog = utmp;
 	else
-		sh = shell;
-	args = (opt_cmd) ? opt_cmd : (char *[]){sh, NULL};
+		prog = sh;
+	args = (opt_cmd) ? opt_cmd : (char *[]) {prog, NULL};
+
 	snprintf(buf, sizeof(buf), "%lu", xw.win);
 
 	unsetenv("COLUMNS");
@@ -1172,7 +1174,7 @@ execsh(void) {
 	unsetenv("TERMCAP");
 	setenv("LOGNAME", pw->pw_name, 1);
 	setenv("USER", pw->pw_name, 1);
-	setenv("SHELL", args[0], 1);
+	setenv("SHELL", sh, 1);
 	setenv("HOME", pw->pw_dir, 1);
 	setenv("TERM", termname, 1);
 	setenv("WINDOWID", buf, 1);
@@ -1184,7 +1186,7 @@ execsh(void) {
 	signal(SIGTERM, SIG_DFL);
 	signal(SIGALRM, SIG_DFL);
 
-	execvp(args[0], args);
+	execvp(prog, args);
 	exit(EXIT_FAILURE);
 }
 

From cd159883d14c5874446a6ae949be031a1c9d37c2 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 21 Oct 2014 16:36:01 +0200
Subject: [PATCH 0758/1146] Reverting smacs and rmacs to the xterm defaults.

These are needed by ncurses to correctly handle the switch between line
drawing. The changes to the alternative characterset code already fixed the
urwid hack.
---
 st.info | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.info b/st.info
index c5a9c2d..3b754db 100644
--- a/st.info
+++ b/st.info
@@ -159,7 +159,7 @@ st| simpleterm,
 	rev=\E[7m,
 	ri=\EM,
 	ritm=\E[23m,
-	rmacs=^O,
+	rmacs=\E(B,
 	rmcup=\E[?1049l,
 	rmir=\E[4l,
 	rmkx=\E[?1l\E>,
@@ -175,7 +175,7 @@ st| simpleterm,
 	sgr0=\E[0m,
 	sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
 	sitm=\E[3m,
-	smacs=^N,
+	smacs=\E(0,
 	smcup=\E[?1049h,
 	smir=\E[4h,
 	smkx=\E[?1h\E=,

From 008aae541b5cb1e67a025048adef9a06eaa11c2e Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq.ml@gmail.com>
Date: Thu, 16 Oct 2014 00:42:53 +0200
Subject: [PATCH 0759/1146] Avoid failing when embedding with a Window id of 0

I'd like to let st run with its own window when trying to embed it to a window with id 0 instead of exiting with an error.
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index bcf96e9..23dd7f1 100644
--- a/st.c
+++ b/st.c
@@ -3136,8 +3136,8 @@ xinit(void) {
 		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
 	xw.attrs.colormap = xw.cmap;
 
-	parent = opt_embed ? strtol(opt_embed, NULL, 0) : \
-			XRootWindow(xw.dpy, xw.scr);
+	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,
 			xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
 			xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity

From 11625c7166b7e4dad414606227acec2de1c36464 Mon Sep 17 00:00:00 2001
From: "czarkoff@gmail.com" <czarkoff@gmail.com>
Date: Tue, 28 Oct 2014 12:55:28 +0100
Subject: [PATCH 0760/1146] Replace character with U+FFFD if wcwidth() is -1

Helpful when new Unicode codepoints are not recognized by libc.
---
 st.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 23dd7f1..ad52280 100644
--- a/st.c
+++ b/st.c
@@ -2576,7 +2576,10 @@ tputc(char *c, int len) {
 		unicodep = ascii = *c;
 	} else {
 		utf8decode(c, &unicodep, UTF_SIZ);
-		width = wcwidth(unicodep);
+		if ((width = wcwidth(unicodep)) == -1) {
+			c = "\357\277\275";	/* UTF_INVALID */
+			width = 1;
+		}
 		control = ISCONTROLC1(unicodep);
 		ascii = unicodep;
 	}

From bafbba56cd5735c680676db2adf6f614ba61356f Mon Sep 17 00:00:00 2001
From: Eric Pruitt <eric.pruitt@gmail.com>
Date: Tue, 28 Oct 2014 17:51:42 -0700
Subject: [PATCH 0761/1146] Check for presence of SHELL environment variable

- POSIX states the SHELL environment variable "... shall represent a
  pathname of the user's preferred command language interpreter." As
  such, st should check for its presence when deciding what shell to
  use; just as HOME can be defined to override one's passwd-defined home
  directory, a user should also be able to override their passwd-defined
  shell using the SHELL environment variable.
---
 st.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index ad52280..068fbb3 100644
--- a/st.c
+++ b/st.c
@@ -1158,7 +1158,10 @@ execsh(void) {
 			die("who are you?\n");
 	}
 
-	sh = (pw->pw_shell[0]) ? pw->pw_shell : shell;
+	if (!(sh = getenv("SHELL"))) {
+		sh = (pw->pw_shell[0]) ? pw->pw_shell : shell;
+	}
+
 	if(opt_cmd)
 		prog = opt_cmd[0];
 	else if(utmp)

From 4418939dd9f3a7b3cfd3071234ed18ae86538f2a Mon Sep 17 00:00:00 2001
From: sin <sin@2f30.org>
Date: Tue, 11 Nov 2014 18:29:11 +0000
Subject: [PATCH 0762/1146] Call _exit() instead of exit() if exec*() fails

exit() will also unwind the atexit() functions.  This is bad
because if exec*() fails the process is in an inconsistent state.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 068fbb3..4499be6 100644
--- a/st.c
+++ b/st.c
@@ -1190,7 +1190,7 @@ execsh(void) {
 	signal(SIGALRM, SIG_DFL);
 
 	execvp(prog, args);
-	exit(EXIT_FAILURE);
+	_exit(EXIT_FAILURE);
 }
 
 void

From 09f5d98251469070b76f3911cc6a83d977871656 Mon Sep 17 00:00:00 2001
From: Ivan Delalande <colona@ycc.fr>
Date: Sun, 16 Nov 2014 09:02:57 +0100
Subject: [PATCH 0763/1146] Trim trailing whitespaces in every selection case

Trailing whitespaces are trimmed when copying from normal selection and
rectangular selection on lines that have their last character included
or on the left of the selection. It leads to inconsistent behaviors when
copying the exact same text from the left and right window in
applications with vertical splits.
This patch solves this issue by always trimming the selection.
---
 st.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.c b/st.c
index 4499be6..fc91334 100644
--- a/st.c
+++ b/st.c
@@ -947,6 +947,8 @@ getsel(void) {
 			lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
 		}
 		last = &term.line[y][MIN(lastx, linelen-1)];
+		while(last >= gp && last->c[0] == ' ')
+			--last;
 
 		for( ; gp <= last; ++gp) {
 			if(gp->mode & ATTR_WDUMMY)

From 708b697ed77e1ba4e96399ed6cb0f73a37565321 Mon Sep 17 00:00:00 2001
From: Ivan Delalande <colona@ycc.fr>
Date: Fri, 12 Dec 2014 08:39:07 +0100
Subject: [PATCH 0764/1146] Fix crash due to invalid timespec given to pselect

If blinktimeout is set to a value greater than 1000, pselect will
receive a timeout argument with tv_nsec greater than 1E9 (1 sec), and
fail, making st crash. This patch just ensures that the timespec
structure is correctly filled with a value properly decomposed between
tv_sec and tv_nsec.

Reported by JasonWoof on IRC. Thanks!
---
 st.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.c b/st.c
index fc91334..db9a332 100644
--- a/st.c
+++ b/st.c
@@ -3922,6 +3922,9 @@ run(void) {
 							TIMEDIFF(now,
 								lastblink)));
 					}
+					drawtimeout.tv_sec = \
+					    drawtimeout.tv_nsec / 1E9;
+					drawtimeout.tv_nsec %= (long)1E9;
 				} else {
 					tv = NULL;
 				}

From 4d14d97547d335974e98aa612ac5b4fcfc25e1d9 Mon Sep 17 00:00:00 2001
From: Rian Hunter <rian+suckless-dev@thelig.ht>
Date: Thu, 29 Jan 2015 15:06:43 -0800
Subject: [PATCH 0765/1146] Fix crash due to wide characters

In tputc(), when a character wasn't large enough to fit
on the current line, we would call tnewline() to place it on
the next line. Unfortunately, we weren't resetting our glyph
pointer and this caused memory corruption when a
wide character (width == 2) was being written. This patch
resets our glyph pointer after calls to tnewline().
---
 st.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index db9a332..6a68c3c 100644
--- a/st.c
+++ b/st.c
@@ -2673,13 +2673,16 @@ tputc(char *c, int len) {
 	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+1 < term.col)
 		memmove(gp+1, gp, (term.col - term.c.x - 1) * sizeof(Glyph));
 
-	if(term.c.x+width > term.col)
+	if(term.c.x+width > term.col) {
 		tnewline(1);
+		gp = &term.line[term.c.y][term.c.x];
+	}
 
 	tsetchar(c, &term.c.attr, term.c.x, term.c.y);
 

From aba6c292af347588b9c2f5d1a400a6270b5a447f Mon Sep 17 00:00:00 2001
From: Rian Hunter <rian@alum.mit.edu>
Date: Thu, 29 Jan 2015 15:00:39 -0800
Subject: [PATCH 0766/1146] Correct shift amount on MODE_INSERT in tputc()

When MODE_INSERT is set we'd shift characters on the same
line forward before inserting our character in tputc().
This did not account for wide characters where width != 1.
This patch makes it so we shift the correct amount.
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 6a68c3c..1deb7bc 100644
--- a/st.c
+++ b/st.c
@@ -2676,8 +2676,8 @@ tputc(char *c, int len) {
 		gp = &term.line[term.c.y][term.c.x];
 	}
 
-	if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col)
-		memmove(gp+1, gp, (term.col - term.c.x - 1) * sizeof(Glyph));
+	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);

From 7dd24bfb4c80960567d2d4dd4cf7ca5f2af95a52 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nils=20Reu=C3=9Fe?= <ml@hxgn.net>
Date: Sun, 15 Feb 2015 17:11:22 +0100
Subject: [PATCH 0767/1146] Fix crash on font resize resize

if you keep downsizing your fontsize until either xw.ch or xw.cw gets 0,
st crashes, because there is an unchecked division in cresize.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 1deb7bc..142a152 100644
--- a/st.c
+++ b/st.c
@@ -2992,7 +2992,7 @@ xloadfonts(char *fontstr, double fontsize) {
 	if(!pattern)
 		die("st: can't open font %s\n", fontstr);
 
-	if(fontsize > 0) {
+	if(fontsize > 1) {
 		FcPatternDel(pattern, FC_PIXEL_SIZE);
 		FcPatternDel(pattern, FC_SIZE);
 		FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize);

From c5f1d74fd83319d84887c7ff6769f3d42c3d1a0d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nils=20Reu=C3=9Fe?= <ml@hxgn.net>
Date: Sun, 15 Feb 2015 17:46:15 +0100
Subject: [PATCH 0768/1146] Update year in usage()

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 142a152..b9d30a7 100644
--- a/st.c
+++ b/st.c
@@ -3938,7 +3938,7 @@ run(void) {
 
 void
 usage(void) {
-	die("%s " VERSION " (c) 2010-2014 st engineers\n" \
+	die("%s " VERSION " (c) 2010-2015 st engineers\n" \
 	"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
 	"          [-i] [-t title] [-w windowid] [-e command ...]\n", argv0);
 }

From ac11bbb03b923cbe02cd17130ae643b2c4b004ec Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 22 Feb 2015 10:58:37 +0000
Subject: [PATCH 0769/1146] Update dates in LICENSE

---
 LICENSE | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LICENSE b/LICENSE
index 0180b49..1be82da 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2,8 +2,8 @@ MIT/X Consortium License
 
 © 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>
 © 2009 Anselm R Garbe <garbeam at gmail dot com>
-© 2012-2014 Roberto E. Vargas Caballero <k0ga at shike2 dot com>
-© 2012-2014 Christoph Lohmann <20h at r-36 dot net>
+© 2012-2015 Roberto E. Vargas Caballero <k0ga at shike2 dot com>
+© 2012-2015 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>

From 3604445ffc6ff1bfdfc7614771ca659e423b404b Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 22 Feb 2015 10:59:26 +0000
Subject: [PATCH 0770/1146] Comment default CC assignment

CC by default is cc, so the assignment was doing nothing, but
it was using non standard syntax, so some system (NetBSD) fail
to compile.
---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 298484e..46457f7 100644
--- a/config.mk
+++ b/config.mk
@@ -24,5 +24,5 @@ CFLAGS += -g -std=c99 -pedantic -Wall -Wvariadic-macros -Os ${INCS} ${CPPFLAGS}
 LDFLAGS += -g ${LIBS}
 
 # compiler and linker
-CC ?= cc
+# CC = cc
 

From 1b514048b254827f1a83c05e1b2a2428bf31924e Mon Sep 17 00:00:00 2001
From: Ivan Delalande <colona@ycc.fr>
Date: Sun, 15 Feb 2015 00:34:03 +0100
Subject: [PATCH 0771/1146] Let curses do the dirty work for flash

Use the terminfo delay syntax ($<x>) in our flash capability to avoid
hardcoding a fixed delay in redraw() when called from tsetmode() with
DECSCNM.
We need to turn on the npc capability so that delays are made with
xon/xoff instead of padding characters.
---
 st.c    | 21 ++++++---------------
 st.info |  3 ++-
 2 files changed, 8 insertions(+), 16 deletions(-)

diff --git a/st.c b/st.c
index b9d30a7..e1139ec 100644
--- a/st.c
+++ b/st.c
@@ -63,8 +63,6 @@ char *argv0;
 #define XK_NO_MOD     0
 #define XK_SWITCH_MOD (1<<13)
 
-#define REDRAW_TIMEOUT (80*1000) /* 80 ms */
-
 /* macros */
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
 #define MAX(a, b)  ((a) < (b) ? (b) : (a))
@@ -349,7 +347,7 @@ typedef struct {
 
 static void die(const char *, ...);
 static void draw(void);
-static void redraw(int);
+static void redraw(void);
 static void drawregion(int, int, int, int);
 static void execsh(void);
 static void sigchld(int);
@@ -1826,7 +1824,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 				mode = term.mode;
 				MODBIT(term.mode, set, MODE_REVERSE);
 				if(mode != term.mode)
-					redraw(REDRAW_TIMEOUT);
+					redraw();
 				break;
 			case 6: /* DECOM -- Origin */
 				MODBIT(term.c.state, set, CURSOR_ORIGIN);
@@ -2200,7 +2198,7 @@ strhandle(void) {
 				 * TODO if defaultbg color is changed, borders
 				 * are dirty
 				 */
-				redraw(0);
+				redraw();
 			}
 			return;
 		}
@@ -3093,7 +3091,7 @@ xzoomabs(const Arg *arg) {
 	xunloadfonts();
 	xloadfonts(usedfont, arg->i);
 	cresize(0, 0);
-	redraw(0);
+	redraw();
 	xhints();
 }
 
@@ -3558,16 +3556,9 @@ xresettitle(void) {
 }
 
 void
-redraw(int timeout) {
-	struct timespec tv = {0, timeout * 1000};
-
+redraw(void) {
 	tfulldirt();
 	draw();
-
-	if(timeout > 0) {
-		nanosleep(&tv, NULL);
-		XSync(xw.dpy, False); /* necessary for a good tput flash */
-	}
 }
 
 void
@@ -3634,7 +3625,7 @@ expose(XEvent *ev) {
 		if(!e->count)
 			xw.state &= ~WIN_REDRAW;
 	}
-	redraw(0);
+	redraw();
 }
 
 void
diff --git a/st.info b/st.info
index 3b754db..99c066d 100644
--- a/st.info
+++ b/st.info
@@ -32,7 +32,7 @@ st| simpleterm,
 	el=\E[K,
 	el1=\E[1K,
 	enacs=\E)0,
-	flash=\E[?5h\E[?5l,
+	flash=\E[?5h$<80/>\E[?5l,
 	fsl=^G,
 	home=\E[H,
 	hpa=\E[%i%p1%dG,
@@ -150,6 +150,7 @@ st| simpleterm,
 	mir,
 	msgr,
 	ncv#3,
+	npc,
 	op=\E[39;49m,
 	pairs#64,
 	mc0=\E[i,

From b8804f9f675b79ddd2db47aeef626d6ae3ce5ca3 Mon Sep 17 00:00:00 2001
From: Greg Reagle <greg.reagle@umbc.edu>
Date: Thu, 19 Feb 2015 16:33:22 -0500
Subject: [PATCH 0772/1146] document keys in man page

---
 st.1 | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/st.1 b/st.1
index e655530..0700787 100644
--- a/st.1
+++ b/st.1
@@ -67,6 +67,31 @@ st executes
 instead of the shell.  If this is used it
 .B must be the last option
 on the command line, as in xterm / rxvt.
+.SH USAGE
+.TP
+.B Ctrl-Print Screen
+toggleprinter()
+.TP
+.B Shift-Print Screen
+printscreen()
+.TP
+.B Print Screen
+printsel()
+.TP
+.B Alt-Shift-Page Up
+increase font size
+.TP
+.B Alt-Shift-Page Down
+decrease font size
+.TP
+.B Alt-Shift-Home
+reset to default font size
+.TP
+.B Shift-Insert
+paste from primary selection
+.TP
+.B Alt-Shift-Insert
+paste from clipboard selection
 .SH CUSTOMIZATION
 .B st
 can be customized by creating a custom config.h and (re)compiling the source

From 29619a1a35175fd79a743ed006af405ea586a0fd Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 28 Feb 2015 16:13:47 +0000
Subject: [PATCH 0773/1146] Small improvements to the FAQ

---
 FAQ | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/FAQ b/FAQ
index a47c024..61f94a5 100644
--- a/FAQ
+++ b/FAQ
@@ -51,7 +51,7 @@ solution for them is to use the following command:
 	$ printf '\033[?1h\033=' >/dev/tty
 
 or
-	$ echo $(tput smkx) >/dev/tty
+	$ tput smkx
 
 In the case of bash, readline is used. Readline has a different note in its
 manpage about this issue:
@@ -86,9 +86,9 @@ 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.
+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
 
@@ -155,3 +155,11 @@ This is an issue that was discussed in suckless mailing list
 	[1] http://www.ibb.net/~anne/keyboard.html
 	[2] http://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-5.html
 
+## But I really want a wrong backspace key and a wrong delete key
+
+If you really want emulate the errors of another terminal emulators
+and have a backspace key that generates a DELETE and a delete key
+that generates BACKSPACE, then you can apply the patch
+found in [1], but please do not tell me it.
+
+[1] http://st.suckless.org/patches/delkey

From 487bbb24d02190efa3d18093cadfa376f816d7fa Mon Sep 17 00:00:00 2001
From: Johannes Postma <jgmpostma@gmail.com>
Date: Thu, 5 Mar 2015 15:52:51 +0000
Subject: [PATCH 0774/1146] Update kdch1 definition to three octal digits.

ncurses wasn't able to detect the delete-character key as KEY_DC.  This
patch fixes that.

kdch1 was defined as "\0177", but terminfo(5) states:
	... characters may be given as three octal digits after a \.

The delete-character key is correctly defined in config.def.h.
---
 st.info | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.info b/st.info
index 99c066d..b91812f 100644
--- a/st.info
+++ b/st.info
@@ -73,7 +73,7 @@ st| simpleterm,
 	kri=\E[1;2A,
 	kclr=\E[3;5~,
 	kdl1=\E[3;2~,
-	kdch1=\0177,
+	kdch1=\177,
 	kich1=\E[2~,
 	kend=\E[4~,
 	kf1=\EOP,

From b0bddc694a79dd24edb8f997acadecbff356a9e0 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 9 Mar 2015 23:16:03 +0100
Subject: [PATCH 0775/1146] Add a hack to handle unknown chars in fontconfig.

The unicode long is added to the cache. So when fontconfig does fall back to
the default font (where there is no easy way to find this out from the
pattern) it isn't reloaded.
---
 st.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index e1139ec..e27daf0 100644
--- a/st.c
+++ b/st.c
@@ -522,6 +522,7 @@ enum {
 typedef struct {
 	XftFont *font;
 	int flags;
+	long unicodep;
 } Fontcache;
 
 /* Fontcache is an array now. A new font will be appended to the array. */
@@ -3208,7 +3209,7 @@ void
 xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
 	    width = charlen * xw.cw, xp, i;
-	int frcflags;
+	int frcflags, charexists;
 	int u8fl, u8fblen, u8cblen, doesexist;
 	char *u8c, *u8fs;
 	long unicodep;
@@ -3391,8 +3392,13 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 		/* Search the font cache. */
 		for(i = 0; i < frclen; i++) {
-			if(XftCharExists(xw.dpy, frc[i].font, unicodep)
-					&& frc[i].flags == frcflags) {
+			charexists = XftCharExists(xw.dpy, frc[i].font, unicodep);
+			/* Everything correct. */
+			if(charexists && frc[i].flags == frcflags)
+				break;
+			/* We got a default font for a not found glyph. */
+			if(!charexists && frc[i].flags == frcflags \
+					&& unicodep == unicodep) {
 				break;
 			}
 		}
@@ -3421,10 +3427,11 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 			FcConfigSubstitute(0, fcpattern,
 					FcMatchPattern);
+			FcPatternPrint(fcpattern);
 			FcDefaultSubstitute(fcpattern);
 
-			fontpattern = FcFontSetMatch(0, fcsets,
-					FcTrue, fcpattern, &fcres);
+			fontpattern = FcFontSetMatch(0, fcsets, 1,
+					fcpattern, &fcres);
 
 			/*
 			 * Overwrite or create the new cache entry.
@@ -3432,11 +3439,13 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 			if(frclen >= LEN(frc)) {
 				frclen = LEN(frc) - 1;
 				XftFontClose(xw.dpy, frc[frclen].font);
+				frc[frclen].unicodep = 0;
 			}
 
 			frc[frclen].font = XftFontOpenPattern(xw.dpy,
 					fontpattern);
 			frc[frclen].flags = frcflags;
+			frc[frclen].unicodep = unicodep;
 
 			i = frclen;
 			frclen++;

From 230d0c8428456603ce3629dac75c46abc4c9f016 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 10 Mar 2015 00:00:44 +0100
Subject: [PATCH 0776/1146] Finally resolving the backspace problem.

The majority now using the Linux behaviour. Minorities have to live in their
ghettos.
---
 config.def.h | 5 +++--
 st.info      | 4 ++--
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index 1667ed6..5b985cd 100644
--- a/config.def.h
+++ b/config.def.h
@@ -203,7 +203,7 @@ static Key key[] = {
 	{ XK_KP_Delete,     ShiftMask,      "\033[2K",      -1,    0,    0},
 	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",    +1,    0,    0},
 	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[P",       -1,    0,    0},
-	{ XK_KP_Delete,     XK_ANY_MOD,     "\177",         +1,    0,    0},
+	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
 	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +2,    0,    0},
 	{ XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +2,    0,    0},
 	{ XK_KP_Enter,      XK_ANY_MOD,     "\033OM",       +2,    0,    0},
@@ -258,7 +258,8 @@ static Key key[] = {
 	{ XK_Delete,        ShiftMask,      "\033[2K",      -1,    0,    0},
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",    +1,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
-	{ XK_Delete,        XK_ANY_MOD,     "\177",         +1,    0,    0},
+	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
+	{ XK_BackSpace,     XK_ANY_MOD,     "\177",         +1,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[2J",       0,   -1,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,   +1,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1,    0},
diff --git a/st.info b/st.info
index b91812f..2acd8b2 100644
--- a/st.info
+++ b/st.info
@@ -53,7 +53,7 @@ st| simpleterm,
 	ka3=\E[5~,
 	kc1=\E[4~,
 	kc3=\E[6~,
-	kbs=\010,
+	kbs=\177,
 	kcbt=\E[Z,
 	kb2=\EOu,
 	kcub1=\EOD,
@@ -73,7 +73,7 @@ st| simpleterm,
 	kri=\E[1;2A,
 	kclr=\E[3;5~,
 	kdl1=\E[3;2~,
-	kdch1=\177,
+	kdch1=\E[3~,
 	kich1=\E[2~,
 	kend=\E[4~,
 	kf1=\EOP,

From cf1fcc4d96f9162272003f82839388093c01360e Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 10 Mar 2015 00:20:28 +0100
Subject: [PATCH 0777/1146] Change the FAQ for the new Backspace behaviour.

---
 FAQ | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/FAQ b/FAQ
index 61f94a5..ee1c154 100644
--- a/FAQ
+++ b/FAQ
@@ -98,10 +98,14 @@ If you want to compile st for OpenBSD you have to remove -lrt from config.mk, an
 st will compile without any loss of functionality, because all the functions are
 included in libc on this platform.
 
-## Backspace key does not work
+## 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
-<http://lists.suckless.org/dev/1404/20697.html>:
+<http://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
@@ -155,11 +159,9 @@ This is an issue that was discussed in suckless mailing list
 	[1] http://www.ibb.net/~anne/keyboard.html
 	[2] http://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-5.html
 
-## But I really want a wrong backspace key and a wrong delete key
+## But I really want the old grumpy behaviour of my terminal
 
-If you really want emulate the errors of another terminal emulators
-and have a backspace key that generates a DELETE and a delete key
-that generates BACKSPACE, then you can apply the patch
-found in [1], but please do not tell me it.
+Apply [1].
 
 [1] http://st.suckless.org/patches/delkey
+

From 9494362d0b35dfe2fa22c3e36ed7b2043b2e8a3d Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 10 Mar 2015 21:11:04 +0100
Subject: [PATCH 0778/1146] Fixing the C reading test.

This was a test to see if anyone actually reads what is submitted. The list of
people not contributing will be valuable in the future.
---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index e27daf0..a494c7d 100644
--- a/st.c
+++ b/st.c
@@ -3398,7 +3398,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 				break;
 			/* We got a default font for a not found glyph. */
 			if(!charexists && frc[i].flags == frcflags \
-					&& unicodep == unicodep) {
+					&& frc[i].unicodep == unicodep) {
 				break;
 			}
 		}
@@ -3427,7 +3427,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 			FcConfigSubstitute(0, fcpattern,
 					FcMatchPattern);
-			FcPatternPrint(fcpattern);
 			FcDefaultSubstitute(fcpattern);
 
 			fontpattern = FcFontSetMatch(0, fcsets, 1,

From adeb2e95d633cf4bbe1bbe5d2caba71776577c21 Mon Sep 17 00:00:00 2001
From: Alexander Huemer <alexander.huemer@xx.vu>
Date: Tue, 10 Mar 2015 01:23:07 +0100
Subject: [PATCH 0779/1146] FAQ: fix wording

---
 FAQ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/FAQ b/FAQ
index ee1c154..cdf4f45 100644
--- a/FAQ
+++ b/FAQ
@@ -92,7 +92,7 @@ in TERM.
 
 ## I cannot compile st in OpenBSD
 
-OpenBSD lacks of librt, despite it begin mandatory in POSIX
+OpenBSD lacks librt, despite it began to be 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

From 28259f5750f0dc7f52bbaf8b746ec3dc576a58ee Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 10 Mar 2015 21:58:32 +0100
Subject: [PATCH 0780/1146] St now does only set PRIMARY on selection.

http://standards.freedesktop.org/clipboards-spec/clipboards-latest.txt
---
 st.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/st.c b/st.c
index a494c7d..39a6836 100644
--- a/st.c
+++ b/st.c
@@ -1079,16 +1079,9 @@ selrequest(XEvent *e) {
 
 void
 xsetsel(char *str) {
-	/* register the selection for both the clipboard and the primary */
-	Atom clipboard;
-
 	free(sel.clip);
 	sel.clip = str;
-
 	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, CurrentTime);
-
-	clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
-	XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
 }
 
 void

From f5075a9e9d27c64e115e056c5b973ab783c6c0f3 Mon Sep 17 00:00:00 2001
From: Ivan Delalande <colona@ycc.fr>
Date: Wed, 11 Mar 2015 17:13:35 +0000
Subject: [PATCH 0781/1146] Backspace value shouldn't depend on keypad state

---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 5b985cd..28a413b 100644
--- a/config.def.h
+++ b/config.def.h
@@ -259,7 +259,7 @@ static Key key[] = {
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",    +1,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
-	{ XK_BackSpace,     XK_ANY_MOD,     "\177",         +1,    0,    0},
+	{ XK_BackSpace,     XK_ANY_MOD,     "\177",          0,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[2J",       0,   -1,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,   +1,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1,    0},

From 4f60751440df55c11a8c601470b5d141d853e594 Mon Sep 17 00:00:00 2001
From: Alexander Huemer <alexander.huemer@xx.vu>
Date: Tue, 10 Mar 2015 01:23:07 +0100
Subject: [PATCH 0782/1146] FAQ: fix wording

---
 FAQ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/FAQ b/FAQ
index cdf4f45..3502c60 100644
--- a/FAQ
+++ b/FAQ
@@ -92,7 +92,7 @@ in TERM.
 
 ## I cannot compile st in OpenBSD
 
-OpenBSD lacks librt, despite it began to be mandatory in POSIX
+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

From b746816b78447b9e4a3af7333a4e992eb8d32254 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 13 Mar 2015 07:26:16 +0000
Subject: [PATCH 0783/1146] Allow combinations with Backspace

XN_ANY_MOD makes that any combination of backspace will return always
DEL. This patch lets to X to decide which value returns.
---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 28a413b..8a8236c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -259,7 +259,7 @@ static Key key[] = {
 	{ XK_Delete,        ShiftMask,      "\033[3;2~",    +1,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
-	{ XK_BackSpace,     XK_ANY_MOD,     "\177",          0,    0,    0},
+	{ XK_BackSpace,     XK_NO_MOD,      "\177",          0,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[2J",       0,   -1,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,   +1,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1,    0},

From 2fcfea1bf149f839cdbcba5c1efc7c4ce31f6d95 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 14 Mar 2015 07:41:59 +0100
Subject: [PATCH 0784/1146] Add Mod + Shift + c/v and no selclear.

Thanks to Alex Pilon <alp@alexpilon.ca>!

Now there is a distinction between the primary and clipboard selection. With
Mod + Shift + c/v the clipboard is handled. The old Insert behavious does
reside.
---
 config.def.h |  2 ++
 st.c         | 69 ++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 56 insertions(+), 15 deletions(-)

diff --git a/config.def.h b/config.def.h
index 8a8236c..56bae2d 100644
--- a/config.def.h
+++ b/config.def.h
@@ -119,6 +119,8 @@ static Shortcut shortcuts[] = {
 	{ MODKEY|ShiftMask,     XK_Home,        xzoomreset,     {.i =  0} },
 	{ ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
 	{ MODKEY|ShiftMask,     XK_Insert,      clippaste,      {.i =  0} },
+	{ MODKEY|ShiftMask,     XK_C,           clipcopy,       {.i =  0} },
+	{ MODKEY|ShiftMask,     XK_V,           clippaste,      {.i =  0} },
 	{ MODKEY,               XK_Num_Lock,    numlock,        {.i =  0} },
 };
 
diff --git a/st.c b/st.c
index 39a6836..4b98b27 100644
--- a/st.c
+++ b/st.c
@@ -290,7 +290,7 @@ typedef struct {
 		int x, y;
 	} nb, ne, ob, oe;
 
-	char *clip;
+	char *primary, *clipboard;
 	Atom xtarget;
 	bool alt;
 	struct timespec tclick1;
@@ -312,6 +312,7 @@ typedef struct {
 } Shortcut;
 
 /* 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 *);
@@ -479,7 +480,11 @@ static void (*handler[LASTEvent])(XEvent *) = {
 	[MotionNotify] = bmotion,
 	[ButtonPress] = bpress,
 	[ButtonRelease] = brelease,
-	[SelectionClear] = selclear,
+/*
+ * Uncomment if you want the selection to disappear when you select something
+ * different in another window.
+ */
+/*	[SelectionClear] = selclear, */
 	[SelectionNotify] = selnotify,
 	[SelectionRequest] = selrequest,
 };
@@ -640,7 +645,8 @@ selinit(void) {
 	memset(&sel.tclick2, 0, sizeof(sel.tclick2));
 	sel.mode = 0;
 	sel.ob.x = -1;
-	sel.clip = NULL;
+	sel.primary = NULL;
+	sel.clipboard = NULL;
 	sel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
 	if(sel.xtarget == None)
 		sel.xtarget = XA_STRING;
@@ -985,12 +991,15 @@ selnotify(XEvent *e) {
 	int format;
 	uchar *data, *last, *repl;
 	Atom type;
+	XSelectionEvent *xsev;
 
 	ofs = 0;
+	xsev = (XSelectionEvent *)e;
 	do {
-		if(XGetWindowProperty(xw.dpy, xw.win, XA_PRIMARY, ofs, BUFSIZ/4,
-					False, AnyPropertyType, &type, &format,
-					&nitems, &rem, &data)) {
+		if(XGetWindowProperty(xw.dpy, xw.win, xsev->property, ofs,
+					BUFSIZ/4, False, AnyPropertyType,
+					&type, &format, &nitems, &rem,
+					&data)) {
 			fprintf(stderr, "Clipboard allocation failed\n");
 			return;
 		}
@@ -1025,12 +1034,26 @@ selpaste(const Arg *dummy) {
 			xw.win, CurrentTime);
 }
 
+void
+clipcopy(const Arg *dummy) {
+	Atom clipboard;
+
+	if(sel.clipboard != NULL)
+		free(sel.clipboard);
+
+	if(sel.primary != NULL) {
+		sel.clipboard = xstrdup(sel.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, sel.xtarget, XA_PRIMARY,
+	XConvertSelection(xw.dpy, clipboard, sel.xtarget, clipboard,
 			xw.win, CurrentTime);
 }
 
@@ -1046,7 +1069,8 @@ void
 selrequest(XEvent *e) {
 	XSelectionRequestEvent *xsre;
 	XSelectionEvent xev;
-	Atom xa_targets, string;
+	Atom xa_targets, string, clipboard;
+	char *seltext;
 
 	xsre = (XSelectionRequestEvent *) e;
 	xev.type = SelectionNotify;
@@ -1065,11 +1089,25 @@ selrequest(XEvent *e) {
 				XA_ATOM, 32, PropModeReplace,
 				(uchar *) &string, 1);
 		xev.property = xsre->property;
-	} else if(xsre->target == sel.xtarget && sel.clip != NULL) {
-		XChangeProperty(xsre->display, xsre->requestor, xsre->property,
-				xsre->target, 8, PropModeReplace,
-				(uchar *) sel.clip, strlen(sel.clip));
-		xev.property = xsre->property;
+	} else if(xsre->target == sel.xtarget) {
+		clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+		if(xsre->selection == XA_PRIMARY) {
+			seltext = sel.primary;
+		} else if(xsre->selection == clipboard) {
+			seltext = sel.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 */
@@ -1079,8 +1117,9 @@ selrequest(XEvent *e) {
 
 void
 xsetsel(char *str) {
-	free(sel.clip);
-	sel.clip = str;
+	free(sel.primary);
+	sel.primary = str;
+
 	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, CurrentTime);
 }
 

From 72d2accc2299cdda9379db17ed62e8e5df5a9426 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 14 Mar 2015 08:43:57 +0100
Subject: [PATCH 0785/1146] Glibc wants me to use _DEFAULT_SOURCe. I do obey.

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 46457f7..7ae510e 100644
--- a/config.mk
+++ b/config.mk
@@ -19,7 +19,7 @@ LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXext -lXft \
        `pkg-config --libs freetype2`
 
 # flags
-CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_XOPEN_SOURCE=600
+CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600
 CFLAGS += -g -std=c99 -pedantic -Wall -Wvariadic-macros -Os ${INCS} ${CPPFLAGS}
 LDFLAGS += -g ${LIBS}
 

From 5406e655daa576a909ad69a5ee6ed1f72ca5b15a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 14 Mar 2015 08:52:37 +0100
Subject: [PATCH 0786/1146] Add the new selection shortcuts to the manpage.

---
 st.1 | 31 ++++++++++++++++++++-----------
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/st.1 b/st.1
index 0700787..a9fec15 100644
--- a/st.1
+++ b/st.1
@@ -45,9 +45,9 @@ for further details.
 .B \-i
 will fixate the position given with the -g option.
 .TP
-.BI \-o " file"
+.BI \-o " iofile"
 writes all the I/O to
-.I file.
+.I iofile.
 This feature is useful when recording st sessions. A value of "-" means
 standard output.
 .TP
@@ -67,31 +67,40 @@ st executes
 instead of the shell.  If this is used it
 .B must be the last option
 on the command line, as in xterm / rxvt.
-.SH USAGE
+.SH SHORTCUTS
 .TP
 .B Ctrl-Print Screen
-toggleprinter()
+Toggle if st should print to the
+.I iofile.
 .TP
 .B Shift-Print Screen
-printscreen()
+Print the full screen to the
+.I iofile.
 .TP
 .B Print Screen
-printsel()
+Print the selection to the
+.I iofile.
 .TP
 .B Alt-Shift-Page Up
-increase font size
+Increase font size.
 .TP
 .B Alt-Shift-Page Down
-decrease font size
+Decrease font size.
 .TP
 .B Alt-Shift-Home
-reset to default font size
+Reset to default font size.
 .TP
 .B Shift-Insert
-paste from primary selection
+Paste from primary selection (middle mouse button).
 .TP
 .B Alt-Shift-Insert
-paste from clipboard selection
+Paste from clipboard selection.
+.TP
+.B Alt-Shift-c
+Copy the selected text to the clipboard selection.
+.TP
+.B Alt-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

From c7e24e44c8d66cd5b0a6b015d2112da5f1e4e581 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 14 Mar 2015 08:53:41 +0100
Subject: [PATCH 0787/1146] TODO: Fix fontconfig

---
 TODO | 1 +
 1 file changed, 1 insertion(+)

diff --git a/TODO b/TODO
index 00cfdac..90e3d56 100644
--- a/TODO
+++ b/TODO
@@ -11,6 +11,7 @@ code & interface
 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
 

From 86d1e432a823dad7bb64808b8192014fddc8cd9f Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sun, 15 Mar 2015 18:07:46 +0000
Subject: [PATCH 0788/1146] Support XA_STRING in notify request

Some programs can only deal with XA_STRING, and it makes impossible st
be able of copying to them. This patch makes st answer also to XA_STRING,
althought it sends utf8 strings. It is not a problem because moderm
applications must support utf8.
---
 st.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 4b98b27..aa4185c 100644
--- a/st.c
+++ b/st.c
@@ -1089,7 +1089,11 @@ selrequest(XEvent *e) {
 				XA_ATOM, 32, PropModeReplace,
 				(uchar *) &string, 1);
 		xev.property = xsre->property;
-	} else if(xsre->target == sel.xtarget) {
+	} else if(xsre->target == sel.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 = sel.primary;

From b341e513514d50cc995a5646a1bbace65dc4ca67 Mon Sep 17 00:00:00 2001
From: Alex Pilon <alp@alexpilon.ca>
Date: Mon, 16 Mar 2015 11:51:23 -0400
Subject: [PATCH 0789/1146] Handle pasting of empty selection.

Otherwise, pasting the X11 primary selection when empty results an
error and Xlib forcibly exits.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.c b/st.c
index aa4185c..836ae21 100644
--- a/st.c
+++ b/st.c
@@ -995,6 +995,8 @@ selnotify(XEvent *e) {
 
 	ofs = 0;
 	xsev = (XSelectionEvent *)e;
+	if (xsev->property == None)
+	    return;
 	do {
 		if(XGetWindowProperty(xw.dpy, xw.win, xsev->property, ofs,
 					BUFSIZ/4, False, AnyPropertyType,

From 246c3481d780067dd3294edbd58cf980c2d960a3 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 16 Mar 2015 22:17:30 +0100
Subject: [PATCH 0790/1146] arg.h wasn't used for dist.

---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 52af636..6158ab2 100644
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,7 @@ clean:
 dist: clean
 	@echo creating dist tarball
 	@mkdir -p st-${VERSION}
-	@cp -R LICENSE Makefile README config.mk config.def.h st.info st.1 ${SRC} st-${VERSION}
+	@cp -R LICENSE Makefile README config.mk config.def.h st.info st.1 arg.h ${SRC} st-${VERSION}
 	@tar -cf st-${VERSION}.tar st-${VERSION}
 	@gzip st-${VERSION}.tar
 	@rm -rf st-${VERSION}

From 580302f3179ef3f24cf0329755686dfa7100996b Mon Sep 17 00:00:00 2001
From: LemonBoy <thatlemon@gmail.com>
Date: Wed, 18 Mar 2015 21:12:47 +0100
Subject: [PATCH 0791/1146] Support the DECSCUSR CSI escape sequence

---
 st.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 49 insertions(+), 13 deletions(-)

diff --git a/st.c b/st.c
index aa4185c..00fca99 100644
--- a/st.c
+++ b/st.c
@@ -197,14 +197,14 @@ typedef struct {
 } TCursor;
 
 /* CSI Escape sequence structs */
-/* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
+/* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
 typedef struct {
 	char buf[ESC_BUF_SIZ]; /* raw string */
 	int len;               /* raw string length */
 	char priv;
 	int arg[ESC_ARG_SIZ];
 	int narg;              /* nb of args */
-	char mode;
+	char mode[2];
 } CSIEscape;
 
 /* STR Escape sequence structs */
@@ -257,6 +257,7 @@ typedef struct {
 	int ch; /* char height */
 	int cw; /* char width  */
 	char state; /* focus, redraw, visible */
+	int cursor; /* cursor style */
 } XWindow;
 
 typedef struct {
@@ -1545,7 +1546,8 @@ csiparse(void) {
 			break;
 		p++;
 	}
-	csiescseq.mode = *p;
+	csiescseq.mode[0] = *p++;
+	csiescseq.mode[1] = (p < csiescseq.buf+csiescseq.len) ? *p : '\0';
 }
 
 /* for absolute user moves, when decom is set */
@@ -1983,7 +1985,7 @@ csihandle(void) {
 	char buf[40];
 	int len;
 
-	switch(csiescseq.mode) {
+	switch(csiescseq.mode[0]) {
 	default:
 	unknown:
 		fprintf(stderr, "erresc: unknown csi ");
@@ -2171,6 +2173,19 @@ csihandle(void) {
 	case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
 		tcursor(CURSOR_LOAD);
 		break;
+	case ' ':
+		switch (csiescseq.mode[1]) {
+			case 'q': /* DECSCUSR -- Set Cursor Style */
+				DEFAULT(csiescseq.arg[0], 1);
+				if (!BETWEEN(csiescseq.arg[0], 0, 6)) {
+					goto unknown;
+				}
+				xw.cursor = csiescseq.arg[0];
+				break;
+			default:
+				goto unknown;
+		}
+		break;
 	}
 }
 
@@ -3551,16 +3566,36 @@ xdrawcursor(void) {
 
 	/* draw the new one */
 	if(xw.state & WIN_FOCUSED) {
-		if(IS_SET(MODE_REVERSE)) {
-			g.mode |= ATTR_REVERSE;
-			g.fg = defaultcs;
-			g.bg = defaultfg;
-		}
+		switch (xw.cursor) {
+			case 0: /* Blinking Block */
+			case 1: /* Blinking Block (Default) */
+			case 2: /* Steady Block */
+				if(IS_SET(MODE_REVERSE)) {
+						g.mode |= ATTR_REVERSE;
+						g.fg = defaultcs;
+						g.bg = defaultfg;
+					}
 
-		sl = utf8len(g.c);
-		width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\
-			? 2 : 1;
-		xdraws(g.c, g, term.c.x, term.c.y, width, sl);
+				sl = utf8len(g.c);
+				width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\
+					? 2 : 1;
+				xdraws(g.c, g, term.c.x, term.c.y, width, sl);
+				break;
+			case 3: /* Blinking Underline */
+			case 4: /* Steady Underline */
+				XftDrawRect(xw.draw, &dc.col[defaultcs],
+						borderpx + curx * xw.cw,
+						borderpx + (term.c.y + 1) * xw.ch - 1,
+						xw.cw, 1);
+				break;
+			case 5: /* Blinking bar */
+			case 6: /* Steady bar */
+				XftDrawRect(xw.draw, &dc.col[defaultcs],
+								borderpx + curx * xw.cw,
+								borderpx + term.c.y * xw.ch,
+								1, xw.ch);
+				break;
+		}
 	} else {
 		XftDrawRect(xw.draw, &dc.col[defaultcs],
 				borderpx + curx * xw.cw,
@@ -3985,6 +4020,7 @@ main(int argc, char *argv[]) {
 
 	xw.l = xw.t = 0;
 	xw.isfixed = False;
+	xw.cursor = 0;
 
 	ARGBEGIN {
 	case 'a':

From 288f80cb06b442ef0f55ea62bbceb3260338bf7a Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 20 Mar 2015 06:46:59 +0000
Subject: [PATCH 0792/1146] Remove strsep() call

strsep() is not a POSIX function, and it means that every system
needs different defines to expose it. If the prototype of strsep
is not exposed then an ugly int/pointer is done and it might mean
a crash. The best solution?, to remove the strsep and make a custom
loop. If C programmers cannot do this kind of loops without calling
a library function, then maybe we should move all the suckless
software to Java.
---
 config.mk |  2 +-
 st.c      | 15 +++++++++++++--
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/config.mk b/config.mk
index 7ae510e..3026d87 100644
--- a/config.mk
+++ b/config.mk
@@ -19,7 +19,7 @@ LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXext -lXft \
        `pkg-config --libs freetype2`
 
 # flags
-CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600
+CPPFLAGS = -DVERSION=\"${VERSION}\" -D_XOPEN_SOURCE=600
 CFLAGS += -g -std=c99 -pedantic -Wall -Wvariadic-macros -Os ${INCS} ${CPPFLAGS}
 LDFLAGS += -g ${LIBS}
 
diff --git a/st.c b/st.c
index 68dc2be..39d3fee 100644
--- a/st.c
+++ b/st.c
@@ -2272,12 +2272,23 @@ strhandle(void) {
 
 void
 strparse(void) {
+	int c;
 	char *p = strescseq.buf;
 
 	strescseq.narg = 0;
 	strescseq.buf[strescseq.len] = '\0';
-	while(p && strescseq.narg < STR_ARG_SIZ)
-		strescseq.args[strescseq.narg++] = strsep(&p, ";");
+
+	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

From 69d1fe06a97619e80872aaae2c4c97ced0540b67 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sun, 5 Apr 2015 23:58:10 +0000
Subject: [PATCH 0793/1146] Fixed STR sequence termination condition

ascii code may only be checked for characters that have length equal to
1, not width equal to 1
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 39d3fee..827ed08 100644
--- a/st.c
+++ b/st.c
@@ -2663,7 +2663,7 @@ tputc(char *c, int len) {
 	 * character.
 	 */
 	if(term.esc & ESC_STR) {
-		if(width == 1 &&
+		if(len == 1 &&
 		   (ascii == '\a' || ascii == 030 ||
 		    ascii == 032  || ascii == 033 ||
 		    ISCONTROLC1(unicodep))) {

From 5bb90125c80a9409745bd7551aaae478dda3f890 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 6 Apr 2015 10:55:00 +0200
Subject: [PATCH 0794/1146] Remove redundant control check

control was set, but it was not ever used because it was set
again some lines later.
---
 st.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.c b/st.c
index 827ed08..6d20977 100644
--- a/st.c
+++ b/st.c
@@ -2648,7 +2648,6 @@ tputc(char *c, int len) {
 			c = "\357\277\275";	/* UTF_INVALID */
 			width = 1;
 		}
-		control = ISCONTROLC1(unicodep);
 		ascii = unicodep;
 	}
 

From 9305f3c184a0179e37802e752c3d1dc830ae893c Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Wed, 8 Apr 2015 23:16:57 +0000
Subject: [PATCH 0795/1146] Remove variable names from function declarations.

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 6d20977..6522c9d 100644
--- a/st.c
+++ b/st.c
@@ -359,7 +359,7 @@ static void csidump(void);
 static void csihandle(void);
 static void csiparse(void);
 static void csireset(void);
-static int eschandle(uchar ascii);
+static int eschandle(uchar);
 static void strdump(void);
 static void strhandle(void);
 static void strparse(void);
@@ -406,7 +406,7 @@ static void ttyread(void);
 static void ttyresize(void);
 static void ttysend(char *, size_t);
 static void ttywrite(const char *, size_t);
-static void tstrsequence(uchar c);
+static void tstrsequence(uchar);
 
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);

From 6524f022f7d1d32f43208254e12f934bf64ed559 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Wed, 8 Apr 2015 23:17:33 +0000
Subject: [PATCH 0796/1146] Remove keywords from function definitions.

---
 st.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/st.c b/st.c
index 6522c9d..7dbd87a 100644
--- a/st.c
+++ b/st.c
@@ -408,6 +408,7 @@ static void ttysend(char *, size_t);
 static void ttywrite(const char *, size_t);
 static void tstrsequence(uchar);
 
+static inline ushort sixd_to_16bit(int);
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
 static void xclear(int, int, int, int);
@@ -452,6 +453,8 @@ static char *getsel(void);
 static void selcopy(void);
 static void selscroll(int, int);
 static void selsnap(int, int *, int *, int);
+static int x2col(int);
+static int y2row(int);
 static void getbuttoninfo(XEvent *);
 static void mousereport(XEvent *);
 
@@ -640,7 +643,7 @@ utf8validate(long *u, size_t i) {
 	return i;
 }
 
-static void
+void
 selinit(void) {
 	memset(&sel.tclick1, 0, sizeof(sel.tclick1));
 	memset(&sel.tclick2, 0, sizeof(sel.tclick2));
@@ -653,7 +656,7 @@ selinit(void) {
 		sel.xtarget = XA_STRING;
 }
 
-static int
+int
 x2col(int x) {
 	x -= borderpx;
 	x /= xw.cw;
@@ -661,7 +664,7 @@ x2col(int x) {
 	return LIMIT(x, 0, term.col-1);
 }
 
-static int
+int
 y2row(int y) {
 	y -= borderpx;
 	y /= xw.ch;
@@ -669,7 +672,7 @@ y2row(int y) {
 	return LIMIT(y, 0, term.row-1);
 }
 
-static int tlinelen(int y) {
+int tlinelen(int y) {
 	int i = term.col;
 
 	if(term.line[y][i - 1].mode & ATTR_WRAP)
@@ -681,7 +684,7 @@ static int tlinelen(int y) {
 	return i;
 }
 
-static void
+void
 selnormalize(void) {
 	int i;
 
@@ -708,7 +711,7 @@ selnormalize(void) {
 		sel.ne.x = term.col - 1;
 }
 
-static inline bool
+bool
 selected(int x, int y) {
 	if(sel.type == SEL_RECTANGULAR)
 		return BETWEEN(y, sel.nb.y, sel.ne.y)
@@ -2857,7 +2860,7 @@ xresize(int col, int row) {
 	xclear(0, 0, xw.w, xw.h);
 }
 
-static inline ushort
+ushort
 sixd_to_16bit(int x) {
 	return x == 0 ? 0 : 0x3737 + 0x2828 * x;
 }
@@ -3772,7 +3775,7 @@ focus(XEvent *ev) {
 	}
 }
 
-static inline bool
+bool
 match(uint mask, uint state) {
 	return mask == XK_ANY_MOD || mask == (state & ~ignoremod);
 }

From 6f5f7701864e6987544cb7e7dc5f2d24db1a4537 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Wed, 8 Apr 2015 23:24:06 +0000
Subject: [PATCH 0797/1146] Remove 'xloadfontset' function.

It was used only once and its return value was ignored.
---
 st.c | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/st.c b/st.c
index 7dbd87a..0065240 100644
--- a/st.c
+++ b/st.c
@@ -419,7 +419,6 @@ static int xsetcolorname(int, const char *);
 static int xgeommasktogravity(int);
 static int xloadfont(Font *, FcPattern *);
 static void xloadfonts(char *, double);
-static int xloadfontset(Font *);
 static void xsettitle(char *);
 static void xresettitle(void);
 static void xsetpointermotion(int);
@@ -3116,15 +3115,6 @@ xloadfonts(char *fontstr, double fontsize) {
 	FcPatternDestroy(pattern);
 }
 
-int
-xloadfontset(Font *f) {
-	FcResult result;
-
-	if(!(f->set = FcFontSort(0, f->pattern, FcTrue, 0, &result)))
-		return 1;
-	return 0;
-}
-
 void
 xunloadfont(Font *f) {
 	XftFontClose(xw.dpy, f->match);
@@ -3472,7 +3462,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		/* Nothing was found. */
 		if(i >= frclen) {
 			if(!font->set)
-				xloadfontset(font);
+				font->set = FcFontSort(0, font->pattern,
+				                       FcTrue, 0, &fcres);
 			fcsets[0] = font->set;
 
 			/*

From 93b54cfcc437c9bac9af3ceb2d9ba19c442de1ff Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Thu, 9 Apr 2015 20:04:43 +0000
Subject: [PATCH 0798/1146] Use MAX macro where possible.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 0065240..a7064b1 100644
--- a/st.c
+++ b/st.c
@@ -4072,7 +4072,7 @@ main(int argc, char *argv[]) {
 run:
 	setlocale(LC_CTYPE, "");
 	XSetLocaleModifiers("");
-	tnew(cols? cols : 1, rows? rows : 1);
+	tnew(MAX(cols, 1), MAX(rows, 1));
 	xinit();
 	selinit();
 	run();

From ecac5ee35ef006001b280461ed3f9812d855250c Mon Sep 17 00:00:00 2001
From: Omar Sandoval <osandov@osandov.com>
Date: Thu, 9 Apr 2015 18:22:31 -0700
Subject: [PATCH 0799/1146] Make DECSCUSR thickness configurable

---
 config.def.h |  5 +++++
 st.c         | 10 +++++-----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/config.def.h b/config.def.h
index 56bae2d..5e7caaf 100644
--- a/config.def.h
+++ b/config.def.h
@@ -41,6 +41,11 @@ static unsigned int actionfps = 30;
  */
 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
diff --git a/st.c b/st.c
index a7064b1..b2bcfe9 100644
--- a/st.c
+++ b/st.c
@@ -3591,15 +3591,15 @@ xdrawcursor(void) {
 			case 4: /* Steady Underline */
 				XftDrawRect(xw.draw, &dc.col[defaultcs],
 						borderpx + curx * xw.cw,
-						borderpx + (term.c.y + 1) * xw.ch - 1,
-						xw.cw, 1);
+						borderpx + (term.c.y + 1) * xw.ch - cursorthickness,
+						xw.cw, cursorthickness);
 				break;
 			case 5: /* Blinking bar */
 			case 6: /* Steady bar */
 				XftDrawRect(xw.draw, &dc.col[defaultcs],
-								borderpx + curx * xw.cw,
-								borderpx + term.c.y * xw.ch,
-								1, xw.ch);
+						borderpx + curx * xw.cw,
+						borderpx + term.c.y * xw.ch,
+						cursorthickness, xw.ch);
 				break;
 		}
 	} else {

From d3e0f3444b91418e3d3cda591c5d8c50caa22957 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sat, 11 Apr 2015 12:18:57 +0200
Subject: [PATCH 0800/1146] Use do..while in window mapping loop.

---
 st.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index b2bcfe9..83acd56 100644
--- a/st.c
+++ b/st.c
@@ -3917,17 +3917,15 @@ run(void) {
 	long deltatime;
 
 	/* Waiting for window mapping */
-	while(1) {
+	do {
 		XNextEvent(xw.dpy, &ev);
 		if(XFilterEvent(&ev, None))
 			continue;
 		if(ev.type == ConfigureNotify) {
 			w = ev.xconfigure.width;
 			h = ev.xconfigure.height;
-		} else if(ev.type == MapNotify) {
-			break;
 		}
-	}
+	} while(ev.type != MapNotify);
 
 	ttynew();
 	cresize(w, h);

From d2937b05aed9cee8d6651cd806d31682a853c773 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sat, 11 Apr 2015 12:15:51 +0200
Subject: [PATCH 0801/1146] Remove unnecessary XFilterEvent call.

XFilterEvent usually filters KeyPress events according to input method.
At this point the window is not mapped. The only events that we process
are ConfigureNotify and MapNotify. They should not be filtered by input
method.
---
 st.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/st.c b/st.c
index 83acd56..c48132a 100644
--- a/st.c
+++ b/st.c
@@ -3919,8 +3919,6 @@ run(void) {
 	/* Waiting for window mapping */
 	do {
 		XNextEvent(xw.dpy, &ev);
-		if(XFilterEvent(&ev, None))
-			continue;
 		if(ev.type == ConfigureNotify) {
 			w = ev.xconfigure.width;
 			h = ev.xconfigure.height;

From b9390a54968c3bc4f4270afdcf5b85911df01611 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sat, 11 Apr 2015 12:47:16 +0200
Subject: [PATCH 0802/1146] Simplify loop condition.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index c48132a..4ed8319 100644
--- a/st.c
+++ b/st.c
@@ -944,7 +944,7 @@ getsel(void) {
 	ptr = str = xmalloc(bufsize);
 
 	/* append every set & selected glyph to the selection */
-	for(y = sel.nb.y; y < sel.ne.y + 1; y++) {
+	for(y = sel.nb.y; y <= sel.ne.y; y++) {
 		linelen = tlinelen(y);
 
 		if(sel.type == SEL_RECTANGULAR) {

From 6352502d644d8295ceb2cdf68a5ecbac0891d4a6 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sat, 11 Apr 2015 19:29:52 +0200
Subject: [PATCH 0803/1146] tresize: move for loop outside if

There is no need to check that slide > 0 before executing loop.
If slide <= 0, loop stops immediately.
---
 st.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 4ed8319..fb37eb5 100644
--- a/st.c
+++ b/st.c
@@ -2780,17 +2780,16 @@ tresize(int col, int row) {
 	}
 
 	/* free unneeded rows */
-	i = 0;
+	for(i = 0; i < slide; i++) {
+		free(term.line[i]);
+		free(term.alt[i]);
+	}
 	if(slide > 0) {
 		/*
 		 * 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 < slide; i++) {
-			free(term.line[i]);
-			free(term.alt[i]);
-		}
 		memmove(term.line, term.line + slide, row * sizeof(Line));
 		memmove(term.alt, term.alt + slide, row * sizeof(Line));
 	}

From 39ae1a4de5c471c8626c80ef1e961f0c83f5199d Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sat, 11 Apr 2015 19:30:12 +0200
Subject: [PATCH 0804/1146] Move tresize comments around.

---
 st.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index fb37eb5..79bf1c8 100644
--- a/st.c
+++ b/st.c
@@ -2779,17 +2779,16 @@ tresize(int col, int row) {
 		return;
 	}
 
-	/* free unneeded rows */
+	/*
+	 * 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 < slide; i++) {
 		free(term.line[i]);
 		free(term.alt[i]);
 	}
 	if(slide > 0) {
-		/*
-		 * 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
-		 */
 		memmove(term.line, term.line + slide, row * sizeof(Line));
 		memmove(term.alt, term.alt + slide, row * sizeof(Line));
 	}

From c569e3146e6999f6a02acecd145929c87e15b528 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sat, 11 Apr 2015 19:30:36 +0200
Subject: [PATCH 0805/1146] Remove 'slide' variable in tresize.

---
 st.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 79bf1c8..2c58a3e 100644
--- a/st.c
+++ b/st.c
@@ -2769,7 +2769,6 @@ tresize(int col, int row) {
 	int i;
 	int minrow = MIN(row, term.row);
 	int mincol = MIN(col, term.col);
-	int slide = term.c.y - row + 1;
 	bool *bp;
 	TCursor c;
 
@@ -2784,13 +2783,13 @@ tresize(int col, int row) {
 	 * tscrollup would work here, but we can optimize to
 	 * memmove because we're freeing the earlier lines
 	 */
-	for(i = 0; i < slide; i++) {
+	for(i = 0; i <= term.c.y - row; i++) {
 		free(term.line[i]);
 		free(term.alt[i]);
 	}
-	if(slide > 0) {
-		memmove(term.line, term.line + slide, row * sizeof(Line));
-		memmove(term.alt, term.alt + slide, row * sizeof(Line));
+	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]);

From 9d1495f9eeee993a480c7ab1755803d081d794e6 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Mon, 13 Apr 2015 14:03:12 +0200
Subject: [PATCH 0806/1146] Fix typo.

It seems that LICENSE files are more common than LICENCE files.
At least this patch makes spelling consistent.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 2c58a3e..0558593 100644
--- a/st.c
+++ b/st.c
@@ -1,4 +1,4 @@
-/* See LICENSE for licence details. */
+/* See LICENSE for license details. */
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>

From b0310fba5de0c519eae0c8a2817ccc7bfcdd5222 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Mon, 13 Apr 2015 14:03:51 +0200
Subject: [PATCH 0807/1146] Simplify tmoveto.

LIMIT returns value. This fact is already used in x2col and y2row.
---
 st.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 0558593..79bb6aa 100644
--- a/st.c
+++ b/st.c
@@ -1571,11 +1571,9 @@ tmoveto(int x, int y) {
 		miny = 0;
 		maxy = term.row - 1;
 	}
-	LIMIT(x, 0, term.col-1);
-	LIMIT(y, miny, maxy);
 	term.c.state &= ~CURSOR_WRAPNEXT;
-	term.c.x = x;
-	term.c.y = y;
+	term.c.x = LIMIT(x, 0, term.col-1);
+	term.c.y = LIMIT(y, miny, maxy);
 }
 
 void

From e6dd0f825da9bf68c7642f45afd069500879f5e2 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Mon, 13 Apr 2015 14:34:23 +0200
Subject: [PATCH 0808/1146] Remove useless if in tstrsequence.

---
 st.c | 28 +++++++++++++---------------
 1 file changed, 13 insertions(+), 15 deletions(-)

diff --git a/st.c b/st.c
index 79bb6aa..4f5cf9e 100644
--- a/st.c
+++ b/st.c
@@ -2444,21 +2444,19 @@ tdectest(char c) {
 
 void
 tstrsequence(uchar c) {
-	if (c & 0x80) {
-		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;
-		}
+	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;

From b94ad75e5ded18d7dcafd69070f79838e0ebf24f Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Mon, 13 Apr 2015 16:05:49 +0200
Subject: [PATCH 0809/1146] Remove 'titles' variable.

We do not free it until exit anyway.
---
 st.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 4f5cf9e..4650990 100644
--- a/st.c
+++ b/st.c
@@ -4010,7 +4010,6 @@ usage(void) {
 
 int
 main(int argc, char *argv[]) {
-	char *titles;
 	uint cols = 80, rows = 24;
 
 	xw.l = xw.t = 0;
@@ -4028,10 +4027,8 @@ main(int argc, char *argv[]) {
 		/* eat all remaining arguments */
 		if(argc > 1) {
 			opt_cmd = &argv[1];
-			if(argv[1] != NULL && opt_title == NULL) {
-				titles = xstrdup(argv[1]);
-				opt_title = basename(titles);
-			}
+			if(argv[1] != NULL && opt_title == NULL)
+				opt_title = basename(xstrdup(argv[1]));
 		}
 		goto run;
 	case 'f':

From a6af2cc46961a9378ab43919bb308162dedd4153 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Mon, 13 Apr 2015 16:06:21 +0200
Subject: [PATCH 0810/1146] Remove old TODO entry.

It probably refers to
http://lists.suckless.org/dev/1211/13427.html
and does not seem like a bug in st.
---
 TODO | 1 -
 1 file changed, 1 deletion(-)

diff --git a/TODO b/TODO
index 90e3d56..5f74cd5 100644
--- a/TODO
+++ b/TODO
@@ -19,7 +19,6 @@ bugs
 ----
 
 * fix shift up/down (shift selection in emacs)
-* fix -e handling
 * remove DEC test sequence when appropriate
 
 misc

From 9619760e129b0994cd3bc4c827c83960f6a5e98f Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sun, 12 Apr 2015 10:30:19 +0200
Subject: [PATCH 0811/1146] tresize: remove unnecessary if

---
 st.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 4650990..2a565b6 100644
--- a/st.c
+++ b/st.c
@@ -2783,10 +2783,8 @@ tresize(int col, int row) {
 		free(term.line[i]);
 		free(term.alt[i]);
 	}
-	if(i > 0) {
-		memmove(term.line, term.line + i, row * sizeof(Line));
-		memmove(term.alt, term.alt + i, row * sizeof(Line));
-	}
+	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]);

From 9eb70a2d3ecbd96a92e5f824868500baba74b688 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Mon, 13 Apr 2015 14:03:35 +0200
Subject: [PATCH 0812/1146] Do not use tmoveto in tputtab.

tmoveto resets CURSOR_WRAPNEXT.

Simple testcase:

for i in $(seq 1 200); do
	printf '\t.';
	usleep 100000;
	printf '\t@';
	usleep 100000;
done

In st executing this script causes @ and . to overwrite each other in
the last column.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 6d20977..7051a4a 100644
--- a/st.c
+++ b/st.c
@@ -2390,7 +2390,7 @@ tputtab(int n) {
 			for(--x; x > 0 && !term.tabs[x]; --x)
 				/* nothing */ ;
 	}
-	tmoveto(x, term.c.y);
+	term.c.x = LIMIT(x, 0, term.col-1);
 }
 
 void

From 42fa1f5ce46593a9d6c2f9196c1aae1a60ca07d1 Mon Sep 17 00:00:00 2001
From: Markus Wichmann <nullplan@gmx.net>
Date: Sat, 11 Apr 2015 21:21:34 +0200
Subject: [PATCH 0813/1146] Implement most ICCCM rules for selection handling.

ICCCM mandates the use of real timestamps to interact with the
selection, to rule out race conditions if the clients are run at
different speeds. I have implemented the low hanging fruit, putting the
timestamps into text selection. Also, ICCCM mandates a check for whether
XSetSelectionOwner() worked. Not sure my version is correct, though.
---
 st.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/st.c b/st.c
index f874127..6bfa834 100644
--- a/st.c
+++ b/st.c
@@ -423,7 +423,7 @@ static void xsettitle(char *);
 static void xresettitle(void);
 static void xsetpointermotion(int);
 static void xseturgency(int);
-static void xsetsel(char *);
+static void xsetsel(char *, Time);
 static void xtermclear(int, int, int, int);
 static void xunloadfont(Font *);
 static void xunloadfonts(void);
@@ -449,7 +449,7 @@ static void selinit(void);
 static void selnormalize(void);
 static inline bool selected(int, int);
 static char *getsel(void);
-static void selcopy(void);
+static void selcopy(Time);
 static void selscroll(int, int);
 static void selsnap(int, int *, int *, int);
 static int x2col(int);
@@ -984,8 +984,8 @@ getsel(void) {
 }
 
 void
-selcopy(void) {
-	xsetsel(getsel());
+selcopy(Time t) {
+	xsetsel(getsel(), t);
 }
 
 void
@@ -997,7 +997,7 @@ selnotify(XEvent *e) {
 	XSelectionEvent *xsev;
 
 	ofs = 0;
-	xsev = (XSelectionEvent *)e;
+	xsev = &e->xselection;
 	if (xsev->property == None)
 	    return;
 	do {
@@ -1083,6 +1083,9 @@ selrequest(XEvent *e) {
 	xev.selection = xsre->selection;
 	xev.target = xsre->target;
 	xev.time = xsre->time;
+        if (xsre->property == None)
+            xsre->property = xsre->target;
+
 	/* reject */
 	xev.property = None;
 
@@ -1125,11 +1128,13 @@ selrequest(XEvent *e) {
 }
 
 void
-xsetsel(char *str) {
+xsetsel(char *str, Time t) {
 	free(sel.primary);
 	sel.primary = str;
 
-	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, CurrentTime);
+	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
+        if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
+            selclear(0);
 }
 
 void
@@ -1146,7 +1151,7 @@ brelease(XEvent *e) {
 			selclear(NULL);
 		} else {
 			getbuttoninfo(e);
-			selcopy();
+			selcopy(e->xbutton.time);
 		}
 		sel.mode = 0;
 		tsetdirt(sel.nb.y, sel.ne.y);

From aff35af275cb82eb876630c9256298ea1d1b2b57 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Tue, 14 Apr 2015 09:53:24 +0200
Subject: [PATCH 0814/1146] Use as command arguments the remaining parameters

This change allows execute st as 'st mutt' while it keeps the
compability with xterm and urxt.
---
 st.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index 40840ce..b1d3791 100644
--- a/st.c
+++ b/st.c
@@ -4008,7 +4008,8 @@ void
 usage(void) {
 	die("%s " VERSION " (c) 2010-2015 st engineers\n" \
 	"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
-	"          [-i] [-t title] [-w windowid] [-e command ...]\n", argv0);
+	"          [-i] [-t title] [-w windowid] [-e command ...] [command ...]\n",
+	argv0);
 }
 
 int
@@ -4027,12 +4028,8 @@ main(int argc, char *argv[]) {
 		opt_class = EARGF(usage());
 		break;
 	case 'e':
-		/* eat all remaining arguments */
-		if(argc > 1) {
-			opt_cmd = &argv[1];
-			if(argv[1] != NULL && opt_title == NULL)
-				opt_title = basename(xstrdup(argv[1]));
-		}
+		if(argc > 1)
+			--argc, ++argv;
 		goto run;
 	case 'f':
 		opt_font = EARGF(usage());
@@ -4059,6 +4056,12 @@ main(int argc, char *argv[]) {
 	} ARGEND;
 
 run:
+	if(argc > 0) {
+		/* eat all remaining arguments */
+		opt_cmd = argv;
+		if(!opt_title)
+			opt_title = basename(xstrdup(argv[0]));
+	}
 	setlocale(LC_CTYPE, "");
 	XSetLocaleModifiers("");
 	tnew(MAX(cols, 1), MAX(rows, 1));

From 56abffb4b67f235d20de30f29ba027ab34c171e3 Mon Sep 17 00:00:00 2001
From: sin <sin@2f30.org>
Date: Wed, 15 Apr 2015 09:43:06 +0100
Subject: [PATCH 0815/1146] Fix memmove() invocation with src/dst being NULL

This fixes a segmentation fault on some systems.
---
 st.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index b1d3791..bb8c365 100644
--- a/st.c
+++ b/st.c
@@ -2788,8 +2788,11 @@ tresize(int col, int row) {
 		free(term.line[i]);
 		free(term.alt[i]);
 	}
-	memmove(term.line, term.line + i, row * sizeof(Line));
-	memmove(term.alt, term.alt + i, row * sizeof(Line));
+	/* 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]);

From 215bdb2da3eca77ba01b70503c527baaad67c359 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 13 Apr 2015 19:03:53 +0200
Subject: [PATCH 0816/1146] Add tty line support

Not always is desirable to create a pseudo terminal, and some times
we want to open a terminal emulator over a tty line. With this new
patch is possible to do someting like:

	$ st -l /dev/ttyS0 115200

Without this option was needed to launch another terminal emulator
over st (for example minicom, picocom, cu, ...).
---
 config.def.h |  1 +
 st.1         | 37 ++++++++++++++++++++++++++++-
 st.c         | 66 ++++++++++++++++++++++++++++++++++++++++++----------
 3 files changed, 91 insertions(+), 13 deletions(-)

diff --git a/config.def.h b/config.def.h
index 5e7caaf..bb5596e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -9,6 +9,7 @@ static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=fals
 static int borderpx = 2;
 static char shell[] = "/bin/sh";
 static char *utmp = NULL;
+static char stty_args[] = "stty raw -echo -iexten echonl";
 
 /* identification sequence returned in DA and DECID */
 static char vtiden[] = "\033[?6c";
diff --git a/st.1 b/st.1
index a9fec15..9548c1a 100644
--- a/st.1
+++ b/st.1
@@ -15,11 +15,36 @@ st \- simple terminal
 .IR file ]
 .RB [ \-t 
 .IR title ]
+.RB [ \-l
+.IR line ]
 .RB [ \-w 
 .IR windowid ]
 .RB [ \-v ]
 .RB [ \-e
 .IR command ...]
+.RI [ commands ...]
+.PP
+.B st
+.RB [ \-a ]
+.RB [ \-c
+.IR class ]
+.RB [ \-f
+.IR font ]
+.RB [ \-g
+.IR geometry ]
+.RB [ \-i ]
+.RB [ \-o
+.IR file ]
+.RB [ \-t
+.IR title ]
+.RB [ \-l
+.IR line ]
+.RB [ \-w
+.IR windowid ]
+.RB [ \-v ]
+.RB [ \-l
+.IR line ]
+.RI [ stty_args ...]
 .SH DESCRIPTION
 .B st
 is a simple terminal emulator.
@@ -58,6 +83,11 @@ defines the window title (default 'st').
 embeds st within the window identified by 
 .I windowid
 .TP
+.BI \-l " line"
+use a tty line instead of a pseudo terminal.
+When this flag is used
+remaining arguments are used as flags for stty.
+.TP
 .B \-v
 prints version information to stderr, then exits.
 .TP
@@ -67,6 +97,9 @@ st executes
 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 compability,
+and all the remaining arguments are used as a command
+even without it.
 .SH SHORTCUTS
 .TP
 .B Ctrl-Print Screen
@@ -110,7 +143,9 @@ 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 tabbed (1),
+.BR utmp (1),
+.BR stty (1)
 .SH BUGS
 See the TODO file in the distribution.
 
diff --git a/st.c b/st.c
index bb8c365..d22c605 100644
--- a/st.c
+++ b/st.c
@@ -352,6 +352,7 @@ static void draw(void);
 static void redraw(void);
 static void drawregion(int, int, int, int);
 static void execsh(void);
+static void stty(void);
 static void sigchld(int);
 static void run(void);
 
@@ -508,6 +509,7 @@ static char *opt_title = NULL;
 static char *opt_embed = NULL;
 static char *opt_class = NULL;
 static char *opt_font = NULL;
+static char *opt_line = NULL;
 static int oldbutton = 3; /* button event on startup: 3 = release */
 
 static char *usedfont = NULL;
@@ -1253,11 +1255,55 @@ sigchld(int a) {
 	exit(EXIT_SUCCESS);
 }
 
+
+void
+stty(void)
+{
+	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 = opt_cmd; p && (s = *p); ++p) {
+		if((n = strlen(s)) > siz-1)
+			die("stty parameter length too long\n");
+		*q++ = ' ';
+		q = memcpy(q, s, n);
+		q += n;
+		siz-= n + 1;
+	}
+	*q = '\0';
+	system(cmd);
+}
+
 void
 ttynew(void) {
 	int m, s;
 	struct winsize w = {term.row, term.col, 0, 0};
 
+	if(opt_io) {
+		term.mode |= MODE_PRINT;
+		iofd = (!strcmp(opt_io, "-")) ?
+			  STDOUT_FILENO :
+			  open(opt_io, O_WRONLY | O_CREAT, 0666);
+		if(iofd < 0) {
+			fprintf(stderr, "Error opening %s:%s\n",
+				opt_io, strerror(errno));
+		}
+	}
+
+	if (opt_line) {
+		if((cmdfd = open(opt_line, O_RDWR)) < 0)
+			die("open line failed: %s\n", strerror(errno));
+		close(STDIN_FILENO);
+		dup(cmdfd);
+		stty();
+		return;
+	}
+
 	/* seems to work fine on linux, openbsd and freebsd */
 	if(openpty(&m, &s, NULL, NULL, &w) < 0)
 		die("openpty failed: %s\n", strerror(errno));
@@ -1267,6 +1313,7 @@ ttynew(void) {
 		die("fork failed\n");
 		break;
 	case 0:
+		close(iofd);
 		setsid(); /* create a new process group */
 		dup2(s, STDIN_FILENO);
 		dup2(s, STDOUT_FILENO);
@@ -1281,16 +1328,6 @@ ttynew(void) {
 		close(s);
 		cmdfd = m;
 		signal(SIGCHLD, sigchld);
-		if(opt_io) {
-			term.mode |= MODE_PRINT;
-			iofd = (!strcmp(opt_io, "-")) ?
-				  STDOUT_FILENO :
-				  open(opt_io, O_WRONLY | O_CREAT, 0666);
-			if(iofd < 0) {
-				fprintf(stderr, "Error opening %s:%s\n",
-					opt_io, strerror(errno));
-			}
-		}
 		break;
 	}
 }
@@ -4009,9 +4046,11 @@ run(void) {
 
 void
 usage(void) {
-	die("%s " VERSION " (c) 2010-2015 st engineers\n" \
+	die("%s " VERSION " (c) 2010-2015 st engineers\n"
 	"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
-	"          [-i] [-t title] [-w windowid] [-e command ...] [command ...]\n",
+	"          [-i] [-t title] [-w windowid] [-e command ...] [command ...]\n"
+	"       st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
+	"          [-i] [-t title] [-w windowid] [-l line] [stty_args ...]\n",
 	argv0);
 }
 
@@ -4047,6 +4086,9 @@ main(int argc, char *argv[]) {
 	case 'o':
 		opt_io = EARGF(usage());
 		break;
+	case 'l':
+		opt_line = EARGF(usage());
+		break;
 	case 't':
 		opt_title = EARGF(usage());
 		break;

From 6ee56d65906362f3f6ade570da0ce9c28788eaf5 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sat, 18 Apr 2015 18:45:21 +0200
Subject: [PATCH 0817/1146] Place tlinelen type on separate line.

---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index d22c605..bf5b675 100644
--- a/st.c
+++ b/st.c
@@ -673,7 +673,8 @@ y2row(int y) {
 	return LIMIT(y, 0, term.row-1);
 }
 
-int tlinelen(int y) {
+int
+tlinelen(int y) {
 	int i = term.col;
 
 	if(term.line[y][i - 1].mode & ATTR_WRAP)

From c27c731b9f77c1b1c99f3bde737be53996809fcb Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sat, 18 Apr 2015 18:46:17 +0200
Subject: [PATCH 0818/1146] Monotonic clock cannot jump backwards.

The check was introduced back when st used gettimeofday.
The condition is also modified to increment the accuaracy of the
calculation.
---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index bf5b675..c7589f4 100644
--- a/st.c
+++ b/st.c
@@ -4003,8 +4003,7 @@ run(void) {
 			dodraw = 1;
 		}
 		deltatime = TIMEDIFF(now, last);
-		if(deltatime > (xev? (1000/xfps) : (1000/actionfps))
-				|| deltatime < 0) {
+		if(deltatime > 1000 / (xev ? xfps : actionfps)) {
 			dodraw = 1;
 			last = now;
 		}

From 6dc2b546eca11b198c64c9047106970a8d1f85e8 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sat, 18 Apr 2015 18:45:48 +0200
Subject: [PATCH 0819/1146] Increment accuaracy in drawtime calculation

This way is a bit more accurate.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index c7589f4..dcb80ca 100644
--- a/st.c
+++ b/st.c
@@ -3992,7 +3992,7 @@ run(void) {
 
 		clock_gettime(CLOCK_MONOTONIC, &now);
 		drawtimeout.tv_sec = 0;
-		drawtimeout.tv_nsec = (1000/xfps) * 1E6;
+		drawtimeout.tv_nsec =  (1000 * 1E6)/ xfps;
 		tv = &drawtimeout;
 
 		dodraw = 0;

From 5528280fae23968ffd3cf0527881cabddc24cf85 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sun, 19 Apr 2015 01:24:12 +0200
Subject: [PATCH 0820/1146] Remove explicit 'return' from 'void' functions.

---
 st.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/st.c b/st.c
index dcb80ca..c67619d 100644
--- a/st.c
+++ b/st.c
@@ -2504,7 +2504,6 @@ tstrsequence(uchar c) {
 	strreset();
 	strescseq.type = c;
 	term.esc |= ESC_STR;
-	return;
 }
 
 void
@@ -2586,7 +2585,6 @@ tcontrolcode(uchar ascii) {
 	}
 	/* only CAN, SUB, \a and C1 chars interrupt a sequence */
 	term.esc &= ~(ESC_STR_END|ESC_STR);
-	return;
 }
 
 /*

From ab69ea89b759eb457b1e5314d5345fdeea3dec87 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sun, 19 Apr 2015 01:24:28 +0200
Subject: [PATCH 0821/1146] Place memset arguments in the correct order.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index c67619d..71b1521 100644
--- a/st.c
+++ b/st.c
@@ -1459,7 +1459,7 @@ treset(void) {
 	term.top = 0;
 	term.bot = term.row - 1;
 	term.mode = MODE_WRAP;
-	memset(term.trantbl, sizeof(term.trantbl), CS_USA);
+	memset(term.trantbl, CS_USA, sizeof(term.trantbl));
 	term.charset = 0;
 
 	for(i = 0; i < 2; i++) {

From 2fdcc5e5f633083eb5e52b201862106a2c547df9 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sat, 18 Apr 2015 19:33:11 +0200
Subject: [PATCH 0822/1146] Remove WIN_REDRAW flag.

WIN_REDRAW flag was not used since introduction of Xdbe
in commit 94771d05886fbdd2422e66b7c0256ab27fa375cb
---
 st.c | 16 ++--------------
 1 file changed, 2 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index 71b1521..c805117 100644
--- a/st.c
+++ b/st.c
@@ -158,8 +158,7 @@ enum escape_state {
 
 enum window_state {
 	WIN_VISIBLE = 1,
-	WIN_REDRAW  = 2,
-	WIN_FOCUSED = 4
+	WIN_FOCUSED = 2
 };
 
 enum selection_type {
@@ -3739,12 +3738,6 @@ drawregion(int x1, int y1, int x2, int y2) {
 
 void
 expose(XEvent *ev) {
-	XExposeEvent *e = &ev->xexpose;
-
-	if(xw.state & WIN_REDRAW) {
-		if(!e->count)
-			xw.state &= ~WIN_REDRAW;
-	}
 	redraw();
 }
 
@@ -3752,12 +3745,7 @@ void
 visibility(XEvent *ev) {
 	XVisibilityEvent *e = &ev->xvisibility;
 
-	if(e->state == VisibilityFullyObscured) {
-		xw.state &= ~WIN_VISIBLE;
-	} else if(!(xw.state & WIN_VISIBLE)) {
-		/* need a full redraw for next Expose, not just a buf copy */
-		xw.state |= WIN_VISIBLE | WIN_REDRAW;
-	}
+	MODBIT(xw.state, e->state != VisibilityFullyObscured, WIN_VISIBLE);
 }
 
 void

From 84c756b97e31ca6946f634dc329ff8026caa6539 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Sun, 19 Apr 2015 22:24:44 +0200
Subject: [PATCH 0823/1146] Use LEN(dc.col) instead of LEN(colorname).

LEN(colorname) may be below 256 for some configurations.
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index c805117..7f08748 100644
--- a/st.c
+++ b/st.c
@@ -2911,7 +2911,7 @@ xloadcols(void) {
 	}
 
 	/* load colors [0-15] and [256-LEN(colorname)] (config.h) */
-	for(i = 0; i < LEN(colorname); i++) {
+	for(i = 0; i < LEN(dc.col); i++) {
 		if(!colorname[i])
 			continue;
 		if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[i], &dc.col[i])) {
@@ -2942,7 +2942,7 @@ xsetcolorname(int x, const char *name) {
 	XRenderColor color = { .alpha = 0xffff };
 	Color ncolor;
 
-	if(!BETWEEN(x, 0, LEN(colorname)))
+	if(!BETWEEN(x, 0, LEN(dc.col)))
 		return 1;
 
 	if(!name) {

From 89807ed453e27893dea5ac73ee2c6b4f8dd15afb Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Tue, 21 Apr 2015 09:48:33 +0200
Subject: [PATCH 0824/1146] Move common code to xloadcolor

---
 st.c | 82 +++++++++++++++++++++---------------------------------------
 1 file changed, 29 insertions(+), 53 deletions(-)

diff --git a/st.c b/st.c
index 7f08748..0204b2e 100644
--- a/st.c
+++ b/st.c
@@ -2898,10 +2898,31 @@ sixd_to_16bit(int x) {
 	return x == 0 ? 0 : 0x3737 + 0x2828 * x;
 }
 
+bool
+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;
-	XRenderColor color = { .alpha = 0xffff };
 	static bool loaded;
 	Color *cp;
 
@@ -2910,70 +2931,25 @@ xloadcols(void) {
 			XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
 	}
 
-	/* load colors [0-15] and [256-LEN(colorname)] (config.h) */
-	for(i = 0; i < LEN(dc.col); i++) {
-		if(!colorname[i])
-			continue;
-		if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[i], &dc.col[i])) {
-			die("Could not allocate color '%s'\n", colorname[i]);
+	for(i = 0; i < LEN(dc.col); 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);
 		}
-	}
-
-	/* load colors [16-231] ; same colors as xterm */
-	for(i = 16; i < 6*6*6+16; i++) {
-		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 );
-		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i]))
-			die("Could not allocate color %d\n", i);
-	}
-
-	/* load colors [232-255] ; grayscale */
-	for(; i < 256; i++) {
-		color.red = color.green = color.blue = 0x0808 + 0x0a0a * (i-(6*6*6+16));
-		if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i]))
-			die("Could not allocate color %d\n", i);
-	}
 	loaded = true;
 }
 
 int
 xsetcolorname(int x, const char *name) {
-	XRenderColor color = { .alpha = 0xffff };
 	Color ncolor;
 
 	if(!BETWEEN(x, 0, LEN(dc.col)))
 		return 1;
 
-	if(!name) {
-		if(BETWEEN(x, 16, 16 + 215)) { /* 256 color */
-			color.red   = sixd_to_16bit( ((x-16)/36)%6 );
-			color.green = sixd_to_16bit( ((x-16)/6) %6 );
-			color.blue  = sixd_to_16bit( ((x-16)/1) %6 );
-			if(!XftColorAllocValue(xw.dpy, xw.vis,
-						xw.cmap, &color, &ncolor)) {
-				return 1;
-			}
 
-			XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
-			dc.col[x] = ncolor;
-			return 0;
-		} else if(BETWEEN(x, 16 + 216, 255)) { /* greyscale */
-			color.red = color.green = color.blue = \
-				    0x0808 + 0x0a0a * (x - (16 + 216));
-			if(!XftColorAllocValue(xw.dpy, xw.vis,
-						xw.cmap, &color, &ncolor)) {
-				return 1;
-			}
-
-			XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
-			dc.col[x] = ncolor;
-			return 0;
-		} else { /* system colors */
-			name = colorname[x];
-		}
-	}
-	if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &ncolor))
+	if(!xloadcolor(x, name, &ncolor))
 		return 1;
 
 	XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);

From 736685d641c23e8b08f3349d64bf30c1c86cd95d Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Tue, 21 Apr 2015 22:09:49 +0200
Subject: [PATCH 0825/1146] Do not set terminal title based on stty arguments.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index c805117..ece1f64 100644
--- a/st.c
+++ b/st.c
@@ -4090,7 +4090,7 @@ run:
 	if(argc > 0) {
 		/* eat all remaining arguments */
 		opt_cmd = argv;
-		if(!opt_title)
+		if(!opt_title && !opt_line)
 			opt_title = basename(xstrdup(argv[0]));
 	}
 	setlocale(LC_CTYPE, "");

From b17aa18f7c15be8db2afd62ac696b63c75755f1c Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 22 Apr 2015 09:16:35 +0200
Subject: [PATCH 0826/1146] Uses a &[] pointer loop instead of + pointer loop

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index ece1f64..5e92db2 100644
--- a/st.c
+++ b/st.c
@@ -2906,7 +2906,7 @@ xloadcols(void) {
 	Color *cp;
 
 	if(loaded) {
-		for (cp = dc.col; cp < dc.col + LEN(dc.col); ++cp)
+		for (cp = dc.col; cp < &dc.col[LEN(dc.col)]; ++cp)
 			XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
 	}
 

From 0d7448dabc981716d277a5afac22fabc127bacca Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 23 Apr 2015 17:55:41 +0200
Subject: [PATCH 0827/1146] Fix segmentation fault in strhandle()

We cannot pass strescseq.args[0] to atoi when nargs is zero,
because in this case it will be null.
---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 5e92db2..f9aba90 100644
--- a/st.c
+++ b/st.c
@@ -2268,8 +2268,7 @@ strhandle(void) {
 
 	term.esc &= ~(ESC_STR_END|ESC_STR);
 	strparse();
-	narg = strescseq.narg;
-	par = atoi(strescseq.args[0]);
+	par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0;
 
 	switch(strescseq.type) {
 	case ']': /* OSC -- Operating System Command */

From 742a41d6554ce1848f45ea89cb83d62c7e881352 Mon Sep 17 00:00:00 2001
From: "alp@alexpilon.ca" <alp@alexpilon.ca>
Date: Tue, 21 Apr 2015 16:27:51 +0200
Subject: [PATCH 0828/1146] Make build shut up about system() without return
 value check.

    st.c:1321:2: warning: ignoring return value of function declared with warn_unused_result attribute [-Wunused-result]
            system(cmd);
            ^~~~~~ ~~~

Debatable whether an error here should case exit(EXIT_FAILURE). Just
preserving the existing behaviour for now.
---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 8e51344..b042be2 100644
--- a/st.c
+++ b/st.c
@@ -1276,7 +1276,8 @@ stty(void)
 		siz-= n + 1;
 	}
 	*q = '\0';
-	system(cmd);
+	if (system(cmd) != 0)
+	    perror("Couldn't call stty");
 }
 
 void

From 61c35cd24625c6d14b4a2de8bd639da52aa513bd Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Tue, 21 Apr 2015 23:27:22 +0200
Subject: [PATCH 0829/1146] Use utf8len instead of utf8decode.

---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index b042be2..6371a85 100644
--- a/st.c
+++ b/st.c
@@ -3672,7 +3672,6 @@ drawregion(int x1, int y1, int x2, int y2) {
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
 	bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
-	long unicodep;
 
 	if(!(xw.state & WIN_VISIBLE))
 		return;
@@ -3701,7 +3700,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 				base = new;
 			}
 
-			sl = utf8decode(new.c, &unicodep, UTF_SIZ);
+			sl = utf8len(new.c);
 			memcpy(buf+ib, new.c, sl);
 			ib += sl;
 			ic += (new.mode & ATTR_WIDE)? 2 : 1;

From 753fe862b14c7dd4b0449ab2c3bf22ecbb10030e Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Tue, 21 Apr 2015 23:28:40 +0200
Subject: [PATCH 0830/1146] Remove last parameter of utf8encode

This parameter was always UTF_SIZ, so it is better remove it and
use directly UTF_SIZ in it.
---
 st.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 6371a85..8ca310c 100644
--- a/st.c
+++ b/st.c
@@ -459,7 +459,7 @@ static void mousereport(XEvent *);
 
 static size_t utf8decode(char *, long *, size_t);
 static long utf8decodebyte(char, size_t *);
-static size_t utf8encode(long, char *, size_t);
+static size_t utf8encode(long, char *);
 static char utf8encodebyte(long, size_t);
 static size_t utf8len(char *);
 static size_t utf8validate(long *, size_t);
@@ -610,11 +610,11 @@ utf8decodebyte(char c, size_t *i) {
 }
 
 size_t
-utf8encode(long u, char *c, size_t clen) {
+utf8encode(long u, char *c) {
 	size_t len, i;
 
 	len = utf8validate(&u, 0);
-	if(clen < len)
+	if(len > UTF_SIZ)
 		return 0;
 	for(i = len - 1; i != 0; --i) {
 		c[i] = utf8encodebyte(u, 0);
@@ -1351,7 +1351,7 @@ ttyread(void) {
 	buflen += ret;
 	ptr = buf;
 	while((charsize = utf8decode(ptr, &unicodep, buflen))) {
-		utf8encode(unicodep, s, UTF_SIZ);
+		utf8encode(unicodep, s);
 		tputc(s, charsize);
 		ptr += charsize;
 		buflen -= charsize;
@@ -3848,7 +3848,7 @@ kpress(XEvent *ev) {
 		if(IS_SET(MODE_8BIT)) {
 			if(*buf < 0177) {
 				c = *buf | 0x80;
-				len = utf8encode(c, buf, UTF_SIZ);
+				len = utf8encode(c, buf);
 			}
 		} else {
 			buf[1] = buf[0];

From 21f765426c36991edd8b14f4989d66187e9ff597 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Tue, 21 Apr 2015 23:29:01 +0200
Subject: [PATCH 0831/1146] Change internal character representation.

---
 st.c | 73 +++++++++++++++++++++++++++++-------------------------------
 1 file changed, 35 insertions(+), 38 deletions(-)

diff --git a/st.c b/st.c
index 8ca310c..2788746 100644
--- a/st.c
+++ b/st.c
@@ -72,6 +72,7 @@ char *argv0;
 #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177')
 #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
 #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
+#define ISDELIM(u) (BETWEEN(u, 0, 127) && strchr(worddelimiters, u) != NULL)
 #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 IS_SET(flag) ((term.mode & (flag)) != 0)
@@ -180,7 +181,7 @@ typedef XftDraw *Draw;
 typedef XftColor Color;
 
 typedef struct {
-	char c[UTF_SIZ]; /* character code */
+	long u;           /* character code */
 	ushort mode;      /* attribute flags */
 	uint32_t fg;      /* foreground  */
 	uint32_t bg;      /* background  */
@@ -410,6 +411,7 @@ static void tstrsequence(uchar);
 
 static inline ushort sixd_to_16bit(int);
 static void xdraws(char *, Glyph, int, int, int, int);
+static void xdrawglyph(Glyph, int, int);
 static void xhints(void);
 static void xclear(int, int, int, int);
 static void xdrawcursor(void);
@@ -461,7 +463,6 @@ static size_t utf8decode(char *, long *, size_t);
 static long utf8decodebyte(char, size_t *);
 static size_t utf8encode(long, char *);
 static char utf8encodebyte(long, size_t);
-static size_t utf8len(char *);
 static size_t utf8validate(long *, size_t);
 
 static ssize_t xwrite(int, const char *, size_t);
@@ -629,11 +630,6 @@ utf8encodebyte(long u, size_t i) {
 	return utfbyte[i] | (u & ~utfmask[i]);
 }
 
-size_t
-utf8len(char *c) {
-	return utf8decode(c, &(long){0}, UTF_SIZ);
-}
-
 size_t
 utf8validate(long *u, size_t i) {
 	if(!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
@@ -679,7 +675,7 @@ tlinelen(int y) {
 	if(term.line[y][i - 1].mode & ATTR_WRAP)
 		return i;
 
-	while(i > 0 && term.line[y][i - 1].c[0] == ' ')
+	while(i > 0 && term.line[y][i - 1].u == ' ')
 		--i;
 
 	return i;
@@ -736,7 +732,7 @@ selsnap(int mode, int *x, int *y, int direction) {
 		 * beginning of a line.
 		 */
 		prevgp = &term.line[*y][*x];
-		prevdelim = strchr(worddelimiters, prevgp->c[0]) != NULL;
+		prevdelim = ISDELIM(prevgp->u);
 		for(;;) {
 			newx = *x + direction;
 			newy = *y;
@@ -758,9 +754,9 @@ selsnap(int mode, int *x, int *y, int direction) {
 				break;
 
 			gp = &term.line[newy][newx];
-			delim = strchr(worddelimiters, gp->c[0]) != NULL;
+			delim = ISDELIM(gp->u);
 			if(!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
-					|| (delim && gp->c[0] != prevgp->c[0])))
+					|| (delim && gp->u != prevgp->u)))
 				break;
 
 			*x = newx;
@@ -936,7 +932,7 @@ bpress(XEvent *e) {
 char *
 getsel(void) {
 	char *str, *ptr;
-	int y, bufsize, size, lastx, linelen;
+	int y, bufsize, lastx, linelen;
 	Glyph *gp, *last;
 
 	if(sel.ob.x == -1)
@@ -957,16 +953,14 @@ getsel(void) {
 			lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
 		}
 		last = &term.line[y][MIN(lastx, linelen-1)];
-		while(last >= gp && last->c[0] == ' ')
+		while(last >= gp && last->u == ' ')
 			--last;
 
 		for( ; gp <= last; ++gp) {
 			if(gp->mode & ATTR_WDUMMY)
 				continue;
 
-			size = utf8len(gp->c);
-			memcpy(ptr, gp->c, size);
-			ptr += size;
+			ptr += utf8encode(gp->u, ptr);
 		}
 
 		/*
@@ -1643,17 +1637,17 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 
 	if(term.line[y][x].mode & ATTR_WIDE) {
 		if(x+1 < term.col) {
-			term.line[y][x+1].c[0] = ' ';
+			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].c[0] = ' ';
+		term.line[y][x-1].u = ' ';
 		term.line[y][x-1].mode &= ~ATTR_WIDE;
 	}
 
 	term.dirty[y] = 1;
 	term.line[y][x] = *attr;
-	memcpy(term.line[y][x].c, c, UTF_SIZ);
+	utf8decode(c, &term.line[y][x].u, UTF_SIZ);
 }
 
 void
@@ -1680,7 +1674,7 @@ tclearregion(int x1, int y1, int x2, int y2) {
 			gp->fg = term.c.attr.fg;
 			gp->bg = term.c.attr.bg;
 			gp->mode = 0;
-			memcpy(gp->c, " ", 2);
+			gp->u = ' ';
 		}
 	}
 }
@@ -2400,13 +2394,14 @@ tdumpsel(void) {
 
 void
 tdumpline(int n) {
+	char buf[UTF_SIZ];
 	Glyph *bp, *end;
 
 	bp = &term.line[n][0];
 	end = &bp[MIN(tlinelen(n), term.col) - 1];
-	if(bp != end || bp->c[0] != ' ') {
+	if(bp != end || bp->u != ' ') {
 		for( ;bp <= end; ++bp)
-			tprinter(bp->c, utf8len(bp->c));
+			tprinter(buf, utf8encode(bp->u, buf));
 	}
 	tprinter("\n", 1);
 }
@@ -2789,7 +2784,7 @@ tputc(char *c, int len) {
 	if(width == 2) {
 		gp->mode |= ATTR_WIDE;
 		if(term.c.x+1 < term.col) {
-			gp[1].c[0] = '\0';
+			gp[1].u = '\0';
 			gp[1].mode = ATTR_WDUMMY;
 		}
 	}
@@ -3552,11 +3547,20 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	XftDrawSetClip(xw.draw, 0);
 }
 
+void
+xdrawglyph(Glyph g, int x, int y) {
+	static char buf[UTF_SIZ];
+	size_t len = utf8encode(g.u, buf);
+	int width = g.mode & ATTR_WIDE ? 2 : 1;
+
+	xdraws(buf, g, x, y, width, len);
+}
+
 void
 xdrawcursor(void) {
 	static int oldx = 0, oldy = 0;
-	int sl, width, curx;
-	Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs};
+	int curx;
+	Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs};
 
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
@@ -3569,13 +3573,10 @@ xdrawcursor(void) {
 	if(term.line[term.c.y][curx].mode & ATTR_WDUMMY)
 		curx--;
 
-	memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
+	g.u = term.line[term.c.y][term.c.x].u;
 
 	/* remove the old cursor */
-	sl = utf8len(term.line[oldy][oldx].c);
-	width = (term.line[oldy][oldx].mode & ATTR_WIDE)? 2 : 1;
-	xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx,
-			oldy, width, sl);
+	xdrawglyph(term.line[oldy][oldx], oldx, oldy);
 
 	if(IS_SET(MODE_HIDE))
 		return;
@@ -3592,10 +3593,8 @@ xdrawcursor(void) {
 						g.bg = defaultfg;
 					}
 
-				sl = utf8len(g.c);
-				width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\
-					? 2 : 1;
-				xdraws(g.c, g, term.c.x, term.c.y, width, sl);
+				g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE;
+				xdrawglyph(g, term.c.x, term.c.y);
 				break;
 			case 3: /* Blinking Underline */
 			case 4: /* Steady Underline */
@@ -3668,7 +3667,7 @@ draw(void) {
 
 void
 drawregion(int x1, int y1, int x2, int y2) {
-	int ic, ib, x, y, ox, sl;
+	int ic, ib, x, y, ox;
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
 	bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
@@ -3700,9 +3699,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 				base = new;
 			}
 
-			sl = utf8len(new.c);
-			memcpy(buf+ib, new.c, sl);
-			ib += sl;
+			ib += utf8encode(new.u, buf+ib);
 			ic += (new.mode & ATTR_WIDE)? 2 : 1;
 		}
 		if(ib > 0)

From 0622ad9badefa985231ddede467d2bd8d94e93e4 Mon Sep 17 00:00:00 2001
From: "noname@inventati.org" <noname@inventati.org>
Date: Tue, 21 Apr 2015 23:29:15 +0200
Subject: [PATCH 0832/1146] Make tputc, tsetchar and techo accept unicode

---
 st.c | 107 +++++++++++++++++++++++++----------------------------------
 1 file changed, 45 insertions(+), 62 deletions(-)

diff --git a/st.c b/st.c
index 2788746..f527858 100644
--- a/st.c
+++ b/st.c
@@ -383,20 +383,20 @@ static void tmoveato(int, int);
 static void tnew(int, int);
 static void tnewline(int);
 static void tputtab(int);
-static void tputc(char *, int);
+static void tputc(long);
 static void treset(void);
 static void tresize(int, int);
 static void tscrollup(int, int);
 static void tscrolldown(int, int);
 static void tsetattr(int *, int);
-static void tsetchar(char *, Glyph *, int, int);
+static void tsetchar(long, Glyph *, int, int);
 static void tsetscroll(int, int);
 static void tswapscreen(void);
 static void tsetdirt(int, int);
 static void tsetdirtattr(int);
 static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
-static void techo(char *, int);
+static void techo(long);
 static void tcontrolcode(uchar );
 static void tdectest(char );
 static int32_t tdefcolor(int *, int *, int);
@@ -1332,7 +1332,6 @@ ttyread(void) {
 	static char buf[BUFSIZ];
 	static int buflen = 0;
 	char *ptr;
-	char s[UTF_SIZ];
 	int charsize; /* size of utf8 char in bytes */
 	long unicodep;
 	int ret;
@@ -1345,8 +1344,7 @@ ttyread(void) {
 	buflen += ret;
 	ptr = buf;
 	while((charsize = utf8decode(ptr, &unicodep, buflen))) {
-		utf8encode(unicodep, s);
-		tputc(s, charsize);
+		tputc(unicodep);
 		ptr += charsize;
 		buflen -= charsize;
 	}
@@ -1363,9 +1361,16 @@ ttywrite(const char *s, size_t n) {
 
 void
 ttysend(char *s, size_t n) {
+	int len;
+	long u;
+
 	ttywrite(s, n);
 	if(IS_SET(MODE_ECHO))
-		techo(s, n);
+		while((len = utf8decode(s, &u, n)) > 0) {
+			techo(u);
+			n -= len;
+			s += len;
+		}
 }
 
 void
@@ -1614,7 +1619,7 @@ tmoveto(int x, int y) {
 }
 
 void
-tsetchar(char *c, Glyph *attr, int x, int y) {
+tsetchar(long u, Glyph *attr, int x, int y) {
 	static char *vt100_0[62] = { /* 0x41 - 0x7e */
 		"↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */
 		0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
@@ -1629,11 +1634,9 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 	/*
 	 * The table is proudly stolen from rxvt.
 	 */
-	if(term.trantbl[term.charset] == CS_GRAPHIC0) {
-		if(BETWEEN(c[0], 0x41, 0x7e) && vt100_0[c[0] - 0x41]) {
-			c = vt100_0[c[0] - 0x41];
-		}
-	}
+	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) {
@@ -1647,7 +1650,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 
 	term.dirty[y] = 1;
 	term.line[y][x] = *attr;
-	utf8decode(c, &term.line[y][x].u, UTF_SIZ);
+	term.line[y][x].u = u;
 }
 
 void
@@ -2431,26 +2434,18 @@ tputtab(int n) {
 }
 
 void
-techo(char *buf, int len) {
-	for(; len > 0; buf++, len--) {
-		char c = *buf;
-
-		if(ISCONTROL((uchar) c)) { /* control code */
-			if(c & 0x80) {
-				c &= 0x7f;
-				tputc("^", 1);
-				tputc("[", 1);
-			} else if(c != '\n' && c != '\r' && c != '\t') {
-				c ^= 0x40;
-				tputc("^", 1);
-			}
-			tputc(&c, 1);
-		} else {
-			break;
+techo(long u) {
+	if(ISCONTROL(u)) { /* control code */
+		if(u & 0x80) {
+			u &= 0x7f;
+			tputc('^');
+			tputc('[');
+		} else if(u != '\n' && u != '\r' && u != '\t') {
+			u ^= 0x40;
+			tputc('^');
 		}
 	}
-	if(len)
-		tputc(buf, len);
+	tputc(u);
 }
 
 void
@@ -2468,13 +2463,12 @@ tdeftran(char ascii) {
 
 void
 tdectest(char c) {
-	static char E[UTF_SIZ] = "E";
 	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);
+				tsetchar('E', &term.c.attr, x, y);
 		}
 	}
 }
@@ -2502,8 +2496,6 @@ tstrsequence(uchar c) {
 
 void
 tcontrolcode(uchar ascii) {
-	static char question[UTF_SIZ] = "?";
-
 	switch(ascii) {
 	case '\t':   /* HT */
 		tputtab(1);
@@ -2541,7 +2533,7 @@ tcontrolcode(uchar ascii) {
 		term.charset = 1 - (ascii - '\016');
 		return;
 	case '\032': /* SUB */
-		tsetchar(question, &term.c.attr, term.c.x, term.c.y);
+		tsetchar('?', &term.c.attr, term.c.x, term.c.y);
 	case '\030': /* CAN */
 		csireset();
 		break;
@@ -2665,28 +2657,21 @@ eschandle(uchar ascii) {
 }
 
 void
-tputc(char *c, int len) {
-	uchar ascii;
+tputc(long u) {
+	char c[UTF_SIZ];
 	bool control;
-	long unicodep;
-	int width;
+	int width, len;
 	Glyph *gp;
 
-	if(len == 1) {
+	len = utf8encode(u, c);
+	if((width = wcwidth(u)) == -1) {
+		memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
 		width = 1;
-		unicodep = ascii = *c;
-	} else {
-		utf8decode(c, &unicodep, UTF_SIZ);
-		if ((width = wcwidth(unicodep)) == -1) {
-			c = "\357\277\275";	/* UTF_INVALID */
-			width = 1;
-		}
-		ascii = unicodep;
 	}
 
 	if(IS_SET(MODE_PRINT))
 		tprinter(c, len);
-	control = ISCONTROL(unicodep);
+	control = ISCONTROL(u);
 
 	/*
 	 * STR sequence must be checked before anything else
@@ -2695,10 +2680,8 @@ tputc(char *c, int len) {
 	 * character.
 	 */
 	if(term.esc & ESC_STR) {
-		if(len == 1 &&
-		   (ascii == '\a' || ascii == 030 ||
-		    ascii == 032  || ascii == 033 ||
-		    ISCONTROLC1(unicodep))) {
+		if(u == '\a' || u == 030 || u == 032 || u == 033 ||
+		   ISCONTROLC1(u)) {
 			term.esc &= ~(ESC_START|ESC_STR);
 			term.esc |= ESC_STR_END;
 		} else if(strescseq.len + len < sizeof(strescseq.buf) - 1) {
@@ -2729,15 +2712,15 @@ tputc(char *c, int len) {
 	 * they must not cause conflicts with sequences.
 	 */
 	if(control) {
-		tcontrolcode(ascii);
+		tcontrolcode(u);
 		/*
 		 * control codes are not shown ever
 		 */
 		return;
 	} else if(term.esc & ESC_START) {
 		if(term.esc & ESC_CSI) {
-			csiescseq.buf[csiescseq.len++] = ascii;
-			if(BETWEEN(ascii, 0x40, 0x7E)
+			csiescseq.buf[csiescseq.len++] = u;
+			if(BETWEEN(u, 0x40, 0x7E)
 					|| csiescseq.len >= \
 					sizeof(csiescseq.buf)-1) {
 				term.esc = 0;
@@ -2746,11 +2729,11 @@ tputc(char *c, int len) {
 			}
 			return;
 		} else if(term.esc & ESC_ALTCHARSET) {
-			tdeftran(ascii);
+			tdeftran(u);
 		} else if(term.esc & ESC_TEST) {
-			tdectest(ascii);
+			tdectest(u);
 		} else {
-			if (!eschandle(ascii))
+			if (!eschandle(u))
 				return;
 			/* sequence already finished */
 		}
@@ -2779,7 +2762,7 @@ tputc(char *c, int len) {
 		gp = &term.line[term.c.y][term.c.x];
 	}
 
-	tsetchar(c, &term.c.attr, term.c.x, term.c.y);
+	tsetchar(u, &term.c.attr, term.c.x, term.c.y);
 
 	if(width == 2) {
 		gp->mode |= ATTR_WIDE;

From 7ab6c92e18d468968811256e808b02309c160a22 Mon Sep 17 00:00:00 2001
From: suigin <suigin@national.shitposting.agency>
Date: Mon, 27 Apr 2015 10:04:04 +0200
Subject: [PATCH 0833/1146] Optimize memory footprint of line buffers

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index f527858..60c07d0 100644
--- a/st.c
+++ b/st.c
@@ -183,8 +183,8 @@ typedef XftColor Color;
 typedef struct {
 	long u;           /* character code */
 	ushort mode;      /* attribute flags */
-	uint32_t fg;      /* foreground  */
-	uint32_t bg;      /* background  */
+	ushort fg;        /* foreground  */
+	ushort bg;        /* background  */
 } Glyph;
 
 typedef Glyph *Line;

From 3a5053f6c19195df5fde84a7e5eb3217443bb9ab Mon Sep 17 00:00:00 2001
From: "mvdan@mvdan.cc" <mvdan@mvdan.cc>
Date: Wed, 22 Apr 2015 15:07:59 +0200
Subject: [PATCH 0834/1146] Use %u for uint
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 60c07d0..6f8d83f 100644
--- a/st.c
+++ b/st.c
@@ -1744,7 +1744,7 @@ tdefcolor(int *attr, int *npar, int l) {
 		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 (%d,%d,%d)\n",
+			fprintf(stderr, "erresc: bad rgb color (%u,%u,%u)\n",
 				r, g, b);
 		else
 			idx = TRUECOLOR(r, g, b);

From 4f21c41a1c19f769a2bf7941ee18fa0606266cca Mon Sep 17 00:00:00 2001
From: "mvdan@mvdan.cc" <mvdan@mvdan.cc>
Date: Wed, 22 Apr 2015 15:08:00 +0200
Subject: [PATCH 0835/1146] Clarify calculation precedence for '&' and '?'
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 6f8d83f..6c167b5 100644
--- a/st.c
+++ b/st.c
@@ -855,9 +855,9 @@ mousereport(XEvent *e) {
 	}
 
 	if(!IS_SET(MODE_MOUSEX10)) {
-		button += (state & ShiftMask   ? 4  : 0)
-			+ (state & Mod4Mask    ? 8  : 0)
-			+ (state & ControlMask ? 16 : 0);
+		button += ((state & ShiftMask  ) ? 4  : 0)
+			+ ((state & Mod4Mask   ) ? 8  : 0)
+			+ ((state & ControlMask) ? 16 : 0);
 	}
 
 	len = 0;

From 190b94c7a2a7bb2f5d55cbb6eb1779fd042c6467 Mon Sep 17 00:00:00 2001
From: "mvdan@mvdan.cc" <mvdan@mvdan.cc>
Date: Wed, 22 Apr 2015 15:08:06 +0200
Subject: [PATCH 0836/1146] len assignment is never used
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
---
 st.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.c b/st.c
index 6c167b5..d954288 100644
--- a/st.c
+++ b/st.c
@@ -860,7 +860,6 @@ mousereport(XEvent *e) {
 			+ ((state & ControlMask) ? 16 : 0);
 	}
 
-	len = 0;
 	if(IS_SET(MODE_MOUSESGR)) {
 		len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
 				button, x+1, y+1,

From 07ce96a3a0f4a650933f5f586082cbf2064ea2c1 Mon Sep 17 00:00:00 2001
From: Jochen Sprickerhof <dwm@jochen.sprickerhof.de>
Date: Wed, 22 Apr 2015 17:22:34 +0200
Subject: [PATCH 0837/1146] Fix sigchld

Only wait for termination of the shell.
---
 st.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index d954288..300cab6 100644
--- a/st.c
+++ b/st.c
@@ -1238,10 +1238,14 @@ execsh(void) {
 void
 sigchld(int a) {
 	int stat, ret;
+	pid_t p;
 
-	if(waitpid(pid, &stat, 0) < 0)
+	if((p = waitpid(pid, &stat, WNOHANG)) < 0)
 		die("Waiting for pid %hd failed: %s\n", pid, strerror(errno));
 
+	if(pid != p)
+		return;
+
 	ret = WIFEXITED(stat) ? WEXITSTATUS(stat) : EXIT_FAILURE;
 	if (ret != EXIT_SUCCESS)
 		die("child finished with error '%d'\n", stat);

From 765bb0fd1420e36b04ecc03c18f01f5bda96c563 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Thu, 30 Apr 2015 20:51:35 +0000
Subject: [PATCH 0838/1146] Remove first argument of selsnap.

---
 st.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 300cab6..87f3ed2 100644
--- a/st.c
+++ b/st.c
@@ -453,7 +453,7 @@ static inline bool selected(int, int);
 static char *getsel(void);
 static void selcopy(Time);
 static void selscroll(int, int);
-static void selsnap(int, int *, int *, int);
+static void selsnap(int *, int *, int);
 static int x2col(int);
 static int y2row(int);
 static void getbuttoninfo(XEvent *);
@@ -695,8 +695,8 @@ selnormalize(void) {
 	sel.nb.y = MIN(sel.ob.y, sel.oe.y);
 	sel.ne.y = MAX(sel.ob.y, sel.oe.y);
 
-	selsnap(sel.snap, &sel.nb.x, &sel.nb.y, -1);
-	selsnap(sel.snap, &sel.ne.x, &sel.ne.y, +1);
+	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)
@@ -720,12 +720,12 @@ selected(int x, int y) {
 }
 
 void
-selsnap(int mode, int *x, int *y, int direction) {
+selsnap(int *x, int *y, int direction) {
 	int newx, newy, xt, yt;
 	bool delim, prevdelim;
 	Glyph *gp, *prevgp;
 
-	switch(mode) {
+	switch(sel.snap) {
 	case SNAP_WORD:
 		/*
 		 * Snap around if the word wraps around at the end or

From 8751809aff596fc2030026713651c11b3743f88e Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Fri, 1 May 2015 02:22:32 +0000
Subject: [PATCH 0839/1146] selsnap: simplify SNAP_LINE case

Also make sure y never exceeds term.row-1 even if ATTR_WRAP is set for
some reason.
---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 87f3ed2..789e795 100644
--- a/st.c
+++ b/st.c
@@ -772,15 +772,15 @@ selsnap(int *x, int *y, int direction) {
 		 * previous line will be selected.
 		 */
 		*x = (direction < 0) ? 0 : term.col - 1;
-		if(direction < 0 && *y > 0) {
+		if(direction < 0) {
 			for(; *y > 0; *y += direction) {
 				if(!(term.line[*y-1][term.col-1].mode
 						& ATTR_WRAP)) {
 					break;
 				}
 			}
-		} else if(direction > 0 && *y < term.row-1) {
-			for(; *y < term.row; *y += direction) {
+		} else if(direction > 0) {
+			for(; *y < term.row-1; *y += direction) {
 				if(!(term.line[*y][term.col-1].mode
 						& ATTR_WRAP)) {
 					break;

From 22571ea4e8729efee6940b704666566b46e42e76 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Thu, 30 Apr 2015 19:59:24 +0000
Subject: [PATCH 0840/1146] selnormalize: make special case explicit

Special case is when regular selection spans multiple lines.
Otherwise, just sort sel.ob.x and sel.ob.y.
---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 789e795..6138817 100644
--- a/st.c
+++ b/st.c
@@ -685,12 +685,12 @@ void
 selnormalize(void) {
 	int i;
 
-	if(sel.ob.y == sel.oe.y || sel.type == SEL_RECTANGULAR) {
-		sel.nb.x = MIN(sel.ob.x, sel.oe.x);
-		sel.ne.x = MAX(sel.ob.x, sel.oe.x);
-	} else {
+	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);

From 1811b6030cd9ac6bb938449eef778c6f54ab0e49 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Fri, 1 May 2015 17:13:13 +0000
Subject: [PATCH 0841/1146] Add enumeration for sel.mode

This patch also prevents sel.mode from increasing beyond 2. It is almost
impossible, but sel.mode may overflow if mouse is moved around for too
long while selecting.
---
 st.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index 6138817..d6dd4de 100644
--- a/st.c
+++ b/st.c
@@ -162,6 +162,12 @@ enum window_state {
 	WIN_FOCUSED = 2
 };
 
+enum selection_mode {
+	SEL_IDLE = 0,
+	SEL_EMPTY = 1,
+	SEL_READY = 2
+};
+
 enum selection_type {
 	SEL_REGULAR = 1,
 	SEL_RECTANGULAR = 2
@@ -643,7 +649,7 @@ void
 selinit(void) {
 	memset(&sel.tclick1, 0, sizeof(sel.tclick1));
 	memset(&sel.tclick2, 0, sizeof(sel.tclick2));
-	sel.mode = 0;
+	sel.mode = SEL_IDLE;
 	sel.ob.x = -1;
 	sel.primary = NULL;
 	sel.clipboard = NULL;
@@ -897,7 +903,7 @@ bpress(XEvent *e) {
 
 		/* Clear previous selection, logically and visually. */
 		selclear(NULL);
-		sel.mode = 1;
+		sel.mode = SEL_EMPTY;
 		sel.type = SEL_REGULAR;
 		sel.oe.x = sel.ob.x = x2col(e->xbutton.x);
 		sel.oe.y = sel.ob.y = y2row(e->xbutton.y);
@@ -920,7 +926,7 @@ bpress(XEvent *e) {
 		 * make clicks visible
 		 */
 		if(sel.snap != 0) {
-			sel.mode++;
+			sel.mode = SEL_READY;
 			tsetdirt(sel.nb.y, sel.ne.y);
 		}
 		sel.tclick2 = sel.tclick1;
@@ -1142,13 +1148,12 @@ brelease(XEvent *e) {
 	if(e->xbutton.button == Button2) {
 		selpaste(NULL);
 	} else if(e->xbutton.button == Button1) {
-		if(sel.mode < 2) {
-			selclear(NULL);
-		} else {
+		if(sel.mode == SEL_READY) {
 			getbuttoninfo(e);
 			selcopy(e->xbutton.time);
-		}
-		sel.mode = 0;
+		} else
+			selclear(NULL);
+		sel.mode = SEL_IDLE;
 		tsetdirt(sel.nb.y, sel.ne.y);
 	}
 }
@@ -1165,7 +1170,7 @@ bmotion(XEvent *e) {
 	if(!sel.mode)
 		return;
 
-	sel.mode++;
+	sel.mode = SEL_READY;
 	oldey = sel.oe.y;
 	oldex = sel.oe.x;
 	oldsby = sel.nb.y;

From 3cb7f27afe89c33c74b51c5460b7fb16413f786b Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sun, 3 May 2015 02:49:23 +0000
Subject: [PATCH 0842/1146] Fix indentation.

---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index d6dd4de..cf6556a 100644
--- a/st.c
+++ b/st.c
@@ -1084,8 +1084,8 @@ selrequest(XEvent *e) {
 	xev.selection = xsre->selection;
 	xev.target = xsre->target;
 	xev.time = xsre->time;
-        if (xsre->property == None)
-            xsre->property = xsre->target;
+	if (xsre->property == None)
+		xsre->property = xsre->target;
 
 	/* reject */
 	xev.property = None;
@@ -1134,8 +1134,8 @@ xsetsel(char *str, Time t) {
 	sel.primary = str;
 
 	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
-        if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
-            selclear(0);
+	if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
+		selclear(0);
 }
 
 void

From c990abfedf56cb8d3176fe6d5152ff65bb68bff0 Mon Sep 17 00:00:00 2001
From: noname <noname@inventati.org>
Date: Sun, 3 May 2015 19:28:10 +0000
Subject: [PATCH 0843/1146] Fix empty selection highlighting bug.

When user clicks LMB, one character is selected, but will not be copied
to selection until the user moves cursor a bit. Therefore, the character
should not be highlighted as selected yet.

Before the patch, the trick was not to mark line as dirty to avoid
highlighting it. However, if user has already selected something and
clicks in line that contains selection, selclear sets the line as dirty
and one character is highlighted when it should not.

This patch replaces dirty trick with explicit check for sel.mode inside
selected().
---
 st.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index cf6556a..3eb66fa 100644
--- a/st.c
+++ b/st.c
@@ -716,6 +716,9 @@ selnormalize(void) {
 
 bool
 selected(int x, int y) {
+	if(sel.mode == SEL_EMPTY)
+		return false;
+
 	if(sel.type == SEL_RECTANGULAR)
 		return BETWEEN(y, sel.nb.y, sel.ne.y)
 		    && BETWEEN(x, sel.nb.x, sel.ne.x);
@@ -921,14 +924,9 @@ bpress(XEvent *e) {
 		}
 		selnormalize();
 
-		/*
-		 * Draw selection, unless it's regular and we don't want to
-		 * make clicks visible
-		 */
-		if(sel.snap != 0) {
+		if(sel.snap != 0)
 			sel.mode = SEL_READY;
-			tsetdirt(sel.nb.y, sel.ne.y);
-		}
+		tsetdirt(sel.nb.y, sel.ne.y);
 		sel.tclick2 = sel.tclick1;
 		sel.tclick1 = now;
 	}

From 38af006b5e4a36c77f25affbb3f7e28899db75ed Mon Sep 17 00:00:00 2001
From: suigin <suigin@national.shitposting.agency>
Date: Tue, 5 May 2015 13:13:21 -0700
Subject: [PATCH 0844/1146] Changed type for UTF-32 codepoints from long to
 uint_least32_t

---
 st.c | 52 +++++++++++++++++++++++++++-------------------------
 1 file changed, 27 insertions(+), 25 deletions(-)

diff --git a/st.c b/st.c
index 3eb66fa..4add638 100644
--- a/st.c
+++ b/st.c
@@ -183,11 +183,13 @@ typedef unsigned int uint;
 typedef unsigned long ulong;
 typedef unsigned short ushort;
 
+typedef uint_least32_t Rune;
+
 typedef XftDraw *Draw;
 typedef XftColor Color;
 
 typedef struct {
-	long u;           /* character code */
+	Rune u;           /* character code */
 	ushort mode;      /* attribute flags */
 	ushort fg;        /* foreground  */
 	ushort bg;        /* background  */
@@ -389,20 +391,20 @@ static void tmoveato(int, int);
 static void tnew(int, int);
 static void tnewline(int);
 static void tputtab(int);
-static void tputc(long);
+static void tputc(Rune);
 static void treset(void);
 static void tresize(int, int);
 static void tscrollup(int, int);
 static void tscrolldown(int, int);
 static void tsetattr(int *, int);
-static void tsetchar(long, Glyph *, int, int);
+static void tsetchar(Rune, Glyph *, int, int);
 static void tsetscroll(int, int);
 static void tswapscreen(void);
 static void tsetdirt(int, int);
 static void tsetdirtattr(int);
 static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
-static void techo(long);
+static void techo(Rune);
 static void tcontrolcode(uchar );
 static void tdectest(char );
 static int32_t tdefcolor(int *, int *, int);
@@ -465,11 +467,11 @@ static int y2row(int);
 static void getbuttoninfo(XEvent *);
 static void mousereport(XEvent *);
 
-static size_t utf8decode(char *, long *, size_t);
-static long utf8decodebyte(char, size_t *);
-static size_t utf8encode(long, char *);
-static char utf8encodebyte(long, size_t);
-static size_t utf8validate(long *, size_t);
+static size_t utf8decode(char *, Rune *, size_t);
+static Rune utf8decodebyte(char, size_t *);
+static size_t utf8encode(Rune, char *);
+static char utf8encodebyte(Rune, size_t);
+static size_t utf8validate(Rune *, size_t);
 
 static ssize_t xwrite(int, const char *, size_t);
 static void *xmalloc(size_t);
@@ -524,8 +526,8 @@ static double defaultfontsize = 0;
 
 static uchar utfbyte[UTF_SIZ + 1] = {0x80,    0, 0xC0, 0xE0, 0xF0};
 static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
-static long utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  0x10000};
-static long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
+static Rune utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  0x10000};
+static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
 
 /* Font Ring Cache */
 enum {
@@ -538,7 +540,7 @@ enum {
 typedef struct {
 	XftFont *font;
 	int flags;
-	long unicodep;
+	Rune unicodep;
 } Fontcache;
 
 /* Fontcache is an array now. A new font will be appended to the array. */
@@ -586,9 +588,9 @@ xstrdup(char *s) {
 }
 
 size_t
-utf8decode(char *c, long *u, size_t clen) {
+utf8decode(char *c, Rune *u, size_t clen) {
 	size_t i, j, len, type;
-	long udecoded;
+	Rune udecoded;
 
 	*u = UTF_INVALID;
 	if(!clen)
@@ -608,7 +610,7 @@ utf8decode(char *c, long *u, size_t clen) {
 	return len;
 }
 
-long
+Rune
 utf8decodebyte(char c, size_t *i) {
 	for(*i = 0; *i < LEN(utfmask); ++(*i))
 		if(((uchar)c & utfmask[*i]) == utfbyte[*i])
@@ -617,7 +619,7 @@ utf8decodebyte(char c, size_t *i) {
 }
 
 size_t
-utf8encode(long u, char *c) {
+utf8encode(Rune u, char *c) {
 	size_t len, i;
 
 	len = utf8validate(&u, 0);
@@ -632,12 +634,12 @@ utf8encode(long u, char *c) {
 }
 
 char
-utf8encodebyte(long u, size_t i) {
+utf8encodebyte(Rune u, size_t i) {
 	return utfbyte[i] | (u & ~utfmask[i]);
 }
 
 size_t
-utf8validate(long *u, size_t i) {
+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)
@@ -1339,7 +1341,7 @@ ttyread(void) {
 	static int buflen = 0;
 	char *ptr;
 	int charsize; /* size of utf8 char in bytes */
-	long unicodep;
+	Rune unicodep;
 	int ret;
 
 	/* append read bytes to unprocessed bytes */
@@ -1368,7 +1370,7 @@ ttywrite(const char *s, size_t n) {
 void
 ttysend(char *s, size_t n) {
 	int len;
-	long u;
+	Rune u;
 
 	ttywrite(s, n);
 	if(IS_SET(MODE_ECHO))
@@ -1625,7 +1627,7 @@ tmoveto(int x, int y) {
 }
 
 void
-tsetchar(long u, Glyph *attr, int x, int y) {
+tsetchar(Rune u, Glyph *attr, int x, int y) {
 	static char *vt100_0[62] = { /* 0x41 - 0x7e */
 		"↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */
 		0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
@@ -2440,7 +2442,7 @@ tputtab(int n) {
 }
 
 void
-techo(long u) {
+techo(Rune u) {
 	if(ISCONTROL(u)) { /* control code */
 		if(u & 0x80) {
 			u &= 0x7f;
@@ -2663,7 +2665,7 @@ eschandle(uchar ascii) {
 }
 
 void
-tputc(long u) {
+tputc(Rune u) {
 	char c[UTF_SIZ];
 	bool control;
 	int width, len;
@@ -3262,7 +3264,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	int frcflags, charexists;
 	int u8fl, u8fblen, u8cblen, doesexist;
 	char *u8c, *u8fs;
-	long unicodep;
+	Rune unicodep;
 	Font *font = &dc.font;
 	FcResult fcres;
 	FcPattern *fcpattern, *fontpattern;
@@ -3805,7 +3807,7 @@ kpress(XEvent *ev) {
 	KeySym ksym;
 	char buf[32], *customkey;
 	int len;
-	long c;
+	Rune c;
 	Status status;
 	Shortcut *bp;
 

From ae1923d27533ff46400d93765e971558201ca1ee Mon Sep 17 00:00:00 2001
From: suigin <suigin@national.shitposting.agency>
Date: Tue, 5 May 2015 20:24:00 -0700
Subject: [PATCH 0845/1146] Clean up xdraws and optimize glyph drawing with
 non-unit kerning values

I have another patch here for review that optimizes the performance of
glyph drawing, primarily when using non-unit kerning values, and fixes a
few other minor issues. It's dependent on the earlier patch from me that
stores unicode codepoints in a Rune type, typedef'd to uint_least32_t.

This patch is a pretty big change to xdraws so your scrutiny is
appreciated.

First, some performance numbers. I used Yu-Jie Lin termfps.sh shell
script to benchmark before and after, and you can find it in the
attachments. On my Kaveri A10 7850k machine, I get the following
results:

Before Patch
============

1) Font: "Liberation Mono:pixelsize=12:antialias=false:autohint=false"
   cwscale: 1.0, chscale: 1.0
   For 273x83 100 frames.
   Elapsed time :     1.553
   Frames/second:    64.352
   Chars /second: 1,458,159

2) Font: "Inconsolata:pixelsize=14:antialias=true:autohint=true"
   cwscale: 1.001, chscale: 1.001
   For 239x73 100 frames.
   Elapsed time :   159.286
   Frames/second:     0.627
   Chars /second:    10,953

After Patch
===========

3) Font: "Liberation Mono:pixelsize=12:antialias=false:autohint=false"
   cwscale: 1.0, chscale: 1.0
   For 273x83 100 frames.
   Elapsed time :     1.544
   Frames/second:    64.728
   Chars /second: 1,466,690

4) Font: "Inconsolata:pixelsize=14:antialias=true:autohint=true"
   cwscale: 1.001, chscale: 1.001
   For 239x73 100 frames.
   Elapsed time :     1.955
   Frames/second:    51.146
   Chars /second:   892,361

As you can see, while the improvements for fonts with unit-kerning is
marginal, there's a huge ~81x performance increase with the patch when
using kerning values other than 1.0.

So what does the patch do?

The `xdraws' function would render each glyph one at a time if non-unit
kerning values were configured, and this was the primary cause of the
slow down. Xft provides a handful of functions which allow you to render
multiple characters or glyphs at time, each with a unique <x,y> position,
so it was simply a matter of massaging the data into a format that would
allow us to use one of these functions.

I've split `xdraws' up into two functions. In the first pass with
`xmakeglyphfontspecs' it will iterate over all of the glyphs in a given
row and it will build up an array of corresponding XftGlyphFontSpec
records. Much of the old logic for resolving fonts for glyphs using Xft
and fontconfig went into this function.

The second pass is done with `xrenderglyphfontspecs' which contains the
old logic for determining colors, clearing the background, and finally
rendering the array of XftGlyphFontSpec records.

There's a couple of other things that have been improved by this patch.
For instance, the UTF-32 codepoints in the Line's were being re-encoded
back into UTF-8 strings to be passed to `xdraws' which in turn would then
decode back to UTF-32 to verify that the Font contained a matching glyph
for the code point. Next, the UTF-8 string was being passed to
`XftDrawStringUtf8' which internally mallocs a scratch buffer and decodes
back to UTF-32 and does the lookup of the glyphs all over again.

This patch gets rid of all of this redundant round-trip encoding and
decoding of characters to be rendered and only looks up the glyph index
once (per font) during the font resolution phase. So this is probably
what's responsible for the marginal improvements seen when kerning values
are kept to 1.0.

I imagine there are other performance improvements here too, not seen in
the above benchmarks, if the user has lots of non-ASCII code plane characters
on the screen, or several different fonts are being utilized during
screen redraw.

Anyway, if you see any problems, please let me know and I can fix them.
---
 st.c | 383 +++++++++++++++++++++++++++++------------------------------
 1 file changed, 187 insertions(+), 196 deletions(-)

diff --git a/st.c b/st.c
index 4add638..c2da66b 100644
--- a/st.c
+++ b/st.c
@@ -58,7 +58,6 @@ char *argv0;
 #define ESC_ARG_SIZ   16
 #define STR_BUF_SIZ   ESC_BUF_SIZ
 #define STR_ARG_SIZ   ESC_ARG_SIZ
-#define DRAW_BUF_SIZ  20*1024
 #define XK_ANY_MOD    UINT_MAX
 #define XK_NO_MOD     0
 #define XK_SWITCH_MOD (1<<13)
@@ -87,18 +86,19 @@ char *argv0;
 
 
 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_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 cursor_movement {
@@ -232,6 +232,7 @@ typedef struct {
 	Line *line;   /* screen */
 	Line *alt;    /* alternate screen */
 	bool *dirty;  /* dirtyness of lines */
+	XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */
 	TCursor c;    /* cursor */
 	int top;      /* top    scroll limit */
 	int bot;      /* bottom scroll limit */
@@ -418,7 +419,8 @@ static void ttywrite(const char *, size_t);
 static void tstrsequence(uchar);
 
 static inline ushort sixd_to_16bit(int);
-static void xdraws(char *, Glyph, int, int, int, 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 xhints(void);
 static void xclear(int, int, int, int);
@@ -2819,6 +2821,9 @@ tresize(int col, int row) {
 		free(term.alt[i]);
 	}
 
+	/* resize to new width */
+	term.specbuf = xrealloc(term.specbuf, col * sizeof(XftGlyphFontSpec));
+
 	/* resize to new height */
 	term.line = xrealloc(term.line, row * sizeof(Line));
 	term.alt  = xrealloc(term.alt,  row * sizeof(Line));
@@ -3257,38 +3262,155 @@ xinit(void) {
 	XSync(xw.dpy, False);
 }
 
-void
-xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
-	int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
-	    width = charlen * xw.cw, xp, i;
-	int frcflags, charexists;
-	int u8fl, u8fblen, u8cblen, doesexist;
-	char *u8c, *u8fs;
-	Rune unicodep;
+int
+xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
+{
+	float winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, xp, yp;
+	ushort mode, prevmode = USHRT_MAX;
 	Font *font = &dc.font;
+	int frcflags = FRC_NORMAL;
+	float runewidth = xw.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 = xw.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,
+				                       FcTrue, 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,
+					FcTrue);
+
+			FcConfigSubstitute(0, fcpattern,
+					FcMatchPattern);
+			FcDefaultSubstitute(fcpattern);
+
+			fontpattern = FcFontSetMatch(0, fcsets, 1,
+					fcpattern, &fcres);
+
+			/*
+			 * Overwrite or create the new cache entry.
+			 */
+			if(frclen >= LEN(frc)) {
+				frclen = LEN(frc) - 1;
+				XftFontClose(xw.dpy, frc[frclen].font);
+				frc[frclen].unicodep = 0;
+			}
+
+			frc[frclen].font = XftFontOpenPattern(xw.dpy,
+					fontpattern);
+			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)(winy + frc[f].font->ascent);
+		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 * xw.cw, winy = borderpx + y * xw.ch,
+	    width = charlen * xw.cw;
 	Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
 	XRenderColor colfg, colbg;
 	XRectangle r;
-	int oneatatime;
 
-	frcflags = FRC_NORMAL;
-
-	if(base.mode & ATTR_ITALIC) {
-		if(base.fg == defaultfg)
+	/* Determine foreground and background colors based on mode. */
+	if(base.fg == defaultfg) {
+		if(base.mode & ATTR_ITALIC)
 			base.fg = defaultitalic;
-		font = &dc.ifont;
-		frcflags = FRC_ITALIC;
-	} else if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) {
-		if(base.fg == defaultfg)
+		else if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD))
 			base.fg = defaultitalic;
-		font = &dc.ibfont;
-		frcflags = FRC_ITALICBOLD;
-	} else if(base.mode & ATTR_UNDERLINE) {
-		if(base.fg == defaultfg)
+		else if(base.mode & ATTR_UNDERLINE)
 			base.fg = defaultunderline;
 	}
 
@@ -3314,22 +3436,9 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		bg = &dc.col[base.bg];
 	}
 
-	if(base.mode & ATTR_BOLD) {
-		/*
-		 * change basic system colors [0-7]
-		 * to bright system colors [8-15]
-		 */
-		if(BETWEEN(base.fg, 0, 7) && !(base.mode & ATTR_FAINT))
-			fg = &dc.col[base.fg + 8];
-
-		if(base.mode & ATTR_ITALIC) {
-			font = &dc.ibfont;
-			frcflags = FRC_ITALICBOLD;
-		} else {
-			font = &dc.bfont;
-			frcflags = FRC_BOLD;
-		}
-	}
+	/* 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]) {
@@ -3363,7 +3472,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		bg = temp;
 	}
 
-	if(base.mode & ATTR_FAINT && !(base.mode & ATTR_BOLD)) {
+	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;
@@ -3401,136 +3510,17 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 	r.width = width;
 	XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
 
-	for(xp = winx; bytelen > 0;) {
-		/*
-		 * Search for the range in the to be printed string of glyphs
-		 * that are in the main font. Then print that range. If
-		 * some glyph is found that is not in the font, do the
-		 * fallback dance.
-		 */
-		u8fs = s;
-		u8fblen = 0;
-		u8fl = 0;
-		oneatatime = font->width != xw.cw;
-		for(;;) {
-			u8c = s;
-			u8cblen = utf8decode(s, &unicodep, UTF_SIZ);
-			s += u8cblen;
-			bytelen -= u8cblen;
-
-			doesexist = XftCharExists(xw.dpy, font->match, unicodep);
-			if(doesexist) {
-					u8fl++;
-					u8fblen += u8cblen;
-					if(!oneatatime && bytelen > 0)
-							continue;
-			}
-
-			if(u8fl > 0) {
-				XftDrawStringUtf8(xw.draw, fg,
-						font->match, xp,
-						winy + font->ascent,
-						(FcChar8 *)u8fs,
-						u8fblen);
-				xp += xw.cw * u8fl;
-			}
-			break;
-		}
-		if(doesexist) {
-			if(oneatatime)
-				continue;
-			break;
-		}
-
-		/* Search the font cache. */
-		for(i = 0; i < frclen; i++) {
-			charexists = XftCharExists(xw.dpy, frc[i].font, unicodep);
-			/* Everything correct. */
-			if(charexists && frc[i].flags == frcflags)
-				break;
-			/* We got a default font for a not found glyph. */
-			if(!charexists && frc[i].flags == frcflags \
-					&& frc[i].unicodep == unicodep) {
-				break;
-			}
-		}
-
-		/* Nothing was found. */
-		if(i >= frclen) {
-			if(!font->set)
-				font->set = FcFontSort(0, font->pattern,
-				                       FcTrue, 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, unicodep);
-			FcPatternAddCharSet(fcpattern, FC_CHARSET,
-					fccharset);
-			FcPatternAddBool(fcpattern, FC_SCALABLE,
-					FcTrue);
-
-			FcConfigSubstitute(0, fcpattern,
-					FcMatchPattern);
-			FcDefaultSubstitute(fcpattern);
-
-			fontpattern = FcFontSetMatch(0, fcsets, 1,
-					fcpattern, &fcres);
-
-			/*
-			 * Overwrite or create the new cache entry.
-			 */
-			if(frclen >= LEN(frc)) {
-				frclen = LEN(frc) - 1;
-				XftFontClose(xw.dpy, frc[frclen].font);
-				frc[frclen].unicodep = 0;
-			}
-
-			frc[frclen].font = XftFontOpenPattern(xw.dpy,
-					fontpattern);
-			frc[frclen].flags = frcflags;
-			frc[frclen].unicodep = unicodep;
-
-			i = frclen;
-			frclen++;
-
-			FcPatternDestroy(fcpattern);
-			FcCharSetDestroy(fccharset);
-		}
-
-		XftDrawStringUtf8(xw.draw, fg, frc[i].font,
-				xp, winy + frc[i].font->ascent,
-				(FcChar8 *)u8c, u8cblen);
-
-		xp += xw.cw * wcwidth(unicodep);
-	}
-
-	/*
-	 * This is how the loop above actually should be. Why does the
-	 * application have to care about font details?
-	 *
-	 * I have to repeat: Xft and Fontconfig are design failures.
-	 */
-	/*
-	XftDrawStringUtf8(xw.draw, fg, font->set, winx,
-			winy + font->ascent, (FcChar8 *)s, bytelen);
-	*/
+	/* Render the glyphs. */
+	XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
 
+	/* Render underline and strikethrough. */
 	if(base.mode & ATTR_UNDERLINE) {
-		XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1,
+		XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
 				width, 1);
 	}
 
 	if(base.mode & ATTR_STRUCK) {
-		XftDrawRect(xw.draw, fg, winx, winy + 2 * font->ascent / 3,
+		XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3,
 				width, 1);
 	}
 
@@ -3540,11 +3530,10 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 
 void
 xdrawglyph(Glyph g, int x, int y) {
-	static char buf[UTF_SIZ];
-	size_t len = utf8encode(g.u, buf);
-	int width = g.mode & ATTR_WIDE ? 2 : 1;
-
-	xdraws(buf, g, x, y, width, len);
+	int numspecs;
+	XftGlyphFontSpec spec;
+	numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
+	xdrawglyphfontspecs(&spec, g, numspecs, x, y);
 }
 
 void
@@ -3658,9 +3647,9 @@ draw(void) {
 
 void
 drawregion(int x1, int y1, int x2, int y2) {
-	int ic, ib, x, y, ox;
+	int i, x, y, ox, numspecs;
 	Glyph base, new;
-	char buf[DRAW_BUF_SIZ];
+	XftGlyphFontSpec* specs;
 	bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 
 	if(!(xw.state & WIN_VISIBLE))
@@ -3672,29 +3661,31 @@ drawregion(int x1, int y1, int x2, int y2) {
 
 		xtermclear(0, y, term.col, y);
 		term.dirty[y] = 0;
-		base = term.line[y][0];
-		ic = ib = ox = 0;
-		for(x = x1; x < x2; x++) {
+
+		specs = term.specbuf;
+		numspecs = xmakeglyphfontspecs(specs, &term.line[y][0], x2 - x1, x1, y);
+
+		i = ox = 0;
+		for(x = x1; x < x2 && i < numspecs; x++) {
 			new = term.line[y][x];
 			if(new.mode == ATTR_WDUMMY)
 				continue;
 			if(ena_sel && selected(x, y))
 				new.mode ^= ATTR_REVERSE;
-			if(ib > 0 && (ATTRCMP(base, new)
-					|| ib >= DRAW_BUF_SIZ-UTF_SIZ)) {
-				xdraws(buf, base, ox, y, ic, ib);
-				ic = ib = 0;
+			if(i > 0 && ATTRCMP(base, new)) {
+				xdrawglyphfontspecs(specs, base, i, ox, y);
+				specs += i;
+				numspecs -= i;
+				i = 0;
 			}
-			if(ib == 0) {
+			if(i == 0) {
 				ox = x;
 				base = new;
 			}
-
-			ib += utf8encode(new.u, buf+ib);
-			ic += (new.mode & ATTR_WIDE)? 2 : 1;
+			i++;
 		}
-		if(ib > 0)
-			xdraws(buf, base, ox, y, ic, ib);
+		if(i > 0)
+			xdrawglyphfontspecs(specs, base, i, ox, y);
 	}
 	xdrawcursor();
 }

From 980991fa6e7b737d54f8e5c60c26275890eb28ff Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 10 May 2015 15:19:48 +0200
Subject: [PATCH 0846/1146] Fix the new -e handling. An empty cmd has to work
 for backwards compatibility.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index c2da66b..55a5c56 100644
--- a/st.c
+++ b/st.c
@@ -4010,7 +4010,7 @@ main(int argc, char *argv[]) {
 		opt_class = EARGF(usage());
 		break;
 	case 'e':
-		if(argc > 1)
+		if(argc > 0)
 			--argc, ++argv;
 		goto run;
 	case 'f':

From 89cf0fc597a2bcc16b1516c6f6d750a06175f1c7 Mon Sep 17 00:00:00 2001
From: suigin <suigin@national.shitposting.agency>
Date: Sat, 9 May 2015 15:22:40 -0700
Subject: [PATCH 0847/1146] Small bugfix for makeglyphfontspecs call in
 drawregion

Here's a patch that fixes a bug when calling `makedrawglyphfontspecs'
in `drawregion'. Wasn't offseting the pointer into the input glyphs
array by `x1'. The bug isn't causing any problems currently, because
`drawregion' is always called with `x1' and `y1' values of 0, but if
this ever changes in the future, the bug would certainly cause some
problems.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index c2da66b..73fe291 100644
--- a/st.c
+++ b/st.c
@@ -3663,7 +3663,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 		term.dirty[y] = 0;
 
 		specs = term.specbuf;
-		numspecs = xmakeglyphfontspecs(specs, &term.line[y][0], x2 - x1, x1, y);
+		numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y);
 
 		i = ox = 0;
 		for(x = x1; x < x2 && i < numspecs; x++) {

From 8e15887de95a7076b9515dcbb428b364f6dc3849 Mon Sep 17 00:00:00 2001
From: v4hn <me@v4hn.de>
Date: Thu, 14 May 2015 15:46:07 +0200
Subject: [PATCH 0848/1146] set selection to IDLE on clear

Otherwise a tangling bmotion event will consider
the selection still valid and selnormalize segfaults
because of an invalid sel.ob.y index.
---
 st.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index 73fe291..c0a9bf3 100644
--- a/st.c
+++ b/st.c
@@ -1069,6 +1069,7 @@ void
 selclear(XEvent *e) {
 	if(sel.ob.x == -1)
 		return;
+	sel.mode = SEL_IDLE;
 	sel.ob.x = -1;
 	tsetdirt(sel.nb.y, sel.ne.y);
 }

From caa97cc781ccf29f28c3d9e6683a66eb3f70e2bd Mon Sep 17 00:00:00 2001
From: Jan Christoph Ebersbach <jceb@e-jc.de>
Date: Fri, 22 May 2015 16:06:57 +0200
Subject: [PATCH 0849/1146] Support UTF-8 characters as word delimiters

For a higher usefulness of the utf8strchr function, the index of the
UTF-8 character could be returned in addition with a Rune instead of a
char*.  Since utf8strchr is currently only used by ISDELIM I didn't
bother to increase the complexity.
---
 st.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 0c6b9c3..3460a37 100644
--- a/st.c
+++ b/st.c
@@ -71,7 +71,7 @@ char *argv0;
 #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177')
 #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
 #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
-#define ISDELIM(u) (BETWEEN(u, 0, 127) && strchr(worddelimiters, u) != NULL)
+#define ISDELIM(u) (utf8strchr(worddelimiters, u) != NULL)
 #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 IS_SET(flag) ((term.mode & (flag)) != 0)
@@ -473,6 +473,7 @@ static size_t utf8decode(char *, Rune *, size_t);
 static Rune utf8decodebyte(char, size_t *);
 static size_t utf8encode(Rune, char *);
 static char utf8encodebyte(Rune, size_t);
+static char *utf8strchr(char *s, Rune u);
 static size_t utf8validate(Rune *, size_t);
 
 static ssize_t xwrite(int, const char *, size_t);
@@ -640,6 +641,21 @@ utf8encodebyte(Rune u, size_t i) {
 	return utfbyte[i] | (u & ~utfmask[i]);
 }
 
+char *
+utf8strchr(char *s, Rune u) {
+	Rune r;
+	size_t i, j, len;
+
+	len = strlen(s);
+	for(i = 0, j = 0; i < len; i += j) {
+		if(!(j = utf8decode(&s[i], &r, len - i)))
+			break;
+		if(r == u)
+			return &(s[i]);
+	}
+	return NULL;
+}
+
 size_t
 utf8validate(Rune *u, size_t i) {
 	if(!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))

From 71fa10f613a22b3e75e0e897ee1be6667be3f449 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 3 Jun 2015 08:07:55 +0200
Subject: [PATCH 0850/1146] Revert "Optimize memory footprint of line buffers"

This reverts commit 7ab6c92e18d468968811256e808b02309c160a22.
We need 32 bits for real color support.
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 3460a37..3dd5caf 100644
--- a/st.c
+++ b/st.c
@@ -191,8 +191,8 @@ typedef XftColor Color;
 typedef struct {
 	Rune u;           /* character code */
 	ushort mode;      /* attribute flags */
-	ushort fg;        /* foreground  */
-	ushort bg;        /* background  */
+	uint32_t fg;      /* foreground  */
+	uint32_t bg;      /* background  */
 } Glyph;
 
 typedef Glyph *Line;

From bdd649a10289ade364f3deab3bbf6ee3169d67ca Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@quinq.eu.org>
Date: Sun, 31 May 2015 12:26:11 +0200
Subject: [PATCH 0851/1146] do not truncate font size when zooming

---
 config.def.h |  6 +++---
 st.c         | 15 +++++++--------
 2 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/config.def.h b/config.def.h
index bb5596e..64e75b8 100644
--- a/config.def.h
+++ b/config.def.h
@@ -120,9 +120,9 @@ static Shortcut shortcuts[] = {
 	{ ControlMask,          XK_Print,       toggleprinter,  {.i =  0} },
 	{ ShiftMask,            XK_Print,       printscreen,    {.i =  0} },
 	{ XK_ANY_MOD,           XK_Print,       printsel,       {.i =  0} },
-	{ MODKEY|ShiftMask,     XK_Prior,       xzoom,          {.i = +1} },
-	{ MODKEY|ShiftMask,     XK_Next,        xzoom,          {.i = -1} },
-	{ MODKEY|ShiftMask,     XK_Home,        xzoomreset,     {.i =  0} },
+	{ MODKEY|ShiftMask,     XK_Prior,       xzoom,          {.f = +1} },
+	{ MODKEY|ShiftMask,     XK_Next,        xzoom,          {.f = -1} },
+	{ MODKEY|ShiftMask,     XK_Home,        xzoomreset,     {.f =  0} },
 	{ ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
 	{ MODKEY|ShiftMask,     XK_Insert,      clippaste,      {.i =  0} },
 	{ MODKEY|ShiftMask,     XK_C,           clipcopy,       {.i =  0} },
diff --git a/st.c b/st.c
index 3dd5caf..bb64c55 100644
--- a/st.c
+++ b/st.c
@@ -3061,7 +3061,6 @@ xloadfont(Font *f, FcPattern *pattern) {
 void
 xloadfonts(char *fontstr, double fontsize) {
 	FcPattern *pattern;
-	FcResult r_sz, r_psz;
 	double fontval;
 	float ceilf(float);
 
@@ -3080,11 +3079,11 @@ xloadfonts(char *fontstr, double fontsize) {
 		FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize);
 		usedfontsize = fontsize;
 	} else {
-		r_psz = FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval);
-		r_sz = FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval);
-		if(r_psz == FcResultMatch) {
+		if(FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) ==
+				FcResultMatch) {
 			usedfontsize = fontval;
-		} else if(r_sz == FcResultMatch) {
+		} else if(FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) ==
+				FcResultMatch) {
 			usedfontsize = -1;
 		} else {
 			/*
@@ -3157,14 +3156,14 @@ void
 xzoom(const Arg *arg) {
 	Arg larg;
 
-	larg.i = usedfontsize + arg->i;
+	larg.f = usedfontsize + arg->f;
 	xzoomabs(&larg);
 }
 
 void
 xzoomabs(const Arg *arg) {
 	xunloadfonts();
-	xloadfonts(usedfont, arg->i);
+	xloadfonts(usedfont, arg->f);
 	cresize(0, 0);
 	redraw();
 	xhints();
@@ -3175,7 +3174,7 @@ xzoomreset(const Arg *arg) {
 	Arg larg;
 
 	if(defaultfontsize > 0) {
-		larg.i = defaultfontsize;
+		larg.f = defaultfontsize;
 		xzoomabs(&larg);
 	}
 }

From 5f48e89716a74e75b6040fdb067372180626b699 Mon Sep 17 00:00:00 2001
From: Weng Xuetian <wengxt@gmail.com>
Date: Thu, 2 Jul 2015 08:31:12 +0200
Subject: [PATCH 0852/1146] Revert "Remove unnecessary XFilterEvent call."

This reverts commit d2937b05aed9cee8d6651cd806d31682a853c773.
---
 st.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/st.c b/st.c
index bb64c55..b89d094 100644
--- a/st.c
+++ b/st.c
@@ -3912,6 +3912,13 @@ run(void) {
 	/* Waiting for window mapping */
 	do {
 		XNextEvent(xw.dpy, &ev);
+		/*
+		 * XFilterEvent is required to be called after you using XOpenIM,
+		 * this is not unnecessary.It does not only filter the key event,
+		 * but some clientmessage for input method as well.
+		 */
+		if(XFilterEvent(&ev, None))
+			continue;
 		if(ev.type == ConfigureNotify) {
 			w = ev.xconfigure.width;
 			h = ev.xconfigure.height;

From 92e092efe6c6b2a6b6ec9da33170317d4426cab0 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 7 Jul 2015 22:26:44 +0200
Subject: [PATCH 0853/1146] Commit to push the 0.6 release.

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 3026d87..67844dc 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.5
+VERSION = 0.6
 
 # Customize below to fit your system
 

From abfad4c4fc69ebb22febfe32677aadd112ce375a Mon Sep 17 00:00:00 2001
From: FRIGN <dev@frign.de>
Date: Wed, 8 Jul 2015 23:49:25 +0200
Subject: [PATCH 0854/1146] Remove insane *_FILENO and EXIT_* usage

Any system having different assignments than the usual 0, 1, 2 for
the standard file numbers and 0, 1 for the exit-statuses is broken
beyond repair.
Let's keep it simple and just use the numbers, no reason to fall
out of the window here and bend down for POSIX.
In one occasion, the ret-variable was not necessary. The check was
rewritten.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 26 ++++++++++++--------------
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index b89d094..46c0b6e 100644
--- a/st.c
+++ b/st.c
@@ -513,7 +513,7 @@ static STREscape strescseq;
 static int cmdfd;
 static pid_t pid;
 static Selection sel;
-static int iofd = STDOUT_FILENO;
+static int iofd = 1;
 static char **opt_cmd = NULL;
 static char *opt_io = NULL;
 static char *opt_title = NULL;
@@ -1207,7 +1207,7 @@ die(const char *errstr, ...) {
 	va_start(ap, errstr);
 	vfprintf(stderr, errstr, ap);
 	va_end(ap);
-	exit(EXIT_FAILURE);
+	exit(1);
 }
 
 void
@@ -1256,12 +1256,12 @@ execsh(void) {
 	signal(SIGALRM, SIG_DFL);
 
 	execvp(prog, args);
-	_exit(EXIT_FAILURE);
+	_exit(1);
 }
 
 void
 sigchld(int a) {
-	int stat, ret;
+	int stat;
 	pid_t p;
 
 	if((p = waitpid(pid, &stat, WNOHANG)) < 0)
@@ -1270,10 +1270,9 @@ sigchld(int a) {
 	if(pid != p)
 		return;
 
-	ret = WIFEXITED(stat) ? WEXITSTATUS(stat) : EXIT_FAILURE;
-	if (ret != EXIT_SUCCESS)
+	if (!WIFEXITED(stat) || WEXITSTATUS(stat))
 		die("child finished with error '%d'\n", stat);
-	exit(EXIT_SUCCESS);
+	exit(0);
 }
 
 
@@ -1309,8 +1308,7 @@ ttynew(void) {
 	if(opt_io) {
 		term.mode |= MODE_PRINT;
 		iofd = (!strcmp(opt_io, "-")) ?
-			  STDOUT_FILENO :
-			  open(opt_io, O_WRONLY | O_CREAT, 0666);
+			  1 : open(opt_io, O_WRONLY | O_CREAT, 0666);
 		if(iofd < 0) {
 			fprintf(stderr, "Error opening %s:%s\n",
 				opt_io, strerror(errno));
@@ -1320,7 +1318,7 @@ ttynew(void) {
 	if (opt_line) {
 		if((cmdfd = open(opt_line, O_RDWR)) < 0)
 			die("open line failed: %s\n", strerror(errno));
-		close(STDIN_FILENO);
+		close(0);
 		dup(cmdfd);
 		stty();
 		return;
@@ -1337,9 +1335,9 @@ ttynew(void) {
 	case 0:
 		close(iofd);
 		setsid(); /* create a new process group */
-		dup2(s, STDIN_FILENO);
-		dup2(s, STDOUT_FILENO);
-		dup2(s, STDERR_FILENO);
+		dup2(s, 0);
+		dup2(s, 1);
+		dup2(s, 2);
 		if(ioctl(s, TIOCSCTTY, NULL) < 0)
 			die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
 		close(s);
@@ -3871,7 +3869,7 @@ cmessage(XEvent *e) {
 	} else if(e->xclient.data.l[0] == xw.wmdeletewin) {
 		/* Send SIGHUP to shell */
 		kill(pid, SIGHUP);
-		exit(EXIT_SUCCESS);
+		exit(0);
 	}
 }
 

From 9de853a98da8fe0f458b244970f0e0d3e9b38a50 Mon Sep 17 00:00:00 2001
From: FRIGN <dev@frign.de>
Date: Wed, 8 Jul 2015 23:56:55 +0200
Subject: [PATCH 0855/1146] Unboolify st

This practice proved itself in sbase, ubase and a couple of other
projects.
Also remove the True and False defined in X11 and FcTrue and FcFalse
defined in Fontconfig.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 config.def.h |  2 +-
 st.c         | 56 +++++++++++++++++++++++++---------------------------
 2 files changed, 28 insertions(+), 30 deletions(-)

diff --git a/config.def.h b/config.def.h
index 64e75b8..e246e3c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -30,7 +30,7 @@ static unsigned int doubleclicktimeout = 300;
 static unsigned int tripleclicktimeout = 600;
 
 /* alt screens */
-static bool allowaltscreen = true;
+static int allowaltscreen = 1;
 
 /* frames per second st should at maximum draw to the screen */
 static unsigned int xfps = 120;
diff --git a/st.c b/st.c
index 46c0b6e..b052b2b 100644
--- a/st.c
+++ b/st.c
@@ -6,7 +6,6 @@
 #include <locale.h>
 #include <pwd.h>
 #include <stdarg.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -231,7 +230,7 @@ typedef struct {
 	int col;      /* nb col */
 	Line *line;   /* screen */
 	Line *alt;    /* alternate screen */
-	bool *dirty;  /* dirtyness of lines */
+	int *dirty;  /* dirtyness of lines */
 	XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */
 	TCursor c;    /* cursor */
 	int top;      /* top    scroll limit */
@@ -241,8 +240,8 @@ typedef struct {
 	char trantbl[4]; /* charset table translation */
 	int charset;  /* current charset */
 	int icharset; /* selected charset for sequence */
-	bool numlock; /* lock numbers in keyboard */
-	bool *tabs;
+	int numlock; /* lock numbers in keyboard */
+	int *tabs;
 } Term;
 
 /* Purely graphic info */
@@ -258,7 +257,7 @@ typedef struct {
 	Visual *vis;
 	XSetWindowAttributes attrs;
 	int scr;
-	bool isfixed; /* is fixed geometry? */
+	int isfixed; /* is fixed geometry? */
 	int l, t; /* left and top offset */
 	int gm; /* geometry mask */
 	int tw, th; /* tty width and height */
@@ -302,7 +301,7 @@ typedef struct {
 
 	char *primary, *clipboard;
 	Atom xtarget;
-	bool alt;
+	int alt;
 	struct timespec tclick1;
 	struct timespec tclick2;
 } Selection;
@@ -403,14 +402,14 @@ static void tsetscroll(int, int);
 static void tswapscreen(void);
 static void tsetdirt(int, int);
 static void tsetdirtattr(int);
-static void tsetmode(bool, bool, int *, int);
+static void tsetmode(int, int, int *, int);
 static void tfulldirt(void);
 static void techo(Rune);
 static void tcontrolcode(uchar );
 static void tdectest(char );
 static int32_t tdefcolor(int *, int *, int);
 static void tdeftran(char);
-static inline bool match(uint, uint);
+static inline int match(uint, uint);
 static void ttynew(void);
 static void ttyread(void);
 static void ttyresize(void);
@@ -459,7 +458,7 @@ static void selrequest(XEvent *);
 
 static void selinit(void);
 static void selnormalize(void);
-static inline bool selected(int, int);
+static inline int selected(int, int);
 static char *getsel(void);
 static void selcopy(Time);
 static void selscroll(int, int);
@@ -734,10 +733,10 @@ selnormalize(void) {
 		sel.ne.x = term.col - 1;
 }
 
-bool
+int
 selected(int x, int y) {
 	if(sel.mode == SEL_EMPTY)
-		return false;
+		return 0;
 
 	if(sel.type == SEL_RECTANGULAR)
 		return BETWEEN(y, sel.nb.y, sel.ne.y)
@@ -751,7 +750,7 @@ selected(int x, int y) {
 void
 selsnap(int *x, int *y, int direction) {
 	int newx, newy, xt, yt;
-	bool delim, prevdelim;
+	int delim, prevdelim;
 	Glyph *gp, *prevgp;
 
 	switch(sel.snap) {
@@ -1143,7 +1142,7 @@ selrequest(XEvent *e) {
 	}
 
 	/* all done, send a notification to the listener */
-	if(!XSendEvent(xsre->display, xsre->requestor, True, 0, (XEvent *) &xev))
+	if(!XSendEvent(xsre->display, xsre->requestor, 1, 0, (XEvent *) &xev))
 		fprintf(stderr, "Error sending SelectionNotify event\n");
 }
 
@@ -1457,7 +1456,7 @@ tfulldirt(void) {
 void
 tcursor(int mode) {
 	static TCursor c[2];
-	bool alt = IS_SET(MODE_ALTSCREEN);
+	int alt = IS_SET(MODE_ALTSCREEN);
 
 	if(mode == CURSOR_SAVE) {
 		c[alt] = term.c;
@@ -1916,9 +1915,9 @@ tsetscroll(int t, int b) {
 }
 
 void
-tsetmode(bool priv, bool set, int *args, int narg) {
+tsetmode(int priv, int set, int *args, int narg) {
 	int *lim, mode;
-	bool alt;
+	int alt;
 
 	for(lim = args + narg; args < lim; ++args) {
 		if(priv) {
@@ -2684,7 +2683,7 @@ eschandle(uchar ascii) {
 void
 tputc(Rune u) {
 	char c[UTF_SIZ];
-	bool control;
+	int control;
 	int width, len;
 	Glyph *gp;
 
@@ -2808,7 +2807,7 @@ tresize(int col, int row) {
 	int i;
 	int minrow = MIN(row, term.row);
 	int mincol = MIN(col, term.col);
-	bool *bp;
+	int *bp;
 	TCursor c;
 
 	if(col < 1 || row < 1) {
@@ -2904,7 +2903,7 @@ sixd_to_16bit(int x) {
 	return x == 0 ? 0 : 0x3737 + 0x2828 * x;
 }
 
-bool
+int
 xloadcolor(int i, const char *name, Color *ncolor) {
 	XRenderColor color = { .alpha = 0xffff };
 
@@ -2929,7 +2928,7 @@ xloadcolor(int i, const char *name, Color *ncolor) {
 void
 xloadcols(void) {
 	int i;
-	static bool loaded;
+	static int loaded;
 	Color *cp;
 
 	if(loaded) {
@@ -2944,7 +2943,7 @@ xloadcols(void) {
 			else
 				die("Could not allocate color %d\n", i);
 		}
-	loaded = true;
+	loaded = 1;
 }
 
 int
@@ -2998,7 +2997,7 @@ xhints(void) {
 	sizeh->width_inc = xw.cw;
 	sizeh->base_height = 2 * borderpx;
 	sizeh->base_width = 2 * borderpx;
-	if(xw.isfixed == True) {
+	if(xw.isfixed) {
 		sizeh->flags |= PMaxSize | PMinSize;
 		sizeh->min_width = sizeh->max_width = xw.w;
 		sizeh->min_height = sizeh->max_height = xw.h;
@@ -3349,7 +3348,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
 		if(f >= frclen) {
 			if(!font->set)
 				font->set = FcFontSort(0, font->pattern,
-				                       FcTrue, 0, &fcres);
+				                       1, 0, &fcres);
 			fcsets[0] = font->set;
 
 			/*
@@ -3365,8 +3364,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
 			FcCharSetAddChar(fccharset, rune);
 			FcPatternAddCharSet(fcpattern, FC_CHARSET,
 					fccharset);
-			FcPatternAddBool(fcpattern, FC_SCALABLE,
-					FcTrue);
+			FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
 
 			FcConfigSubstitute(0, fcpattern,
 					FcMatchPattern);
@@ -3664,7 +3662,7 @@ drawregion(int x1, int y1, int x2, int y2) {
 	int i, x, y, ox, numspecs;
 	Glyph base, new;
 	XftGlyphFontSpec* specs;
-	bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
+	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 
 	if(!(xw.state & WIN_VISIBLE))
 		return;
@@ -3757,7 +3755,7 @@ focus(XEvent *ev) {
 	}
 }
 
-bool
+int
 match(uint mask, uint state) {
 	return mask == XK_ANY_MOD || mask == (state & ~ignoremod);
 }
@@ -4025,7 +4023,7 @@ main(int argc, char *argv[]) {
 
 	ARGBEGIN {
 	case 'a':
-		allowaltscreen = false;
+		allowaltscreen = 0;
 		break;
 	case 'c':
 		opt_class = EARGF(usage());
@@ -4042,7 +4040,7 @@ main(int argc, char *argv[]) {
 				&xw.l, &xw.t, &cols, &rows);
 		break;
 	case 'i':
-		xw.isfixed = True;
+		xw.isfixed = 1;
 		break;
 	case 'o':
 		opt_io = EARGF(usage());

From 13233574ed1ead29bb7e99e71a0665e62c640617 Mon Sep 17 00:00:00 2001
From: FRIGN <dev@frign.de>
Date: Thu, 9 Jul 2015 23:59:50 +0200
Subject: [PATCH 0856/1146] Use BSD-style function notation

Put the opening brace on a new line. This was already used for some
functions inside st.c.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 385 +++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 256 insertions(+), 129 deletions(-)

diff --git a/st.c b/st.c
index b052b2b..03866f1 100644
--- a/st.c
+++ b/st.c
@@ -550,7 +550,8 @@ static Fontcache frc[16];
 static int frclen = 0;
 
 ssize_t
-xwrite(int fd, const char *s, size_t len) {
+xwrite(int fd, const char *s, size_t len)
+{
 	size_t aux = len;
 
 	while(len > 0) {
@@ -564,7 +565,8 @@ xwrite(int fd, const char *s, size_t len) {
 }
 
 void *
-xmalloc(size_t len) {
+xmalloc(size_t len)
+{
 	void *p = malloc(len);
 
 	if(!p)
@@ -574,7 +576,8 @@ xmalloc(size_t len) {
 }
 
 void *
-xrealloc(void *p, size_t len) {
+xrealloc(void *p, size_t len)
+{
 	if((p = realloc(p, len)) == NULL)
 		die("Out of memory\n");
 
@@ -582,7 +585,8 @@ xrealloc(void *p, size_t len) {
 }
 
 char *
-xstrdup(char *s) {
+xstrdup(char *s)
+{
 	if((s = strdup(s)) == NULL)
 		die("Out of memory\n");
 
@@ -590,7 +594,8 @@ xstrdup(char *s) {
 }
 
 size_t
-utf8decode(char *c, Rune *u, size_t clen) {
+utf8decode(char *c, Rune *u, size_t clen)
+{
 	size_t i, j, len, type;
 	Rune udecoded;
 
@@ -613,7 +618,8 @@ utf8decode(char *c, Rune *u, size_t clen) {
 }
 
 Rune
-utf8decodebyte(char c, size_t *i) {
+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];
@@ -621,7 +627,8 @@ utf8decodebyte(char c, size_t *i) {
 }
 
 size_t
-utf8encode(Rune u, char *c) {
+utf8encode(Rune u, char *c)
+{
 	size_t len, i;
 
 	len = utf8validate(&u, 0);
@@ -636,12 +643,14 @@ utf8encode(Rune u, char *c) {
 }
 
 char
-utf8encodebyte(Rune u, size_t i) {
+utf8encodebyte(Rune u, size_t i)
+{
 	return utfbyte[i] | (u & ~utfmask[i]);
 }
 
 char *
-utf8strchr(char *s, Rune u) {
+utf8strchr(char *s, Rune u)
+{
 	Rune r;
 	size_t i, j, len;
 
@@ -656,7 +665,8 @@ utf8strchr(char *s, Rune u) {
 }
 
 size_t
-utf8validate(Rune *u, size_t i) {
+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)
@@ -665,7 +675,8 @@ utf8validate(Rune *u, size_t i) {
 }
 
 void
-selinit(void) {
+selinit(void)
+{
 	memset(&sel.tclick1, 0, sizeof(sel.tclick1));
 	memset(&sel.tclick2, 0, sizeof(sel.tclick2));
 	sel.mode = SEL_IDLE;
@@ -678,7 +689,8 @@ selinit(void) {
 }
 
 int
-x2col(int x) {
+x2col(int x)
+{
 	x -= borderpx;
 	x /= xw.cw;
 
@@ -686,7 +698,8 @@ x2col(int x) {
 }
 
 int
-y2row(int y) {
+y2row(int y)
+{
 	y -= borderpx;
 	y /= xw.ch;
 
@@ -694,7 +707,8 @@ y2row(int y) {
 }
 
 int
-tlinelen(int y) {
+tlinelen(int y)
+{
 	int i = term.col;
 
 	if(term.line[y][i - 1].mode & ATTR_WRAP)
@@ -707,7 +721,8 @@ tlinelen(int y) {
 }
 
 void
-selnormalize(void) {
+selnormalize(void)
+{
 	int i;
 
 	if(sel.type == SEL_REGULAR && sel.ob.y != sel.oe.y) {
@@ -734,7 +749,8 @@ selnormalize(void) {
 }
 
 int
-selected(int x, int y) {
+selected(int x, int y)
+{
 	if(sel.mode == SEL_EMPTY)
 		return 0;
 
@@ -748,7 +764,8 @@ selected(int x, int y) {
 }
 
 void
-selsnap(int *x, int *y, int direction) {
+selsnap(int *x, int *y, int direction)
+{
 	int newx, newy, xt, yt;
 	int delim, prevdelim;
 	Glyph *gp, *prevgp;
@@ -820,7 +837,8 @@ selsnap(int *x, int *y, int direction) {
 }
 
 void
-getbuttoninfo(XEvent *e) {
+getbuttoninfo(XEvent *e)
+{
 	int type;
 	uint state = e->xbutton.state & ~(Button1Mask | forceselmod);
 
@@ -840,7 +858,8 @@ getbuttoninfo(XEvent *e) {
 }
 
 void
-mousereport(XEvent *e) {
+mousereport(XEvent *e)
+{
 	int x = x2col(e->xbutton.x), y = y2row(e->xbutton.y),
 	    button = e->xbutton.button, state = e->xbutton.state,
 	    len;
@@ -903,7 +922,8 @@ mousereport(XEvent *e) {
 }
 
 void
-bpress(XEvent *e) {
+bpress(XEvent *e)
+{
 	struct timespec now;
 	Mousekey *mk;
 
@@ -952,7 +972,8 @@ bpress(XEvent *e) {
 }
 
 char *
-getsel(void) {
+getsel(void)
+{
 	char *str, *ptr;
 	int y, bufsize, lastx, linelen;
 	Glyph *gp, *last;
@@ -1002,12 +1023,14 @@ getsel(void) {
 }
 
 void
-selcopy(Time t) {
+selcopy(Time t)
+{
 	xsetsel(getsel(), t);
 }
 
 void
-selnotify(XEvent *e) {
+selnotify(XEvent *e)
+{
 	ulong nitems, ofs, rem;
 	int format;
 	uchar *data, *last, *repl;
@@ -1052,13 +1075,15 @@ selnotify(XEvent *e) {
 }
 
 void
-selpaste(const Arg *dummy) {
+selpaste(const Arg *dummy)
+{
 	XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY,
 			xw.win, CurrentTime);
 }
 
 void
-clipcopy(const Arg *dummy) {
+clipcopy(const Arg *dummy)
+{
 	Atom clipboard;
 
 	if(sel.clipboard != NULL)
@@ -1072,7 +1097,8 @@ clipcopy(const Arg *dummy) {
 }
 
 void
-clippaste(const Arg *dummy) {
+clippaste(const Arg *dummy)
+{
 	Atom clipboard;
 
 	clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
@@ -1081,7 +1107,8 @@ clippaste(const Arg *dummy) {
 }
 
 void
-selclear(XEvent *e) {
+selclear(XEvent *e)
+{
 	if(sel.ob.x == -1)
 		return;
 	sel.mode = SEL_IDLE;
@@ -1090,7 +1117,8 @@ selclear(XEvent *e) {
 }
 
 void
-selrequest(XEvent *e) {
+selrequest(XEvent *e)
+{
 	XSelectionRequestEvent *xsre;
 	XSelectionEvent xev;
 	Atom xa_targets, string, clipboard;
@@ -1147,7 +1175,8 @@ selrequest(XEvent *e) {
 }
 
 void
-xsetsel(char *str, Time t) {
+xsetsel(char *str, Time t)
+{
 	free(sel.primary);
 	sel.primary = str;
 
@@ -1157,7 +1186,8 @@ xsetsel(char *str, Time t) {
 }
 
 void
-brelease(XEvent *e) {
+brelease(XEvent *e)
+{
 	if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);
 		return;
@@ -1177,7 +1207,8 @@ brelease(XEvent *e) {
 }
 
 void
-bmotion(XEvent *e) {
+bmotion(XEvent *e)
+{
 	int oldey, oldex, oldsby, oldsey;
 
 	if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
@@ -1200,7 +1231,8 @@ bmotion(XEvent *e) {
 }
 
 void
-die(const char *errstr, ...) {
+die(const char *errstr, ...)
+{
 	va_list ap;
 
 	va_start(ap, errstr);
@@ -1210,7 +1242,8 @@ die(const char *errstr, ...) {
 }
 
 void
-execsh(void) {
+execsh(void)
+{
 	char **args, *sh, *prog;
 	const struct passwd *pw;
 	char buf[sizeof(long) * 8 + 1];
@@ -1259,7 +1292,8 @@ execsh(void) {
 }
 
 void
-sigchld(int a) {
+sigchld(int a)
+{
 	int stat;
 	pid_t p;
 
@@ -1300,7 +1334,8 @@ stty(void)
 }
 
 void
-ttynew(void) {
+ttynew(void)
+{
 	int m, s;
 	struct winsize w = {term.row, term.col, 0, 0};
 
@@ -1352,7 +1387,8 @@ ttynew(void) {
 }
 
 void
-ttyread(void) {
+ttyread(void)
+{
 	static char buf[BUFSIZ];
 	static int buflen = 0;
 	char *ptr;
@@ -1378,13 +1414,15 @@ ttyread(void) {
 }
 
 void
-ttywrite(const char *s, size_t n) {
+ttywrite(const char *s, size_t n)
+{
 	if(xwrite(cmdfd, s, n) == -1)
 		die("write error on tty: %s\n", strerror(errno));
 }
 
 void
-ttysend(char *s, size_t n) {
+ttysend(char *s, size_t n)
+{
 	int len;
 	Rune u;
 
@@ -1398,7 +1436,8 @@ ttysend(char *s, size_t n) {
 }
 
 void
-ttyresize(void) {
+ttyresize(void)
+{
 	struct winsize w;
 
 	w.ws_row = term.row;
@@ -1410,7 +1449,8 @@ ttyresize(void) {
 }
 
 int
-tattrset(int attr) {
+tattrset(int attr)
+{
 	int i, j;
 
 	for(i = 0; i < term.row-1; i++) {
@@ -1424,7 +1464,8 @@ tattrset(int attr) {
 }
 
 void
-tsetdirt(int top, int bot) {
+tsetdirt(int top, int bot)
+{
 	int i;
 
 	LIMIT(top, 0, term.row-1);
@@ -1435,7 +1476,8 @@ tsetdirt(int top, int bot) {
 }
 
 void
-tsetdirtattr(int attr) {
+tsetdirtattr(int attr)
+{
 	int i, j;
 
 	for(i = 0; i < term.row-1; i++) {
@@ -1449,12 +1491,14 @@ tsetdirtattr(int attr) {
 }
 
 void
-tfulldirt(void) {
+tfulldirt(void)
+{
 	tsetdirt(0, term.row-1);
 }
 
 void
-tcursor(int mode) {
+tcursor(int mode)
+{
 	static TCursor c[2];
 	int alt = IS_SET(MODE_ALTSCREEN);
 
@@ -1467,7 +1511,8 @@ tcursor(int mode) {
 }
 
 void
-treset(void) {
+treset(void)
+{
 	uint i;
 
 	term.c = (TCursor){{
@@ -1494,7 +1539,8 @@ treset(void) {
 }
 
 void
-tnew(int col, int row) {
+tnew(int col, int row)
+{
 	term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
 	tresize(col, row);
 	term.numlock = 1;
@@ -1503,7 +1549,8 @@ tnew(int col, int row) {
 }
 
 void
-tswapscreen(void) {
+tswapscreen(void)
+{
 	Line *tmp = term.line;
 
 	term.line = term.alt;
@@ -1513,7 +1560,8 @@ tswapscreen(void) {
 }
 
 void
-tscrolldown(int orig, int n) {
+tscrolldown(int orig, int n)
+{
 	int i;
 	Line temp;
 
@@ -1532,7 +1580,8 @@ tscrolldown(int orig, int n) {
 }
 
 void
-tscrollup(int orig, int n) {
+tscrollup(int orig, int n)
+{
 	int i;
 	Line temp;
 
@@ -1551,7 +1600,8 @@ tscrollup(int orig, int n) {
 }
 
 void
-selscroll(int orig, int n) {
+selscroll(int orig, int n)
+{
 	if(sel.ob.x == -1)
 		return;
 
@@ -1580,7 +1630,8 @@ selscroll(int orig, int n) {
 }
 
 void
-tnewline(int first_col) {
+tnewline(int first_col)
+{
 	int y = term.c.y;
 
 	if(y == term.bot) {
@@ -1592,7 +1643,8 @@ tnewline(int first_col) {
 }
 
 void
-csiparse(void) {
+csiparse(void)
+{
 	char *p = csiescseq.buf, *np;
 	long int v;
 
@@ -1622,12 +1674,14 @@ csiparse(void) {
 
 /* for absolute user moves, when decom is set */
 void
-tmoveato(int x, int y) {
+tmoveato(int x, int y)
+{
 	tmoveto(x, y + ((term.c.state & CURSOR_ORIGIN) ? term.top: 0));
 }
 
 void
-tmoveto(int x, int y) {
+tmoveto(int x, int y)
+{
 	int miny, maxy;
 
 	if(term.c.state & CURSOR_ORIGIN) {
@@ -1643,7 +1697,8 @@ tmoveto(int x, int y) {
 }
 
 void
-tsetchar(Rune u, Glyph *attr, int x, int y) {
+tsetchar(Rune u, Glyph *attr, int x, int y)
+{
 	static char *vt100_0[62] = { /* 0x41 - 0x7e */
 		"↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */
 		0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
@@ -1678,7 +1733,8 @@ tsetchar(Rune u, Glyph *attr, int x, int y) {
 }
 
 void
-tclearregion(int x1, int y1, int x2, int y2) {
+tclearregion(int x1, int y1, int x2, int y2)
+{
 	int x, y, temp;
 	Glyph *gp;
 
@@ -1707,7 +1763,8 @@ tclearregion(int x1, int y1, int x2, int y2) {
 }
 
 void
-tdeletechar(int n) {
+tdeletechar(int n)
+{
 	int dst, src, size;
 	Glyph *line;
 
@@ -1723,7 +1780,8 @@ tdeletechar(int n) {
 }
 
 void
-tinsertblank(int n) {
+tinsertblank(int n)
+{
 	int dst, src, size;
 	Glyph *line;
 
@@ -1739,19 +1797,22 @@ tinsertblank(int n) {
 }
 
 void
-tinsertblankline(int n) {
+tinsertblankline(int n)
+{
 	if(BETWEEN(term.c.y, term.top, term.bot))
 		tscrolldown(term.c.y, n);
 }
 
 void
-tdeleteline(int n) {
+tdeleteline(int n)
+{
 	if(BETWEEN(term.c.y, term.top, term.bot))
 		tscrollup(term.c.y, n);
 }
 
 int32_t
-tdefcolor(int *attr, int *npar, int l) {
+tdefcolor(int *attr, int *npar, int l)
+{
 	int32_t idx = -1;
 	uint r, g, b;
 
@@ -1800,7 +1861,8 @@ tdefcolor(int *attr, int *npar, int l) {
 }
 
 void
-tsetattr(int *attr, int l) {
+tsetattr(int *attr, int l)
+{
 	int i;
 	int32_t idx;
 
@@ -1900,7 +1962,8 @@ tsetattr(int *attr, int l) {
 }
 
 void
-tsetscroll(int t, int b) {
+tsetscroll(int t, int b)
+{
 	int temp;
 
 	LIMIT(t, 0, term.row-1);
@@ -1915,7 +1978,8 @@ tsetscroll(int t, int b) {
 }
 
 void
-tsetmode(int priv, int set, int *args, int narg) {
+tsetmode(int priv, int set, int *args, int narg)
+{
 	int *lim, mode;
 	int alt;
 
@@ -2047,7 +2111,8 @@ tsetmode(int priv, int set, int *args, int narg) {
 }
 
 void
-csihandle(void) {
+csihandle(void)
+{
 	char buf[40];
 	int len;
 
@@ -2256,7 +2321,8 @@ csihandle(void) {
 }
 
 void
-csidump(void) {
+csidump(void)
+{
 	int i;
 	uint c;
 
@@ -2279,12 +2345,14 @@ csidump(void) {
 }
 
 void
-csireset(void) {
+csireset(void)
+{
 	memset(&csiescseq, 0, sizeof(csiescseq));
 }
 
 void
-strhandle(void) {
+strhandle(void)
+{
 	char *p = NULL;
 	int j, narg, par;
 
@@ -2334,7 +2402,8 @@ strhandle(void) {
 }
 
 void
-strparse(void) {
+strparse(void)
+{
 	int c;
 	char *p = strescseq.buf;
 
@@ -2355,7 +2424,8 @@ strparse(void) {
 }
 
 void
-strdump(void) {
+strdump(void)
+{
 	int i;
 	uint c;
 
@@ -2380,12 +2450,14 @@ strdump(void) {
 }
 
 void
-strreset(void) {
+strreset(void)
+{
 	memset(&strescseq, 0, sizeof(strescseq));
 }
 
 void
-tprinter(char *s, size_t len) {
+tprinter(char *s, size_t len)
+{
 	if(iofd != -1 && xwrite(iofd, s, len) < 0) {
 		fprintf(stderr, "Error writing in %s:%s\n",
 			opt_io, strerror(errno));
@@ -2395,22 +2467,26 @@ tprinter(char *s, size_t len) {
 }
 
 void
-toggleprinter(const Arg *arg) {
+toggleprinter(const Arg *arg)
+{
 	term.mode ^= MODE_PRINT;
 }
 
 void
-printscreen(const Arg *arg) {
+printscreen(const Arg *arg)
+{
 	tdump();
 }
 
 void
-printsel(const Arg *arg) {
+printsel(const Arg *arg)
+{
 	tdumpsel();
 }
 
 void
-tdumpsel(void) {
+tdumpsel(void)
+{
 	char *ptr;
 
 	if((ptr = getsel())) {
@@ -2420,7 +2496,8 @@ tdumpsel(void) {
 }
 
 void
-tdumpline(int n) {
+tdumpline(int n)
+{
 	char buf[UTF_SIZ];
 	Glyph *bp, *end;
 
@@ -2434,7 +2511,8 @@ tdumpline(int n) {
 }
 
 void
-tdump(void) {
+tdump(void)
+{
 	int i;
 
 	for(i = 0; i < term.row; ++i)
@@ -2442,7 +2520,8 @@ tdump(void) {
 }
 
 void
-tputtab(int n) {
+tputtab(int n)
+{
 	uint x = term.c.x;
 
 	if(n > 0) {
@@ -2458,7 +2537,8 @@ tputtab(int n) {
 }
 
 void
-techo(Rune u) {
+techo(Rune u)
+{
 	if(ISCONTROL(u)) { /* control code */
 		if(u & 0x80) {
 			u &= 0x7f;
@@ -2473,7 +2553,8 @@ techo(Rune u) {
 }
 
 void
-tdeftran(char ascii) {
+tdeftran(char ascii)
+{
 	static char cs[] = "0B";
 	static int vcs[] = {CS_GRAPHIC0, CS_USA};
 	char *p;
@@ -2486,7 +2567,8 @@ tdeftran(char ascii) {
 }
 
 void
-tdectest(char c) {
+tdectest(char c)
+{
 	int x, y;
 
 	if(c == '8') { /* DEC screen alignment test. */
@@ -2498,7 +2580,8 @@ tdectest(char c) {
 }
 
 void
-tstrsequence(uchar c) {
+tstrsequence(uchar c)
+{
 	switch (c) {
 	case 0x90:   /* DCS -- Device Control String */
 		c = 'P';
@@ -2519,7 +2602,8 @@ tstrsequence(uchar c) {
 }
 
 void
-tcontrolcode(uchar ascii) {
+tcontrolcode(uchar ascii)
+{
 	switch(ascii) {
 	case '\t':   /* HT */
 		tputtab(1);
@@ -2602,7 +2686,8 @@ tcontrolcode(uchar ascii) {
  * more characters for this sequence, otherwise 0
  */
 int
-eschandle(uchar ascii) {
+eschandle(uchar ascii)
+{
 	switch(ascii) {
 	case '[':
 		term.esc |= ESC_CSI;
@@ -2681,7 +2766,8 @@ eschandle(uchar ascii) {
 }
 
 void
-tputc(Rune u) {
+tputc(Rune u)
+{
 	char c[UTF_SIZ];
 	int control;
 	int width, len;
@@ -2803,7 +2889,8 @@ tputc(Rune u) {
 }
 
 void
-tresize(int col, int row) {
+tresize(int col, int row)
+{
 	int i;
 	int minrow = MIN(row, term.row);
 	int mincol = MIN(col, term.col);
@@ -2887,7 +2974,8 @@ tresize(int col, int row) {
 }
 
 void
-xresize(int col, int row) {
+xresize(int col, int row)
+{
 	xw.tw = MAX(1, col * xw.cw);
 	xw.th = MAX(1, row * xw.ch);
 
@@ -2899,12 +2987,14 @@ xresize(int col, int row) {
 }
 
 ushort
-sixd_to_16bit(int x) {
+sixd_to_16bit(int x)
+{
 	return x == 0 ? 0 : 0x3737 + 0x2828 * x;
 }
 
 int
-xloadcolor(int i, const char *name, Color *ncolor) {
+xloadcolor(int i, const char *name, Color *ncolor)
+{
 	XRenderColor color = { .alpha = 0xffff };
 
 	if(!name) {
@@ -2926,7 +3016,8 @@ xloadcolor(int i, const char *name, Color *ncolor) {
 }
 
 void
-xloadcols(void) {
+xloadcols(void)
+{
 	int i;
 	static int loaded;
 	Color *cp;
@@ -2947,7 +3038,8 @@ xloadcols(void) {
 }
 
 int
-xsetcolorname(int x, const char *name) {
+xsetcolorname(int x, const char *name)
+{
 	Color ncolor;
 
 	if(!BETWEEN(x, 0, LEN(dc.col)))
@@ -2963,7 +3055,8 @@ xsetcolorname(int x, const char *name) {
 }
 
 void
-xtermclear(int col1, int row1, int col2, int row2) {
+xtermclear(int col1, int row1, int col2, int row2)
+{
 	XftDrawRect(xw.draw,
 			&dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
 			borderpx + col1 * xw.cw,
@@ -2976,14 +3069,16 @@ xtermclear(int col1, int row1, int col2, int row2) {
  * Absolute coordinates.
  */
 void
-xclear(int x1, int y1, int x2, int y2) {
+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) {
+xhints(void)
+{
 	XClassHint class = {opt_class ? opt_class : termname, termname};
 	XWMHints wm = {.flags = InputHint, .input = 1};
 	XSizeHints *sizeh = NULL;
@@ -3015,7 +3110,8 @@ xhints(void) {
 }
 
 int
-xgeommasktogravity(int mask) {
+xgeommasktogravity(int mask)
+{
 	switch(mask & (XNegative|YNegative)) {
 	case 0:
 		return NorthWestGravity;
@@ -3028,7 +3124,8 @@ xgeommasktogravity(int mask) {
 }
 
 int
-xloadfont(Font *f, FcPattern *pattern) {
+xloadfont(Font *f, FcPattern *pattern)
+{
 	FcPattern *match;
 	FcResult result;
 
@@ -3056,7 +3153,8 @@ xloadfont(Font *f, FcPattern *pattern) {
 }
 
 void
-xloadfonts(char *fontstr, double fontsize) {
+xloadfonts(char *fontstr, double fontsize)
+{
 	FcPattern *pattern;
 	double fontval;
 	float ceilf(float);
@@ -3130,7 +3228,8 @@ xloadfonts(char *fontstr, double fontsize) {
 }
 
 void
-xunloadfont(Font *f) {
+xunloadfont(Font *f)
+{
 	XftFontClose(xw.dpy, f->match);
 	FcPatternDestroy(f->pattern);
 	if(f->set)
@@ -3138,7 +3237,8 @@ xunloadfont(Font *f) {
 }
 
 void
-xunloadfonts(void) {
+xunloadfonts(void)
+{
 	/* Free the loaded fonts in the font cache.  */
 	while(frclen > 0)
 		XftFontClose(xw.dpy, frc[--frclen].font);
@@ -3150,7 +3250,8 @@ xunloadfonts(void) {
 }
 
 void
-xzoom(const Arg *arg) {
+xzoom(const Arg *arg)
+{
 	Arg larg;
 
 	larg.f = usedfontsize + arg->f;
@@ -3158,7 +3259,8 @@ xzoom(const Arg *arg) {
 }
 
 void
-xzoomabs(const Arg *arg) {
+xzoomabs(const Arg *arg)
+{
 	xunloadfonts();
 	xloadfonts(usedfont, arg->f);
 	cresize(0, 0);
@@ -3167,7 +3269,8 @@ xzoomabs(const Arg *arg) {
 }
 
 void
-xzoomreset(const Arg *arg) {
+xzoomreset(const Arg *arg)
+{
 	Arg larg;
 
 	if(defaultfontsize > 0) {
@@ -3177,7 +3280,8 @@ xzoomreset(const Arg *arg) {
 }
 
 void
-xinit(void) {
+xinit(void)
+{
 	XGCValues gcvalues;
 	Cursor cursor;
 	Window parent;
@@ -3408,7 +3512,8 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
 }
 
 void
-xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) {
+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 * xw.cw, winy = borderpx + y * xw.ch,
 	    width = charlen * xw.cw;
@@ -3541,7 +3646,8 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 }
 
 void
-xdrawglyph(Glyph g, int x, int y) {
+xdrawglyph(Glyph g, int x, int y)
+{
 	int numspecs;
 	XftGlyphFontSpec spec;
 	numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
@@ -3549,7 +3655,8 @@ xdrawglyph(Glyph g, int x, int y) {
 }
 
 void
-xdrawcursor(void) {
+xdrawcursor(void)
+{
 	static int oldx = 0, oldy = 0;
 	int curx;
 	Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs};
@@ -3626,7 +3733,8 @@ xdrawcursor(void) {
 
 
 void
-xsettitle(char *p) {
+xsettitle(char *p)
+{
 	XTextProperty prop;
 
 	Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
@@ -3637,18 +3745,21 @@ xsettitle(char *p) {
 }
 
 void
-xresettitle(void) {
+xresettitle(void)
+{
 	xsettitle(opt_title ? opt_title : "st");
 }
 
 void
-redraw(void) {
+redraw(void)
+{
 	tfulldirt();
 	draw();
 }
 
 void
-draw(void) {
+draw(void)
+{
 	drawregion(0, 0, term.col, term.row);
 	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
 			xw.h, 0, 0);
@@ -3658,7 +3769,8 @@ draw(void) {
 }
 
 void
-drawregion(int x1, int y1, int x2, int y2) {
+drawregion(int x1, int y1, int x2, int y2)
+{
 	int i, x, y, ox, numspecs;
 	Glyph base, new;
 	XftGlyphFontSpec* specs;
@@ -3703,30 +3815,35 @@ drawregion(int x1, int y1, int x2, int y2) {
 }
 
 void
-expose(XEvent *ev) {
+expose(XEvent *ev)
+{
 	redraw();
 }
 
 void
-visibility(XEvent *ev) {
+visibility(XEvent *ev)
+{
 	XVisibilityEvent *e = &ev->xvisibility;
 
 	MODBIT(xw.state, e->state != VisibilityFullyObscured, WIN_VISIBLE);
 }
 
 void
-unmap(XEvent *ev) {
+unmap(XEvent *ev)
+{
 	xw.state &= ~WIN_VISIBLE;
 }
 
 void
-xsetpointermotion(int set) {
+xsetpointermotion(int set)
+{
 	MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
 	XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
 }
 
 void
-xseturgency(int add) {
+xseturgency(int add)
+{
 	XWMHints *h = XGetWMHints(xw.dpy, xw.win);
 
 	MODBIT(h->flags, add, XUrgencyHint);
@@ -3735,7 +3852,8 @@ xseturgency(int add) {
 }
 
 void
-focus(XEvent *ev) {
+focus(XEvent *ev)
+{
 	XFocusChangeEvent *e = &ev->xfocus;
 
 	if(e->mode == NotifyGrab)
@@ -3756,17 +3874,20 @@ focus(XEvent *ev) {
 }
 
 int
-match(uint mask, uint state) {
+match(uint mask, uint state)
+{
 	return mask == XK_ANY_MOD || mask == (state & ~ignoremod);
 }
 
 void
-numlock(const Arg *dummy) {
+numlock(const Arg *dummy)
+{
 	term.numlock ^= 1;
 }
 
 char*
-kmap(KeySym k, uint state) {
+kmap(KeySym k, uint state)
+{
 	Key *kp;
 	int i;
 
@@ -3805,7 +3926,8 @@ kmap(KeySym k, uint state) {
 }
 
 void
-kpress(XEvent *ev) {
+kpress(XEvent *ev)
+{
 	XKeyEvent *e = &ev->xkey;
 	KeySym ksym;
 	char buf[32], *customkey;
@@ -3852,7 +3974,8 @@ kpress(XEvent *ev) {
 
 
 void
-cmessage(XEvent *e) {
+cmessage(XEvent *e)
+{
 	/*
 	 * See xembed specs
 	 *  http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html
@@ -3872,7 +3995,8 @@ cmessage(XEvent *e) {
 }
 
 void
-cresize(int width, int height) {
+cresize(int width, int height)
+{
 	int col, row;
 
 	if(width != 0)
@@ -3889,7 +4013,8 @@ cresize(int width, int height) {
 }
 
 void
-resize(XEvent *e) {
+resize(XEvent *e)
+{
 	if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
 		return;
 
@@ -3897,7 +4022,8 @@ resize(XEvent *e) {
 }
 
 void
-run(void) {
+run(void)
+{
 	XEvent ev;
 	int w = xw.w, h = xw.h;
 	fd_set rfd;
@@ -4004,7 +4130,8 @@ run(void) {
 }
 
 void
-usage(void) {
+usage(void)
+{
 	die("%s " VERSION " (c) 2010-2015 st engineers\n"
 	"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
 	"          [-i] [-t title] [-w windowid] [-e command ...] [command ...]\n"
@@ -4014,7 +4141,8 @@ usage(void) {
 }
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char *argv[])
+{
 	uint cols = 80, rows = 24;
 
 	xw.l = xw.t = 0;
@@ -4075,4 +4203,3 @@ run:
 
 	return 0;
 }
-

From f1307d91e2ec351a4a8b7352be8b5f6e4cb24294 Mon Sep 17 00:00:00 2001
From: FRIGN <dev@frign.de>
Date: Fri, 10 Jul 2015 10:29:53 +0200
Subject: [PATCH 0857/1146] Don't treat clauses like functions

and add a space between the keyword and the parentheses.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 764 +++++++++++++++++++++++++++++------------------------------
 1 file changed, 382 insertions(+), 382 deletions(-)

diff --git a/st.c b/st.c
index 03866f1..274ac5d 100644
--- a/st.c
+++ b/st.c
@@ -554,9 +554,9 @@ xwrite(int fd, const char *s, size_t len)
 {
 	size_t aux = len;
 
-	while(len > 0) {
+	while (len > 0) {
 		ssize_t r = write(fd, s, len);
-		if(r < 0)
+		if (r < 0)
 			return r;
 		len -= r;
 		s += r;
@@ -569,7 +569,7 @@ xmalloc(size_t len)
 {
 	void *p = malloc(len);
 
-	if(!p)
+	if (!p)
 		die("Out of memory\n");
 
 	return p;
@@ -578,7 +578,7 @@ xmalloc(size_t len)
 void *
 xrealloc(void *p, size_t len)
 {
-	if((p = realloc(p, len)) == NULL)
+	if ((p = realloc(p, len)) == NULL)
 		die("Out of memory\n");
 
 	return p;
@@ -587,7 +587,7 @@ xrealloc(void *p, size_t len)
 char *
 xstrdup(char *s)
 {
-	if((s = strdup(s)) == NULL)
+	if ((s = strdup(s)) == NULL)
 		die("Out of memory\n");
 
 	return s;
@@ -600,17 +600,17 @@ utf8decode(char *c, Rune *u, size_t clen)
 	Rune udecoded;
 
 	*u = UTF_INVALID;
-	if(!clen)
+	if (!clen)
 		return 0;
 	udecoded = utf8decodebyte(c[0], &len);
-	if(!BETWEEN(len, 1, UTF_SIZ))
+	if (!BETWEEN(len, 1, UTF_SIZ))
 		return 1;
-	for(i = 1, j = 1; i < clen && j < len; ++i, ++j) {
+	for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
 		udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
-		if(type != 0)
+		if (type != 0)
 			return j;
 	}
-	if(j < len)
+	if (j < len)
 		return 0;
 	*u = udecoded;
 	utf8validate(u, len);
@@ -620,8 +620,8 @@ utf8decode(char *c, Rune *u, size_t clen)
 Rune
 utf8decodebyte(char c, size_t *i)
 {
-	for(*i = 0; *i < LEN(utfmask); ++(*i))
-		if(((uchar)c & utfmask[*i]) == utfbyte[*i])
+	for (*i = 0; *i < LEN(utfmask); ++(*i))
+		if (((uchar)c & utfmask[*i]) == utfbyte[*i])
 			return (uchar)c & ~utfmask[*i];
 	return 0;
 }
@@ -632,9 +632,9 @@ utf8encode(Rune u, char *c)
 	size_t len, i;
 
 	len = utf8validate(&u, 0);
-	if(len > UTF_SIZ)
+	if (len > UTF_SIZ)
 		return 0;
-	for(i = len - 1; i != 0; --i) {
+	for (i = len - 1; i != 0; --i) {
 		c[i] = utf8encodebyte(u, 0);
 		u >>= 6;
 	}
@@ -655,10 +655,10 @@ utf8strchr(char *s, Rune u)
 	size_t i, j, len;
 
 	len = strlen(s);
-	for(i = 0, j = 0; i < len; i += j) {
-		if(!(j = utf8decode(&s[i], &r, len - i)))
+	for (i = 0, j = 0; i < len; i += j) {
+		if (!(j = utf8decode(&s[i], &r, len - i)))
 			break;
-		if(r == u)
+		if (r == u)
 			return &(s[i]);
 	}
 	return NULL;
@@ -667,9 +667,9 @@ utf8strchr(char *s, Rune u)
 size_t
 utf8validate(Rune *u, size_t i)
 {
-	if(!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
+	if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
 		*u = UTF_INVALID;
-	for(i = 1; *u > utfmax[i]; ++i)
+	for (i = 1; *u > utfmax[i]; ++i)
 		;
 	return i;
 }
@@ -684,7 +684,7 @@ selinit(void)
 	sel.primary = NULL;
 	sel.clipboard = NULL;
 	sel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
-	if(sel.xtarget == None)
+	if (sel.xtarget == None)
 		sel.xtarget = XA_STRING;
 }
 
@@ -711,10 +711,10 @@ tlinelen(int y)
 {
 	int i = term.col;
 
-	if(term.line[y][i - 1].mode & ATTR_WRAP)
+	if (term.line[y][i - 1].mode & ATTR_WRAP)
 		return i;
 
-	while(i > 0 && term.line[y][i - 1].u == ' ')
+	while (i > 0 && term.line[y][i - 1].u == ' ')
 		--i;
 
 	return i;
@@ -725,7 +725,7 @@ selnormalize(void)
 {
 	int i;
 
-	if(sel.type == SEL_REGULAR && sel.ob.y != sel.oe.y) {
+	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 {
@@ -751,10 +751,10 @@ selnormalize(void)
 int
 selected(int x, int y)
 {
-	if(sel.mode == SEL_EMPTY)
+	if (sel.mode == SEL_EMPTY)
 		return 0;
 
-	if(sel.type == SEL_RECTANGULAR)
+	if (sel.type == SEL_RECTANGULAR)
 		return BETWEEN(y, sel.nb.y, sel.ne.y)
 		    && BETWEEN(x, sel.nb.x, sel.ne.x);
 
@@ -770,7 +770,7 @@ selsnap(int *x, int *y, int direction)
 	int delim, prevdelim;
 	Glyph *gp, *prevgp;
 
-	switch(sel.snap) {
+	switch (sel.snap) {
 	case SNAP_WORD:
 		/*
 		 * Snap around if the word wraps around at the end or
@@ -778,20 +778,20 @@ selsnap(int *x, int *y, int direction)
 		 */
 		prevgp = &term.line[*y][*x];
 		prevdelim = ISDELIM(prevgp->u);
-		for(;;) {
+		for (;;) {
 			newx = *x + direction;
 			newy = *y;
-			if(!BETWEEN(newx, 0, term.col - 1)) {
+			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)
+				if (direction > 0)
 					yt = *y, xt = *x;
 				else
 					yt = newy, xt = newx;
-				if(!(term.line[yt][xt].mode & ATTR_WRAP))
+				if (!(term.line[yt][xt].mode & ATTR_WRAP))
 					break;
 			}
 
@@ -800,7 +800,7 @@ selsnap(int *x, int *y, int direction)
 
 			gp = &term.line[newy][newx];
 			delim = ISDELIM(gp->u);
-			if(!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
+			if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
 					|| (delim && gp->u != prevgp->u)))
 				break;
 
@@ -817,16 +817,16 @@ selsnap(int *x, int *y, int direction)
 		 * 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
+		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
+		} else if (direction > 0) {
+			for (; *y < term.row-1; *y += direction) {
+				if (!(term.line[*y][term.col-1].mode
 						& ATTR_WRAP)) {
 					break;
 				}
@@ -849,8 +849,8 @@ getbuttoninfo(XEvent *e)
 	selnormalize();
 
 	sel.type = SEL_REGULAR;
-	for(type = 1; type < LEN(selmasks); ++type) {
-		if(match(selmasks[type], state)) {
+	for (type = 1; type < LEN(selmasks); ++type) {
+		if (match(selmasks[type], state)) {
 			sel.type = type;
 			break;
 		}
@@ -867,51 +867,51 @@ mousereport(XEvent *e)
 	static int ox, oy;
 
 	/* from urxvt */
-	if(e->xbutton.type == MotionNotify) {
-		if(x == ox && y == oy)
+	if (e->xbutton.type == MotionNotify) {
+		if (x == ox && y == oy)
 			return;
-		if(!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
+		if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
 			return;
 		/* MOUSE_MOTION: no reporting if no button is pressed */
-		if(IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
+		if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
 			return;
 
 		button = oldbutton + 32;
 		ox = x;
 		oy = y;
 	} else {
-		if(!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
+		if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
 			button = 3;
 		} else {
 			button -= Button1;
-			if(button >= 3)
+			if (button >= 3)
 				button += 64 - 3;
 		}
-		if(e->xbutton.type == ButtonPress) {
+		if (e->xbutton.type == ButtonPress) {
 			oldbutton = button;
 			ox = x;
 			oy = y;
-		} else if(e->xbutton.type == ButtonRelease) {
+		} else if (e->xbutton.type == ButtonRelease) {
 			oldbutton = 3;
 			/* MODE_MOUSEX10: no button release reporting */
-			if(IS_SET(MODE_MOUSEX10))
+			if (IS_SET(MODE_MOUSEX10))
 				return;
 			if (button == 64 || button == 65)
 				return;
 		}
 	}
 
-	if(!IS_SET(MODE_MOUSEX10)) {
+	if (!IS_SET(MODE_MOUSEX10)) {
 		button += ((state & ShiftMask  ) ? 4  : 0)
 			+ ((state & Mod4Mask   ) ? 8  : 0)
 			+ ((state & ControlMask) ? 16 : 0);
 	}
 
-	if(IS_SET(MODE_MOUSESGR)) {
+	if (IS_SET(MODE_MOUSESGR)) {
 		len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
 				button, x+1, y+1,
 				e->xbutton.type == ButtonRelease ? 'm' : 'M');
-	} else if(x < 223 && y < 223) {
+	} else if (x < 223 && y < 223) {
 		len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
 				32+button, 32+x+1, 32+y+1);
 	} else {
@@ -927,20 +927,20 @@ bpress(XEvent *e)
 	struct timespec now;
 	Mousekey *mk;
 
-	if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);
 		return;
 	}
 
-	for(mk = mshortcuts; mk < mshortcuts + LEN(mshortcuts); mk++) {
-		if(e->xbutton.button == mk->b
+	for (mk = mshortcuts; mk < mshortcuts + LEN(mshortcuts); mk++) {
+		if (e->xbutton.button == mk->b
 				&& match(mk->mask, e->xbutton.state)) {
 			ttysend(mk->s, strlen(mk->s));
 			return;
 		}
 	}
 
-	if(e->xbutton.button == Button1) {
+	if (e->xbutton.button == Button1) {
 		clock_gettime(CLOCK_MONOTONIC, &now);
 
 		/* Clear previous selection, logically and visually. */
@@ -954,16 +954,16 @@ bpress(XEvent *e)
 		 * If the user clicks below predefined timeouts specific
 		 * snapping behaviour is exposed.
 		 */
-		if(TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) {
+		if (TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) {
 			sel.snap = SNAP_LINE;
-		} else if(TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) {
+		} else if (TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) {
 			sel.snap = SNAP_WORD;
 		} else {
 			sel.snap = 0;
 		}
 		selnormalize();
 
-		if(sel.snap != 0)
+		if (sel.snap != 0)
 			sel.mode = SEL_READY;
 		tsetdirt(sel.nb.y, sel.ne.y);
 		sel.tclick2 = sel.tclick1;
@@ -978,17 +978,17 @@ getsel(void)
 	int y, bufsize, lastx, linelen;
 	Glyph *gp, *last;
 
-	if(sel.ob.x == -1)
+	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++) {
+	for (y = sel.nb.y; y <= sel.ne.y; y++) {
 		linelen = tlinelen(y);
 
-		if(sel.type == SEL_RECTANGULAR) {
+		if (sel.type == SEL_RECTANGULAR) {
 			gp = &term.line[y][sel.nb.x];
 			lastx = sel.ne.x;
 		} else {
@@ -996,11 +996,11 @@ getsel(void)
 			lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
 		}
 		last = &term.line[y][MIN(lastx, linelen-1)];
-		while(last >= gp && last->u == ' ')
+		while (last >= gp && last->u == ' ')
 			--last;
 
-		for( ; gp <= last; ++gp) {
-			if(gp->mode & ATTR_WDUMMY)
+		for ( ; gp <= last; ++gp) {
+			if (gp->mode & ATTR_WDUMMY)
 				continue;
 
 			ptr += utf8encode(gp->u, ptr);
@@ -1015,7 +1015,7 @@ getsel(void)
 		 * st.
 		 * FIXME: Fix the computer world.
 		 */
-		if((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP))
+		if ((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP))
 			*ptr++ = '\n';
 	}
 	*ptr = 0;
@@ -1042,7 +1042,7 @@ selnotify(XEvent *e)
 	if (xsev->property == None)
 	    return;
 	do {
-		if(XGetWindowProperty(xw.dpy, xw.win, xsev->property, ofs,
+		if (XGetWindowProperty(xw.dpy, xw.win, xsev->property, ofs,
 					BUFSIZ/4, False, AnyPropertyType,
 					&type, &format, &nitems, &rem,
 					&data)) {
@@ -1059,19 +1059,19 @@ selnotify(XEvent *e)
 		 */
 		repl = data;
 		last = data + nitems * format / 8;
-		while((repl = memchr(repl, '\n', last - repl))) {
+		while ((repl = memchr(repl, '\n', last - repl))) {
 			*repl++ = '\r';
 		}
 
-		if(IS_SET(MODE_BRCKTPASTE))
+		if (IS_SET(MODE_BRCKTPASTE))
 			ttywrite("\033[200~", 6);
 		ttysend((char *)data, nitems * format / 8);
-		if(IS_SET(MODE_BRCKTPASTE))
+		if (IS_SET(MODE_BRCKTPASTE))
 			ttywrite("\033[201~", 6);
 		XFree(data);
 		/* number of 32-bit chunks returned */
 		ofs += nitems * format / 32;
-	} while(rem > 0);
+	} while (rem > 0);
 }
 
 void
@@ -1086,10 +1086,10 @@ clipcopy(const Arg *dummy)
 {
 	Atom clipboard;
 
-	if(sel.clipboard != NULL)
+	if (sel.clipboard != NULL)
 		free(sel.clipboard);
 
-	if(sel.primary != NULL) {
+	if (sel.primary != NULL) {
 		sel.clipboard = xstrdup(sel.primary);
 		clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
 		XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
@@ -1109,7 +1109,7 @@ clippaste(const Arg *dummy)
 void
 selclear(XEvent *e)
 {
-	if(sel.ob.x == -1)
+	if (sel.ob.x == -1)
 		return;
 	sel.mode = SEL_IDLE;
 	sel.ob.x = -1;
@@ -1137,22 +1137,22 @@ selrequest(XEvent *e)
 	xev.property = None;
 
 	xa_targets = XInternAtom(xw.dpy, "TARGETS", 0);
-	if(xsre->target == xa_targets) {
+	if (xsre->target == xa_targets) {
 		/* respond with the supported type */
 		string = sel.xtarget;
 		XChangeProperty(xsre->display, xsre->requestor, xsre->property,
 				XA_ATOM, 32, PropModeReplace,
 				(uchar *) &string, 1);
 		xev.property = xsre->property;
-	} else if(xsre->target == sel.xtarget || xsre->target == XA_STRING) {
+	} else if (xsre->target == sel.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) {
+		if (xsre->selection == XA_PRIMARY) {
 			seltext = sel.primary;
-		} else if(xsre->selection == clipboard) {
+		} else if (xsre->selection == clipboard) {
 			seltext = sel.clipboard;
 		} else {
 			fprintf(stderr,
@@ -1160,7 +1160,7 @@ selrequest(XEvent *e)
 				xsre->selection);
 			return;
 		}
-		if(seltext != NULL) {
+		if (seltext != NULL) {
 			XChangeProperty(xsre->display, xsre->requestor,
 					xsre->property, xsre->target,
 					8, PropModeReplace,
@@ -1170,7 +1170,7 @@ selrequest(XEvent *e)
 	}
 
 	/* all done, send a notification to the listener */
-	if(!XSendEvent(xsre->display, xsre->requestor, 1, 0, (XEvent *) &xev))
+	if (!XSendEvent(xsre->display, xsre->requestor, 1, 0, (XEvent *) &xev))
 		fprintf(stderr, "Error sending SelectionNotify event\n");
 }
 
@@ -1188,15 +1188,15 @@ xsetsel(char *str, Time t)
 void
 brelease(XEvent *e)
 {
-	if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);
 		return;
 	}
 
-	if(e->xbutton.button == Button2) {
+	if (e->xbutton.button == Button2) {
 		selpaste(NULL);
-	} else if(e->xbutton.button == Button1) {
-		if(sel.mode == SEL_READY) {
+	} else if (e->xbutton.button == Button1) {
+		if (sel.mode == SEL_READY) {
 			getbuttoninfo(e);
 			selcopy(e->xbutton.time);
 		} else
@@ -1211,12 +1211,12 @@ bmotion(XEvent *e)
 {
 	int oldey, oldex, oldsby, oldsey;
 
-	if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);
 		return;
 	}
 
-	if(!sel.mode)
+	if (!sel.mode)
 		return;
 
 	sel.mode = SEL_READY;
@@ -1226,7 +1226,7 @@ bmotion(XEvent *e)
 	oldsey = sel.ne.y;
 	getbuttoninfo(e);
 
-	if(oldey != sel.oe.y || oldex != sel.oe.x)
+	if (oldey != sel.oe.y || oldex != sel.oe.x)
 		tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
 }
 
@@ -1249,8 +1249,8 @@ execsh(void)
 	char buf[sizeof(long) * 8 + 1];
 
 	errno = 0;
-	if((pw = getpwuid(getuid())) == NULL) {
-		if(errno)
+	if ((pw = getpwuid(getuid())) == NULL) {
+		if (errno)
 			die("getpwuid:%s\n", strerror(errno));
 		else
 			die("who are you?\n");
@@ -1260,9 +1260,9 @@ execsh(void)
 		sh = (pw->pw_shell[0]) ? pw->pw_shell : shell;
 	}
 
-	if(opt_cmd)
+	if (opt_cmd)
 		prog = opt_cmd[0];
-	else if(utmp)
+	else if (utmp)
 		prog = utmp;
 	else
 		prog = sh;
@@ -1297,10 +1297,10 @@ sigchld(int a)
 	int stat;
 	pid_t p;
 
-	if((p = waitpid(pid, &stat, WNOHANG)) < 0)
+	if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
 		die("Waiting for pid %hd failed: %s\n", pid, strerror(errno));
 
-	if(pid != p)
+	if (pid != p)
 		return;
 
 	if (!WIFEXITED(stat) || WEXITSTATUS(stat))
@@ -1315,13 +1315,13 @@ stty(void)
 	char cmd[_POSIX_ARG_MAX], **p, *q, *s;
 	size_t n, siz;
 
-	if((n = strlen(stty_args)) > sizeof(cmd)-1)
+	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 = opt_cmd; p && (s = *p); ++p) {
-		if((n = strlen(s)) > siz-1)
+	for (p = opt_cmd; p && (s = *p); ++p) {
+		if ((n = strlen(s)) > siz-1)
 			die("stty parameter length too long\n");
 		*q++ = ' ';
 		q = memcpy(q, s, n);
@@ -1339,18 +1339,18 @@ ttynew(void)
 	int m, s;
 	struct winsize w = {term.row, term.col, 0, 0};
 
-	if(opt_io) {
+	if (opt_io) {
 		term.mode |= MODE_PRINT;
 		iofd = (!strcmp(opt_io, "-")) ?
 			  1 : open(opt_io, O_WRONLY | O_CREAT, 0666);
-		if(iofd < 0) {
+		if (iofd < 0) {
 			fprintf(stderr, "Error opening %s:%s\n",
 				opt_io, strerror(errno));
 		}
 	}
 
 	if (opt_line) {
-		if((cmdfd = open(opt_line, O_RDWR)) < 0)
+		if ((cmdfd = open(opt_line, O_RDWR)) < 0)
 			die("open line failed: %s\n", strerror(errno));
 		close(0);
 		dup(cmdfd);
@@ -1359,10 +1359,10 @@ ttynew(void)
 	}
 
 	/* seems to work fine on linux, openbsd and freebsd */
-	if(openpty(&m, &s, NULL, NULL, &w) < 0)
+	if (openpty(&m, &s, NULL, NULL, &w) < 0)
 		die("openpty failed: %s\n", strerror(errno));
 
-	switch(pid = fork()) {
+	switch (pid = fork()) {
 	case -1:
 		die("fork failed\n");
 		break;
@@ -1372,7 +1372,7 @@ ttynew(void)
 		dup2(s, 0);
 		dup2(s, 1);
 		dup2(s, 2);
-		if(ioctl(s, TIOCSCTTY, NULL) < 0)
+		if (ioctl(s, TIOCSCTTY, NULL) < 0)
 			die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
 		close(s);
 		close(m);
@@ -1397,13 +1397,13 @@ ttyread(void)
 	int ret;
 
 	/* append read bytes to unprocessed bytes */
-	if((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
+	if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
 		die("Couldn't read from shell: %s\n", strerror(errno));
 
 	/* process every complete utf8 char */
 	buflen += ret;
 	ptr = buf;
-	while((charsize = utf8decode(ptr, &unicodep, buflen))) {
+	while ((charsize = utf8decode(ptr, &unicodep, buflen))) {
 		tputc(unicodep);
 		ptr += charsize;
 		buflen -= charsize;
@@ -1416,7 +1416,7 @@ ttyread(void)
 void
 ttywrite(const char *s, size_t n)
 {
-	if(xwrite(cmdfd, s, n) == -1)
+	if (xwrite(cmdfd, s, n) == -1)
 		die("write error on tty: %s\n", strerror(errno));
 }
 
@@ -1427,8 +1427,8 @@ ttysend(char *s, size_t n)
 	Rune u;
 
 	ttywrite(s, n);
-	if(IS_SET(MODE_ECHO))
-		while((len = utf8decode(s, &u, n)) > 0) {
+	if (IS_SET(MODE_ECHO))
+		while ((len = utf8decode(s, &u, n)) > 0) {
 			techo(u);
 			n -= len;
 			s += len;
@@ -1444,7 +1444,7 @@ ttyresize(void)
 	w.ws_col = term.col;
 	w.ws_xpixel = xw.tw;
 	w.ws_ypixel = xw.th;
-	if(ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
+	if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
 		fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno));
 }
 
@@ -1453,9 +1453,9 @@ 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)
+	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;
 		}
 	}
@@ -1471,7 +1471,7 @@ tsetdirt(int top, int bot)
 	LIMIT(top, 0, term.row-1);
 	LIMIT(bot, 0, term.row-1);
 
-	for(i = top; i <= bot; i++)
+	for (i = top; i <= bot; i++)
 		term.dirty[i] = 1;
 }
 
@@ -1480,9 +1480,9 @@ 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) {
+	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;
 			}
@@ -1502,9 +1502,9 @@ tcursor(int mode)
 	static TCursor c[2];
 	int alt = IS_SET(MODE_ALTSCREEN);
 
-	if(mode == CURSOR_SAVE) {
+	if (mode == CURSOR_SAVE) {
 		c[alt] = term.c;
-	} else if(mode == CURSOR_LOAD) {
+	} else if (mode == CURSOR_LOAD) {
 		term.c = c[alt];
 		tmoveto(c[alt].x, c[alt].y);
 	}
@@ -1522,7 +1522,7 @@ treset(void)
 	}, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
 
 	memset(term.tabs, 0, term.col * sizeof(*term.tabs));
-	for(i = tabspaces; i < term.col; i += tabspaces)
+	for (i = tabspaces; i < term.col; i += tabspaces)
 		term.tabs[i] = 1;
 	term.top = 0;
 	term.bot = term.row - 1;
@@ -1530,7 +1530,7 @@ treset(void)
 	memset(term.trantbl, CS_USA, sizeof(term.trantbl));
 	term.charset = 0;
 
-	for(i = 0; i < 2; i++) {
+	for (i = 0; i < 2; i++) {
 		tmoveto(0, 0);
 		tcursor(CURSOR_SAVE);
 		tclearregion(0, 0, term.col-1, term.row-1);
@@ -1570,7 +1570,7 @@ tscrolldown(int orig, int n)
 	tsetdirt(orig, term.bot-n);
 	tclearregion(0, term.bot-n+1, term.col-1, term.bot);
 
-	for(i = term.bot; i >= orig+n; i--) {
+	for (i = term.bot; i >= orig+n; i--) {
 		temp = term.line[i];
 		term.line[i] = term.line[i-n];
 		term.line[i-n] = temp;
@@ -1590,7 +1590,7 @@ tscrollup(int orig, int n)
 	tclearregion(0, orig, term.col-1, orig+n-1);
 	tsetdirt(orig+n, term.bot);
 
-	for(i = orig; i <= term.bot-n; i++) {
+	for (i = orig; i <= term.bot-n; i++) {
 		temp = term.line[i];
 		term.line[i] = term.line[i+n];
 		term.line[i+n] = temp;
@@ -1602,25 +1602,25 @@ tscrollup(int orig, int n)
 void
 selscroll(int orig, int n)
 {
-	if(sel.ob.x == -1)
+	if (sel.ob.x == -1)
 		return;
 
-	if(BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig, term.bot)) {
-		if((sel.ob.y += n) > term.bot || (sel.oe.y += n) < term.top) {
+	if (BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig, term.bot)) {
+		if ((sel.ob.y += n) > term.bot || (sel.oe.y += n) < term.top) {
 			selclear(NULL);
 			return;
 		}
-		if(sel.type == SEL_RECTANGULAR) {
-			if(sel.ob.y < term.top)
+		if (sel.type == SEL_RECTANGULAR) {
+			if (sel.ob.y < term.top)
 				sel.ob.y = term.top;
-			if(sel.oe.y > term.bot)
+			if (sel.oe.y > term.bot)
 				sel.oe.y = term.bot;
 		} else {
-			if(sel.ob.y < term.top) {
+			if (sel.ob.y < term.top) {
 				sel.ob.y = term.top;
 				sel.ob.x = 0;
 			}
-			if(sel.oe.y > term.bot) {
+			if (sel.oe.y > term.bot) {
 				sel.oe.y = term.bot;
 				sel.oe.x = term.col;
 			}
@@ -1634,7 +1634,7 @@ tnewline(int first_col)
 {
 	int y = term.c.y;
 
-	if(y == term.bot) {
+	if (y == term.bot) {
 		tscrollup(term.top, 1);
 	} else {
 		y++;
@@ -1649,22 +1649,22 @@ csiparse(void)
 	long int v;
 
 	csiescseq.narg = 0;
-	if(*p == '?') {
+	if (*p == '?') {
 		csiescseq.priv = 1;
 		p++;
 	}
 
 	csiescseq.buf[csiescseq.len] = '\0';
-	while(p < csiescseq.buf+csiescseq.len) {
+	while (p < csiescseq.buf+csiescseq.len) {
 		np = NULL;
 		v = strtol(p, &np, 10);
-		if(np == p)
+		if (np == p)
 			v = 0;
-		if(v == LONG_MAX || v == LONG_MIN)
+		if (v == LONG_MAX || v == LONG_MIN)
 			v = -1;
 		csiescseq.arg[csiescseq.narg++] = v;
 		p = np;
-		if(*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
+		if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
 			break;
 		p++;
 	}
@@ -1684,7 +1684,7 @@ tmoveto(int x, int y)
 {
 	int miny, maxy;
 
-	if(term.c.state & CURSOR_ORIGIN) {
+	if (term.c.state & CURSOR_ORIGIN) {
 		miny = term.top;
 		maxy = term.bot;
 	} else {
@@ -1713,16 +1713,16 @@ tsetchar(Rune u, Glyph *attr, int x, int y)
 	/*
 	 * The table is proudly stolen from rxvt.
 	 */
-	if(term.trantbl[term.charset] == CS_GRAPHIC0 &&
+	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) {
+	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) {
+	} else if (term.line[y][x].mode & ATTR_WDUMMY) {
 		term.line[y][x-1].u = ' ';
 		term.line[y][x-1].mode &= ~ATTR_WIDE;
 	}
@@ -1738,9 +1738,9 @@ tclearregion(int x1, int y1, int x2, int y2)
 	int x, y, temp;
 	Glyph *gp;
 
-	if(x1 > x2)
+	if (x1 > x2)
 		temp = x1, x1 = x2, x2 = temp;
-	if(y1 > y2)
+	if (y1 > y2)
 		temp = y1, y1 = y2, y2 = temp;
 
 	LIMIT(x1, 0, term.col-1);
@@ -1748,11 +1748,11 @@ tclearregion(int x1, int y1, int x2, int y2)
 	LIMIT(y1, 0, term.row-1);
 	LIMIT(y2, 0, term.row-1);
 
-	for(y = y1; y <= y2; y++) {
+	for (y = y1; y <= y2; y++) {
 		term.dirty[y] = 1;
-		for(x = x1; x <= x2; x++) {
+		for (x = x1; x <= x2; x++) {
 			gp = &term.line[y][x];
-			if(selected(x, y))
+			if (selected(x, y))
 				selclear(NULL);
 			gp->fg = term.c.attr.fg;
 			gp->bg = term.c.attr.bg;
@@ -1799,14 +1799,14 @@ tinsertblank(int n)
 void
 tinsertblankline(int n)
 {
-	if(BETWEEN(term.c.y, term.top, term.bot))
+	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))
+	if (BETWEEN(term.c.y, term.top, term.bot))
 		tscrollup(term.c.y, n);
 }
 
@@ -1828,7 +1828,7 @@ tdefcolor(int *attr, int *npar, int l)
 		g = attr[*npar + 3];
 		b = attr[*npar + 4];
 		*npar += 4;
-		if(!BETWEEN(r, 0, 255) || !BETWEEN(g, 0, 255) || !BETWEEN(b, 0, 255))
+		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
@@ -1842,7 +1842,7 @@ tdefcolor(int *attr, int *npar, int l)
 			break;
 		}
 		*npar += 2;
-		if(!BETWEEN(attr[*npar], 0, 255))
+		if (!BETWEEN(attr[*npar], 0, 255))
 			fprintf(stderr, "erresc: bad fgcolor %d\n", attr[*npar]);
 		else
 			idx = attr[*npar];
@@ -1866,8 +1866,8 @@ tsetattr(int *attr, int l)
 	int i;
 	int32_t idx;
 
-	for(i = 0; i < l; i++) {
-		switch(attr[i]) {
+	for (i = 0; i < l; i++) {
+		switch (attr[i]) {
 		case 0:
 			term.c.attr.mode &= ~(
 				ATTR_BOLD       |
@@ -1943,13 +1943,13 @@ tsetattr(int *attr, int l)
 			term.c.attr.bg = defaultbg;
 			break;
 		default:
-			if(BETWEEN(attr[i], 30, 37)) {
+			if (BETWEEN(attr[i], 30, 37)) {
 				term.c.attr.fg = attr[i] - 30;
-			} else if(BETWEEN(attr[i], 40, 47)) {
+			} else if (BETWEEN(attr[i], 40, 47)) {
 				term.c.attr.bg = attr[i] - 40;
-			} else if(BETWEEN(attr[i], 90, 97)) {
+			} else if (BETWEEN(attr[i], 90, 97)) {
 				term.c.attr.fg = attr[i] - 90 + 8;
-			} else if(BETWEEN(attr[i], 100, 107)) {
+			} else if (BETWEEN(attr[i], 100, 107)) {
 				term.c.attr.bg = attr[i] - 100 + 8;
 			} else {
 				fprintf(stderr,
@@ -1968,7 +1968,7 @@ tsetscroll(int t, int b)
 
 	LIMIT(t, 0, term.row-1);
 	LIMIT(b, 0, term.row-1);
-	if(t > b) {
+	if (t > b) {
 		temp = t;
 		t = b;
 		b = temp;
@@ -1983,16 +1983,16 @@ tsetmode(int priv, int set, int *args, int narg)
 	int *lim, mode;
 	int alt;
 
-	for(lim = args + narg; args < lim; ++args) {
-		if(priv) {
-			switch(*args) {
+	for (lim = args + narg; args < lim; ++args) {
+		if (priv) {
+			switch (*args) {
 			case 1: /* DECCKM -- Cursor key */
 				MODBIT(term.mode, set, MODE_APPCURSOR);
 				break;
 			case 5: /* DECSCNM -- Reverse video */
 				mode = term.mode;
 				MODBIT(term.mode, set, MODE_REVERSE);
-				if(mode != term.mode)
+				if (mode != term.mode)
 					redraw();
 				break;
 			case 6: /* DECOM -- Origin */
@@ -2054,13 +2054,13 @@ tsetmode(int priv, int set, int *args, int narg)
 				if (!allowaltscreen)
 					break;
 				alt = IS_SET(MODE_ALTSCREEN);
-				if(alt) {
+				if (alt) {
 					tclearregion(0, 0, term.col-1,
 							term.row-1);
 				}
-				if(set ^ alt) /* set is always 1 or 0 */
+				if (set ^ alt) /* set is always 1 or 0 */
 					tswapscreen();
-				if(*args != 1049)
+				if (*args != 1049)
 					break;
 				/* FALLTHROUGH */
 			case 1048:
@@ -2085,7 +2085,7 @@ tsetmode(int priv, int set, int *args, int narg)
 				break;
 			}
 		} else {
-			switch(*args) {
+			switch (*args) {
 			case 0:  /* Error (IGNORED) */
 				break;
 			case 2:  /* KAM -- keyboard action */
@@ -2116,7 +2116,7 @@ csihandle(void)
 	char buf[40];
 	int len;
 
-	switch(csiescseq.mode[0]) {
+	switch (csiescseq.mode[0]) {
 	default:
 	unknown:
 		fprintf(stderr, "erresc: unknown csi ");
@@ -2137,7 +2137,7 @@ csihandle(void)
 		tmoveto(term.c.x, term.c.y+csiescseq.arg[0]);
 		break;
 	case 'i': /* MC -- Media Copy */
-		switch(csiescseq.arg[0]) {
+		switch (csiescseq.arg[0]) {
 		case 0:
 			tdump();
 			break;
@@ -2156,7 +2156,7 @@ csihandle(void)
 		}
 		break;
 	case 'c': /* DA -- Device Attributes */
-		if(csiescseq.arg[0] == 0)
+		if (csiescseq.arg[0] == 0)
 			ttywrite(vtiden, sizeof(vtiden) - 1);
 		break;
 	case 'C': /* CUF -- Cursor <n> Forward */
@@ -2177,7 +2177,7 @@ csihandle(void)
 		tmoveto(0, term.c.y-csiescseq.arg[0]);
 		break;
 	case 'g': /* TBC -- Tabulation clear */
-		switch(csiescseq.arg[0]) {
+		switch (csiescseq.arg[0]) {
 		case 0: /* clear current tab stop */
 			term.tabs[term.c.x] = 0;
 			break;
@@ -2205,16 +2205,16 @@ csihandle(void)
 		break;
 	case 'J': /* ED -- Clear screen */
 		selclear(NULL);
-		switch(csiescseq.arg[0]) {
+		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) {
+			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)
+			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;
@@ -2226,7 +2226,7 @@ csihandle(void)
 		}
 		break;
 	case 'K': /* EL -- Clear line */
-		switch(csiescseq.arg[0]) {
+		switch (csiescseq.arg[0]) {
 		case 0: /* right */
 			tclearregion(term.c.x, term.c.y, term.col-1,
 					term.c.y);
@@ -2289,7 +2289,7 @@ csihandle(void)
 		}
 		break;
 	case 'r': /* DECSTBM -- Set Scrolling Region */
-		if(csiescseq.priv) {
+		if (csiescseq.priv) {
 			goto unknown;
 		} else {
 			DEFAULT(csiescseq.arg[0], 1);
@@ -2327,15 +2327,15 @@ csidump(void)
 	uint c;
 
 	printf("ESC[");
-	for(i = 0; i < csiescseq.len; i++) {
+	for (i = 0; i < csiescseq.len; i++) {
 		c = csiescseq.buf[i] & 0xff;
-		if(isprint(c)) {
+		if (isprint(c)) {
 			putchar(c);
-		} else if(c == '\n') {
+		} else if (c == '\n') {
 			printf("(\\n)");
-		} else if(c == '\r') {
+		} else if (c == '\r') {
 			printf("(\\r)");
-		} else if(c == 0x1b) {
+		} else if (c == 0x1b) {
 			printf("(\\e)");
 		} else {
 			printf("(%02x)", c);
@@ -2360,23 +2360,23 @@ strhandle(void)
 	strparse();
 	par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0;
 
-	switch(strescseq.type) {
+	switch (strescseq.type) {
 	case ']': /* OSC -- Operating System Command */
-		switch(par) {
+		switch (par) {
 		case 0:
 		case 1:
 		case 2:
-			if(narg > 1)
+			if (narg > 1)
 				xsettitle(strescseq.args[1]);
 			return;
 		case 4: /* color set */
-			if(narg < 3)
+			if (narg < 3)
 				break;
 			p = strescseq.args[2];
 			/* FALLTHROUGH */
 		case 104: /* color reset, here p = NULL */
 			j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
-			if(xsetcolorname(j, p)) {
+			if (xsetcolorname(j, p)) {
 				fprintf(stderr, "erresc: invalid color %s\n", p);
 			} else {
 				/*
@@ -2410,14 +2410,14 @@ strparse(void)
 	strescseq.narg = 0;
 	strescseq.buf[strescseq.len] = '\0';
 
-	if(*p == '\0')
+	if (*p == '\0')
 		return;
 
-	while(strescseq.narg < STR_ARG_SIZ) {
+	while (strescseq.narg < STR_ARG_SIZ) {
 		strescseq.args[strescseq.narg++] = p;
-		while((c = *p) != ';' && c != '\0')
+		while ((c = *p) != ';' && c != '\0')
 			++p;
-		if(c == '\0')
+		if (c == '\0')
 			return;
 		*p++ = '\0';
 	}
@@ -2430,17 +2430,17 @@ strdump(void)
 	uint c;
 
 	printf("ESC%c", strescseq.type);
-	for(i = 0; i < strescseq.len; i++) {
+	for (i = 0; i < strescseq.len; i++) {
 		c = strescseq.buf[i] & 0xff;
-		if(c == '\0') {
+		if (c == '\0') {
 			return;
-		} else if(isprint(c)) {
+		} else if (isprint(c)) {
 			putchar(c);
-		} else if(c == '\n') {
+		} else if (c == '\n') {
 			printf("(\\n)");
-		} else if(c == '\r') {
+		} else if (c == '\r') {
 			printf("(\\r)");
-		} else if(c == 0x1b) {
+		} else if (c == 0x1b) {
 			printf("(\\e)");
 		} else {
 			printf("(%02x)", c);
@@ -2458,7 +2458,7 @@ strreset(void)
 void
 tprinter(char *s, size_t len)
 {
-	if(iofd != -1 && xwrite(iofd, s, len) < 0) {
+	if (iofd != -1 && xwrite(iofd, s, len) < 0) {
 		fprintf(stderr, "Error writing in %s:%s\n",
 			opt_io, strerror(errno));
 		close(iofd);
@@ -2489,7 +2489,7 @@ tdumpsel(void)
 {
 	char *ptr;
 
-	if((ptr = getsel())) {
+	if ((ptr = getsel())) {
 		tprinter(ptr, strlen(ptr));
 		free(ptr);
 	}
@@ -2503,8 +2503,8 @@ tdumpline(int n)
 
 	bp = &term.line[n][0];
 	end = &bp[MIN(tlinelen(n), term.col) - 1];
-	if(bp != end || bp->u != ' ') {
-		for( ;bp <= end; ++bp)
+	if (bp != end || bp->u != ' ') {
+		for ( ;bp <= end; ++bp)
 			tprinter(buf, utf8encode(bp->u, buf));
 	}
 	tprinter("\n", 1);
@@ -2515,7 +2515,7 @@ tdump(void)
 {
 	int i;
 
-	for(i = 0; i < term.row; ++i)
+	for (i = 0; i < term.row; ++i)
 		tdumpline(i);
 }
 
@@ -2524,13 +2524,13 @@ 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)
+	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)
+	} 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);
@@ -2539,12 +2539,12 @@ tputtab(int n)
 void
 techo(Rune u)
 {
-	if(ISCONTROL(u)) { /* control code */
-		if(u & 0x80) {
+	if (ISCONTROL(u)) { /* control code */
+		if (u & 0x80) {
 			u &= 0x7f;
 			tputc('^');
 			tputc('[');
-		} else if(u != '\n' && u != '\r' && u != '\t') {
+		} else if (u != '\n' && u != '\r' && u != '\t') {
 			u ^= 0x40;
 			tputc('^');
 		}
@@ -2559,7 +2559,7 @@ tdeftran(char ascii)
 	static int vcs[] = {CS_GRAPHIC0, CS_USA};
 	char *p;
 
-	if((p = strchr(cs, ascii)) == NULL) {
+	if ((p = strchr(cs, ascii)) == NULL) {
 		fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
 	} else {
 		term.trantbl[term.icharset] = vcs[p - cs];
@@ -2571,9 +2571,9 @@ 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)
+	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);
 		}
 	}
@@ -2604,7 +2604,7 @@ tstrsequence(uchar c)
 void
 tcontrolcode(uchar ascii)
 {
-	switch(ascii) {
+	switch (ascii) {
 	case '\t':   /* HT */
 		tputtab(1);
 		return;
@@ -2621,11 +2621,11 @@ tcontrolcode(uchar ascii)
 		tnewline(IS_SET(MODE_CRLF));
 		return;
 	case '\a':   /* BEL */
-		if(term.esc & ESC_STR_END) {
+		if (term.esc & ESC_STR_END) {
 			/* backwards compatibility to xterm */
 			strhandle();
 		} else {
-			if(!(xw.state & WIN_FOCUSED))
+			if (!(xw.state & WIN_FOCUSED))
 				xseturgency(1);
 			if (bellvolume)
 				XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL);
@@ -2688,7 +2688,7 @@ tcontrolcode(uchar ascii)
 int
 eschandle(uchar ascii)
 {
-	switch(ascii) {
+	switch (ascii) {
 	case '[':
 		term.esc |= ESC_CSI;
 		return 0;
@@ -2714,7 +2714,7 @@ eschandle(uchar ascii)
 		term.esc |= ESC_ALTCHARSET;
 		return 0;
 	case 'D': /* IND -- Linefeed */
-		if(term.c.y == term.bot) {
+		if (term.c.y == term.bot) {
 			tscrollup(term.top, 1);
 		} else {
 			tmoveto(term.c.x, term.c.y+1);
@@ -2727,7 +2727,7 @@ eschandle(uchar ascii)
 		term.tabs[term.c.x] = 1;
 		break;
 	case 'M': /* RI -- Reverse index */
-		if(term.c.y == term.top) {
+		if (term.c.y == term.top) {
 			tscrolldown(term.top, 1);
 		} else {
 			tmoveto(term.c.x, term.c.y-1);
@@ -2754,7 +2754,7 @@ eschandle(uchar ascii)
 		tcursor(CURSOR_LOAD);
 		break;
 	case '\\': /* ST -- String Terminator */
-		if(term.esc & ESC_STR_END)
+		if (term.esc & ESC_STR_END)
 			strhandle();
 		break;
 	default:
@@ -2774,12 +2774,12 @@ tputc(Rune u)
 	Glyph *gp;
 
 	len = utf8encode(u, c);
-	if((width = wcwidth(u)) == -1) {
+	if ((width = wcwidth(u)) == -1) {
 		memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
 		width = 1;
 	}
 
-	if(IS_SET(MODE_PRINT))
+	if (IS_SET(MODE_PRINT))
 		tprinter(c, len);
 	control = ISCONTROL(u);
 
@@ -2789,12 +2789,12 @@ tputc(Rune u)
 	 * 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 ||
+	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;
-		} else if(strescseq.len + len < sizeof(strescseq.buf) - 1) {
+		} else if (strescseq.len + len < sizeof(strescseq.buf) - 1) {
 			memmove(&strescseq.buf[strescseq.len], c, len);
 			strescseq.len += len;
 			return;
@@ -2821,16 +2821,16 @@ tputc(Rune u)
 	 * because they can be embedded inside a control sequence, and
 	 * they must not cause conflicts with sequences.
 	 */
-	if(control) {
+	if (control) {
 		tcontrolcode(u);
 		/*
 		 * control codes are not shown ever
 		 */
 		return;
-	} else if(term.esc & ESC_START) {
-		if(term.esc & ESC_CSI) {
+	} else if (term.esc & ESC_START) {
+		if (term.esc & ESC_CSI) {
 			csiescseq.buf[csiescseq.len++] = u;
-			if(BETWEEN(u, 0x40, 0x7E)
+			if (BETWEEN(u, 0x40, 0x7E)
 					|| csiescseq.len >= \
 					sizeof(csiescseq.buf)-1) {
 				term.esc = 0;
@@ -2838,9 +2838,9 @@ tputc(Rune u)
 				csihandle();
 			}
 			return;
-		} else if(term.esc & ESC_ALTCHARSET) {
+		} else if (term.esc & ESC_ALTCHARSET) {
 			tdeftran(u);
-		} else if(term.esc & ESC_TEST) {
+		} else if (term.esc & ESC_TEST) {
 			tdectest(u);
 		} else {
 			if (!eschandle(u))
@@ -2854,34 +2854,34 @@ tputc(Rune u)
 		 */
 		return;
 	}
-	if(sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
+	if (sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
 		selclear(NULL);
 
 	gp = &term.line[term.c.y][term.c.x];
-	if(IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
+	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)
+	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) {
+	if (term.c.x+width > term.col) {
 		tnewline(1);
 		gp = &term.line[term.c.y][term.c.x];
 	}
 
 	tsetchar(u, &term.c.attr, term.c.x, term.c.y);
 
-	if(width == 2) {
+	if (width == 2) {
 		gp->mode |= ATTR_WIDE;
-		if(term.c.x+1 < term.col) {
+		if (term.c.x+1 < term.col) {
 			gp[1].u = '\0';
 			gp[1].mode = ATTR_WDUMMY;
 		}
 	}
-	if(term.c.x+width < term.col) {
+	if (term.c.x+width < term.col) {
 		tmoveto(term.c.x+width, term.c.y);
 	} else {
 		term.c.state |= CURSOR_WRAPNEXT;
@@ -2897,7 +2897,7 @@ tresize(int col, int row)
 	int *bp;
 	TCursor c;
 
-	if(col < 1 || row < 1) {
+	if (col < 1 || row < 1) {
 		fprintf(stderr,
 		        "tresize: error resizing to %dx%d\n", col, row);
 		return;
@@ -2908,7 +2908,7 @@ tresize(int col, int row)
 	 * 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++) {
+	for (i = 0; i <= term.c.y - row; i++) {
 		free(term.line[i]);
 		free(term.alt[i]);
 	}
@@ -2917,7 +2917,7 @@ tresize(int col, int row)
 		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++) {
+	for (i += row; i < term.row; i++) {
 		free(term.line[i]);
 		free(term.alt[i]);
 	}
@@ -2932,23 +2932,23 @@ tresize(int col, int row)
 	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++) {
+	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++) {
+	for (/* i == minrow */; i < row; i++) {
 		term.line[i] = xmalloc(col * sizeof(Glyph));
 		term.alt[i] = xmalloc(col * sizeof(Glyph));
 	}
-	if(col > term.col) {
+	if (col > term.col) {
 		bp = term.tabs + term.col;
 
 		memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
-		while(--bp > term.tabs && !*bp)
+		while (--bp > term.tabs && !*bp)
 			/* nothing */ ;
-		for(bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
+		for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
 			*bp = 1;
 	}
 	/* update terminal size */
@@ -2960,11 +2960,11 @@ tresize(int col, int row)
 	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) {
+	for (i = 0; i < 2; i++) {
+		if (mincol < col && 0 < minrow) {
 			tclearregion(mincol, 0, col - 1, minrow - 1);
 		}
-		if(0 < col && minrow < row) {
+		if (0 < col && minrow < row) {
 			tclearregion(0, minrow, col - 1, row - 1);
 		}
 		tswapscreen();
@@ -2997,9 +2997,9 @@ 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 */
+	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 );
@@ -3022,14 +3022,14 @@ xloadcols(void)
 	static int loaded;
 	Color *cp;
 
-	if(loaded) {
+	if (loaded) {
 		for (cp = dc.col; cp < &dc.col[LEN(dc.col)]; ++cp)
 			XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
 	}
 
-	for(i = 0; i < LEN(dc.col); i++)
-		if(!xloadcolor(i, NULL, &dc.col[i])) {
-			if(colorname[i])
+	for (i = 0; i < LEN(dc.col); 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);
@@ -3042,11 +3042,11 @@ xsetcolorname(int x, const char *name)
 {
 	Color ncolor;
 
-	if(!BETWEEN(x, 0, LEN(dc.col)))
+	if (!BETWEEN(x, 0, LEN(dc.col)))
 		return 1;
 
 
-	if(!xloadcolor(x, name, &ncolor))
+	if (!xloadcolor(x, name, &ncolor))
 		return 1;
 
 	XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
@@ -3092,12 +3092,12 @@ xhints(void)
 	sizeh->width_inc = xw.cw;
 	sizeh->base_height = 2 * borderpx;
 	sizeh->base_width = 2 * borderpx;
-	if(xw.isfixed) {
+	if (xw.isfixed) {
 		sizeh->flags |= PMaxSize | PMinSize;
 		sizeh->min_width = sizeh->max_width = xw.w;
 		sizeh->min_height = sizeh->max_height = xw.h;
 	}
-	if(xw.gm & (XValue|YValue)) {
+	if (xw.gm & (XValue|YValue)) {
 		sizeh->flags |= USPosition | PWinGravity;
 		sizeh->x = xw.l;
 		sizeh->y = xw.t;
@@ -3112,7 +3112,7 @@ xhints(void)
 int
 xgeommasktogravity(int mask)
 {
-	switch(mask & (XNegative|YNegative)) {
+	switch (mask & (XNegative|YNegative)) {
 	case 0:
 		return NorthWestGravity;
 	case XNegative:
@@ -3130,10 +3130,10 @@ xloadfont(Font *f, FcPattern *pattern)
 	FcResult result;
 
 	match = FcFontMatch(NULL, pattern, &result);
-	if(!match)
+	if (!match)
 		return 1;
 
-	if(!(f->match = XftFontOpenPattern(xw.dpy, match))) {
+	if (!(f->match = XftFontOpenPattern(xw.dpy, match))) {
 		FcPatternDestroy(match);
 		return 1;
 	}
@@ -3159,25 +3159,25 @@ xloadfonts(char *fontstr, double fontsize)
 	double fontval;
 	float ceilf(float);
 
-	if(fontstr[0] == '-') {
+	if (fontstr[0] == '-') {
 		pattern = XftXlfdParse(fontstr, False, False);
 	} else {
 		pattern = FcNameParse((FcChar8 *)fontstr);
 	}
 
-	if(!pattern)
+	if (!pattern)
 		die("st: can't open font %s\n", fontstr);
 
-	if(fontsize > 1) {
+	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) ==
+		if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) ==
 				FcResultMatch) {
 			usedfontsize = fontval;
-		} else if(FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) ==
+		} else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) ==
 				FcResultMatch) {
 			usedfontsize = -1;
 		} else {
@@ -3194,14 +3194,14 @@ xloadfonts(char *fontstr, double fontsize)
 	FcConfigSubstitute(0, pattern, FcMatchPattern);
 	FcDefaultSubstitute(pattern);
 
-	if(xloadfont(&dc.font, pattern))
+	if (xloadfont(&dc.font, pattern))
 		die("st: can't open font %s\n", fontstr);
 
-	if(usedfontsize < 0) {
+	if (usedfontsize < 0) {
 		FcPatternGetDouble(dc.font.match->pattern,
 		                   FC_PIXEL_SIZE, 0, &fontval);
 		usedfontsize = fontval;
-		if(fontsize == 0)
+		if (fontsize == 0)
 			defaultfontsize = fontval;
 	}
 
@@ -3211,17 +3211,17 @@ xloadfonts(char *fontstr, double fontsize)
 
 	FcPatternDel(pattern, FC_SLANT);
 	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
-	if(xloadfont(&dc.ifont, pattern))
+	if (xloadfont(&dc.ifont, pattern))
 		die("st: can't open font %s\n", fontstr);
 
 	FcPatternDel(pattern, FC_WEIGHT);
 	FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
-	if(xloadfont(&dc.ibfont, pattern))
+	if (xloadfont(&dc.ibfont, pattern))
 		die("st: can't open font %s\n", fontstr);
 
 	FcPatternDel(pattern, FC_SLANT);
 	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
-	if(xloadfont(&dc.bfont, pattern))
+	if (xloadfont(&dc.bfont, pattern))
 		die("st: can't open font %s\n", fontstr);
 
 	FcPatternDestroy(pattern);
@@ -3232,7 +3232,7 @@ xunloadfont(Font *f)
 {
 	XftFontClose(xw.dpy, f->match);
 	FcPatternDestroy(f->pattern);
-	if(f->set)
+	if (f->set)
 		FcFontSetDestroy(f->set);
 }
 
@@ -3240,7 +3240,7 @@ void
 xunloadfonts(void)
 {
 	/* Free the loaded fonts in the font cache.  */
-	while(frclen > 0)
+	while (frclen > 0)
 		XftFontClose(xw.dpy, frc[--frclen].font);
 
 	xunloadfont(&dc.font);
@@ -3273,7 +3273,7 @@ xzoomreset(const Arg *arg)
 {
 	Arg larg;
 
-	if(defaultfontsize > 0) {
+	if (defaultfontsize > 0) {
 		larg.f = defaultfontsize;
 		xzoomabs(&larg);
 	}
@@ -3287,13 +3287,13 @@ xinit(void)
 	Window parent;
 	pid_t thispid = getpid();
 
-	if(!(xw.dpy = XOpenDisplay(NULL)))
+	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())
+	if (!FcInit())
 		die("Could not init fontconfig.\n");
 
 	usedfont = (opt_font == NULL)? font : opt_font;
@@ -3306,9 +3306,9 @@ xinit(void)
 	/* adjust fixed window geometry */
 	xw.w = 2 * borderpx + term.col * xw.cw;
 	xw.h = 2 * borderpx + term.row * xw.ch;
-	if(xw.gm & XNegative)
+	if (xw.gm & XNegative)
 		xw.l += DisplayWidth(xw.dpy, xw.scr) - xw.w - 2;
-	if(xw.gm & YNegative)
+	if (xw.gm & YNegative)
 		xw.t += DisplayWidth(xw.dpy, xw.scr) - xw.h - 2;
 
 	/* Events */
@@ -3340,11 +3340,11 @@ xinit(void)
 	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
 
 	/* input methods */
-	if((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+	if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
 		XSetLocaleModifiers("@im=local");
-		if((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+		if ((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
 			XSetLocaleModifiers("@im=");
-			if((xw.xim = XOpenIM(xw.dpy,
+			if ((xw.xim = XOpenIM(xw.dpy,
 					NULL, NULL, NULL)) == NULL) {
 				die("XOpenIM failed. Could not open input"
 					" device.\n");
@@ -3354,7 +3354,7 @@ xinit(void)
 	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
 					   | XIMStatusNothing, XNClientWindow, xw.win,
 					   XNFocusWindow, xw.win, NULL);
-	if(xw.xic == NULL)
+	if (xw.xic == NULL)
 		die("XCreateIC failed. Could not obtain input method.\n");
 
 	/* white cursor, black outline */
@@ -3395,28 +3395,28 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
 	FcCharSet *fccharset;
 	int i, f, numspecs = 0;
 
-	for(i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
+	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)
+		if (mode == ATTR_WDUMMY)
 			continue;
 
 		/* Determine font for glyph if different from previous glyph. */
-		if(prevmode != mode) {
+		if (prevmode != mode) {
 			prevmode = mode;
 			font = &dc.font;
 			frcflags = FRC_NORMAL;
 			runewidth = xw.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f);
-			if((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
+			if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
 				font = &dc.ibfont;
 				frcflags = FRC_ITALICBOLD;
-			} else if(mode & ATTR_ITALIC) {
+			} else if (mode & ATTR_ITALIC) {
 				font = &dc.ifont;
 				frcflags = FRC_ITALIC;
-			} else if(mode & ATTR_BOLD) {
+			} else if (mode & ATTR_BOLD) {
 				font = &dc.bfont;
 				frcflags = FRC_BOLD;
 			}
@@ -3425,7 +3425,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
 
 		/* Lookup character index with default font. */
 		glyphidx = XftCharIndex(xw.dpy, font->match, rune);
-		if(glyphidx) {
+		if (glyphidx) {
 			specs[numspecs].font = font->match;
 			specs[numspecs].glyph = glyphidx;
 			specs[numspecs].x = (short)xp;
@@ -3436,21 +3436,21 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
 		}
 
 		/* Fallback on font cache, search the font cache for match. */
-		for(f = 0; f < frclen; f++) {
+		for (f = 0; f < frclen; f++) {
 			glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune);
 			/* Everything correct. */
-			if(glyphidx && frc[f].flags == frcflags)
+			if (glyphidx && frc[f].flags == frcflags)
 				break;
 			/* We got a default font for a not found glyph. */
-			if(!glyphidx && frc[f].flags == frcflags
+			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)
+		if (f >= frclen) {
+			if (!font->set)
 				font->set = FcFontSort(0, font->pattern,
 				                       1, 0, &fcres);
 			fcsets[0] = font->set;
@@ -3480,7 +3480,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
 			/*
 			 * Overwrite or create the new cache entry.
 			 */
-			if(frclen >= LEN(frc)) {
+			if (frclen >= LEN(frc)) {
 				frclen = LEN(frc) - 1;
 				XftFontClose(xw.dpy, frc[frclen].font);
 				frc[frclen].unicodep = 0;
@@ -3522,16 +3522,16 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 	XRectangle r;
 
 	/* Determine foreground and background colors based on mode. */
-	if(base.fg == defaultfg) {
-		if(base.mode & ATTR_ITALIC)
+	if (base.fg == defaultfg) {
+		if (base.mode & ATTR_ITALIC)
 			base.fg = defaultitalic;
-		else if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD))
+		else if ((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD))
 			base.fg = defaultitalic;
-		else if(base.mode & ATTR_UNDERLINE)
+		else if (base.mode & ATTR_UNDERLINE)
 			base.fg = defaultunderline;
 	}
 
-	if(IS_TRUECOL(base.fg)) {
+	if (IS_TRUECOL(base.fg)) {
 		colfg.alpha = 0xffff;
 		colfg.red = TRUERED(base.fg);
 		colfg.green = TRUEGREEN(base.fg);
@@ -3542,7 +3542,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 		fg = &dc.col[base.fg];
 	}
 
-	if(IS_TRUECOL(base.bg)) {
+	if (IS_TRUECOL(base.bg)) {
 		colbg.alpha = 0xffff;
 		colbg.green = TRUEGREEN(base.bg);
 		colbg.red = TRUERED(base.bg);
@@ -3554,11 +3554,11 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 	}
 
 	/* 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))
+	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]) {
+	if (IS_SET(MODE_REVERSE)) {
+		if (fg == &dc.col[defaultfg]) {
 			fg = &dc.col[defaultbg];
 		} else {
 			colfg.red = ~fg->color.red;
@@ -3570,7 +3570,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 			fg = &revfg;
 		}
 
-		if(bg == &dc.col[defaultbg]) {
+		if (bg == &dc.col[defaultbg]) {
 			bg = &dc.col[defaultfg];
 		} else {
 			colbg.red = ~bg->color.red;
@@ -3583,13 +3583,13 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 		}
 	}
 
-	if(base.mode & ATTR_REVERSE) {
+	if (base.mode & ATTR_REVERSE) {
 		temp = fg;
 		fg = bg;
 		bg = temp;
 	}
 
-	if((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) {
+	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;
@@ -3597,24 +3597,24 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 		fg = &revfg;
 	}
 
-	if(base.mode & ATTR_BLINK && term.mode & MODE_BLINK)
+	if (base.mode & ATTR_BLINK && term.mode & MODE_BLINK)
 		fg = bg;
 
-	if(base.mode & ATTR_INVISIBLE)
+	if (base.mode & ATTR_INVISIBLE)
 		fg = bg;
 
 	/* Intelligent cleaning up of the borders. */
-	if(x == 0) {
+	if (x == 0) {
 		xclear(0, (y == 0)? 0 : winy, borderpx,
 			winy + xw.ch + ((y >= term.row-1)? xw.h : 0));
 	}
-	if(x + charlen >= term.col) {
+	if (x + charlen >= term.col) {
 		xclear(winx + width, (y == 0)? 0 : winy, xw.w,
 			((y >= term.row-1)? xw.h : (winy + xw.ch)));
 	}
-	if(y == 0)
+	if (y == 0)
 		xclear(winx, 0, winx + width, borderpx);
-	if(y == term.row-1)
+	if (y == term.row-1)
 		xclear(winx, winy + xw.ch, winx + width, xw.h);
 
 	/* Clean up the region we want to draw to. */
@@ -3631,12 +3631,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 	XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
 
 	/* Render underline and strikethrough. */
-	if(base.mode & ATTR_UNDERLINE) {
+	if (base.mode & ATTR_UNDERLINE) {
 		XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
 				width, 1);
 	}
 
-	if(base.mode & ATTR_STRUCK) {
+	if (base.mode & ATTR_STRUCK) {
 		XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3,
 				width, 1);
 	}
@@ -3667,9 +3667,9 @@ xdrawcursor(void)
 	curx = term.c.x;
 
 	/* adjust position if in dummy */
-	if(term.line[oldy][oldx].mode & ATTR_WDUMMY)
+	if (term.line[oldy][oldx].mode & ATTR_WDUMMY)
 		oldx--;
-	if(term.line[term.c.y][curx].mode & ATTR_WDUMMY)
+	if (term.line[term.c.y][curx].mode & ATTR_WDUMMY)
 		curx--;
 
 	g.u = term.line[term.c.y][term.c.x].u;
@@ -3677,16 +3677,16 @@ xdrawcursor(void)
 	/* remove the old cursor */
 	xdrawglyph(term.line[oldy][oldx], oldx, oldy);
 
-	if(IS_SET(MODE_HIDE))
+	if (IS_SET(MODE_HIDE))
 		return;
 
 	/* draw the new one */
-	if(xw.state & WIN_FOCUSED) {
+	if (xw.state & WIN_FOCUSED) {
 		switch (xw.cursor) {
 			case 0: /* Blinking Block */
 			case 1: /* Blinking Block (Default) */
 			case 2: /* Steady Block */
-				if(IS_SET(MODE_REVERSE)) {
+				if (IS_SET(MODE_REVERSE)) {
 						g.mode |= ATTR_REVERSE;
 						g.fg = defaultcs;
 						g.bg = defaultfg;
@@ -3776,11 +3776,11 @@ drawregion(int x1, int y1, int x2, int y2)
 	XftGlyphFontSpec* specs;
 	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 
-	if(!(xw.state & WIN_VISIBLE))
+	if (!(xw.state & WIN_VISIBLE))
 		return;
 
-	for(y = y1; y < y2; y++) {
-		if(!term.dirty[y])
+	for (y = y1; y < y2; y++) {
+		if (!term.dirty[y])
 			continue;
 
 		xtermclear(0, y, term.col, y);
@@ -3790,25 +3790,25 @@ drawregion(int x1, int y1, int x2, int y2)
 		numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y);
 
 		i = ox = 0;
-		for(x = x1; x < x2 && i < numspecs; x++) {
+		for (x = x1; x < x2 && i < numspecs; x++) {
 			new = term.line[y][x];
-			if(new.mode == ATTR_WDUMMY)
+			if (new.mode == ATTR_WDUMMY)
 				continue;
-			if(ena_sel && selected(x, y))
+			if (ena_sel && selected(x, y))
 				new.mode ^= ATTR_REVERSE;
-			if(i > 0 && ATTRCMP(base, new)) {
+			if (i > 0 && ATTRCMP(base, new)) {
 				xdrawglyphfontspecs(specs, base, i, ox, y);
 				specs += i;
 				numspecs -= i;
 				i = 0;
 			}
-			if(i == 0) {
+			if (i == 0) {
 				ox = x;
 				base = new;
 			}
 			i++;
 		}
-		if(i > 0)
+		if (i > 0)
 			xdrawglyphfontspecs(specs, base, i, ox, y);
 	}
 	xdrawcursor();
@@ -3856,19 +3856,19 @@ focus(XEvent *ev)
 {
 	XFocusChangeEvent *e = &ev->xfocus;
 
-	if(e->mode == NotifyGrab)
+	if (e->mode == NotifyGrab)
 		return;
 
-	if(ev->type == FocusIn) {
+	if (ev->type == FocusIn) {
 		XSetICFocus(xw.xic);
 		xw.state |= WIN_FOCUSED;
 		xseturgency(0);
-		if(IS_SET(MODE_FOCUS))
+		if (IS_SET(MODE_FOCUS))
 			ttywrite("\033[I", 3);
 	} else {
 		XUnsetICFocus(xw.xic);
 		xw.state &= ~WIN_FOCUSED;
-		if(IS_SET(MODE_FOCUS))
+		if (IS_SET(MODE_FOCUS))
 			ttywrite("\033[O", 3);
 	}
 }
@@ -3892,31 +3892,31 @@ kmap(KeySym k, uint state)
 	int i;
 
 	/* Check for mapped keys out of X11 function keys. */
-	for(i = 0; i < LEN(mappedkeys); i++) {
-		if(mappedkeys[i] == k)
+	for (i = 0; i < LEN(mappedkeys); i++) {
+		if (mappedkeys[i] == k)
 			break;
 	}
-	if(i == LEN(mappedkeys)) {
-		if((k & 0xFFFF) < 0xFD00)
+	if (i == LEN(mappedkeys)) {
+		if ((k & 0xFFFF) < 0xFD00)
 			return NULL;
 	}
 
-	for(kp = key; kp < key + LEN(key); kp++) {
-		if(kp->k != k)
+	for (kp = key; kp < key + LEN(key); kp++) {
+		if (kp->k != k)
 			continue;
 
-		if(!match(kp->mask, state))
+		if (!match(kp->mask, state))
 			continue;
 
-		if(IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0)
+		if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0)
 			continue;
-		if(term.numlock && kp->appkey == 2)
+		if (term.numlock && kp->appkey == 2)
 			continue;
 
-		if(IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0)
+		if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0)
 			continue;
 
-		if(IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0)
+		if (IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0)
 			continue;
 
 		return kp->s;
@@ -3936,30 +3936,30 @@ kpress(XEvent *ev)
 	Status status;
 	Shortcut *bp;
 
-	if(IS_SET(MODE_KBDLOCK))
+	if (IS_SET(MODE_KBDLOCK))
 		return;
 
 	len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
 	/* 1. shortcuts */
-	for(bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
-		if(ksym == bp->keysym && match(bp->mod, e->state)) {
+	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))) {
+	if ((customkey = kmap(ksym, e->state))) {
 		ttysend(customkey, strlen(customkey));
 		return;
 	}
 
 	/* 3. composed string from input method */
-	if(len == 0)
+	if (len == 0)
 		return;
-	if(len == 1 && e->state & Mod1Mask) {
-		if(IS_SET(MODE_8BIT)) {
-			if(*buf < 0177) {
+	if (len == 1 && e->state & Mod1Mask) {
+		if (IS_SET(MODE_8BIT)) {
+			if (*buf < 0177) {
 				c = *buf | 0x80;
 				len = utf8encode(c, buf);
 			}
@@ -3980,14 +3980,14 @@ 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) {
+	if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
+		if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
 			xw.state |= WIN_FOCUSED;
 			xseturgency(0);
-		} else if(e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
+		} else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
 			xw.state &= ~WIN_FOCUSED;
 		}
-	} else if(e->xclient.data.l[0] == xw.wmdeletewin) {
+	} else if (e->xclient.data.l[0] == xw.wmdeletewin) {
 		/* Send SIGHUP to shell */
 		kill(pid, SIGHUP);
 		exit(0);
@@ -3999,9 +3999,9 @@ cresize(int width, int height)
 {
 	int col, row;
 
-	if(width != 0)
+	if (width != 0)
 		xw.w = width;
-	if(height != 0)
+	if (height != 0)
 		xw.h = height;
 
 	col = (xw.w - 2 * borderpx) / xw.cw;
@@ -4015,7 +4015,7 @@ cresize(int width, int height)
 void
 resize(XEvent *e)
 {
-	if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
+	if (e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
 		return;
 
 	cresize(e->xconfigure.width, e->xconfigure.height);
@@ -4039,13 +4039,13 @@ run(void)
 		 * this is not unnecessary.It does not only filter the key event,
 		 * but some clientmessage for input method as well.
 		 */
-		if(XFilterEvent(&ev, None))
+		if (XFilterEvent(&ev, None))
 			continue;
-		if(ev.type == ConfigureNotify) {
+		if (ev.type == ConfigureNotify) {
 			w = ev.xconfigure.width;
 			h = ev.xconfigure.height;
 		}
-	} while(ev.type != MapNotify);
+	} while (ev.type != MapNotify);
 
 	ttynew();
 	cresize(w, h);
@@ -4053,26 +4053,26 @@ run(void)
 	clock_gettime(CLOCK_MONOTONIC, &last);
 	lastblink = last;
 
-	for(xev = actionfps;;) {
+	for (xev = actionfps;;) {
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);
 
-		if(pselect(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
-			if(errno == EINTR)
+		if (pselect(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
+			if (errno == EINTR)
 				continue;
 			die("select failed: %s\n", strerror(errno));
 		}
-		if(FD_ISSET(cmdfd, &rfd)) {
+		if (FD_ISSET(cmdfd, &rfd)) {
 			ttyread();
-			if(blinktimeout) {
+			if (blinktimeout) {
 				blinkset = tattrset(ATTR_BLINK);
-				if(!blinkset)
+				if (!blinkset)
 					MODBIT(term.mode, 0, MODE_BLINK);
 			}
 		}
 
-		if(FD_ISSET(xfd, &rfd))
+		if (FD_ISSET(xfd, &rfd))
 			xev = actionfps;
 
 		clock_gettime(CLOCK_MONOTONIC, &now);
@@ -4081,35 +4081,35 @@ run(void)
 		tv = &drawtimeout;
 
 		dodraw = 0;
-		if(blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
+		if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
 			tsetdirtattr(ATTR_BLINK);
 			term.mode ^= MODE_BLINK;
 			lastblink = now;
 			dodraw = 1;
 		}
 		deltatime = TIMEDIFF(now, last);
-		if(deltatime > 1000 / (xev ? xfps : actionfps)) {
+		if (deltatime > 1000 / (xev ? xfps : actionfps)) {
 			dodraw = 1;
 			last = now;
 		}
 
-		if(dodraw) {
-			while(XPending(xw.dpy)) {
+		if (dodraw) {
+			while (XPending(xw.dpy)) {
 				XNextEvent(xw.dpy, &ev);
-				if(XFilterEvent(&ev, None))
+				if (XFilterEvent(&ev, None))
 					continue;
-				if(handler[ev.type])
+				if (handler[ev.type])
 					(handler[ev.type])(&ev);
 			}
 
 			draw();
 			XFlush(xw.dpy);
 
-			if(xev && !FD_ISSET(xfd, &rfd))
+			if (xev && !FD_ISSET(xfd, &rfd))
 				xev--;
-			if(!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
-				if(blinkset) {
-					if(TIMEDIFF(now, lastblink) \
+			if (!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
+				if (blinkset) {
+					if (TIMEDIFF(now, lastblink) \
 							> blinktimeout) {
 						drawtimeout.tv_nsec = 1000;
 					} else {
@@ -4157,7 +4157,7 @@ main(int argc, char *argv[])
 		opt_class = EARGF(usage());
 		break;
 	case 'e':
-		if(argc > 0)
+		if (argc > 0)
 			--argc, ++argv;
 		goto run;
 	case 'f':
@@ -4188,10 +4188,10 @@ main(int argc, char *argv[])
 	} ARGEND;
 
 run:
-	if(argc > 0) {
+	if (argc > 0) {
 		/* eat all remaining arguments */
 		opt_cmd = argv;
-		if(!opt_title && !opt_line)
+		if (!opt_title && !opt_line)
 			opt_title = basename(xstrdup(argv[0]));
 	}
 	setlocale(LC_CTYPE, "");

From 539afe3af1b0d8b56b9ebfaa3bb7fc4e40f68c71 Mon Sep 17 00:00:00 2001
From: FRIGN <dev@frign.de>
Date: Fri, 10 Jul 2015 12:27:13 +0200
Subject: [PATCH 0858/1146] Update LICENSE

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 LICENSE | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LICENSE b/LICENSE
index 1be82da..e61610a 100644
--- a/LICENSE
+++ b/LICENSE
@@ -10,7 +10,7 @@ MIT/X Consortium License
 © 2013 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 Laslo Hunhold <dev at frign 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"),

From f8c6e7d0419d10c1425cb2c7123c5798ffb3b942 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 10 Jul 2015 14:10:17 +0200
Subject: [PATCH 0859/1146] Implement INCR transfers in the clipboard.

---
 st.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 68 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index 274ac5d..17e0a65 100644
--- a/st.c
+++ b/st.c
@@ -452,6 +452,7 @@ static void focus(XEvent *);
 static void brelease(XEvent *);
 static void bpress(XEvent *);
 static void bmotion(XEvent *);
+static void propnotify(XEvent *);
 static void selnotify(XEvent *);
 static void selclear(XEvent *);
 static void selrequest(XEvent *);
@@ -500,6 +501,11 @@ static void (*handler[LASTEvent])(XEvent *) = {
  */
 /*	[SelectionClear] = selclear, */
 	[SelectionNotify] = selnotify,
+/*
+ * PropertyNotify is only turned on when there is some INCR transfer happening
+ * for the selection retrieval.
+ */
+	[PropertyNotify] = propnotify,
 	[SelectionRequest] = selrequest,
 };
 
@@ -1028,21 +1034,41 @@ selcopy(Time t)
 	xsetsel(getsel(), t);
 }
 
+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)) {
+		slenotify(e);
+	}
+}
+
 void
 selnotify(XEvent *e)
 {
 	ulong nitems, ofs, rem;
 	int format;
 	uchar *data, *last, *repl;
-	Atom type;
-	XSelectionEvent *xsev;
+	Atom type, incratom, property;
 
 	ofs = 0;
-	xsev = &e->xselection;
-	if (xsev->property == None)
-	    return;
+	if (e->type == SelectionNotify) {
+		property = e->xselection.property;
+	} else if(e->type == PropertyNotify) {
+		property = e->xproperty.atom;
+	} else {
+		return;
+	}
+	if (property == None)
+		return;
+
 	do {
-		if (XGetWindowProperty(xw.dpy, xw.win, xsev->property, ofs,
+		if (XGetWindowProperty(xw.dpy, xw.win, property, ofs,
 					BUFSIZ/4, False, AnyPropertyType,
 					&type, &format, &nitems, &rem,
 					&data)) {
@@ -1050,6 +1076,35 @@ selnotify(XEvent *e)
 			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
@@ -1072,6 +1127,13 @@ selnotify(XEvent *e)
 		/* 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.
+	 */
+	if (e->type == PropertyNotify)
+		XDeleteProperty(xw.dpy, xw.win, (int)property);
 }
 
 void

From 261ea4b7e0b8d979c0c91ec75251c6970caf39e2 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 10 Jul 2015 14:15:39 +0200
Subject: [PATCH 0860/1146] Implement chunked write to the cmdfd.

This is needed so big input like a paste of several megabyte does not clog our
I/O.
---
 st.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 51 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 17e0a65..e65e981 100644
--- a/st.c
+++ b/st.c
@@ -1478,8 +1478,57 @@ ttyread(void)
 void
 ttywrite(const char *s, size_t n)
 {
-	if (xwrite(cmdfd, s, n) == -1)
-		die("write error on tty: %s\n", strerror(errno));
+	fd_set wfd;
+	struct timespec tv;
+	ssize_t r;
+
+	/*
+	 * 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_SET(cmdfd, &wfd);
+		tv.tv_sec = 0;
+		tv.tv_nsec = 0;
+
+		/* Check if we can write. */
+		if (pselect(cmdfd+1, NULL, &wfd, NULL, &tv, NULL) < 0) {
+			if (errno == EINTR)
+				continue;
+			die("select failed: %s\n", strerror(errno));
+		}
+		if(!FD_ISSET(cmdfd, &wfd)) {
+			/* No, then free some buffer space. */
+			ttyread();
+		} else {
+			/*
+			 * Only write 256 bytes at maximum. This seems to be a
+			 * reasonable value for a serial line. Bigger values
+			 * might clog the I/O.
+			 */
+			r = write(cmdfd, s, (n < 256)? n : 256);
+			if (r < 0) {
+				die("write error on tty: %s\n",
+						strerror(errno));
+			}
+			if (r < n) {
+				/*
+				 * We weren't able to write out everything.
+				 * This means the buffer is getting full
+				 * again. Empty it.
+				 */
+				ttyread();
+				n -= r;
+				s += r;
+			} else {
+				/* All bytes have been written. */
+				break;
+			}
+		}
+	}
 }
 
 void

From 41f70a1cff9c5653bebea996728fa76e2507eca3 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 10 Jul 2015 14:17:51 +0200
Subject: [PATCH 0861/1146] Typo and the missing incr atom from the patches.

---
 st.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index e65e981..486735d 100644
--- a/st.c
+++ b/st.c
@@ -1044,7 +1044,7 @@ propnotify(XEvent *e)
 	if (xpev->state == PropertyNewValue &&
 			(xpev->atom == XA_PRIMARY ||
 			 xpev->atom == clipboard)) {
-		slenotify(e);
+		selnotify(e);
 	}
 }
 
@@ -1056,6 +1056,8 @@ selnotify(XEvent *e)
 	uchar *data, *last, *repl;
 	Atom type, incratom, property;
 
+	incratom = XInternAtom(xw.dpy, "INCR", 0);
+
 	ofs = 0;
 	if (e->type == SelectionNotify) {
 		property = e->xselection.property;

From d3c7b6fb73bc5273b56c84c6c4c50a61ee5ab2bc Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 10 Jul 2015 14:19:31 +0200
Subject: [PATCH 0862/1146] No inline declarations please.

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 486735d..8f28582 100644
--- a/st.c
+++ b/st.c
@@ -558,10 +558,10 @@ static int frclen = 0;
 ssize_t
 xwrite(int fd, const char *s, size_t len)
 {
-	size_t aux = len;
+	size_t aux = len, r;
 
 	while (len > 0) {
-		ssize_t r = write(fd, s, len);
+		r = write(fd, s, len);
 		if (r < 0)
 			return r;
 		len -= r;

From 684f0a0729442e18115f71bc594a159725418ce8 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 10 Jul 2015 14:19:52 +0200
Subject: [PATCH 0863/1146] Unix end of file.

---
 st.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index 8f28582..97e1800 100644
--- a/st.c
+++ b/st.c
@@ -4316,3 +4316,4 @@ run:
 
 	return 0;
 }
+

From b823f57fa045bf8efa5648adbfeb0b6a7a9eb48b Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 10 Jul 2015 14:21:52 +0200
Subject: [PATCH 0864/1146] Aligning the macros.

---
 st.c | 40 +++++++++++++++++++++-------------------
 1 file changed, 21 insertions(+), 19 deletions(-)

diff --git a/st.c b/st.c
index 97e1800..4f958d8 100644
--- a/st.c
+++ b/st.c
@@ -62,26 +62,28 @@ char *argv0;
 #define XK_SWITCH_MOD (1<<13)
 
 /* 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 DEFAULT(a, b)     (a) = (a) ? (a) : (b)
-#define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (b))
-#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177')
-#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
-#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
-#define ISDELIM(u) (utf8strchr(worddelimiters, u) != NULL)
-#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 IS_SET(flag) ((term.mode & (flag)) != 0)
-#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 MIN(a, b)		((a) < (b) ? (a) : (b))
+#define MAX(a, b)		((a) < (b) ? (b) : (a))
+#define LEN(a)			(sizeof(a) / sizeof(a)[0])
+#define DEFAULT(a, b)		(a) = (a) ? (a) : (b)
+#define BETWEEN(x, a, b)	((a) <= (x) && (x) <= (b))
+#define ISCONTROLC0(c)		(BETWEEN(c, 0, 0x1f) || (c) == '\177')
+#define ISCONTROLC1(c)		(BETWEEN(c, 0x80, 0x9f))
+#define ISCONTROL(c)		(ISCONTROLC0(c) || ISCONTROLC1(c))
+#define ISDELIM(u)		(utf8strchr(worddelimiters, u) != NULL)
+#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 IS_SET(flag)		((term.mode & (flag)) != 0)
+#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))
-#define TRUERED(x)       (((x) & 0xff0000) >> 8)
-#define TRUEGREEN(x)     (((x) & 0xff00))
-#define TRUEBLUE(x)      (((x) & 0xff) << 8)
+#define TRUECOLOR(r,g,b)	(1 << 24 | (r) << 16 | (g) << 8 | (b))
+#define IS_TRUECOL(x)		(1 << 24 & (x))
+#define TRUERED(x)		(((x) & 0xff0000) >> 8)
+#define TRUEGREEN(x)		(((x) & 0xff00))
+#define TRUEBLUE(x)		(((x) & 0xff) << 8)
 
 
 enum glyph_attribute {

From 684c72d05e54780c283c6580f271fb6920c3060d Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 10 Jul 2015 14:30:37 +0200
Subject: [PATCH 0865/1146] Return style unification.

---
 st.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/st.c b/st.c
index 4f958d8..c07cc3b 100644
--- a/st.c
+++ b/st.c
@@ -569,6 +569,7 @@ xwrite(int fd, const char *s, size_t len)
 		len -= r;
 		s += r;
 	}
+
 	return aux;
 }
 
@@ -622,6 +623,7 @@ utf8decode(char *c, Rune *u, size_t clen)
 		return 0;
 	*u = udecoded;
 	utf8validate(u, len);
+
 	return len;
 }
 
@@ -631,6 +633,7 @@ 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;
 }
 
@@ -642,11 +645,13 @@ utf8encode(Rune u, char *c)
 	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;
 }
 
@@ -669,6 +674,7 @@ utf8strchr(char *s, Rune u)
 		if (r == u)
 			return &(s[i]);
 	}
+
 	return NULL;
 }
 
@@ -679,6 +685,7 @@ utf8validate(Rune *u, size_t i)
 		*u = UTF_INVALID;
 	for (i = 1; *u > utfmax[i]; ++i)
 		;
+
 	return i;
 }
 
@@ -3127,6 +3134,7 @@ xloadcolor(int i, const char *name, Color *ncolor)
 		} else
 			name = colorname[i];
 	}
+
 	return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
 }
 
@@ -3166,6 +3174,7 @@ xsetcolorname(int x, const char *name)
 
 	XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
 	dc.col[x] = ncolor;
+
 	return 0;
 }
 
@@ -3235,6 +3244,7 @@ xgeommasktogravity(int mask)
 	case YNegative:
 		return SouthWestGravity;
 	}
+
 	return SouthEastGravity;
 }
 

From d032b6159719b2fbbbd550781b378ca79a25d3a2 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 10 Jul 2015 14:31:40 +0200
Subject: [PATCH 0866/1146] Make the comment for the IM XFilter more
 understandable.

---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index c07cc3b..64e2cec 100644
--- a/st.c
+++ b/st.c
@@ -4160,9 +4160,9 @@ run(void)
 	do {
 		XNextEvent(xw.dpy, &ev);
 		/*
-		 * XFilterEvent is required to be called after you using XOpenIM,
-		 * this is not unnecessary.It does not only filter the key event,
-		 * but some clientmessage for input method as well.
+		 * 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;

From 62756fdb4945a80f4a53e6d354d5d93f51035517 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 24 Jul 2015 07:44:34 +0200
Subject: [PATCH 0867/1146] Fix style in execsh

---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 64e2cec..b604f0e 100644
--- a/st.c
+++ b/st.c
@@ -1329,9 +1329,8 @@ execsh(void)
 			die("who are you?\n");
 	}
 
-	if (!(sh = getenv("SHELL"))) {
+	if ((sh = getenv("SHELL")) == NULL)
 		sh = (pw->pw_shell[0]) ? pw->pw_shell : shell;
-	}
 
 	if (opt_cmd)
 		prog = opt_cmd[0];

From 1d348e98e3745ef98bf9fa36119ead6294c6c80b Mon Sep 17 00:00:00 2001
From: Mytchel Hammond <mytchel@openmailbox.org>
Date: Fri, 24 Jul 2015 17:58:18 +1200
Subject: [PATCH 0868/1146] added note about the low precedence of shell to
 config.def.h

---
 config.def.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/config.def.h b/config.def.h
index e246e3c..2616dea 100644
--- a/config.def.h
+++ b/config.def.h
@@ -7,6 +7,15 @@
  */
 static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=false";
 static int borderpx = 2;
+
+/*
+ * What program is execed by st depends of these precedence rules:
+ * 1: program passed with -e
+ * 2: utmp option
+ * 3: SHELL environment variable
+ * 4: value of shell in /etc/passwd
+ * 5: value of shell in config.h
+ */
 static char shell[] = "/bin/sh";
 static char *utmp = NULL;
 static char stty_args[] = "stty raw -echo -iexten echonl";

From 4a193b96862c8ed7147048592aa4a898b3c05b5b Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq+hackers@fifth.space>
Date: Fri, 24 Jul 2015 11:52:17 +0200
Subject: [PATCH 0869/1146] Fix type for write(2) return variable.

A little fix in xwrite().

>From 3727d2e3344b57128ab51c7839795204f1f839ff Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Fri, 24 Jul 2015 11:40:46 +0200
Subject: [PATCH] Fix type for write(2) return variable.

The allocated lengh of s fits into an integer so we can safely use
ssize_t here.
---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index b604f0e..f53378c 100644
--- a/st.c
+++ b/st.c
@@ -560,7 +560,8 @@ static int frclen = 0;
 ssize_t
 xwrite(int fd, const char *s, size_t len)
 {
-	size_t aux = len, r;
+	size_t aux = len;
+	ssize_t r;
 
 	while (len > 0) {
 		r = write(fd, s, len);

From b5e29cce5246f30dc671cbb9486af704bc8cd2fc Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 24 Jul 2015 18:24:10 +0200
Subject: [PATCH 0870/1146] Add -T, as recommended by Dmitrij D. Czarkoff

---
 st.1 | 7 +++++++
 st.c | 1 +
 2 files changed, 8 insertions(+)

diff --git a/st.1 b/st.1
index 9548c1a..82e228a 100644
--- a/st.1
+++ b/st.1
@@ -15,6 +15,8 @@ st \- simple terminal
 .IR file ]
 .RB [ \-t 
 .IR title ]
+.RB [ \-T
+.IR title ]
 .RB [ \-l
 .IR line ]
 .RB [ \-w 
@@ -37,6 +39,8 @@ st \- simple terminal
 .IR file ]
 .RB [ \-t
 .IR title ]
+.RB [ \-T
+.IR title ]
 .RB [ \-l
 .IR line ]
 .RB [ \-w
@@ -79,6 +83,9 @@ standard output.
 .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
diff --git a/st.c b/st.c
index f53378c..c384977 100644
--- a/st.c
+++ b/st.c
@@ -4302,6 +4302,7 @@ main(int argc, char *argv[])
 		opt_line = EARGF(usage());
 		break;
 	case 't':
+	case 'T':
 		opt_title = EARGF(usage());
 		break;
 	case 'w':

From dc33d1d66e89ee974cc6d7cfa2efb693ce67aa86 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 24 Jul 2015 18:25:33 +0200
Subject: [PATCH 0871/1146] Adding -T to the usage too.

---
 st.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index c384977..0db3d58 100644
--- a/st.c
+++ b/st.c
@@ -4259,9 +4259,11 @@ usage(void)
 {
 	die("%s " VERSION " (c) 2010-2015 st engineers\n"
 	"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
-	"          [-i] [-t title] [-w windowid] [-e command ...] [command ...]\n"
+	"          [-i] [-t title] [-T title] [-w windowid] [-e command ...]"
+	" [command ...]\n"
 	"       st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
-	"          [-i] [-t title] [-w windowid] [-l line] [stty_args ...]\n",
+	"          [-i] [-t title] [-T title] [-w windowid] [-l line]"
+	" [stty_args ...]\n",
 	argv0);
 }
 

From ee5cad439b427fa974903a6f0bb2689d11119d89 Mon Sep 17 00:00:00 2001
From: Alex Kozadaev <akozadaev at yahoo com>
Date: Tue, 28 Jul 2015 10:30:14 +0100
Subject: [PATCH 0872/1146] Adding mouse colour/shape settings

---
 config.def.h |  8 ++++++++
 st.c         | 20 ++++++++++++++++----
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index 2616dea..930e468 100644
--- a/config.def.h
+++ b/config.def.h
@@ -105,6 +105,14 @@ static unsigned int defaultfg = 7;
 static unsigned int defaultbg = 0;
 static unsigned int defaultcs = 256;
 
+
+/*
+ * Default colour and shape of the mouse cursor
+ */
+static unsigned int mouseshape = XC_xterm;
+static unsigned int mousefg = 7;
+static unsigned int mousebg = 0;
+
 /*
  * Colors used, when the specific fg == defaultfg. So in reverse mode this
  * will reverse too. Another logic would only make the simple feature too
diff --git a/st.c b/st.c
index 0db3d58..1df4fde 100644
--- a/st.c
+++ b/st.c
@@ -3411,6 +3411,7 @@ xinit(void)
 	Cursor cursor;
 	Window parent;
 	pid_t thispid = getpid();
+	XColor xmousefg, xmousebg;
 
 	if (!(xw.dpy = XOpenDisplay(NULL)))
 		die("Can't open display\n");
@@ -3483,11 +3484,22 @@ xinit(void)
 		die("XCreateIC failed. Could not obtain input method.\n");
 
 	/* white cursor, black outline */
-	cursor = XCreateFontCursor(xw.dpy, XC_xterm);
+	cursor = XCreateFontCursor(xw.dpy, mouseshape);
 	XDefineCursor(xw.dpy, xw.win, cursor);
-	XRecolorCursor(xw.dpy, cursor,
-		&(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff},
-		&(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
+
+	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);

From 9984ad4ba730b043d064095dca42b490904e38f3 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Tue, 11 Aug 2015 17:47:12 +0200
Subject: [PATCH 0873/1146] st.info: replace the acsc entry from xterm to urxvt

The current acsc entry, copied from xterm was not exposing capability to
display arrows.
---
 st.info | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.info b/st.info
index 2acd8b2..b70fefa 100644
--- a/st.info
+++ b/st.info
@@ -1,5 +1,5 @@
 st| simpleterm,
-	acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
+	acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
 	am,
 	bce,
 	bel=^G,

From 7e61f5e4c514a233250442263b62d887c9e5ca9c Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Mon, 17 Aug 2015 11:25:38 +0200
Subject: [PATCH 0874/1146] Do not mark as invalid UTF8 control codes

wcwidth() returns -1 for all the non visible characters, but it doesn't
necessarilly mean that they are incorrect. It only means that they are not
printable.
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 1df4fde..35a840b 100644
--- a/st.c
+++ b/st.c
@@ -2895,15 +2895,15 @@ tputc(Rune u)
 	int width, len;
 	Glyph *gp;
 
+	control = ISCONTROL(u);
 	len = utf8encode(u, c);
-	if ((width = wcwidth(u)) == -1) {
+	if (!control && (width = wcwidth(u)) == -1) {
 		memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
 		width = 1;
 	}
 
 	if (IS_SET(MODE_PRINT))
 		tprinter(c, len);
-	control = ISCONTROL(u);
 
 	/*
 	 * STR sequence must be checked before anything else

From 0d838b72437c6cac0d87366352939fdb86c2b697 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 30 Aug 2015 11:28:35 +0200
Subject: [PATCH 0875/1146] Don't read if we chunked the input data.

---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 1df4fde..e76aaf3 100644
--- a/st.c
+++ b/st.c
@@ -1531,7 +1531,8 @@ ttywrite(const char *s, size_t n)
 				 * This means the buffer is getting full
 				 * again. Empty it.
 				 */
-				ttyread();
+				if (n < 256)
+					ttyread();
 				n -= r;
 				s += r;
 			} else {

From 9eeb4e1ea22b9ca53b885615b896cd5ed8dee04a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 31 Aug 2015 15:26:21 +0200
Subject: [PATCH 0876/1146] Reordering and adding control codes.

For completeness and documentation add all C1 control codes.
---
 st.c | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index aaf868d..d49804b 100644
--- a/st.c
+++ b/st.c
@@ -2774,18 +2774,37 @@ tcontrolcode(uchar ascii)
 	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, sizeof(vtiden) - 1);
@@ -2794,9 +2813,9 @@ tcontrolcode(uchar ascii)
 	case 0x9c:   /* TODO: ST */
 		break;
 	case 0x90:   /* DCS -- Device Control String */
-	case 0x9f:   /* APC -- Application Program Command */
-	case 0x9e:   /* PM -- Privacy Message */
 	case 0x9d:   /* OSC -- Operating System Command */
+	case 0x9e:   /* PM -- Privacy Message */
+	case 0x9f:   /* APC -- Application Program Command */
 		tstrsequence(ascii);
 		return;
 	}

From 080a5ae4252c9c9a9d83b702d8478966ab79326e Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 7 Sep 2015 20:00:49 +0200
Subject: [PATCH 0877/1146] Fix the st manpage for -l line.

---
 st.1 | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/st.1 b/st.1
index 82e228a..b961b26 100644
--- a/st.1
+++ b/st.1
@@ -41,13 +41,11 @@ st \- simple terminal
 .IR title ]
 .RB [ \-T
 .IR title ]
-.RB [ \-l
-.IR line ]
 .RB [ \-w
 .IR windowid ]
 .RB [ \-v ]
-.RB [ \-l
-.IR line ]
+.RB \-l
+.IR line
 .RI [ stty_args ...]
 .SH DESCRIPTION
 .B st

From aa5d4c3b340d180eb0b375b3b4a923cf91ffb04a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 7 Sep 2015 22:59:05 +0200
Subject: [PATCH 0878/1146] Making st.1 more descriptive about -l and fix -l in
 st.c.

---
 st.1 | 21 ++++++++++++++++++---
 st.c |  2 +-
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/st.1 b/st.1
index b961b26..29e3163 100644
--- a/st.1
+++ b/st.1
@@ -89,9 +89,24 @@ embeds st within the window identified by
 .I windowid
 .TP
 .BI \-l " line"
-use a tty line instead of a pseudo terminal.
-When this flag is used
-remaining arguments are used as flags for stty.
+use a tty
+.I line
+instead of a pseudo terminal.
+.I line
+should be a (pseudo-)serial device (e.g. /dev/ttySO 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 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
+parenb parodd 115200'. Set the number of bits by using for example 'st -l cs7
+115200'. See
+.BR stty(1)
+for more arguments and cases.
 .TP
 .B \-v
 prints version information to stderr, then exits.
diff --git a/st.c b/st.c
index d49804b..256f8f5 100644
--- a/st.c
+++ b/st.c
@@ -4294,7 +4294,7 @@ usage(void)
 	"          [-i] [-t title] [-T title] [-w windowid] [-e command ...]"
 	" [command ...]\n"
 	"       st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
-	"          [-i] [-t title] [-T title] [-w windowid] [-l line]"
+	"          [-i] [-t title] [-T title] [-w windowid] -l line"
 	" [stty_args ...]\n",
 	argv0);
 }

From 473326f2e3115f4b745730be782b2eba63e0934c Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 8 Sep 2015 10:44:35 +0200
Subject: [PATCH 0879/1146] Set default values of stty according to the man
 page

This configuration is basically 38400 8N1, without echo and
in raw mode. Kernel will not process any of the characters
sent by the user.
---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 930e468..11a0c02 100644
--- a/config.def.h
+++ b/config.def.h
@@ -18,7 +18,7 @@ static int borderpx = 2;
  */
 static char shell[] = "/bin/sh";
 static char *utmp = NULL;
-static char stty_args[] = "stty raw -echo -iexten echonl";
+static char stty_args[] = "stty raw pass8 nl -echo -iexten -cstopb 38400";
 
 /* identification sequence returned in DA and DECID */
 static char vtiden[] = "\033[?6c";

From 1f087aa8b70fce67e7c43f689b5fb35667b5d84c Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 8 Sep 2015 12:10:11 +0200
Subject: [PATCH 0880/1146] Add key to send a break to the serial line

---
 config.def.h | 1 +
 st.1         | 3 +++
 st.c         | 9 +++++++++
 3 files changed, 13 insertions(+)

diff --git a/config.def.h b/config.def.h
index 11a0c02..7129fa1 100644
--- a/config.def.h
+++ b/config.def.h
@@ -134,6 +134,7 @@ static Mousekey mshortcuts[] = {
 
 static Shortcut shortcuts[] = {
 	/* mask                 keysym          function        argument */
+	{ XK_NO_MOD,            XK_Pause,       sendbreak,      {.i =  0} },
 	{ ControlMask,          XK_Print,       toggleprinter,  {.i =  0} },
 	{ ShiftMask,            XK_Print,       printscreen,    {.i =  0} },
 	{ XK_ANY_MOD,           XK_Print,       printsel,       {.i =  0} },
diff --git a/st.1 b/st.1
index 29e3163..f2f3f0e 100644
--- a/st.1
+++ b/st.1
@@ -122,6 +122,9 @@ and all the remaining arguments are used as a command
 even without it.
 .SH SHORTCUTS
 .TP
+.B Pause
+Send a break in the serial line
+.TP
 .B Ctrl-Print Screen
 Toggle if st should print to the
 .I iofile.
diff --git a/st.c b/st.c
index 256f8f5..7804316 100644
--- a/st.c
+++ b/st.c
@@ -17,6 +17,7 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <termios.h>
 #include <time.h>
 #include <unistd.h>
 #include <libgen.h>
@@ -333,6 +334,7 @@ static void xzoomreset(const Arg *);
 static void printsel(const Arg *);
 static void printscreen(const Arg *) ;
 static void toggleprinter(const Arg *);
+static void sendbreak(const Arg *);
 
 /* Config.h for applying patches and the configuration. */
 #include "config.h"
@@ -2578,6 +2580,13 @@ strreset(void)
 	memset(&strescseq, 0, sizeof(strescseq));
 }
 
+void
+sendbreak(const Arg *arg)
+{
+	if (tcsendbreak(cmdfd, 0))
+		perror("Error sending break");
+}
+
 void
 tprinter(char *s, size_t len)
 {

From 3ba9c8fc3f547a5762b3d4a6a16cc794446d76a3 Mon Sep 17 00:00:00 2001
From: Jan Christoph Ebersbach <jceb@e-jc.de>
Date: Tue, 8 Sep 2015 07:28:52 +0200
Subject: [PATCH 0881/1146] Expose cursor shape in config.def.h

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 config.def.h | 9 +++++++++
 st.c         | 2 +-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 7129fa1..c7ce3b4 100644
--- a/config.def.h
+++ b/config.def.h
@@ -105,6 +105,15 @@ static unsigned int defaultfg = 7;
 static unsigned int defaultbg = 0;
 static unsigned int defaultcs = 256;
 
+/*
+ * Default shape of cursor
+ * 2: Block
+ * 4: Underline
+ * 6: IBeam
+ */
+
+static unsigned int cursorshape = 2;
+
 
 /*
  * Default colour and shape of the mouse cursor
diff --git a/st.c b/st.c
index 7804316..530d7e4 100644
--- a/st.c
+++ b/st.c
@@ -4315,7 +4315,7 @@ main(int argc, char *argv[])
 
 	xw.l = xw.t = 0;
 	xw.isfixed = False;
-	xw.cursor = 0;
+	xw.cursor = cursorshape;
 
 	ARGBEGIN {
 	case 'a':

From a1ed5071e54e4f8ce765c07d5415da7d8cedf618 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Tue, 8 Sep 2015 17:00:20 +0200
Subject: [PATCH 0882/1146] Change Pause to Break in shortcut for serial break

---
 config.def.h | 2 +-
 st.1         | 6 ++++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/config.def.h b/config.def.h
index c7ce3b4..52bf3a4 100644
--- a/config.def.h
+++ b/config.def.h
@@ -143,7 +143,7 @@ static Mousekey mshortcuts[] = {
 
 static Shortcut shortcuts[] = {
 	/* mask                 keysym          function        argument */
-	{ XK_NO_MOD,            XK_Pause,       sendbreak,      {.i =  0} },
+	{ 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} },
diff --git a/st.1 b/st.1
index f2f3f0e..187a734 100644
--- a/st.1
+++ b/st.1
@@ -122,8 +122,10 @@ and all the remaining arguments are used as a command
 even without it.
 .SH SHORTCUTS
 .TP
-.B Pause
-Send a break in the serial line
+.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

From 5d2d9d540d84761cf11648ea42a6413001a5d7b9 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 10 Sep 2015 11:53:11 +0200
Subject: [PATCH 0883/1146] Fix copy of line with len = 0

When a line has no any character linelen is 0, so last = &term.line[y][MIN(lastx, linelen-1)]
generated a pointer to the end of the previous line. The best thing we can do in this case
is to add a newline, because we don't have a glyph to print (and consult its state of
wrapping).
---
 st.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 530d7e4..bd8b815 100644
--- a/st.c
+++ b/st.c
@@ -1004,7 +1004,10 @@ getsel(void)
 
 	/* append every set & selected glyph to the selection */
 	for (y = sel.nb.y; y <= sel.ne.y; y++) {
-		linelen = tlinelen(y);
+		if ((linelen = tlinelen(y)) == 0) {
+			*ptr++ = '\n';
+			continue;
+		}
 
 		if (sel.type == SEL_RECTANGULAR) {
 			gp = &term.line[y][sel.nb.x];

From bf8c71e42937b623f76ced22c9557f87e3d945da Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 12 Sep 2015 16:43:32 +0200
Subject: [PATCH 0884/1146] The times of bad fonts are over.

The antialiasing was false due to circumstances that do not exist anymore. We
need antialiasing on big screens with big fonts. Autohinting too.
---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 52bf3a4..b6adc5e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -5,7 +5,7 @@
  *
  * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
  */
-static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=false";
+static char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
 static int borderpx = 2;
 
 /*

From 20d53cebc122829449524ef339ce44e13c6e85ec Mon Sep 17 00:00:00 2001
From: FRIGN <dev@frign.de>
Date: Tue, 22 Sep 2015 13:13:25 +0200
Subject: [PATCH 0885/1146] dup() -> dup2()

gcc would warn about an unused result. We know it is 0 and dup()
can't fail in these circumstances, as we closed fd0 previously.
Using dup2() to do the same saves one line and shuts gcc up, bringing
us a clean build back.
---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index bd8b815..bcf74b3 100644
--- a/st.c
+++ b/st.c
@@ -1430,8 +1430,7 @@ ttynew(void)
 	if (opt_line) {
 		if ((cmdfd = open(opt_line, O_RDWR)) < 0)
 			die("open line failed: %s\n", strerror(errno));
-		close(0);
-		dup(cmdfd);
+		dup2(cmdfd, 0);
 		stty();
 		return;
 	}

From 4be353e381e07fd8100f0cf29b299180f6681e46 Mon Sep 17 00:00:00 2001
From: dequis <dx@dxzone.com.ar>
Date: Fri, 25 Sep 2015 00:56:15 -0300
Subject: [PATCH 0886/1146] Fix extra bracketed paste markers when pasting >8kb

Before this patch, when pasting over BUFSIZE (8192 bytes here), st would
do the following:

    \e[200~...8192 bytes...\e[201~\e[200~...remaining bytes...\e[201~

With this patch, the start marker is only sent when the offset is 0 (at
the beginning of selnotify) and the end marker is only sent when the
remaining bytes to read are 0 (at the end).

For short pastes, both conditions are true in the same iteration.

For long pastes, it removes the extra markers in the middle, keeping the
intended wrapping:

    \e[200~...8192 bytes......remaining bytes...\e[201~

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index bcf74b3..9de30ec 100644
--- a/st.c
+++ b/st.c
@@ -1135,10 +1135,10 @@ selnotify(XEvent *e)
 			*repl++ = '\r';
 		}
 
-		if (IS_SET(MODE_BRCKTPASTE))
+		if (IS_SET(MODE_BRCKTPASTE) && ofs == 0)
 			ttywrite("\033[200~", 6);
 		ttysend((char *)data, nitems * format / 8);
-		if (IS_SET(MODE_BRCKTPASTE))
+		if (IS_SET(MODE_BRCKTPASTE) && rem == 0)
 			ttywrite("\033[201~", 6);
 		XFree(data);
 		/* number of 32-bit chunks returned */

From 168248432705eff5fc44cf8a566bc090ca59d78a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 28 Sep 2015 20:08:58 +0200
Subject: [PATCH 0887/1146] There's no need for libXext to compile st.

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 67844dc..81e3e47 100644
--- a/config.mk
+++ b/config.mk
@@ -14,7 +14,7 @@ X11LIB = /usr/X11R6/lib
 INCS = -I. -I/usr/include -I${X11INC} \
        `pkg-config --cflags fontconfig` \
        `pkg-config --cflags freetype2`
-LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXext -lXft \
+LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXft \
        `pkg-config --libs fontconfig`  \
        `pkg-config --libs freetype2`
 

From 2bef36ab81c356b106f00221038b743819cd20bd Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 5 Oct 2015 20:08:21 +0200
Subject: [PATCH 0888/1146] Small style change.

---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 9de30ec..4d4f115 100644
--- a/st.c
+++ b/st.c
@@ -3855,10 +3855,10 @@ xdrawcursor(void)
 			case 1: /* Blinking Block (Default) */
 			case 2: /* Steady Block */
 				if (IS_SET(MODE_REVERSE)) {
-						g.mode |= ATTR_REVERSE;
-						g.fg = defaultcs;
-						g.bg = defaultfg;
-					}
+					g.mode |= ATTR_REVERSE;
+					g.fg = defaultcs;
+					g.bg = defaultfg;
+				}
 
 				g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE;
 				xdrawglyph(g, term.c.x, term.c.y);

From 5ece2b5f4a2e56ddfb82e797dc973fca38c5273d Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 5 Oct 2015 20:48:24 +0200
Subject: [PATCH 0889/1146] More style changes. We forgot some switches.

---
 st.c | 66 ++++++++++++++++++++++++++++++------------------------------
 1 file changed, 33 insertions(+), 33 deletions(-)

diff --git a/st.c b/st.c
index 4d4f115..144954b 100644
--- a/st.c
+++ b/st.c
@@ -2433,15 +2433,15 @@ csihandle(void)
 		break;
 	case ' ':
 		switch (csiescseq.mode[1]) {
-			case 'q': /* DECSCUSR -- Set Cursor Style */
-				DEFAULT(csiescseq.arg[0], 1);
-				if (!BETWEEN(csiescseq.arg[0], 0, 6)) {
-					goto unknown;
-				}
-				xw.cursor = csiescseq.arg[0];
-				break;
-			default:
+		case 'q': /* DECSCUSR -- Set Cursor Style */
+			DEFAULT(csiescseq.arg[0], 1);
+			if (!BETWEEN(csiescseq.arg[0], 0, 6)) {
 				goto unknown;
+			}
+			xw.cursor = csiescseq.arg[0];
+			break;
+		default:
+			goto unknown;
 		}
 		break;
 	}
@@ -3851,32 +3851,32 @@ xdrawcursor(void)
 	/* draw the new one */
 	if (xw.state & WIN_FOCUSED) {
 		switch (xw.cursor) {
-			case 0: /* Blinking Block */
-			case 1: /* Blinking Block (Default) */
-			case 2: /* Steady Block */
-				if (IS_SET(MODE_REVERSE)) {
-					g.mode |= ATTR_REVERSE;
-					g.fg = defaultcs;
-					g.bg = defaultfg;
-				}
+		case 0: /* Blinking Block */
+		case 1: /* Blinking Block (Default) */
+		case 2: /* Steady Block */
+			if (IS_SET(MODE_REVERSE)) {
+				g.mode |= ATTR_REVERSE;
+				g.fg = defaultcs;
+				g.bg = defaultfg;
+			}
 
-				g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE;
-				xdrawglyph(g, term.c.x, term.c.y);
-				break;
-			case 3: /* Blinking Underline */
-			case 4: /* Steady Underline */
-				XftDrawRect(xw.draw, &dc.col[defaultcs],
-						borderpx + curx * xw.cw,
-						borderpx + (term.c.y + 1) * xw.ch - cursorthickness,
-						xw.cw, cursorthickness);
-				break;
-			case 5: /* Blinking bar */
-			case 6: /* Steady bar */
-				XftDrawRect(xw.draw, &dc.col[defaultcs],
-						borderpx + curx * xw.cw,
-						borderpx + term.c.y * xw.ch,
-						cursorthickness, xw.ch);
-				break;
+			g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE;
+			xdrawglyph(g, term.c.x, term.c.y);
+			break;
+		case 3: /* Blinking Underline */
+		case 4: /* Steady Underline */
+			XftDrawRect(xw.draw, &dc.col[defaultcs],
+					borderpx + curx * xw.cw,
+					borderpx + (term.c.y + 1) * xw.ch - cursorthickness,
+					xw.cw, cursorthickness);
+			break;
+		case 5: /* Blinking bar */
+		case 6: /* Steady bar */
+			XftDrawRect(xw.draw, &dc.col[defaultcs],
+					borderpx + curx * xw.cw,
+					borderpx + term.c.y * xw.ch,
+					cursorthickness, xw.ch);
+			break;
 		}
 	} else {
 		XftDrawRect(xw.draw, &dc.col[defaultcs],

From 2677296147fe658376be67821449b8f232c65064 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 5 Oct 2015 21:06:42 +0200
Subject: [PATCH 0890/1146] Reverse the cursor on selection.

---
 st.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.c b/st.c
index 144954b..e0417e5 100644
--- a/st.c
+++ b/st.c
@@ -3828,6 +3828,7 @@ xdrawcursor(void)
 	static int oldx = 0, oldy = 0;
 	int curx;
 	Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs};
+	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
@@ -3841,6 +3842,8 @@ xdrawcursor(void)
 		curx--;
 
 	g.u = term.line[term.c.y][term.c.x].u;
+	if (ena_sel && selected(term.c.x, term.c.y))
+		g.mode ^= ATTR_REVERSE;
 
 	/* remove the old cursor */
 	xdrawglyph(term.line[oldy][oldx], oldx, oldy);

From 91c70213d1e595467b14ce6d28f333dbedd97cab Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 5 Oct 2015 21:18:34 +0200
Subject: [PATCH 0891/1146] When the cursor is moved, clear the selection.

---
 st.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index e0417e5..0c528d5 100644
--- a/st.c
+++ b/st.c
@@ -1811,6 +1811,7 @@ tmoveto(int x, int y)
 {
 	int miny, maxy;
 
+	selclear(NULL);
 	if (term.c.state & CURSOR_ORIGIN) {
 		miny = term.top;
 		maxy = term.bot;

From 594a25983639847ed063a3d181893dba54825f5a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 5 Oct 2015 22:09:51 +0200
Subject: [PATCH 0892/1146] Fixing the cursor movement in selections.

Before the fix the cursor wouldn't obey if it's in a selection. If it is
inside it will now change to the reverse. This patch also adds that the
defaultcs will be reversed for the manually drawn cursors.
---
 st.c | 46 ++++++++++++++++++++++++++++++++--------------
 1 file changed, 32 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index 0c528d5..457f266 100644
--- a/st.c
+++ b/st.c
@@ -1811,7 +1811,6 @@ tmoveto(int x, int y)
 {
 	int miny, maxy;
 
-	selclear(NULL);
 	if (term.c.state & CURSOR_ORIGIN) {
 		miny = term.top;
 		maxy = term.bot;
@@ -3819,6 +3818,7 @@ xdrawglyph(Glyph g, int x, int y)
 {
 	int numspecs;
 	XftGlyphFontSpec spec;
+
 	numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
 	xdrawglyphfontspecs(&spec, g, numspecs, x, y);
 }
@@ -3828,8 +3828,10 @@ xdrawcursor(void)
 {
 	static int oldx = 0, oldy = 0;
 	int curx;
-	Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs};
+	Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og;
 	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
+	Color drawcol;
+	XRenderColor dccol;
 
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
@@ -3842,12 +3844,28 @@ xdrawcursor(void)
 	if (term.line[term.c.y][curx].mode & ATTR_WDUMMY)
 		curx--;
 
-	g.u = term.line[term.c.y][term.c.x].u;
-	if (ena_sel && selected(term.c.x, term.c.y))
-		g.mode ^= ATTR_REVERSE;
-
 	/* remove the old cursor */
-	xdrawglyph(term.line[oldy][oldx], oldx, oldy);
+	og = term.line[oldy][oldx];
+	if (ena_sel && selected(oldx, oldy))
+		og.mode ^= ATTR_REVERSE;
+	xdrawglyph(og, oldx, oldy);
+
+	g.u = term.line[term.c.y][term.c.x].u;
+	if (ena_sel && selected(term.c.x, term.c.y)) {
+		/*
+		 * Allocate the drawing color which is the reverse of
+		 * defaultcs, if we are selected.
+		 */
+		dccol.red = ~dc.col[defaultcs].color.red;
+		dccol.green = ~dc.col[defaultcs].color.green;
+		dccol.blue = ~dc.col[defaultcs].color.blue;
+		dccol.alpha = ~dc.col[defaultcs].color.alpha;
+		XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &dccol, &drawcol);
+
+		g.mode ^= ATTR_REVERSE;
+	} else {
+		drawcol = dc.col[defaultcs];
+	}
 
 	if (IS_SET(MODE_HIDE))
 		return;
@@ -3869,33 +3887,33 @@ xdrawcursor(void)
 			break;
 		case 3: /* Blinking Underline */
 		case 4: /* Steady Underline */
-			XftDrawRect(xw.draw, &dc.col[defaultcs],
+			XftDrawRect(xw.draw, &drawcol,
 					borderpx + curx * xw.cw,
 					borderpx + (term.c.y + 1) * xw.ch - cursorthickness,
 					xw.cw, cursorthickness);
 			break;
 		case 5: /* Blinking bar */
 		case 6: /* Steady bar */
-			XftDrawRect(xw.draw, &dc.col[defaultcs],
+			XftDrawRect(xw.draw, &drawcol,
 					borderpx + curx * xw.cw,
 					borderpx + term.c.y * xw.ch,
 					cursorthickness, xw.ch);
 			break;
 		}
 	} else {
-		XftDrawRect(xw.draw, &dc.col[defaultcs],
+		XftDrawRect(xw.draw, &drawcol,
 				borderpx + curx * xw.cw,
 				borderpx + term.c.y * xw.ch,
 				xw.cw - 1, 1);
-		XftDrawRect(xw.draw, &dc.col[defaultcs],
+		XftDrawRect(xw.draw, &drawcol,
 				borderpx + curx * xw.cw,
 				borderpx + term.c.y * xw.ch,
 				1, xw.ch - 1);
-		XftDrawRect(xw.draw, &dc.col[defaultcs],
+		XftDrawRect(xw.draw, &drawcol,
 				borderpx + (curx + 1) * xw.cw - 1,
 				borderpx + term.c.y * xw.ch,
 				1, xw.ch - 1);
-		XftDrawRect(xw.draw, &dc.col[defaultcs],
+		XftDrawRect(xw.draw, &drawcol,
 				borderpx + curx * xw.cw,
 				borderpx + (term.c.y + 1) * xw.ch - 1,
 				xw.cw, 1);
@@ -3945,7 +3963,7 @@ drawregion(int x1, int y1, int x2, int y2)
 {
 	int i, x, y, ox, numspecs;
 	Glyph base, new;
-	XftGlyphFontSpec* specs;
+	XftGlyphFontSpec *specs;
 	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 
 	if (!(xw.state & WIN_VISIBLE))

From f7b80caebe2b96ef65e301634d8dc4e02325e357 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 5 Oct 2015 22:38:19 +0200
Subject: [PATCH 0893/1146] The definition of the reverse cursor is now up to
 the user.

---
 config.def.h |  4 +++-
 st.c         | 15 +++------------
 2 files changed, 6 insertions(+), 13 deletions(-)

diff --git a/config.def.h b/config.def.h
index b6adc5e..85921dc 100644
--- a/config.def.h
+++ b/config.def.h
@@ -94,16 +94,18 @@ static const char *colorname[] = {
 
 	/* more colors can be added after 255 to use with DefaultXX */
 	"#cccccc",
+	"#555555",
 };
 
 
 /*
  * Default colors (colorname index)
- * foreground, background, cursor
+ * foreground, background, cursor, reverse cursor
  */
 static unsigned int defaultfg = 7;
 static unsigned int defaultbg = 0;
 static unsigned int defaultcs = 256;
+static unsigned int defaultrcs = 257;
 
 /*
  * Default shape of cursor
diff --git a/st.c b/st.c
index 457f266..782d18e 100644
--- a/st.c
+++ b/st.c
@@ -3831,7 +3831,6 @@ xdrawcursor(void)
 	Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og;
 	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 	Color drawcol;
-	XRenderColor dccol;
 
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
@@ -3852,16 +3851,7 @@ xdrawcursor(void)
 
 	g.u = term.line[term.c.y][term.c.x].u;
 	if (ena_sel && selected(term.c.x, term.c.y)) {
-		/*
-		 * Allocate the drawing color which is the reverse of
-		 * defaultcs, if we are selected.
-		 */
-		dccol.red = ~dc.col[defaultcs].color.red;
-		dccol.green = ~dc.col[defaultcs].color.green;
-		dccol.blue = ~dc.col[defaultcs].color.blue;
-		dccol.alpha = ~dc.col[defaultcs].color.alpha;
-		XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &dccol, &drawcol);
-
+		drawcol = dc.col[defaultrcs];
 		g.mode ^= ATTR_REVERSE;
 	} else {
 		drawcol = dc.col[defaultcs];
@@ -3889,7 +3879,8 @@ xdrawcursor(void)
 		case 4: /* Steady Underline */
 			XftDrawRect(xw.draw, &drawcol,
 					borderpx + curx * xw.cw,
-					borderpx + (term.c.y + 1) * xw.ch - cursorthickness,
+					borderpx + (term.c.y + 1) * xw.ch - \
+						cursorthickness,
 					xw.cw, cursorthickness);
 			break;
 		case 5: /* Blinking bar */

From 78b04865fb5c8cb841e646058f9a24e7ec9094d2 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 5 Oct 2015 22:54:44 +0200
Subject: [PATCH 0894/1146] Style normalisation in the config.def.h.

This adds an awareness commit for the big key array too.
---
 config.def.h | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/config.def.h b/config.def.h
index 85921dc..342c9d4 100644
--- a/config.def.h
+++ b/config.def.h
@@ -62,12 +62,11 @@ static unsigned int cursorthickness = 2;
  */
 static int bellvolume = 0;
 
-/* TERM value */
+/* default TERM value */
 static char termname[] = "st-256color";
 
 static unsigned int tabspaces = 8;
 
-
 /* Terminal colors (16 first used in escape sequence) */
 static const char *colorname[] = {
 	/* 8 normal colors */
@@ -113,10 +112,8 @@ static unsigned int defaultrcs = 257;
  * 4: Underline
  * 6: IBeam
  */
-
 static unsigned int cursorshape = 2;
 
-
 /*
  * Default colour and shape of the mouse cursor
  */
@@ -132,8 +129,10 @@ static unsigned int mousebg = 0;
 static unsigned int defaultitalic = 11;
 static unsigned int defaultunderline = 7;
 
-/* Internal mouse shortcuts. */
-/* Beware that overloading Button1 will disable the selection. */
+/*
+ * Internal mouse shortcuts.
+ * Beware that overloading Button1 will disable the selection.
+ */
 static Mousekey mshortcuts[] = {
 	/* button               mask            string */
 	{ Button4,              XK_ANY_MOD,     "\031" },
@@ -196,11 +195,17 @@ static KeySym mappedkeys[] = { -1 };
  */
 static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
 
-/* Override mouse-select while mask is active (when MODE_MOUSE is set).
+/*
+ * Override mouse-select while mask is active (when MODE_MOUSE is set).
  * Note that if you want to use ShiftMask with selmasks, set this to an other
- * modifier, set to 0 to not use it. */
+ * modifier, set to 0 to not use it.
+ */
 static uint forceselmod = ShiftMask;
 
+/*
+ * This is the huge key array which defines all compatibility to the Linux
+ * world. Please decide about changes wisely.
+ */
 static Key key[] = {
 	/* keysym           mask            string      appkey appcursor crlf */
 	{ XK_KP_Home,       ShiftMask,      "\033[2J",       0,   -1,    0},

From 52d0e82df723297438339822f2398f83470fbcd4 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 5 Oct 2015 22:59:04 +0200
Subject: [PATCH 0895/1146] Snowman is everywhere.

---
 config.def.h | 1 +
 st.c         | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/config.def.h b/config.def.h
index 342c9d4..89732b4 100644
--- a/config.def.h
+++ b/config.def.h
@@ -111,6 +111,7 @@ static unsigned int defaultrcs = 257;
  * 2: Block
  * 4: Underline
  * 6: IBeam
+ * 7: Snowman
  */
 static unsigned int cursorshape = 2;
 
diff --git a/st.c b/st.c
index 782d18e..4ead319 100644
--- a/st.c
+++ b/st.c
@@ -3863,6 +3863,8 @@ xdrawcursor(void)
 	/* draw the new one */
 	if (xw.state & WIN_FOCUSED) {
 		switch (xw.cursor) {
+		case 7: /* st extension: snowman */
+			utf8decode("☃", &g.u, UTF_SIZ);
 		case 0: /* Blinking Block */
 		case 1: /* Blinking Block (Default) */
 		case 2: /* Steady Block */

From a2a60f0a2ce33dbd4ef07aaa4a914391481fa1de Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 5 Oct 2015 23:05:38 +0200
Subject: [PATCH 0896/1146] Make the cursor shapes more descriptive.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

»IBeam« is now »Bar« because it's named like that in the source code.
---
 config.def.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index 89732b4..860ce3d 100644
--- a/config.def.h
+++ b/config.def.h
@@ -108,10 +108,10 @@ static unsigned int defaultrcs = 257;
 
 /*
  * Default shape of cursor
- * 2: Block
- * 4: Underline
- * 6: IBeam
- * 7: Snowman
+ * 2: Block ("█")
+ * 4: Underline ("_")
+ * 6: Bar ("|")
+ * 7: Snowman ("☃")
  */
 static unsigned int cursorshape = 2;
 

From 80fe97f8a66d31945bdddbb9381b2cc54359f48e Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Mon, 5 Oct 2015 23:10:48 +0200
Subject: [PATCH 0897/1146] Fix the cursor color when over selection.

If we want to show a custom selected cursor color, we must not set the
revert attribute to the drawn glyph.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 4ead319..d9f0ba6 100644
--- a/st.c
+++ b/st.c
@@ -3852,7 +3852,8 @@ xdrawcursor(void)
 	g.u = term.line[term.c.y][term.c.x].u;
 	if (ena_sel && selected(term.c.x, term.c.y)) {
 		drawcol = dc.col[defaultrcs];
-		g.mode ^= ATTR_REVERSE;
+		g.fg = defaultfg;
+		g.bg = defaultrcs;
 	} else {
 		drawcol = dc.col[defaultcs];
 	}

From 2ea02c937e3a1810050a5fb9f51e7e522d23af3b Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 6 Oct 2015 00:21:44 +0200
Subject: [PATCH 0898/1146] Normalize the whole color selection in xdrawcursor.

---
 st.c | 33 ++++++++++++++++++++++-----------
 1 file changed, 22 insertions(+), 11 deletions(-)

diff --git a/st.c b/st.c
index d9f0ba6..e885a7d 100644
--- a/st.c
+++ b/st.c
@@ -3850,12 +3850,29 @@ xdrawcursor(void)
 	xdrawglyph(og, oldx, oldy);
 
 	g.u = term.line[term.c.y][term.c.x].u;
-	if (ena_sel && selected(term.c.x, term.c.y)) {
-		drawcol = dc.col[defaultrcs];
-		g.fg = defaultfg;
-		g.bg = defaultrcs;
+
+	/*
+	 * Select the right color for the right mode.
+	 */
+	if (IS_SET(MODE_REVERSE)) {
+		g.mode |= ATTR_REVERSE;
+		g.bg = defaultfg;
+		if (ena_sel && selected(term.c.x, term.c.y)) {
+			drawcol = dc.col[defaultcs];
+			g.fg = defaultrcs;
+		} else {
+			drawcol = dc.col[defaultrcs];
+			g.fg = defaultcs;
+		}
 	} else {
-		drawcol = dc.col[defaultcs];
+		g.fg = defaultfg;
+		if (ena_sel && selected(term.c.x, term.c.y)) {
+			g.bg = defaultcs;
+			drawcol = dc.col[defaultrcs];
+		} else {
+			drawcol = dc.col[defaultcs];
+			g.bg = defaultrcs;
+		}
 	}
 
 	if (IS_SET(MODE_HIDE))
@@ -3869,12 +3886,6 @@ xdrawcursor(void)
 		case 0: /* Blinking Block */
 		case 1: /* Blinking Block (Default) */
 		case 2: /* Steady Block */
-			if (IS_SET(MODE_REVERSE)) {
-				g.mode |= ATTR_REVERSE;
-				g.fg = defaultcs;
-				g.bg = defaultfg;
-			}
-
 			g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE;
 			xdrawglyph(g, term.c.x, term.c.y);
 			break;

From 293f573efd8c1c9cddd319caa7564736aa60639a Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Tue, 6 Oct 2015 10:29:44 +0200
Subject: [PATCH 0899/1146] Fix the cursor colors selection

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index e885a7d..01d4410 100644
--- a/st.c
+++ b/st.c
@@ -3865,13 +3865,12 @@ xdrawcursor(void)
 			g.fg = defaultcs;
 		}
 	} else {
-		g.fg = defaultfg;
 		if (ena_sel && selected(term.c.x, term.c.y)) {
-			g.bg = defaultcs;
 			drawcol = dc.col[defaultrcs];
+			g.fg = defaultfg;
+			g.bg = defaultrcs;
 		} else {
 			drawcol = dc.col[defaultcs];
-			g.bg = defaultrcs;
 		}
 	}
 

From f56c58a968c1b3ddae76864bc9e27e5b9cc055c4 Mon Sep 17 00:00:00 2001
From: Jason Woofenden <jason@jasonwoof.com>
Date: Sun, 11 Oct 2015 11:44:34 +0200
Subject: [PATCH 0900/1146] fix bug where first selection snaps to lines

---
 st.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 01d4410..b2a4fff 100644
--- a/st.c
+++ b/st.c
@@ -695,9 +695,10 @@ utf8validate(Rune *u, size_t i)
 void
 selinit(void)
 {
-	memset(&sel.tclick1, 0, sizeof(sel.tclick1));
-	memset(&sel.tclick2, 0, sizeof(sel.tclick2));
+	clock_gettime(CLOCK_MONOTONIC, &sel.tclick1);
+	clock_gettime(CLOCK_MONOTONIC, &sel.tclick2);
 	sel.mode = SEL_IDLE;
+	sel.snap = 0;
 	sel.ob.x = -1;
 	sel.primary = NULL;
 	sel.clipboard = NULL;

From e2aa03e6b71436e1c9207b01777baa16b7a00ea5 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 31 Oct 2015 09:29:04 +0100
Subject: [PATCH 0901/1146] Now the Shortcuts are more consistent.

Keep the debile happy.
---
 config.def.h | 2 +-
 st.c         | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/config.def.h b/config.def.h
index 860ce3d..fd09d72 100644
--- a/config.def.h
+++ b/config.def.h
@@ -134,7 +134,7 @@ static unsigned int defaultunderline = 7;
  * Internal mouse shortcuts.
  * Beware that overloading Button1 will disable the selection.
  */
-static Mousekey mshortcuts[] = {
+static MouseShortcut mshortcuts[] = {
 	/* button               mask            string */
 	{ Button4,              XK_ANY_MOD,     "\031" },
 	{ Button5,              XK_ANY_MOD,     "\005" },
diff --git a/st.c b/st.c
index b2a4fff..386e6c0 100644
--- a/st.c
+++ b/st.c
@@ -275,7 +275,7 @@ typedef struct {
 	uint b;
 	uint mask;
 	char *s;
-} Mousekey;
+} MouseShortcut;
 
 typedef struct {
 	KeySym k;
@@ -944,7 +944,7 @@ void
 bpress(XEvent *e)
 {
 	struct timespec now;
-	Mousekey *mk;
+	MouseShortcut *mk;
 
 	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);

From f0398db4d172e838ef4b4ae55db3fb6a6fee6717 Mon Sep 17 00:00:00 2001
From: Ivan Tham <pickfire@riseup.net>
Date: Sun, 1 Nov 2015 10:53:56 +0800
Subject: [PATCH 0902/1146] Now the mshortcuts are even more consistent.

    Keep everyone happy

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index 386e6c0..65a1866 100644
--- a/st.c
+++ b/st.c
@@ -944,17 +944,17 @@ void
 bpress(XEvent *e)
 {
 	struct timespec now;
-	MouseShortcut *mk;
+	MouseShortcut *ms;
 
 	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);
 		return;
 	}
 
-	for (mk = mshortcuts; mk < mshortcuts + LEN(mshortcuts); mk++) {
-		if (e->xbutton.button == mk->b
-				&& match(mk->mask, e->xbutton.state)) {
-			ttysend(mk->s, strlen(mk->s));
+	for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
+		if (e->xbutton.button == ms->b
+				&& match(ms->mask, e->xbutton.state)) {
+			ttysend(ms->s, strlen(ms->s));
 			return;
 		}
 	}

From 9f6d8845df3f81e2bc86f593a2f93e098422b2fa Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 6 Nov 2015 20:01:00 +0100
Subject: [PATCH 0903/1146] Fix ttywrite()

ttywrite was assuming that if it could not write then it could
read, but this is not necessarily true, there are some situations
where you cannot read or write. The correct behaviour is to detect
if you can read or/and write.
---
 st.c | 38 ++++++++++++++++++++------------------
 1 file changed, 20 insertions(+), 18 deletions(-)

diff --git a/st.c b/st.c
index 65a1866..900534b 100644
--- a/st.c
+++ b/st.c
@@ -415,7 +415,7 @@ static int32_t tdefcolor(int *, int *, int);
 static void tdeftran(char);
 static inline int match(uint, uint);
 static void ttynew(void);
-static void ttyread(void);
+static size_t ttyread(void);
 static void ttyresize(void);
 static void ttysend(char *, size_t);
 static void ttywrite(const char *, size_t);
@@ -1464,7 +1464,7 @@ ttynew(void)
 	}
 }
 
-void
+size_t
 ttyread(void)
 {
 	static char buf[BUFSIZ];
@@ -1489,14 +1489,16 @@ ttyread(void)
 
 	/* keep any uncomplete utf8 char for the next call */
 	memmove(buf, ptr, buflen);
+
+	return ret;
 }
 
 void
 ttywrite(const char *s, size_t n)
 {
-	fd_set wfd;
-	struct timespec tv;
+	fd_set wfd, rfd;
 	ssize_t r;
+	size_t lim = 256;
 
 	/*
 	 * Remember that we are using a pty, which might be a modem line.
@@ -1506,38 +1508,34 @@ ttywrite(const char *s, size_t n)
 	 */
 	while (n > 0) {
 		FD_ZERO(&wfd);
+		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &wfd);
-		tv.tv_sec = 0;
-		tv.tv_nsec = 0;
+		FD_SET(cmdfd, &rfd);
 
 		/* Check if we can write. */
-		if (pselect(cmdfd+1, NULL, &wfd, NULL, &tv, NULL) < 0) {
+		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)) {
-			/* No, then free some buffer space. */
-			ttyread();
-		} else {
+		if (FD_ISSET(cmdfd, &rfd))
+			lim = ttyread();
+		if (FD_ISSET(cmdfd, &wfd)) {
 			/*
 			 * Only write 256 bytes at maximum. This seems to be a
 			 * reasonable value for a serial line. Bigger values
 			 * might clog the I/O.
 			 */
-			r = write(cmdfd, s, (n < 256)? n : 256);
-			if (r < 0) {
-				die("write error on tty: %s\n",
-						strerror(errno));
-			}
+			if ((r = write(cmdfd, s, (n < 256)? n : 256)) < 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 < 256)
-					ttyread();
+				if (n < lim)
+					lim = ttyread();
 				n -= r;
 				s += r;
 			} else {
@@ -1546,6 +1544,10 @@ ttywrite(const char *s, size_t n)
 			}
 		}
 	}
+	return;
+
+write_error:
+	die("write error on tty: %s\n", strerror(errno));
 }
 
 void

From 00873e65eed161ee5f8916fbfb25c1a7f7a9b2f8 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 6 Nov 2015 20:46:23 +0100
Subject: [PATCH 0904/1146] Introduce lim in all ttywrite() checks.

---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 900534b..a47f094 100644
--- a/st.c
+++ b/st.c
@@ -1522,11 +1522,11 @@ ttywrite(const char *s, size_t n)
 			lim = ttyread();
 		if (FD_ISSET(cmdfd, &wfd)) {
 			/*
-			 * Only write 256 bytes at maximum. This seems to be a
-			 * reasonable value for a serial line. Bigger values
-			 * might clog the I/O.
+			 * 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 < 256)? n : 256)) < 0)
+			if ((r = write(cmdfd, s, (n < lim)? n : lim)) < 0)
 				goto write_error;
 			if (r < n) {
 				/*

From d836561b96097b04760104e7e0f8d014f5889a18 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq+hackers@fifth.space>
Date: Sun, 8 Nov 2015 17:14:58 +0100
Subject: [PATCH 0905/1146] arg.h: remove unused macros

ARGUM isn't used and ARGNUMF uses estrtol() that isn't defined anywhere.
Those were probably copied from sbase arg.h.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 arg.h | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/arg.h b/arg.h
index 4df77a7..a94e6b5 100644
--- a/arg.h
+++ b/arg.h
@@ -28,26 +28,11 @@ extern char *argv0;
 						break;\
 					argc_ = argv[0][0];\
 					switch (argc_)
-
-/* Handles obsolete -NUM syntax */
-#define ARGNUM				case '0':\
-					case '1':\
-					case '2':\
-					case '3':\
-					case '4':\
-					case '5':\
-					case '6':\
-					case '7':\
-					case '8':\
-					case '9'
-
 #define ARGEND			}\
 			}
 
 #define ARGC()		argc_
 
-#define ARGNUMF(base)	(brk_ = 1, estrtol(argv[0], (base)))
-
 #define EARGF(x)	((argv[0][1] == '\0' && argv[1] == NULL)?\
 				((x), abort(), (char *)0) :\
 				(brk_ = 1, (argv[0][1] != '\0')?\

From 375b28720f7c78e6fac1c274f9dee7c40a78aacb Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 21 Nov 2015 18:21:03 +0100
Subject: [PATCH 0906/1146] Avoid recursive call to ttywrite from ttyread

Ttyread() calls to ttywrite, so if we check for reading before
that for writing in ttywrite we can get a circular call sequence.
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index a47f094..c5d62c1 100644
--- a/st.c
+++ b/st.c
@@ -1518,8 +1518,6 @@ ttywrite(const char *s, size_t n)
 				continue;
 			die("select failed: %s\n", strerror(errno));
 		}
-		if (FD_ISSET(cmdfd, &rfd))
-			lim = ttyread();
 		if (FD_ISSET(cmdfd, &wfd)) {
 			/*
 			 * Only write the bytes written by ttywrite() or the
@@ -1543,6 +1541,8 @@ ttywrite(const char *s, size_t n)
 				break;
 			}
 		}
+		if (FD_ISSET(cmdfd, &rfd))
+			lim = ttyread();
 	}
 	return;
 

From ff241199edc7631d6599c22414ef6823059a1072 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sun, 20 Dec 2015 01:43:32 +0100
Subject: [PATCH 0907/1146] Fixing the XClassHint setting in st.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index c5d62c1..dc428ab 100644
--- a/st.c
+++ b/st.c
@@ -3237,7 +3237,7 @@ xclear(int x1, int y1, int x2, int y2)
 void
 xhints(void)
 {
-	XClassHint class = {opt_class ? opt_class : termname, termname};
+	XClassHint class = {termname, opt_class ? opt_class : termname};
 	XWMHints wm = {.flags = InputHint, .input = 1};
 	XSizeHints *sizeh = NULL;
 

From 610723a58f1fbd3c5d911c853a8b94c315fc7c2a Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 1 Jan 2016 14:18:43 +0100
Subject: [PATCH 0908/1146] Bump year.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index dc428ab..427ec46 100644
--- a/st.c
+++ b/st.c
@@ -4329,7 +4329,7 @@ run(void)
 void
 usage(void)
 {
-	die("%s " VERSION " (c) 2010-2015 st engineers\n"
+	die("%s " VERSION " (c) 2010-2016 st engineers\n"
 	"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
 	"          [-i] [-t title] [-T title] [-w windowid] [-e command ...]"
 	" [command ...]\n"

From 9031e228ce283cd4847832acf012a910f74ad1ed Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 14 Jan 2016 23:19:03 +0100
Subject: [PATCH 0909/1146] Height is height.

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 427ec46..98622ec 100644
--- a/st.c
+++ b/st.c
@@ -3469,7 +3469,7 @@ xinit(void)
 	if (xw.gm & XNegative)
 		xw.l += DisplayWidth(xw.dpy, xw.scr) - xw.w - 2;
 	if (xw.gm & YNegative)
-		xw.t += DisplayWidth(xw.dpy, xw.scr) - xw.h - 2;
+		xw.t += DisplayHeight(xw.dpy, xw.scr) - xw.h - 2;
 
 	/* Events */
 	xw.attrs.background_pixel = dc.col[defaultbg].pixel;

From 504a165277c13797840c42c64807b59cd4e5f3a5 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 28 Jan 2016 18:09:11 +0100
Subject: [PATCH 0910/1146] Enforce a terminal size to reduce race conditions
 in too efficient apps.

dvtm is too fast in starting up. It will then have a race condition in finding
the right. terminal size.
---
 st.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/st.c b/st.c
index 98622ec..3a0a519 100644
--- a/st.c
+++ b/st.c
@@ -1440,6 +1440,8 @@ ttynew(void)
 	if (openpty(&m, &s, NULL, NULL, &w) < 0)
 		die("openpty failed: %s\n", strerror(errno));
 
+	ttyresize();
+
 	switch (pid = fork()) {
 	case -1:
 		die("fork failed\n");

From bd5fdbe64c8abfb624ad59939ed9b221c8b04eef Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Fri, 29 Jan 2016 22:02:40 +0100
Subject: [PATCH 0911/1146] Reformat usage and separate version from it

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.1 | 40 ++++++++++++++++++----------------------
 st.c | 24 ++++++++++++++++--------
 2 files changed, 34 insertions(+), 30 deletions(-)

diff --git a/st.1 b/st.1
index 187a734..fe2e731 100644
--- a/st.1
+++ b/st.1
@@ -3,47 +3,43 @@
 st \- simple terminal
 .SH SYNOPSIS
 .B st
-.RB [ \-a ]
+.RB [ \-aiv ]
 .RB [ \-c
 .IR class ]
 .RB [ \-f
 .IR font ]
 .RB [ \-g
 .IR geometry ]
-.RB [ \-i ]
 .RB [ \-o
-.IR file ]
-.RB [ \-t 
-.IR title ]
+.IR iofile ]
 .RB [ \-T
 .IR title ]
+.RB [ \-t
+.IR title ]
 .RB [ \-l
 .IR line ]
-.RB [ \-w 
+.RB [ \-w
 .IR windowid ]
-.RB [ \-v ]
-.RB [ \-e
-.IR command ...]
-.RI [ commands ...]
+.RB [[ \-e ]
+.IR command
+.RI [ arguments ...]]
 .PP
 .B st
-.RB [ \-a ]
+.RB [ \-aiv ]
 .RB [ \-c
 .IR class ]
 .RB [ \-f
 .IR font ]
 .RB [ \-g
 .IR geometry ]
-.RB [ \-i ]
 .RB [ \-o
-.IR file ]
-.RB [ \-t
-.IR title ]
+.IR iofile ]
 .RB [ \-T
 .IR title ]
+.RB [ \-t
+.IR title ]
 .RB [ \-w
 .IR windowid ]
-.RB [ \-v ]
 .RB \-l
 .IR line
 .RI [ stty_args ...]
@@ -78,14 +74,14 @@ writes all the I/O to
 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 \-t " title"
+defines the window title (default 'st').
+.TP
 .BI \-w " windowid"
-embeds st within the window identified by 
+embeds st within the window identified by
 .I windowid
 .TP
 .BI \-l " line"
@@ -111,9 +107,9 @@ for more arguments and cases.
 .B \-v
 prints version information to stderr, then exits.
 .TP
-.BI \-e " program " [ " arguments " "... ]"
+.BI \-e " command " [ " arguments " "... ]"
 st executes
-.I program
+.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.
diff --git a/st.c b/st.c
index 3a0a519..2bbf484 100644
--- a/st.c
+++ b/st.c
@@ -486,6 +486,7 @@ static void *xrealloc(void *, size_t);
 static char *xstrdup(char *);
 
 static void usage(void);
+static void version(void);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
@@ -4331,14 +4332,19 @@ run(void)
 void
 usage(void)
 {
-	die("%s " VERSION " (c) 2010-2016 st engineers\n"
-	"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
-	"          [-i] [-t title] [-T title] [-w windowid] [-e command ...]"
-	" [command ...]\n"
-	"       st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
-	"          [-i] [-t title] [-T title] [-w windowid] -l line"
-	" [stty_args ...]\n",
-	argv0);
+	die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]"
+	" [-o file] [-T title]\n"
+	"          [-t title] [-w windowid] [[-e] command [args ...]]\n"
+	"       %s [-aiv] [-c class] [-f font] [-g geometry]"
+	" [-o file] [-T title]\n"
+	"          [-t title] [-w windowid] -l line [stty_args ...]\n",
+	argv0, argv0);
+}
+
+void
+version(void)
+{
+	die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0);
 }
 
 int
@@ -4385,6 +4391,8 @@ main(int argc, char *argv[])
 		opt_embed = EARGF(usage());
 		break;
 	case 'v':
+		version();
+		break;
 	default:
 		usage();
 	} ARGEND;

From 0cd5117a2cfc4134712de748ec416be0655838b2 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Fri, 29 Jan 2016 22:03:01 +0100
Subject: [PATCH 0912/1146] Add -n option for setting WM_CLASS instance name

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.1 |  7 +++++++
 st.c | 34 +++++++++++++++++++---------------
 2 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/st.1 b/st.1
index fe2e731..1e3f1d4 100644
--- a/st.1
+++ b/st.1
@@ -10,6 +10,8 @@ st \- simple terminal
 .IR font ]
 .RB [ \-g
 .IR geometry ]
+.RB [ \-n
+.IR name ]
 .RB [ \-o
 .IR iofile ]
 .RB [ \-T
@@ -32,6 +34,8 @@ st \- simple terminal
 .IR font ]
 .RB [ \-g
 .IR geometry ]
+.RB [ \-n
+.IR name ]
 .RB [ \-o
 .IR iofile ]
 .RB [ \-T
@@ -68,6 +72,9 @@ for further details.
 .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.
diff --git a/st.c b/st.c
index 2bbf484..38abffb 100644
--- a/st.c
+++ b/st.c
@@ -524,14 +524,15 @@ static int cmdfd;
 static pid_t pid;
 static Selection sel;
 static int iofd = 1;
-static char **opt_cmd = NULL;
-static char *opt_io = NULL;
-static char *opt_title = NULL;
-static char *opt_embed = NULL;
+static char **opt_cmd  = NULL;
 static char *opt_class = NULL;
-static char *opt_font = NULL;
-static char *opt_line = NULL;
-static int oldbutton = 3; /* button event on startup: 3 = release */
+static char *opt_embed = NULL;
+static char *opt_font  = NULL;
+static char *opt_io    = NULL;
+static char *opt_line  = NULL;
+static char *opt_name  = NULL;
+static char *opt_title = NULL;
+static int oldbutton   = 3; /* button event on startup: 3 = release */
 
 static char *usedfont = NULL;
 static double usedfontsize = 0;
@@ -3240,7 +3241,8 @@ xclear(int x1, int y1, int x2, int y2)
 void
 xhints(void)
 {
-	XClassHint class = {termname, opt_class ? opt_class : termname};
+	XClassHint class = {opt_name ? opt_name : termname,
+	                    opt_class ? opt_class : termname};
 	XWMHints wm = {.flags = InputHint, .input = 1};
 	XSizeHints *sizeh = NULL;
 
@@ -4332,13 +4334,12 @@ run(void)
 void
 usage(void)
 {
-	die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]"
-	" [-o file] [-T title]\n"
-	"          [-t title] [-w windowid] [[-e] command [args ...]]\n"
-	"       %s [-aiv] [-c class] [-f font] [-g geometry]"
-	" [-o file] [-T title]\n"
-	"          [-t title] [-w windowid] -l line [stty_args ...]\n",
-	argv0, argv0);
+	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  "
+	"        [-o file] [-T title] [-t title] [-w windowid] -l line"
+	" [stty_args ...]\n", argv0, argv0);
 }
 
 void
@@ -4383,6 +4384,9 @@ main(int argc, char *argv[])
 	case 'l':
 		opt_line = EARGF(usage());
 		break;
+	case 'n':
+		opt_name = EARGF(usage());
+		break;
 	case 't':
 	case 'T':
 		opt_title = EARGF(usage());

From 82335583eba15e87749d0e663270353005fca30b Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Sat, 30 Jan 2016 09:50:18 +0100
Subject: [PATCH 0913/1146] Ok, no need for a separate version function.

This is just redundant metadata. Please add Java comment meta classes too.
---
 st.c | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/st.c b/st.c
index 38abffb..005bf1d 100644
--- a/st.c
+++ b/st.c
@@ -486,7 +486,6 @@ static void *xrealloc(void *, size_t);
 static char *xstrdup(char *);
 
 static void usage(void);
-static void version(void);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
@@ -4342,12 +4341,6 @@ usage(void)
 	" [stty_args ...]\n", argv0, argv0);
 }
 
-void
-version(void)
-{
-	die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0);
-}
-
 int
 main(int argc, char *argv[])
 {
@@ -4395,7 +4388,7 @@ main(int argc, char *argv[])
 		opt_embed = EARGF(usage());
 		break;
 	case 'v':
-		version();
+		die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0);
 		break;
 	default:
 		usage();

From 6e70bb97d4e98a5e2fa7c5488b0cba1da140b78f Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Sat, 30 Jan 2016 17:54:41 +0100
Subject: [PATCH 0914/1146] Extract ttyresize() out of cresize()

This way we can call cresize() to set the terminal size before creating
a tty or spawning a process, which will start with the correct size.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 005bf1d..41f6942 100644
--- a/st.c
+++ b/st.c
@@ -1441,8 +1441,6 @@ ttynew(void)
 	if (openpty(&m, &s, NULL, NULL, &w) < 0)
 		die("openpty failed: %s\n", strerror(errno));
 
-	ttyresize();
-
 	switch (pid = fork()) {
 	case -1:
 		die("fork failed\n");
@@ -3427,6 +3425,7 @@ xzoomabs(const Arg *arg)
 	xunloadfonts();
 	xloadfonts(usedfont, arg->f);
 	cresize(0, 0);
+	ttyresize();
 	redraw();
 	xhints();
 }
@@ -4210,7 +4209,6 @@ cresize(int width, int height)
 
 	tresize(col, row);
 	xresize(col, row);
-	ttyresize();
 }
 
 void
@@ -4220,6 +4218,7 @@ resize(XEvent *e)
 		return;
 
 	cresize(e->xconfigure.width, e->xconfigure.height);
+	ttyresize();
 }
 
 void
@@ -4248,8 +4247,9 @@ run(void)
 		}
 	} while (ev.type != MapNotify);
 
-	ttynew();
 	cresize(w, h);
+	ttynew();
+	ttyresize();
 
 	clock_gettime(CLOCK_MONOTONIC, &last);
 	lastblink = last;

From 6d636beb229cebf3b897446c72c7a341bee9f820 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Mon, 1 Feb 2016 12:20:33 +0100
Subject: [PATCH 0915/1146] Fix forgotten bracket and duplicate option in
 usage()

Scratch the preceding patch, this one is more correct
(don't forget to 'git am --scissors' ;))
-- >8 --

Also reformat the strings in a saner layout

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index 41f6942..0536b6f 100644
--- a/st.c
+++ b/st.c
@@ -4333,12 +4333,14 @@ run(void)
 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  "
-	"        [-o file] [-T title] [-t title] [-w windowid] -l line"
-	" [stty_args ...]\n", argv0, argv0);
+	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

From 4fdba860c8db70035e9749806ecc6ca2d7c418d0 Mon Sep 17 00:00:00 2001
From: Lucas Gabriel Vuotto <l.vuotto92@gmail.com>
Date: Fri, 19 Feb 2016 15:59:49 -0300
Subject: [PATCH 0916/1146] arg.h: fixed argv checks order

This prevents accessing to a potentially out-of-bounds memory section.

Signed-off-by: Lucas Gabriel Vuotto <l.vuotto92@gmail.com>
Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 arg.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arg.h b/arg.h
index a94e6b5..ba3fb3f 100644
--- a/arg.h
+++ b/arg.h
@@ -10,8 +10,8 @@ extern char *argv0;
 
 /* use main(int argc, char *argv[]) */
 #define ARGBEGIN	for (argv0 = *argv, argv++, argc--;\
-					argv[0] && argv[0][1]\
-					&& argv[0][0] == '-';\
+					argv[0] && argv[0][0] == '-'\
+					&& argv[0][1];\
 					argc--, argv++) {\
 				char argc_;\
 				char **argv_;\

From 30440295bc054f37a2a8275acca769cd83bcb780 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Mon, 7 Mar 2016 14:33:05 +0100
Subject: [PATCH 0917/1146] xtermclear() is now done by xdrawglyphfontspecs()

Thanks Ton van den Heuvel for the proposal!
---
 st.c | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/st.c b/st.c
index 0536b6f..2473af7 100644
--- a/st.c
+++ b/st.c
@@ -439,7 +439,6 @@ static void xresettitle(void);
 static void xsetpointermotion(int);
 static void xseturgency(int);
 static void xsetsel(char *, Time);
-static void xtermclear(int, int, int, int);
 static void xunloadfont(Font *);
 static void xunloadfonts(void);
 static void xresize(int, int);
@@ -3213,17 +3212,6 @@ xsetcolorname(int x, const char *name)
 	return 0;
 }
 
-void
-xtermclear(int col1, int row1, int col2, int row2)
-{
-	XftDrawRect(xw.draw,
-			&dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
-			borderpx + col1 * xw.cw,
-			borderpx + row1 * xw.ch,
-			(col2-col1+1) * xw.cw,
-			(row2-row1+1) * xw.ch);
-}
-
 /*
  * Absolute coordinates.
  */
@@ -3983,7 +3971,6 @@ drawregion(int x1, int y1, int x2, int y2)
 		if (!term.dirty[y])
 			continue;
 
-		xtermclear(0, y, term.col, y);
 		term.dirty[y] = 0;
 
 		specs = term.specbuf;

From 034a5c8a09e23ce0a410d0c608dd7e050b83681e Mon Sep 17 00:00:00 2001
From: Ryusei Yamaguchi <mandel59@gmail.com>
Date: Tue, 8 Mar 2016 12:26:04 +0900
Subject: [PATCH 0918/1146] Measure the single advance width with a heuristic
 method

This fix is needed to use dual-width fonts, which have double-width
glyphs (e.g. CJK unified ideographs).

Signed-off-by: Ryusei Yamaguchi <mandel59@gmail.com>
Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 config.def.h | 8 ++++++++
 st.c         | 8 +++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index fd09d72..a1e7d5a 100644
--- a/config.def.h
+++ b/config.def.h
@@ -417,3 +417,11 @@ 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.c b/st.c
index 2473af7..ca126d7 100644
--- a/st.c
+++ b/st.c
@@ -68,6 +68,7 @@ char *argv0;
 #define LEN(a)			(sizeof(a) / sizeof(a)[0])
 #define DEFAULT(a, b)		(a) = (a) ? (a) : (b)
 #define BETWEEN(x, a, b)	((a) <= (x) && (x) <= (b))
+#define DIVCEIL(n, d)		(((n) + ((d) - 1)) / (d))
 #define ISCONTROLC0(c)		(BETWEEN(c, 0, 0x1f) || (c) == '\177')
 #define ISCONTROLC1(c)		(BETWEEN(c, 0x80, 0x9f))
 #define ISCONTROL(c)		(ISCONTROLC0(c) || ISCONTROLC1(c))
@@ -3277,6 +3278,7 @@ xloadfont(Font *f, FcPattern *pattern)
 {
 	FcPattern *match;
 	FcResult result;
+	XGlyphInfo extents;
 
 	match = FcFontMatch(NULL, pattern, &result);
 	if (!match)
@@ -3287,6 +3289,10 @@ xloadfont(Font *f, FcPattern *pattern)
 		return 1;
 	}
 
+	XftTextExtentsUtf8(xw.dpy, f->match,
+		(const FcChar8 *) ascii_printable,
+		LEN(ascii_printable), &extents);
+
 	f->set = NULL;
 	f->pattern = FcPatternDuplicate(pattern);
 
@@ -3296,7 +3302,7 @@ xloadfont(Font *f, FcPattern *pattern)
 	f->rbearing = f->match->max_advance_width;
 
 	f->height = f->ascent + f->descent;
-	f->width = f->lbearing + f->rbearing;
+	f->width = DIVCEIL(extents.xOff, LEN(ascii_printable));
 
 	return 0;
 }

From 6d8f85232ec741ae2357728d6e96cb8a44e842b4 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Tue, 8 Mar 2016 13:55:22 +0100
Subject: [PATCH 0919/1146] I like empty lines.

---
 config.def.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/config.def.h b/config.def.h
index a1e7d5a..9e61010 100644
--- a/config.def.h
+++ b/config.def.h
@@ -425,3 +425,4 @@ static char ascii_printable[] =
 	" !\"#$%&'()*+,-./0123456789:;<=>?"
 	"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
 	"`abcdefghijklmnopqrstuvwxyz{|}~";
+

From 0e48a1995eee1c2babc58523ef0be296e4b1c3e8 Mon Sep 17 00:00:00 2001
From: Ton van den Heuvel <tonvandenheuvel@gmail.com>
Date: Mon, 7 Mar 2016 22:18:12 +0100
Subject: [PATCH 0920/1146] Fix vertical character alignment in some cases

The y-position of a character found by asking fontconfig for a matching
font does not take the border pixels into account, resulting in a
slightly misaligned vertical position.

Signed-off-by: Ton van den Heuvel <tonvandenheuvel@gmail.com>
Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index ca126d7..f2b3095 100644
--- a/st.c
+++ b/st.c
@@ -3671,7 +3671,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
 		specs[numspecs].font = frc[f].font;
 		specs[numspecs].glyph = glyphidx;
 		specs[numspecs].x = (short)xp;
-		specs[numspecs].y = (short)(winy + frc[f].font->ascent);
+		specs[numspecs].y = (short)yp;
 		xp += runewidth;
 		numspecs++;
 	}

From 39964614b742c4ec98a326762d98470cb987a45b Mon Sep 17 00:00:00 2001
From: Tor Andersson <tor@ccxvii.net>
Date: Wed, 9 Mar 2016 17:11:57 +0100
Subject: [PATCH 0921/1146] st: Fix off-by-one error when calculating character
 width.

LEN(str) is one larger than strlen(str) because it also counts the zero
terminator. The original code would include the .notdef glyph (since it'll
try to encode character 0, which gets encoded to the .notdef glyph) when
measuring the average dimensions of printable ascii characters.

This causes problems with fonts like GNU Unifont where the .notdef glyph is
not the same width as the usual half-width characters.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index f2b3095..839136d 100644
--- a/st.c
+++ b/st.c
@@ -3291,7 +3291,7 @@ xloadfont(Font *f, FcPattern *pattern)
 
 	XftTextExtentsUtf8(xw.dpy, f->match,
 		(const FcChar8 *) ascii_printable,
-		LEN(ascii_printable), &extents);
+		strlen(ascii_printable), &extents);
 
 	f->set = NULL;
 	f->pattern = FcPatternDuplicate(pattern);
@@ -3302,7 +3302,7 @@ xloadfont(Font *f, FcPattern *pattern)
 	f->rbearing = f->match->max_advance_width;
 
 	f->height = f->ascent + f->descent;
-	f->width = DIVCEIL(extents.xOff, LEN(ascii_printable));
+	f->width = DIVCEIL(extents.xOff, strlen(ascii_printable));
 
 	return 0;
 }

From 66556d967028a0b770e9bfcb9667389a6e994a58 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <roberto.vargas@igrid-td.com>
Date: Fri, 15 Apr 2016 07:58:26 +0200
Subject: [PATCH 0922/1146] Remove stupid assignation in memcpy()

---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 839136d..27536d2 100644
--- a/st.c
+++ b/st.c
@@ -1404,9 +1404,9 @@ stty(void)
 		if ((n = strlen(s)) > siz-1)
 			die("stty parameter length too long\n");
 		*q++ = ' ';
-		q = memcpy(q, s, n);
+		memcpy(q, s, n);
 		q += n;
-		siz-= n + 1;
+		siz -= n + 1;
 	}
 	*q = '\0';
 	if (system(cmd) != 0)

From 60aeb37edb8c5280d31b6b3c801d09c7a5fdca76 Mon Sep 17 00:00:00 2001
From: v4hn <me@v4hn.de>
Date: Thu, 19 May 2016 12:16:57 +0200
Subject: [PATCH 0923/1146] delete clipboard properties after pasting them

https://tronche.com/gui/x/icccm/sec-2.html#s-2.4 specifies:
> Once all the data in the selection has been retrieved,
> the requestor should delete the property in the SelectionNotify request

Most Clipboard-Owners ignore whether or not the property is already set,
so this is mostly a cosmetic change to keep the windows property list clean.

However, at least synergy decides to wait for the requestor to delete
the properties if they are already set by a previous paste (from synergy).

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 27536d2..6736464 100644
--- a/st.c
+++ b/st.c
@@ -1151,8 +1151,7 @@ selnotify(XEvent *e)
 	 * Deleting the property again tells the selection owner to send the
 	 * next data chunk in the property.
 	 */
-	if (e->type == PropertyNotify)
-		XDeleteProperty(xw.dpy, xw.win, (int)property);
+	XDeleteProperty(xw.dpy, xw.win, (int)property);
 }
 
 void

From 528241aa3835e2f1f052abeeaf891737712955a0 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Fri, 3 Jun 2016 15:02:32 +0200
Subject: [PATCH 0924/1146] Use XftFontMatch in place of FcFontMatch.

git am -s didn't like your patch:

From: Mark Edgar <medgar123@gmail.com>

XftFontMatch calls XftDefaultSubstitute which configures various match
properties according to the user's configured Xft defaults (xrdb) as well as
according to the current display and screen. Most importantly, the screen DPI
is computed [1]. Without this, st uses a "default" DPI of 75 [2].

[1]: https://cgit.freedesktop.org/xorg/lib/libXft/tree/src/xftdpy.c?id=libXft-2.3.2#n535
[2]: https://cgit.freedesktop.org/fontconfig/tree/src/fcdefault.c?id=2.11.1#n255
---
 st.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 6736464..2594c65 100644
--- a/st.c
+++ b/st.c
@@ -3279,7 +3279,7 @@ xloadfont(Font *f, FcPattern *pattern)
 	FcResult result;
 	XGlyphInfo extents;
 
-	match = FcFontMatch(NULL, pattern, &result);
+	match = XftFontMatch(xw.dpy, xw.scr, pattern, &result);
 	if (!match)
 		return 1;
 
@@ -3345,9 +3345,6 @@ xloadfonts(char *fontstr, double fontsize)
 		defaultfontsize = usedfontsize;
 	}
 
-	FcConfigSubstitute(0, pattern, FcMatchPattern);
-	FcDefaultSubstitute(pattern);
-
 	if (xloadfont(&dc.font, pattern))
 		die("st: can't open font %s\n", fontstr);
 

From 235b438e689e1fab677ee7e6ee53491867c16b9d Mon Sep 17 00:00:00 2001
From: Alive 4ever <alive4ever@live.com>
Date: Sun, 10 Jul 2016 06:38:04 +0000
Subject: [PATCH 0925/1146] Consistent Alt+BackSpace behavior

The default config specifies BackSpace as "\177". The default behavior
should persist across modifier keys, commonly Mod1 (Alt or Meta) which
is widely used to delete a word on readline and text editors, notably
Emacs.

This will make Alt+BackSpace behaves as expected, i.e. sends "\033\177"
instead of "\033\010" as previous default behavior.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
---
 config.def.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/config.def.h b/config.def.h
index 9e61010..0070635 100644
--- a/config.def.h
+++ b/config.def.h
@@ -303,6 +303,7 @@ static Key key[] = {
 	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
 	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
 	{ XK_BackSpace,     XK_NO_MOD,      "\177",          0,    0,    0},
+	{ XK_BackSpace,     Mod1Mask,       "\033\177",      0,    0,    0},
 	{ XK_Home,          ShiftMask,      "\033[2J",       0,   -1,    0},
 	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,   +1,    0},
 	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1,    0},

From 2251f6465ae48aaa012fd686d6dcc4d3f41f77fe Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 20 Jul 2016 13:00:43 +0200
Subject: [PATCH 0926/1146] Add comment about tabspaces.

st.info needs to be changed too, when tabspaces are changed.
---
 config.def.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/config.def.h b/config.def.h
index 0070635..d2c547c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -65,6 +65,15 @@ static int bellvolume = 0;
 /* default TERM value */
 static 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,
+ */
 static unsigned int tabspaces = 8;
 
 /* Terminal colors (16 first used in escape sequence) */

From c4f245eccd649b258c52f1405452df05180f7263 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 20 Jul 2016 13:52:31 +0200
Subject: [PATCH 0927/1146] Add some hint to have the pseudo terminal in the
 right mode.

If you don't make sure that the terminal does not expand tabs to spaces, of
course such a setting won't work.
---
 config.def.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/config.def.h b/config.def.h
index d2c547c..e2bbe43 100644
--- a/config.def.h
+++ b/config.def.h
@@ -73,6 +73,12 @@ static char termname[] = "st-256color";
  * you use this st version.
  *
  *	it#$tabspaces,
+ *
+ * Secondly make sure your terminal 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
  */
 static unsigned int tabspaces = 8;
 

From 308bfbf6be46ac5f0aa77b0e42a242eeb3ae1443 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Wed, 20 Jul 2016 13:56:15 +0200
Subject: [PATCH 0928/1146] Change who's expanding tabs.

---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index e2bbe43..b41747f 100644
--- a/config.def.h
+++ b/config.def.h
@@ -74,7 +74,7 @@ static char termname[] = "st-256color";
  *
  *	it#$tabspaces,
  *
- * Secondly make sure your terminal is not expanding tabs. When running `stty
+ * 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:
  *

From 6e79e8357ed1987a7f7a52cc06249aadef478041 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 11 Aug 2016 16:25:58 +0200
Subject: [PATCH 0929/1146] 0.7 release

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 81e3e47..c84c5ee 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.6
+VERSION = 0.7
 
 # Customize below to fit your system
 

From 023225ef40b23d888353e34d95790ddf1cc79458 Mon Sep 17 00:00:00 2001
From: Christoph Lohmann <20h@r-36.net>
Date: Thu, 11 Aug 2016 16:30:29 +0200
Subject: [PATCH 0930/1146] Update the LICENSE.

This is for the next release.
---
 LICENSE | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LICENSE b/LICENSE
index e61610a..fa0c63e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2,8 +2,8 @@ MIT/X Consortium License
 
 © 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>
 © 2009 Anselm R Garbe <garbeam at gmail dot com>
-© 2012-2015 Roberto E. Vargas Caballero <k0ga at shike2 dot com>
-© 2012-2015 Christoph Lohmann <20h at r-36 dot net>
+© 2012-2016 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>

From 5ce853a1c14bab21c79af5470bff7bed07159ec5 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Thu, 8 Sep 2016 12:57:43 +0200
Subject: [PATCH 0931/1146] st.info: do not prevent st from displaying
 attributes

With ncv set to 3, we prevent st from displaying A_STANDOUT and
A_UNDERLINE with colors while our virtual terminal is capable of it.
---
 st.info | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.info b/st.info
index b70fefa..b9ec445 100644
--- a/st.info
+++ b/st.info
@@ -149,7 +149,7 @@ st| simpleterm,
 	lines#24,
 	mir,
 	msgr,
-	ncv#3,
+	ncv@,
 	npc,
 	op=\E[39;49m,
 	pairs#64,

From 078337d7457f7869a85f4ec364be92b79e93c502 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <roberto.vargas@igrid-td.com>
Date: Fri, 9 Sep 2016 13:11:06 +0200
Subject: [PATCH 0932/1146] Delete ncv capability from terminfo

We do not need to disable the previous ncv definition, because
there is not previous definition.
---
 st.info | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.info b/st.info
index b9ec445..d411be7 100644
--- a/st.info
+++ b/st.info
@@ -149,7 +149,6 @@ st| simpleterm,
 	lines#24,
 	mir,
 	msgr,
-	ncv@,
 	npc,
 	op=\E[39;49m,
 	pairs#64,

From f0e2d28732549690466df995981698173daf39c0 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <roberto.vargas@igrid-td.com>
Date: Tue, 13 Sep 2016 14:01:18 +0200
Subject: [PATCH 0933/1146] Add support for enabling/disabling utf

There are some ocasions where we want to disable the enconding/decoding of utf8, mainly
because it adds an important overhead. This is partial patch for ESC % G and ESC % @,
where they modified the way that st reads and write from/to the serial line, but it does
not modifies how it interacts with the X window part.
---
 st.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 62 insertions(+), 17 deletions(-)

diff --git a/st.c b/st.c
index 2594c65..ebbd7ca 100644
--- a/st.c
+++ b/st.c
@@ -137,6 +137,7 @@ enum term_mode {
 	MODE_MOUSEMANY   = 1 << 18,
 	MODE_BRCKTPASTE  = 1 << 19,
 	MODE_PRINT       = 1 << 20,
+	MODE_UTF8        = 1 << 21,
 	MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
 	                  |MODE_MOUSEMANY,
 };
@@ -158,6 +159,7 @@ enum escape_state {
 	ESC_ALTCHARSET = 8,
 	ESC_STR_END    = 16, /* a final string was encountered */
 	ESC_TEST       = 32, /* Enter in test mode */
+	ESC_UTF8       = 64,
 };
 
 enum window_state {
@@ -412,6 +414,7 @@ static void tfulldirt(void);
 static void techo(Rune);
 static void tcontrolcode(uchar );
 static void tdectest(char );
+static void tdefutf8(char);
 static int32_t tdefcolor(int *, int *, int);
 static void tdeftran(char);
 static inline int match(uint, uint);
@@ -1478,17 +1481,29 @@ ttyread(void)
 	if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
 		die("Couldn't read from shell: %s\n", strerror(errno));
 
-	/* process every complete utf8 char */
 	buflen += ret;
 	ptr = buf;
-	while ((charsize = utf8decode(ptr, &unicodep, buflen))) {
-		tputc(unicodep);
-		ptr += charsize;
-		buflen -= charsize;
-	}
 
+	for (;;) {
+		if (IS_SET(MODE_UTF8)) {
+			/* process a complete utf8 char */
+			charsize = utf8decode(ptr, &unicodep, buflen);
+			if (charsize == 0)
+				break;
+			tputc(unicodep);
+			ptr += charsize;
+			buflen -= charsize;
+
+		} else {
+			if (buflen <= 0)
+				break;
+			tputc(*ptr++ & 0xFF);
+			buflen--;
+		}
+	}
 	/* keep any uncomplete utf8 char for the next call */
-	memmove(buf, ptr, buflen);
+	if (buflen > 0)
+		memmove(buf, ptr, buflen);
 
 	return ret;
 }
@@ -1554,15 +1569,26 @@ void
 ttysend(char *s, size_t n)
 {
 	int len;
+	char *t, *lim;
 	Rune u;
 
 	ttywrite(s, n);
-	if (IS_SET(MODE_ECHO))
-		while ((len = utf8decode(s, &u, n)) > 0) {
-			techo(u);
-			n -= len;
-			s += len;
+	if (!IS_SET(MODE_ECHO))
+		return;
+
+	lim = &s[n];
+	for (t = s; t < lim; t += len) {
+		if (IS_SET(MODE_UTF8)) {
+			len = utf8decode(t, &u, n);
+		} else {
+			u = *t & 0xFF;
+			len = 1;
 		}
+		if (len <= 0)
+			break;
+		techo(u);
+		n -= len;
+	}
 }
 
 void
@@ -1656,7 +1682,7 @@ treset(void)
 		term.tabs[i] = 1;
 	term.top = 0;
 	term.bot = term.row - 1;
-	term.mode = MODE_WRAP;
+	term.mode = MODE_WRAP|MODE_UTF8;
 	memset(term.trantbl, CS_USA, sizeof(term.trantbl));
 	term.charset = 0;
 
@@ -2689,6 +2715,15 @@ techo(Rune u)
 	tputc(u);
 }
 
+void
+tdefutf8(char ascii)
+{
+	if (ascii == 'G')
+		term.mode |= MODE_UTF8;
+	else if (ascii == '@')
+		term.mode &= ~MODE_UTF8;
+}
+
 void
 tdeftran(char ascii)
 {
@@ -2851,6 +2886,9 @@ eschandle(uchar ascii)
 	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 */
@@ -2930,10 +2968,15 @@ tputc(Rune u)
 	Glyph *gp;
 
 	control = ISCONTROL(u);
-	len = utf8encode(u, c);
-	if (!control && (width = wcwidth(u)) == -1) {
-		memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
-		width = 1;
+	if (!IS_SET(MODE_UTF8)) {
+		c[0] = u;
+		width = len = 1;
+	} else {
+		len = utf8encode(u, c);
+		if (!control && (width = wcwidth(u)) == -1) {
+			memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
+			width = 1;
+		}
 	}
 
 	if (IS_SET(MODE_PRINT))
@@ -2994,6 +3037,8 @@ tputc(Rune u)
 				csihandle();
 			}
 			return;
+		} else if (term.esc & ESC_UTF8) {
+			tdefutf8(u);
 		} else if (term.esc & ESC_ALTCHARSET) {
 			tdeftran(u);
 		} else if (term.esc & ESC_TEST) {

From f7398434b8fa949af7bf43472caaefdd97eed0f3 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <roberto.vargas@igrid-td.com>
Date: Wed, 14 Sep 2016 08:27:32 +0200
Subject: [PATCH 0934/1146] Add parsing of DCS q sequences

These sequences are used to operate with sixels, but they are still
str sequences, so they are finished with \a, ST or with a C1 control
code. This patch also disables utf8 handling for the case of sixels.
---
 st.c | 70 +++++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 46 insertions(+), 24 deletions(-)

diff --git a/st.c b/st.c
index ebbd7ca..6c16386 100644
--- a/st.c
+++ b/st.c
@@ -138,6 +138,7 @@ enum term_mode {
 	MODE_BRCKTPASTE  = 1 << 19,
 	MODE_PRINT       = 1 << 20,
 	MODE_UTF8        = 1 << 21,
+	MODE_SIXEL       = 1 << 22,
 	MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
 	                  |MODE_MOUSEMANY,
 };
@@ -155,11 +156,12 @@ enum charset {
 enum escape_state {
 	ESC_START      = 1,
 	ESC_CSI        = 2,
-	ESC_STR        = 4,  /* DCS, OSC, PM, APC */
+	ESC_STR        = 4,  /* 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,
+	ESC_DCS        =128,
 };
 
 enum window_state {
@@ -1485,7 +1487,7 @@ ttyread(void)
 	ptr = buf;
 
 	for (;;) {
-		if (IS_SET(MODE_UTF8)) {
+		if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
 			/* process a complete utf8 char */
 			charsize = utf8decode(ptr, &unicodep, buflen);
 			if (charsize == 0)
@@ -1578,7 +1580,7 @@ ttysend(char *s, size_t n)
 
 	lim = &s[n];
 	for (t = s; t < lim; t += len) {
-		if (IS_SET(MODE_UTF8)) {
+		if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
 			len = utf8decode(t, &u, n);
 		} else {
 			u = *t & 0xFF;
@@ -2548,6 +2550,7 @@ strhandle(void)
 		xsettitle(strescseq.args[0]);
 		return;
 	case 'P': /* DCS -- Device Control String */
+		term.mode |= ESC_DCS;
 	case '_': /* APC -- Application Program Command */
 	case '^': /* PM -- Privacy Message */
 		return;
@@ -2754,9 +2757,12 @@ tdectest(char c)
 void
 tstrsequence(uchar c)
 {
+	strreset();
+
 	switch (c) {
 	case 0x90:   /* DCS -- Device Control String */
 		c = 'P';
+		term.esc |= ESC_DCS;
 		break;
 	case 0x9f:   /* APC -- Application Program Command */
 		c = '_';
@@ -2768,7 +2774,6 @@ tstrsequence(uchar c)
 		c = ']';
 		break;
 	}
-	strreset();
 	strescseq.type = c;
 	term.esc |= ESC_STR;
 }
@@ -2968,7 +2973,7 @@ tputc(Rune u)
 	Glyph *gp;
 
 	control = ISCONTROL(u);
-	if (!IS_SET(MODE_UTF8)) {
+	if (!IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
 		c[0] = u;
 		width = len = 1;
 	} else {
@@ -2991,30 +2996,47 @@ tputc(Rune u)
 	if (term.esc & ESC_STR) {
 		if (u == '\a' || u == 030 || u == 032 || u == 033 ||
 		   ISCONTROLC1(u)) {
-			term.esc &= ~(ESC_START|ESC_STR);
+			term.esc &= ~(ESC_START|ESC_STR|ESC_DCS);
+			if (IS_SET(MODE_SIXEL)) {
+				/* TODO: render sixel */;
+				term.mode &= ~MODE_SIXEL;
+				return;
+			}
 			term.esc |= ESC_STR_END;
-		} else if (strescseq.len + len < sizeof(strescseq.buf) - 1) {
-			memmove(&strescseq.buf[strescseq.len], c, len);
-			strescseq.len += len;
-			return;
-		} else {
-		/*
-		 * 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();
-		 */
+			goto check_control_code;
+		}
+
+
+		if (IS_SET(MODE_SIXEL)) {
+			/* TODO: implement sixel mode */
 			return;
 		}
+		if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q')
+			term.mode |= MODE_SIXEL;
+
+		if (strescseq.len+len >= sizeof(strescseq.buf)-1) {
+			/*
+			 * Here is a bug in terminals. If the user never sends
+			 * some code to stop the str or esc command, then st
+			 * will stop responding. But this is better than
+			 * silently failing with unknown characters. At least
+			 * then users will report back.
+			 *
+			 * In the case users ever get fixed, here is the code:
+			 */
+			/*
+			 * term.esc = 0;
+			 * strhandle();
+			 */
+			return;
+		}
+
+		memmove(&strescseq.buf[strescseq.len], c, len);
+		strescseq.len += len;
+		return;
 	}
 
+check_control_code:
 	/*
 	 * Actions of control codes must be performed as soon they arrive
 	 * because they can be embedded inside a control sequence, and

From 331033f1f6abe259218666e6f6a848f38d884078 Mon Sep 17 00:00:00 2001
From: Klemens Nanni <kl3@posteo.org>
Date: Thu, 13 Oct 2016 16:28:50 +0200
Subject: [PATCH 0935/1146] Add missing device path to '-l' example

Also, it's ttyS0 not ttySO.
---
 st.1 | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.1 b/st.1
index 1e3f1d4..aedc174 100644
--- a/st.1
+++ b/st.1
@@ -96,18 +96,18 @@ use a tty
 .I line
 instead of a pseudo terminal.
 .I line
-should be a (pseudo-)serial device (e.g. /dev/ttySO on Linux for serial port
+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 115200'). Arguments before the last one are
+(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
-parenb parodd 115200'. Set the number of bits by using for example 'st -l cs7
-115200'. See
+/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

From 68bae9c7b121e30114f6b0cabe15da3fae46e673 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Sat, 8 Oct 2016 16:22:18 +0200
Subject: [PATCH 0936/1146] Add support for iso14755

We launch dmenu for getting a codepoint, then convert it and send it to
the terminal.
---
 config.def.h |  1 +
 st.c         | 28 ++++++++++++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/config.def.h b/config.def.h
index b41747f..c2e4ffd 100644
--- a/config.def.h
+++ b/config.def.h
@@ -172,6 +172,7 @@ static Shortcut shortcuts[] = {
 	{ MODKEY|ShiftMask,     XK_C,           clipcopy,       {.i =  0} },
 	{ MODKEY|ShiftMask,     XK_V,           clippaste,      {.i =  0} },
 	{ MODKEY,               XK_Num_Lock,    numlock,        {.i =  0} },
+	{ MODKEY,               XK_Control_L,   iso14755,       {.i =  0} },
 };
 
 /*
diff --git a/st.c b/st.c
index 6c16386..c67623f 100644
--- a/st.c
+++ b/st.c
@@ -66,6 +66,7 @@ char *argv0;
 #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 NUMMAXLEN(x)		((int)(sizeof(x) * 2.56 + 0.5) + 1)
 #define DEFAULT(a, b)		(a) = (a) ? (a) : (b)
 #define BETWEEN(x, a, b)	((a) <= (x) && (x) <= (b))
 #define DIVCEIL(n, d)		(((n) + ((d) - 1)) / (d))
@@ -87,6 +88,8 @@ char *argv0;
 #define TRUEGREEN(x)		(((x) & 0xff00))
 #define TRUEBLUE(x)		(((x) & 0xff) << 8)
 
+/* constants */
+#define ISO14755CMD		"dmenu -w %lu -p codepoint: </dev/null"
 
 enum glyph_attribute {
 	ATTR_NULL       = 0,
@@ -338,6 +341,7 @@ static void xzoomabs(const Arg *);
 static void xzoomreset(const Arg *);
 static void printsel(const Arg *);
 static void printscreen(const Arg *) ;
+static void iso14755(const Arg *);
 static void toggleprinter(const Arg *);
 static void sendbreak(const Arg *);
 
@@ -2632,6 +2636,30 @@ tprinter(char *s, size_t len)
 	}
 }
 
+void
+iso14755(const Arg *arg)
+{
+	char cmd[sizeof(ISO14755CMD) + NUMMAXLEN(xw.win)];
+	FILE *p;
+	char *us, *e, codepoint[9], uc[UTF_SIZ];
+	unsigned long utf32;
+
+	snprintf(cmd, sizeof(cmd), ISO14755CMD, xw.win);
+	if (!(p = popen(cmd, "r")))
+		return;
+
+	us = fgets(codepoint, sizeof(codepoint), p);
+	pclose(p);
+
+	if (!us || *us == '\0' || *us == '-' || strlen(us) > 7)
+		return;
+	if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX ||
+	    (*e != '\n' && *e != '\0'))
+		return;
+
+	ttysend(uc, utf8encode(utf32, uc));
+}
+
 void
 toggleprinter(const Arg *arg)
 {

From 7854fde1ff95ba85239ccfe1b59b555bd245d0db Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Sat, 22 Oct 2016 10:42:46 +0200
Subject: [PATCH 0937/1146] st.1: add an entry for ISO-14755 shortcut

---
 st.1 | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/st.1 b/st.1
index aedc174..c429dcf 100644
--- a/st.1
+++ b/st.1
@@ -162,6 +162,10 @@ Copy the selected text to the clipboard selection.
 .TP
 .B Alt-Shift-v
 Paste from the clipboard selection.
+.TP
+.B Alt-Ctrl
+Launch dmenu to enter a unicode codepoint and send the corresponding glyph
+to st.
 .SH CUSTOMIZATION
 .B st
 can be customized by creating a custom config.h and (re)compiling the source

From 8c99915608beee03eca3bae6ed92264a0da87e2f Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Sat, 22 Oct 2016 16:36:10 +0200
Subject: [PATCH 0938/1146] Do not use color when font attributes are supported

If fontconfig gives us a font without the attributes we asked for,
display an alternative color instead.
---
 config.def.h |  8 +++-----
 st.c         | 40 ++++++++++++++++++++++++++++++++--------
 2 files changed, 35 insertions(+), 13 deletions(-)

diff --git a/config.def.h b/config.def.h
index c2e4ffd..7f465d1 100644
--- a/config.def.h
+++ b/config.def.h
@@ -138,12 +138,10 @@ static unsigned int mousefg = 7;
 static unsigned int mousebg = 0;
 
 /*
- * Colors used, when the specific fg == defaultfg. So in reverse mode this
- * will reverse too. Another logic would only make the simple feature too
- * complex.
+ * Color used to display font attributes when fontconfig selected a font which
+ * doesn't match the ones requested.
  */
-static unsigned int defaultitalic = 11;
-static unsigned int defaultunderline = 7;
+static unsigned int defaultattr = 11;
 
 /*
  * Internal mouse shortcuts.
diff --git a/st.c b/st.c
index c67623f..4d44388 100644
--- a/st.c
+++ b/st.c
@@ -354,6 +354,8 @@ typedef struct {
 	int width;
 	int ascent;
 	int descent;
+	int badslant;
+	int badweight;
 	short lbearing;
 	short rbearing;
 	XftFont *match;
@@ -3373,6 +3375,7 @@ xloadfont(Font *f, FcPattern *pattern)
 	FcPattern *match;
 	FcResult result;
 	XGlyphInfo extents;
+	int wantattr, haveattr;
 
 	match = XftFontMatch(xw.dpy, xw.scr, pattern, &result);
 	if (!match)
@@ -3383,6 +3386,28 @@ xloadfont(Font *f, FcPattern *pattern)
 		return 1;
 	}
 
+	if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) ==
+	    XftResultMatch)) {
+		/*
+		 * Check if xft was unable to find a font with the appropriate
+		 * slant but gave us one anyway. Try to mitigate.
+		 */
+		if ((XftPatternGetInteger(f->match->pattern, "slant", 0,
+		    &haveattr) != XftResultMatch) || haveattr < wantattr) {
+			f->badslant = 1;
+			fputs("st: font slant does not match\n", stderr);
+		}
+	}
+
+	if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) ==
+	    XftResultMatch)) {
+		if ((XftPatternGetInteger(f->match->pattern, "weight", 0,
+		    &haveattr) != XftResultMatch) || haveattr != wantattr) {
+			f->badweight = 1;
+			fputs("st: font weight does not match\n", stderr);
+		}
+	}
+
 	XftTextExtentsUtf8(xw.dpy, f->match,
 		(const FcChar8 *) ascii_printable,
 		strlen(ascii_printable), &extents);
@@ -3780,14 +3805,13 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 	XRenderColor colfg, colbg;
 	XRectangle r;
 
-	/* Determine foreground and background colors based on mode. */
-	if (base.fg == defaultfg) {
-		if (base.mode & ATTR_ITALIC)
-			base.fg = defaultitalic;
-		else if ((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD))
-			base.fg = defaultitalic;
-		else if (base.mode & ATTR_UNDERLINE)
-			base.fg = defaultunderline;
+	/* 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)) {

From 902a392b905107c7b8a318c103837c54e47a068e Mon Sep 17 00:00:00 2001
From: "pl@ninthfloor.org" <pl@ninthfloor.org>
Date: Fri, 11 Nov 2016 17:45:52 +0100
Subject: [PATCH 0939/1146] Make strdump(), csidump(), print to stderr

The two functions strdump(), csidump() are called to show errors and
their output is introduced by a message printed to stderr. Thus, it it
more consistent to have them print to stderr.

Moreover stderr is unbuffered (at least on Linux), making problems
immediately visible.
---
 st.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index 4d44388..0980082 100644
--- a/st.c
+++ b/st.c
@@ -2490,22 +2490,22 @@ csidump(void)
 	int i;
 	uint c;
 
-	printf("ESC[");
+	fprintf(stderr, "ESC[");
 	for (i = 0; i < csiescseq.len; i++) {
 		c = csiescseq.buf[i] & 0xff;
 		if (isprint(c)) {
-			putchar(c);
+			putc(c, stderr);
 		} else if (c == '\n') {
-			printf("(\\n)");
+			fprintf(stderr, "(\\n)");
 		} else if (c == '\r') {
-			printf("(\\r)");
+			fprintf(stderr, "(\\r)");
 		} else if (c == 0x1b) {
-			printf("(\\e)");
+			fprintf(stderr, "(\\e)");
 		} else {
-			printf("(%02x)", c);
+			fprintf(stderr, "(%02x)", c);
 		}
 	}
-	putchar('\n');
+	putc('\n', stderr);
 }
 
 void
@@ -2594,24 +2594,25 @@ strdump(void)
 	int i;
 	uint c;
 
-	printf("ESC%c", strescseq.type);
+	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)) {
-			putchar(c);
+			putc(c, stderr);
 		} else if (c == '\n') {
-			printf("(\\n)");
+			fprintf(stderr, "(\\n)");
 		} else if (c == '\r') {
-			printf("(\\r)");
+			fprintf(stderr, "(\\r)");
 		} else if (c == 0x1b) {
-			printf("(\\e)");
+			fprintf(stderr, "(\\e)");
 		} else {
-			printf("(%02x)", c);
+			fprintf(stderr, "(%02x)", c);
 		}
 	}
-	printf("ESC\\\n");
+	fprintf(stderr, "ESC\\\n");
 }
 
 void

From 06f8cf8ca87a81db15816658c40b2afcd1ad5332 Mon Sep 17 00:00:00 2001
From: "pl@ninthfloor.org" <pl@ninthfloor.org>
Date: Fri, 11 Nov 2016 17:45:46 +0100
Subject: [PATCH 0940/1146] Add tmux capabilities to st.info

---
 st.info | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/st.info b/st.info
index d411be7..13cc8eb 100644
--- a/st.info
+++ b/st.info
@@ -185,7 +185,10 @@ st| simpleterm,
 	tsl=\E]0;,
 	xenl,
 	vpa=\E[%i%p1%dd,
-
+# Tmux unofficial extensions, see TERMINFO EXTENSIONS in tmux(1)
+	Se,
+	Ss,
+	Tc,
 
 st-256color| simpleterm with 256 colors,
 	use=st,

From 3ca7249c8685a9ff2d8ce23273fe0313b5804473 Mon Sep 17 00:00:00 2001
From: "pl@ninthfloor.org" <pl@ninthfloor.org>
Date: Fri, 11 Nov 2016 17:45:45 +0100
Subject: [PATCH 0941/1146] tic -s -> tic -sx (Treat unknown capabilities as
 user-defined.)

---
 FAQ      | 2 +-
 Makefile | 2 +-
 README   | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/FAQ b/FAQ
index 3502c60..4defff9 100644
--- a/FAQ
+++ b/FAQ
@@ -6,7 +6,7 @@ Use the excellent tool of [utmp](http://git.suckless.org/utmp/) for this task.
 
 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 manualy run `tic -s st.info`.
+you can manualy run `tic -sx st.info`.
 
 ## Nothing works, and nothing is said about an unknown terminal!
 
diff --git a/Makefile b/Makefile
index 6158ab2..fb026c4 100644
--- a/Makefile
+++ b/Makefile
@@ -49,7 +49,7 @@ install: all
 	@sed "s/VERSION/${VERSION}/g" < st.1 > ${DESTDIR}${MANPREFIX}/man1/st.1
 	@chmod 644 ${DESTDIR}${MANPREFIX}/man1/st.1
 	@echo Please see the README file regarding the terminfo entry of st.
-	@tic -s st.info
+	@tic -sx st.info
 
 uninstall:
 	@echo removing executable file from ${DESTDIR}${PREFIX}/bin
diff --git a/README b/README
index b38c88b..6a846ed 100644
--- a/README
+++ b/README
@@ -24,7 +24,7 @@ Running st
 If you did not install st with make clean install, you must compile
 the st terminfo entry with the following command:
 
-    tic -s st.info
+    tic -sx st.info
 
 See the man page for additional details.
 

From 424202798b02554092ba84dd59fb7b79b59b7b75 Mon Sep 17 00:00:00 2001
From: "ian@remmler.org" <ian@remmler.org>
Date: Fri, 11 Nov 2016 17:52:07 +0100
Subject: [PATCH 0942/1146] Initial font size issue.

Hi,

When I specify a font by point size (I'm using "Inconsolata:size=12"),
characters that are substituted from another font because they are not in the
main one appear too small.  Doing a zoom reset fixes it.  For example:

Before: http://i.imgur.com/G4Mfv4X.png
After:  http://i.imgur.com/PMDhfQA.png

I found that adding the pixel size (acquired from the initial font load) to the
pattern then reloading the font fixes the problem.  I'm not sure if this is a
proper fix, though.
---
 st.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.c b/st.c
index 0980082..e50e884 100644
--- a/st.c
+++ b/st.c
@@ -3472,6 +3472,9 @@ xloadfonts(char *fontstr, double fontsize)
 	if (usedfontsize < 0) {
 		FcPatternGetDouble(dc.font.match->pattern,
 		                   FC_PIXEL_SIZE, 0, &fontval);
+		FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval);
+		if (xloadfont(&dc.font, pattern))
+			die("st: can't open font %s\n", fontstr);
 		usedfontsize = fontval;
 		if (fontsize == 0)
 			defaultfontsize = fontval;

From 740ada1447a0bf9eb7db327d9433fa0b96e0a4d8 Mon Sep 17 00:00:00 2001
From: Manuel Tobias Schiller <mala@hinterbergen.de>
Date: Mon, 14 Nov 2016 18:25:51 +0100
Subject: [PATCH 0943/1146] make the various combinations of arrow keys and
 shift/control/meta work

When using st with screen, I've bound next, prev, new screen to
combinations like Ctrl-Alt-Right,Left,Down; xterm and (u)rxvt work fine
when this combination of modifiers is pressed, st does not seem to
transport all of them; a single modifier key is fine (e.g. Ctrl-Up,
Alt-Down etc., but combinations are not). While I'm not terribly
familiar with this, I have tried to hack config.h in a more or less
systematic way to generate the expected sequences.
---
 config.def.h | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index 7f465d1..32d107d 100644
--- a/config.def.h
+++ b/config.def.h
@@ -280,23 +280,39 @@ static Key key[] = {
 	{ XK_KP_8,          XK_ANY_MOD,     "\033Ox",       +2,    0,    0},
 	{ XK_KP_9,          XK_ANY_MOD,     "\033Oy",       +2,    0,    0},
 	{ XK_Up,            ShiftMask,      "\033[1;2A",     0,    0,    0},
-	{ XK_Up,            ControlMask,    "\033[1;5A",     0,    0,    0},
 	{ XK_Up,            Mod1Mask,       "\033[1;3A",     0,    0,    0},
+	{ XK_Up,         ShiftMask|Mod1Mask,"\033[1;4A",     0,    0,    0},
+	{ XK_Up,            ControlMask,    "\033[1;5A",     0,    0,    0},
+	{ XK_Up,      ShiftMask|ControlMask,"\033[1;6A",     0,    0,    0},
+	{ XK_Up,       ControlMask|Mod1Mask,"\033[1;7A",     0,    0,    0},
+	{ XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A",  0,    0,    0},
 	{ XK_Up,            XK_ANY_MOD,     "\033[A",        0,   -1,    0},
 	{ XK_Up,            XK_ANY_MOD,     "\033OA",        0,   +1,    0},
 	{ XK_Down,          ShiftMask,      "\033[1;2B",     0,    0,    0},
-	{ XK_Down,          ControlMask,    "\033[1;5B",     0,    0,    0},
 	{ XK_Down,          Mod1Mask,       "\033[1;3B",     0,    0,    0},
+	{ XK_Down,       ShiftMask|Mod1Mask,"\033[1;4B",     0,    0,    0},
+	{ XK_Down,          ControlMask,    "\033[1;5B",     0,    0,    0},
+	{ XK_Down,    ShiftMask|ControlMask,"\033[1;6B",     0,    0,    0},
+	{ XK_Down,     ControlMask|Mod1Mask,"\033[1;7B",     0,    0,    0},
+	{ XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0,    0,    0},
 	{ XK_Down,          XK_ANY_MOD,     "\033[B",        0,   -1,    0},
 	{ XK_Down,          XK_ANY_MOD,     "\033OB",        0,   +1,    0},
 	{ XK_Left,          ShiftMask,      "\033[1;2D",     0,    0,    0},
-	{ XK_Left,          ControlMask,    "\033[1;5D",     0,    0,    0},
 	{ XK_Left,          Mod1Mask,       "\033[1;3D",     0,    0,    0},
+	{ XK_Left,       ShiftMask|Mod1Mask,"\033[1;4D",     0,    0,    0},
+	{ XK_Left,          ControlMask,    "\033[1;5D",     0,    0,    0},
+	{ XK_Left,    ShiftMask|ControlMask,"\033[1;6D",     0,    0,    0},
+	{ XK_Left,     ControlMask|Mod1Mask,"\033[1;7D",     0,    0,    0},
+	{ XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0,    0,    0},
 	{ XK_Left,          XK_ANY_MOD,     "\033[D",        0,   -1,    0},
 	{ XK_Left,          XK_ANY_MOD,     "\033OD",        0,   +1,    0},
 	{ XK_Right,         ShiftMask,      "\033[1;2C",     0,    0,    0},
-	{ XK_Right,         ControlMask,    "\033[1;5C",     0,    0,    0},
 	{ XK_Right,         Mod1Mask,       "\033[1;3C",     0,    0,    0},
+	{ XK_Right,      ShiftMask|Mod1Mask,"\033[1;4C",     0,    0,    0},
+	{ XK_Right,         ControlMask,    "\033[1;5C",     0,    0,    0},
+	{ XK_Right,   ShiftMask|ControlMask,"\033[1;6C",     0,    0,    0},
+	{ XK_Right,    ControlMask|Mod1Mask,"\033[1;7C",     0,    0,    0},
+	{ XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0,   0,    0},
 	{ XK_Right,         XK_ANY_MOD,     "\033[C",        0,   -1,    0},
 	{ XK_Right,         XK_ANY_MOD,     "\033OC",        0,   +1,    0},
 	{ XK_ISO_Left_Tab,  ShiftMask,      "\033[Z",        0,    0,    0},

From fa9a4599720703932d1c4f16b9aeee1f91f96263 Mon Sep 17 00:00:00 2001
From: Spencer Phippen <spencer.phippen@gmail.com>
Date: Wed, 23 Nov 2016 19:17:59 +0100
Subject: [PATCH 0944/1146] Fixed 'missing glyph doesn't use fontconfig config
 substitutions' bug

XftFontMatch does display-specific font configuration (commit 528241a).
Nice. Unfortunately, when we switched from FcFontMatch, we also stopped
storing the post-Fc{Config,Default}Substitute FcPattern for future
lookups. The result is that if a glyph isn't found in the primary font,
secondary font lookups use the original FcPattern, not the configured
one. If you have custom fontconfig rules (like me), this can be
disappointing.

I basically just copied the guts out of XftFontMatch[1] and saved
the intermediate configured FcPattern. Could be related to the bug that
inspired commit 4242027.

[1]: https://cgit.freedesktop.org/xorg/lib/libXft/tree/src/xftfont.c
---
 st.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index e50e884..031272f 100644
--- a/st.c
+++ b/st.c
@@ -3373,16 +3373,32 @@ xgeommasktogravity(int mask)
 int
 xloadfont(Font *f, FcPattern *pattern)
 {
+	FcPattern *configured;
 	FcPattern *match;
 	FcResult result;
 	XGlyphInfo extents;
 	int wantattr, haveattr;
 
-	match = XftFontMatch(xw.dpy, xw.scr, pattern, &result);
-	if (!match)
+	/*
+	 * 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;
 	}
@@ -3414,7 +3430,7 @@ xloadfont(Font *f, FcPattern *pattern)
 		strlen(ascii_printable), &extents);
 
 	f->set = NULL;
-	f->pattern = FcPatternDuplicate(pattern);
+	f->pattern = configured;
 
 	f->ascent = f->match->ascent;
 	f->descent = f->match->descent;

From e44832408bb3147826c346872b49de105a4d0e0b Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Thu, 24 Nov 2016 20:21:19 +0100
Subject: [PATCH 0945/1146] Revert "Initial font size issue."

This reverts commit 424202798b02554092ba84dd59fb7b79b59b7b75.
---
 st.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/st.c b/st.c
index 031272f..d6fe58a 100644
--- a/st.c
+++ b/st.c
@@ -3488,9 +3488,6 @@ xloadfonts(char *fontstr, double fontsize)
 	if (usedfontsize < 0) {
 		FcPatternGetDouble(dc.font.match->pattern,
 		                   FC_PIXEL_SIZE, 0, &fontval);
-		FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval);
-		if (xloadfont(&dc.font, pattern))
-			die("st: can't open font %s\n", fontstr);
 		usedfontsize = fontval;
 		if (fontsize == 0)
 			defaultfontsize = fontval;

From c63a87cd936c1eeef14c4c21572e5b782d3df4bc Mon Sep 17 00:00:00 2001
From: fpqc <harry.gindi@live.com>
Date: Wed, 14 Dec 2016 06:51:27 +0000
Subject: [PATCH 0946/1146] Move column and row default numbers into config.h

---
 config.def.h | 7 +++++++
 st.c         | 2 --
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/config.def.h b/config.def.h
index 32d107d..a719e36 100644
--- a/config.def.h
+++ b/config.def.h
@@ -130,6 +130,13 @@ static unsigned int defaultrcs = 257;
  */
 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
  */
diff --git a/st.c b/st.c
index d6fe58a..fbcd9e0 100644
--- a/st.c
+++ b/st.c
@@ -4471,8 +4471,6 @@ usage(void)
 int
 main(int argc, char *argv[])
 {
-	uint cols = 80, rows = 24;
-
 	xw.l = xw.t = 0;
 	xw.isfixed = False;
 	xw.cursor = cursorshape;

From e2ee5ee6114eb74bb08cb9abe5a3020203e92688 Mon Sep 17 00:00:00 2001
From: Michael Forney <mforney@mforney.org>
Date: Fri, 20 Jan 2017 00:06:39 -0800
Subject: [PATCH 0947/1146] Split X-specific code into x.c

---
 Makefile     |    5 +-
 config.def.h |   64 +-
 st.c         | 2024 ++------------------------------------------------
 st.h         |  272 +++++++
 win.h        |   29 +
 x.c          | 1766 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 2167 insertions(+), 1993 deletions(-)
 create mode 100644 st.h
 create mode 100644 win.h
 create mode 100644 x.c

diff --git a/Makefile b/Makefile
index fb026c4..d8595fe 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 
 include config.mk
 
-SRC = st.c
+SRC = st.c x.c
 OBJ = ${SRC:.c=.o}
 
 all: options st
@@ -21,6 +21,9 @@ config.h:
 	@echo CC $<
 	@${CC} -c ${CFLAGS} $<
 
+st.o: config.h st.h win.h
+x.o: arg.h st.h win.h
+
 ${OBJ}: config.h config.mk
 
 st: ${OBJ}
diff --git a/config.def.h b/config.def.h
index a719e36..fd80923 100644
--- a/config.def.h
+++ b/config.def.h
@@ -5,8 +5,8 @@
  *
  * 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;
+char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
+int borderpx = 2;
 
 /*
  * What program is execed by st depends of these precedence rules:
@@ -24,8 +24,8 @@ static char stty_args[] = "stty raw pass8 nl -echo -iexten -cstopb 38400";
 static char vtiden[] = "\033[?6c";
 
 /* Kerning / character bounding-box multipliers */
-static float cwscale = 1.0;
-static float chscale = 1.0;
+float cwscale = 1.0;
+float chscale = 1.0;
 
 /*
  * word delimiter string
@@ -35,26 +35,26 @@ static float chscale = 1.0;
 static char worddelimiters[] = " ";
 
 /* selection timeouts (in milliseconds) */
-static unsigned int doubleclicktimeout = 300;
-static unsigned int tripleclicktimeout = 600;
+unsigned int doubleclicktimeout = 300;
+unsigned int tripleclicktimeout = 600;
 
 /* alt screens */
-static int allowaltscreen = 1;
+int allowaltscreen = 1;
 
 /* frames per second st should at maximum draw to the screen */
-static unsigned int xfps = 120;
-static unsigned int actionfps = 30;
+unsigned int xfps = 120;
+unsigned int actionfps = 30;
 
 /*
  * blinking timeout (set to 0 to disable blinking) for the terminal blinking
  * attribute.
  */
-static unsigned int blinktimeout = 800;
+unsigned int blinktimeout = 800;
 
 /*
  * thickness of underline and bar cursors
  */
-static unsigned int cursorthickness = 2;
+unsigned int cursorthickness = 2;
 
 /*
  * bell volume. It must be a value between -100 and 100. Use 0 for disabling
@@ -63,7 +63,7 @@ static unsigned int cursorthickness = 2;
 static int bellvolume = 0;
 
 /* default TERM value */
-static char termname[] = "st-256color";
+char termname[] = "st-256color";
 
 /*
  * spaces per tab
@@ -83,7 +83,7 @@ static char termname[] = "st-256color";
 static unsigned int tabspaces = 8;
 
 /* Terminal colors (16 first used in escape sequence) */
-static const char *colorname[] = {
+const char *colorname[] = {
 	/* 8 normal colors */
 	"black",
 	"red3",
@@ -116,10 +116,10 @@ static const char *colorname[] = {
  * Default colors (colorname index)
  * foreground, background, cursor, reverse cursor
  */
-static unsigned int defaultfg = 7;
-static unsigned int defaultbg = 0;
-static unsigned int defaultcs = 256;
-static unsigned int defaultrcs = 257;
+unsigned int defaultfg = 7;
+unsigned int defaultbg = 0;
+unsigned int defaultcs = 256;
+unsigned int defaultrcs = 257;
 
 /*
  * Default shape of cursor
@@ -128,33 +128,33 @@ static unsigned int defaultrcs = 257;
  * 6: Bar ("|")
  * 7: Snowman ("☃")
  */
-static unsigned int cursorshape = 2;
+unsigned int cursorshape = 2;
 
 /*
  * Default columns and rows numbers
  */
 
-static unsigned int cols = 80;
-static unsigned int rows = 24;
+unsigned int cols = 80;
+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;
+unsigned int mouseshape = XC_xterm;
+unsigned int mousefg = 7;
+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;
+unsigned int defaultattr = 11;
 
 /*
  * Internal mouse shortcuts.
  * Beware that overloading Button1 will disable the selection.
  */
-static MouseShortcut mshortcuts[] = {
+MouseShortcut mshortcuts[] = {
 	/* button               mask            string */
 	{ Button4,              XK_ANY_MOD,     "\031" },
 	{ Button5,              XK_ANY_MOD,     "\005" },
@@ -163,15 +163,15 @@ static MouseShortcut mshortcuts[] = {
 /* Internal keyboard shortcuts. */
 #define MODKEY Mod1Mask
 
-static Shortcut shortcuts[] = {
+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} },
-	{ MODKEY|ShiftMask,     XK_Prior,       xzoom,          {.f = +1} },
-	{ MODKEY|ShiftMask,     XK_Next,        xzoom,          {.f = -1} },
-	{ MODKEY|ShiftMask,     XK_Home,        xzoomreset,     {.f =  0} },
+	{ MODKEY|ShiftMask,     XK_Prior,       zoom,           {.f = +1} },
+	{ MODKEY|ShiftMask,     XK_Next,        zoom,           {.f = -1} },
+	{ MODKEY|ShiftMask,     XK_Home,        zoomreset,      {.f =  0} },
 	{ ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
 	{ MODKEY|ShiftMask,     XK_Insert,      clippaste,      {.i =  0} },
 	{ MODKEY|ShiftMask,     XK_C,           clipcopy,       {.i =  0} },
@@ -222,7 +222,7 @@ static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
  * Note that if you want to use ShiftMask with selmasks, set this to an other
  * modifier, set to 0 to not use it.
  */
-static uint forceselmod = ShiftMask;
+uint forceselmod = ShiftMask;
 
 /*
  * This is the huge key array which defines all compatibility to the Linux
@@ -451,7 +451,7 @@ static Key key[] = {
  * ButtonRelease and MotionNotify.
  * If no match is found, regular selection is used.
  */
-static uint selmasks[] = {
+uint selmasks[] = {
 	[SEL_RECTANGULAR] = Mod1Mask,
 };
 
@@ -459,7 +459,7 @@ static uint selmasks[] = {
  * Printable characters in ASCII, used to estimate the advance width
  * of single wide characters.
  */
-static char ascii_printable[] =
+char ascii_printable[] =
 	" !\"#$%&'()*+,-./0123456789:;<=>?"
 	"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
 	"`abcdefghijklmnopqrstuvwxyz{|}~";
diff --git a/st.c b/st.c
index fbcd9e0..1e4196e 100644
--- a/st.c
+++ b/st.c
@@ -21,23 +21,21 @@
 #include <time.h>
 #include <unistd.h>
 #include <libgen.h>
-#include <X11/Xatom.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/cursorfont.h>
-#include <X11/keysym.h>
-#include <X11/Xft/Xft.h>
-#include <X11/XKBlib.h>
 #include <fontconfig/fontconfig.h>
 #include <wchar.h>
 
-#include "arg.h"
+/* X11 */
+#include <X11/cursorfont.h>
+#include <X11/Xft/Xft.h>
 
 char *argv0;
 
 #define Glyph Glyph_
 #define Font Font_
 
+#include "win.h"
+#include "st.h"
+
 #if   defined(__linux)
  #include <pty.h>
 #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
@@ -46,67 +44,24 @@ char *argv0;
  #include <libutil.h>
 #endif
 
-
-/* XEMBED messages */
-#define XEMBED_FOCUS_IN  4
-#define XEMBED_FOCUS_OUT 5
-
 /* 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
-#define XK_ANY_MOD    UINT_MAX
-#define XK_NO_MOD     0
-#define XK_SWITCH_MOD (1<<13)
 
 /* 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 NUMMAXLEN(x)		((int)(sizeof(x) * 2.56 + 0.5) + 1)
 #define DEFAULT(a, b)		(a) = (a) ? (a) : (b)
-#define BETWEEN(x, a, b)	((a) <= (x) && (x) <= (b))
-#define DIVCEIL(n, d)		(((n) + ((d) - 1)) / (d))
 #define ISCONTROLC0(c)		(BETWEEN(c, 0, 0x1f) || (c) == '\177')
 #define ISCONTROLC1(c)		(BETWEEN(c, 0x80, 0x9f))
 #define ISCONTROL(c)		(ISCONTROLC0(c) || ISCONTROLC1(c))
 #define ISDELIM(u)		(utf8strchr(worddelimiters, u) != NULL)
-#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 IS_SET(flag)		((term.mode & (flag)) != 0)
-#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))
-#define TRUERED(x)		(((x) & 0xff0000) >> 8)
-#define TRUEGREEN(x)		(((x) & 0xff00))
-#define TRUEBLUE(x)		(((x) & 0xff) << 8)
 
 /* constants */
 #define ISO14755CMD		"dmenu -w %lu -p codepoint: </dev/null"
 
-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 cursor_movement {
 	CURSOR_SAVE,
 	CURSOR_LOAD
@@ -118,34 +73,6 @@ enum cursor_state {
 	CURSOR_ORIGIN   = 2
 };
 
-enum term_mode {
-	MODE_WRAP        = 1 << 0,
-	MODE_INSERT      = 1 << 1,
-	MODE_APPKEYPAD   = 1 << 2,
-	MODE_ALTSCREEN   = 1 << 3,
-	MODE_CRLF        = 1 << 4,
-	MODE_MOUSEBTN    = 1 << 5,
-	MODE_MOUSEMOTION = 1 << 6,
-	MODE_REVERSE     = 1 << 7,
-	MODE_KBDLOCK     = 1 << 8,
-	MODE_HIDE        = 1 << 9,
-	MODE_ECHO        = 1 << 10,
-	MODE_APPCURSOR   = 1 << 11,
-	MODE_MOUSESGR    = 1 << 12,
-	MODE_8BIT        = 1 << 13,
-	MODE_BLINK       = 1 << 14,
-	MODE_FBLINK      = 1 << 15,
-	MODE_FOCUS       = 1 << 16,
-	MODE_MOUSEX10    = 1 << 17,
-	MODE_MOUSEMANY   = 1 << 18,
-	MODE_BRCKTPASTE  = 1 << 19,
-	MODE_PRINT       = 1 << 20,
-	MODE_UTF8        = 1 << 21,
-	MODE_SIXEL       = 1 << 22,
-	MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
-	                  |MODE_MOUSEMANY,
-};
-
 enum charset {
 	CS_GRAPHIC0,
 	CS_GRAPHIC1,
@@ -167,53 +94,6 @@ enum escape_state {
 	ESC_DCS        =128,
 };
 
-enum window_state {
-	WIN_VISIBLE = 1,
-	WIN_FOCUSED = 2
-};
-
-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;
-
-typedef XftDraw *Draw;
-typedef XftColor Color;
-
-typedef struct {
-	Rune u;           /* character code */
-	ushort mode;      /* attribute flags */
-	uint32_t fg;      /* foreground  */
-	uint32_t bg;      /* background  */
-} Glyph;
-
-typedef Glyph *Line;
-
-typedef struct {
-	Glyph attr; /* current char attributes */
-	int x;
-	int y;
-	char state;
-} TCursor;
-
 /* CSI Escape sequence structs */
 /* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
 typedef struct {
@@ -235,56 +115,6 @@ typedef struct {
 	int narg;              /* nb of args */
 } STREscape;
 
-/* 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 */
-	XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */
-	TCursor c;    /* cursor */
-	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 numlock; /* lock numbers in keyboard */
-	int *tabs;
-} Term;
-
-/* Purely graphic info */
-typedef struct {
-	Display *dpy;
-	Colormap cmap;
-	Window win;
-	Drawable buf;
-	Atom xembed, wmdeletewin, netwmname, netwmpid;
-	XIM xim;
-	XIC xic;
-	Draw draw;
-	Visual *vis;
-	XSetWindowAttributes attrs;
-	int scr;
-	int isfixed; /* is fixed geometry? */
-	int l, t; /* left and top offset */
-	int gm; /* geometry mask */
-	int tw, th; /* tty width and height */
-	int w, h; /* window width and height */
-	int ch; /* char height */
-	int cw; /* char width  */
-	char state; /* focus, redraw, visible */
-	int cursor; /* cursor style */
-} XWindow;
-
-typedef struct {
-	uint b;
-	uint mask;
-	char *s;
-} MouseShortcut;
-
 typedef struct {
 	KeySym k;
 	uint mask;
@@ -295,89 +125,26 @@ typedef struct {
 	signed char crlf;      /* crlf mode          */
 } Key;
 
-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;
-
-	char *primary, *clipboard;
-	Atom xtarget;
-	int alt;
-	struct timespec tclick1;
-	struct timespec tclick2;
-} Selection;
-
-typedef union {
-	int i;
-	uint ui;
-	float f;
-	const void *v;
-} Arg;
-
-typedef struct {
-	uint mod;
-	KeySym keysym;
-	void (*func)(const Arg *);
-	const Arg arg;
-} Shortcut;
-
 /* 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 xzoom(const Arg *);
-static void xzoomabs(const Arg *);
-static void xzoomreset(const Arg *);
+static void zoom(const Arg *);
+static void zoomabs(const Arg *);
+static void zoomreset(const Arg *);
 static void printsel(const Arg *);
 static void printscreen(const Arg *) ;
 static void iso14755(const Arg *);
 static void toggleprinter(const Arg *);
 static void sendbreak(const Arg *);
 
-/* Config.h for applying patches and the configuration. */
+/* config.h for applying patches and the configuration. */
 #include "config.h"
 
-/* Font structure */
-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[MAX(LEN(colorname), 256)];
-	Font font, bfont, ifont, ibfont;
-	GC gc;
-} DC;
-
-static void die(const char *, ...);
-static void draw(void);
-static void redraw(void);
-static void drawregion(int, int, int, int);
 static void execsh(void);
 static void stty(void);
 static void sigchld(int);
-static void run(void);
 
 static void csidump(void);
 static void csihandle(void);
@@ -389,7 +156,6 @@ static void strhandle(void);
 static void strparse(void);
 static void strreset(void);
 
-static int tattrset(int);
 static void tprinter(char *, size_t);
 static void tdumpsel(void);
 static void tdumpline(int);
@@ -403,7 +169,6 @@ static void tinsertblankline(int);
 static int tlinelen(int);
 static void tmoveto(int, int);
 static void tmoveato(int, int);
-static void tnew(int, int);
 static void tnewline(int);
 static void tputtab(int);
 static void tputc(Rune);
@@ -415,8 +180,6 @@ static void tsetattr(int *, int);
 static void tsetchar(Rune, Glyph *, int, int);
 static void tsetscroll(int, int);
 static void tswapscreen(void);
-static void tsetdirt(int, int);
-static void tsetdirtattr(int);
 static void tsetmode(int, int, int *, int);
 static void tfulldirt(void);
 static void techo(Rune);
@@ -425,151 +188,53 @@ static void tdectest(char );
 static void tdefutf8(char);
 static int32_t tdefcolor(int *, int *, int);
 static void tdeftran(char);
-static inline int match(uint, uint);
-static void ttynew(void);
-static size_t ttyread(void);
-static void ttyresize(void);
-static void ttysend(char *, size_t);
-static void ttywrite(const char *, size_t);
 static void tstrsequence(uchar);
 
-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 xhints(void);
-static void xclear(int, int, int, int);
-static void xdrawcursor(void);
-static void xinit(void);
-static void xloadcols(void);
-static int xsetcolorname(int, const char *);
-static int xgeommasktogravity(int);
-static int xloadfont(Font *, FcPattern *);
-static void xloadfonts(char *, double);
-static void xsettitle(char *);
-static void xresettitle(void);
-static void xsetpointermotion(int);
-static void xseturgency(int);
-static void xsetsel(char *, Time);
-static void xunloadfont(Font *);
-static void xunloadfonts(void);
-static void xresize(int, int);
-
-static void expose(XEvent *);
-static void visibility(XEvent *);
-static void unmap(XEvent *);
-static char *kmap(KeySym, uint);
-static void kpress(XEvent *);
-static void cmessage(XEvent *);
-static void cresize(int, int);
-static void resize(XEvent *);
-static void focus(XEvent *);
-static void brelease(XEvent *);
-static void bpress(XEvent *);
-static void bmotion(XEvent *);
-static void propnotify(XEvent *);
-static void selnotify(XEvent *);
-static void selclear(XEvent *);
-static void selrequest(XEvent *);
-
-static void selinit(void);
-static void selnormalize(void);
-static inline int selected(int, int);
-static char *getsel(void);
-static void selcopy(Time);
 static void selscroll(int, int);
 static void selsnap(int *, int *, int);
-static int x2col(int);
-static int y2row(int);
-static void getbuttoninfo(XEvent *);
-static void mousereport(XEvent *);
 
-static size_t utf8decode(char *, Rune *, size_t);
 static Rune utf8decodebyte(char, size_t *);
-static size_t utf8encode(Rune, char *);
 static char utf8encodebyte(Rune, size_t);
 static char *utf8strchr(char *s, Rune u);
 static size_t utf8validate(Rune *, size_t);
 
 static ssize_t xwrite(int, const char *, size_t);
-static void *xmalloc(size_t);
 static void *xrealloc(void *, size_t);
-static char *xstrdup(char *);
-
-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 Term term;
+TermWindow win;
+Term term;
+Selection sel;
+int cmdfd;
+pid_t pid;
+char **opt_cmd  = NULL;
+char *opt_class = NULL;
+char *opt_embed = NULL;
+char *opt_font  = NULL;
+char *opt_io    = NULL;
+char *opt_line  = NULL;
+char *opt_name  = NULL;
+char *opt_title = NULL;
+int oldbutton   = 3; /* button event on startup: 3 = release */
+
 static CSIEscape csiescseq;
 static STREscape strescseq;
-static int cmdfd;
-static pid_t pid;
-static Selection sel;
 static int iofd = 1;
-static char **opt_cmd  = NULL;
-static char *opt_class = NULL;
-static char *opt_embed = NULL;
-static char *opt_font  = NULL;
-static char *opt_io    = NULL;
-static char *opt_line  = NULL;
-static char *opt_name  = NULL;
-static char *opt_title = NULL;
-static int oldbutton   = 3; /* button event on startup: 3 = release */
 
-static char *usedfont = NULL;
-static double usedfontsize = 0;
-static double defaultfontsize = 0;
+char *usedfont = NULL;
+double usedfontsize = 0;
+double defaultfontsize = 0;
 
 static uchar utfbyte[UTF_SIZ + 1] = {0x80,    0, 0xC0, 0xE0, 0xF0};
 static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
 static Rune utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  0x10000};
 static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
 
-/* Font Ring Cache */
-enum {
-	FRC_NORMAL,
-	FRC_ITALIC,
-	FRC_BOLD,
-	FRC_ITALICBOLD
-};
-
-typedef struct {
-	XftFont *font;
-	int flags;
-	Rune unicodep;
-} Fontcache;
-
-/* Fontcache is an array now. A new font will be appended to the array. */
-static Fontcache frc[16];
-static int frclen = 0;
+/* config.h array lengths */
+size_t colornamelen = LEN(colorname);
+size_t mshortcutslen = LEN(mshortcuts);
+size_t shortcutslen = LEN(shortcuts);
+size_t selmaskslen = LEN(selmasks);
 
 ssize_t
 xwrite(int fd, const char *s, size_t len)
@@ -714,16 +379,13 @@ selinit(void)
 	sel.ob.x = -1;
 	sel.primary = NULL;
 	sel.clipboard = NULL;
-	sel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
-	if (sel.xtarget == None)
-		sel.xtarget = XA_STRING;
 }
 
 int
 x2col(int x)
 {
 	x -= borderpx;
-	x /= xw.cw;
+	x /= win.cw;
 
 	return LIMIT(x, 0, term.col-1);
 }
@@ -732,7 +394,7 @@ int
 y2row(int y)
 {
 	y -= borderpx;
-	y /= xw.ch;
+	y /= win.ch;
 
 	return LIMIT(y, 0, term.row-1);
 }
@@ -867,141 +529,6 @@ selsnap(int *x, int *y, int direction)
 	}
 }
 
-void
-getbuttoninfo(XEvent *e)
-{
-	int type;
-	uint state = e->xbutton.state & ~(Button1Mask | forceselmod);
-
-	sel.alt = IS_SET(MODE_ALTSCREEN);
-
-	sel.oe.x = x2col(e->xbutton.x);
-	sel.oe.y = y2row(e->xbutton.y);
-	selnormalize();
-
-	sel.type = SEL_REGULAR;
-	for (type = 1; type < LEN(selmasks); ++type) {
-		if (match(selmasks[type], state)) {
-			sel.type = type;
-			break;
-		}
-	}
-}
-
-void
-mousereport(XEvent *e)
-{
-	int x = x2col(e->xbutton.x), y = y2row(e->xbutton.y),
-	    button = e->xbutton.button, state = e->xbutton.state,
-	    len;
-	char buf[40];
-	static int ox, oy;
-
-	/* from urxvt */
-	if (e->xbutton.type == MotionNotify) {
-		if (x == ox && y == oy)
-			return;
-		if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
-			return;
-		/* MOUSE_MOTION: no reporting if no button is pressed */
-		if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
-			return;
-
-		button = oldbutton + 32;
-		ox = x;
-		oy = y;
-	} else {
-		if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
-			button = 3;
-		} else {
-			button -= Button1;
-			if (button >= 3)
-				button += 64 - 3;
-		}
-		if (e->xbutton.type == ButtonPress) {
-			oldbutton = button;
-			ox = x;
-			oy = y;
-		} else if (e->xbutton.type == ButtonRelease) {
-			oldbutton = 3;
-			/* MODE_MOUSEX10: no button release reporting */
-			if (IS_SET(MODE_MOUSEX10))
-				return;
-			if (button == 64 || button == 65)
-				return;
-		}
-	}
-
-	if (!IS_SET(MODE_MOUSEX10)) {
-		button += ((state & ShiftMask  ) ? 4  : 0)
-			+ ((state & Mod4Mask   ) ? 8  : 0)
-			+ ((state & ControlMask) ? 16 : 0);
-	}
-
-	if (IS_SET(MODE_MOUSESGR)) {
-		len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
-				button, x+1, y+1,
-				e->xbutton.type == ButtonRelease ? 'm' : 'M');
-	} else if (x < 223 && y < 223) {
-		len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
-				32+button, 32+x+1, 32+y+1);
-	} else {
-		return;
-	}
-
-	ttywrite(buf, len);
-}
-
-void
-bpress(XEvent *e)
-{
-	struct timespec now;
-	MouseShortcut *ms;
-
-	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
-		mousereport(e);
-		return;
-	}
-
-	for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
-		if (e->xbutton.button == ms->b
-				&& match(ms->mask, e->xbutton.state)) {
-			ttysend(ms->s, strlen(ms->s));
-			return;
-		}
-	}
-
-	if (e->xbutton.button == Button1) {
-		clock_gettime(CLOCK_MONOTONIC, &now);
-
-		/* Clear previous selection, logically and visually. */
-		selclear(NULL);
-		sel.mode = SEL_EMPTY;
-		sel.type = SEL_REGULAR;
-		sel.oe.x = sel.ob.x = x2col(e->xbutton.x);
-		sel.oe.y = sel.ob.y = y2row(e->xbutton.y);
-
-		/*
-		 * If the user clicks below predefined timeouts specific
-		 * snapping behaviour is exposed.
-		 */
-		if (TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) {
-			sel.snap = SNAP_LINE;
-		} else if (TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) {
-			sel.snap = SNAP_WORD;
-		} else {
-			sel.snap = 0;
-		}
-		selnormalize();
-
-		if (sel.snap != 0)
-			sel.mode = SEL_READY;
-		tsetdirt(sel.nb.y, sel.ne.y);
-		sel.tclick2 = sel.tclick1;
-		sel.tclick1 = now;
-	}
-}
-
 char *
 getsel(void)
 {
@@ -1056,149 +583,26 @@ getsel(void)
 	return str;
 }
 
-void
-selcopy(Time t)
-{
-	xsetsel(getsel(), t);
-}
-
-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;
-
-	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;
-	} else {
-		return;
-	}
-	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);
-		ttysend((char *)data, nitems * format / 8);
-		if (IS_SET(MODE_BRCKTPASTE) && rem == 0)
-			ttywrite("\033[201~", 6);
-		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
 selpaste(const Arg *dummy)
 {
-	XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY,
-			xw.win, CurrentTime);
+	xselpaste();
 }
 
 void
 clipcopy(const Arg *dummy)
 {
-	Atom clipboard;
-
-	if (sel.clipboard != NULL)
-		free(sel.clipboard);
-
-	if (sel.primary != NULL) {
-		sel.clipboard = xstrdup(sel.primary);
-		clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
-		XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
-	}
+	xclipcopy();
 }
 
 void
 clippaste(const Arg *dummy)
 {
-	Atom clipboard;
-
-	clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
-	XConvertSelection(xw.dpy, clipboard, sel.xtarget, clipboard,
-			xw.win, CurrentTime);
+	xclippaste();
 }
 
 void
-selclear(XEvent *e)
+selclear(void)
 {
 	if (sel.ob.x == -1)
 		return;
@@ -1207,120 +611,6 @@ selclear(XEvent *e)
 	tsetdirt(sel.nb.y, sel.ne.y);
 }
 
-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 = sel.xtarget;
-		XChangeProperty(xsre->display, xsre->requestor, xsre->property,
-				XA_ATOM, 32, PropModeReplace,
-				(uchar *) &string, 1);
-		xev.property = xsre->property;
-	} else if (xsre->target == sel.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 = sel.primary;
-		} else if (xsre->selection == clipboard) {
-			seltext = sel.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
-xsetsel(char *str, Time t)
-{
-	free(sel.primary);
-	sel.primary = str;
-
-	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
-	if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
-		selclear(0);
-}
-
-void
-brelease(XEvent *e)
-{
-	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
-		mousereport(e);
-		return;
-	}
-
-	if (e->xbutton.button == Button2) {
-		selpaste(NULL);
-	} else if (e->xbutton.button == Button1) {
-		if (sel.mode == SEL_READY) {
-			getbuttoninfo(e);
-			selcopy(e->xbutton.time);
-		} else
-			selclear(NULL);
-		sel.mode = SEL_IDLE;
-		tsetdirt(sel.nb.y, sel.ne.y);
-	}
-}
-
-void
-bmotion(XEvent *e)
-{
-	int oldey, oldex, oldsby, oldsey;
-
-	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
-		mousereport(e);
-		return;
-	}
-
-	if (!sel.mode)
-		return;
-
-	sel.mode = SEL_READY;
-	oldey = sel.oe.y;
-	oldex = sel.oe.x;
-	oldsby = sel.nb.y;
-	oldsey = sel.ne.y;
-	getbuttoninfo(e);
-
-	if (oldey != sel.oe.y || oldex != sel.oe.x)
-		tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
-}
-
 void
 die(const char *errstr, ...)
 {
@@ -1337,7 +627,6 @@ execsh(void)
 {
 	char **args, *sh, *prog;
 	const struct passwd *pw;
-	char buf[sizeof(long) * 8 + 1];
 
 	errno = 0;
 	if ((pw = getpwuid(getuid())) == NULL) {
@@ -1358,8 +647,6 @@ execsh(void)
 		prog = sh;
 	args = (opt_cmd) ? opt_cmd : (char *[]) {prog, NULL};
 
-	snprintf(buf, sizeof(buf), "%lu", xw.win);
-
 	unsetenv("COLUMNS");
 	unsetenv("LINES");
 	unsetenv("TERMCAP");
@@ -1368,7 +655,7 @@ execsh(void)
 	setenv("SHELL", sh, 1);
 	setenv("HOME", pw->pw_dir, 1);
 	setenv("TERM", termname, 1);
-	setenv("WINDOWID", buf, 1);
+	xsetenv();
 
 	signal(SIGCHLD, SIG_DFL);
 	signal(SIGHUP, SIG_DFL);
@@ -1606,8 +893,8 @@ ttyresize(void)
 
 	w.ws_row = term.row;
 	w.ws_col = term.col;
-	w.ws_xpixel = xw.tw;
-	w.ws_ypixel = xw.th;
+	w.ws_xpixel = win.tw;
+	w.ws_ypixel = win.th;
 	if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
 		fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno));
 }
@@ -1771,7 +1058,7 @@ selscroll(int orig, int n)
 
 	if (BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig, term.bot)) {
 		if ((sel.ob.y += n) > term.bot || (sel.oe.y += n) < term.top) {
-			selclear(NULL);
+			selclear();
 			return;
 		}
 		if (sel.type == SEL_RECTANGULAR) {
@@ -1917,7 +1204,7 @@ tclearregion(int x1, int y1, int x2, int y2)
 		for (x = x1; x <= x2; x++) {
 			gp = &term.line[y][x];
 			if (selected(x, y))
-				selclear(NULL);
+				selclear();
 			gp->fg = term.c.attr.fg;
 			gp->bg = term.c.attr.bg;
 			gp->mode = 0;
@@ -2368,7 +1655,7 @@ csihandle(void)
 		tputtab(csiescseq.arg[0]);
 		break;
 	case 'J': /* ED -- Clear screen */
-		selclear(NULL);
+		selclear();
 		switch (csiescseq.arg[0]) {
 		case 0: /* below */
 			tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
@@ -2475,7 +1762,7 @@ csihandle(void)
 			if (!BETWEEN(csiescseq.arg[0], 0, 6)) {
 				goto unknown;
 			}
-			xw.cursor = csiescseq.arg[0];
+			win.cursor = csiescseq.arg[0];
 			break;
 		default:
 			goto unknown;
@@ -2642,12 +1929,13 @@ tprinter(char *s, size_t len)
 void
 iso14755(const Arg *arg)
 {
-	char cmd[sizeof(ISO14755CMD) + NUMMAXLEN(xw.win)];
+	unsigned long id = xwinid();
+	char cmd[sizeof(ISO14755CMD) + NUMMAXLEN(id)];
 	FILE *p;
 	char *us, *e, codepoint[9], uc[UTF_SIZ];
 	unsigned long utf32;
 
-	snprintf(cmd, sizeof(cmd), ISO14755CMD, xw.win);
+	snprintf(cmd, sizeof(cmd), ISO14755CMD, id);
 	if (!(p = popen(cmd, "r")))
 		return;
 
@@ -2833,10 +2121,10 @@ tcontrolcode(uchar ascii)
 			/* backwards compatibility to xterm */
 			strhandle();
 		} else {
-			if (!(xw.state & WIN_FOCUSED))
+			if (!(win.state & WIN_FOCUSED))
 				xseturgency(1);
 			if (bellvolume)
-				XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL);
+				xbell(bellvolume);
 		}
 		break;
 	case '\033': /* ESC */
@@ -2968,7 +2256,7 @@ eschandle(uchar ascii)
 		break;
 	case 'c': /* RIS -- Reset to inital state */
 		treset();
-		xresettitle();
+		resettitle();
 		xloadcols();
 		break;
 	case '=': /* DECPAM -- Application keypad */
@@ -3109,7 +2397,7 @@ check_control_code:
 		return;
 	}
 	if (sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
-		selclear(NULL);
+		selclear();
 
 	gp = &term.line[term.c.y][term.c.x];
 	if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
@@ -3177,7 +2465,7 @@ tresize(int col, int row)
 	}
 
 	/* resize to new width */
-	term.specbuf = xrealloc(term.specbuf, col * sizeof(XftGlyphFontSpec));
+	term.specbuf = xrealloc(term.specbuf, col * sizeof(GlyphFontSpec));
 
 	/* resize to new height */
 	term.line = xrealloc(term.line, row * sizeof(Line));
@@ -3228,326 +2516,16 @@ tresize(int col, int row)
 }
 
 void
-xresize(int col, int row)
-{
-	xw.tw = MAX(1, col * xw.cw);
-	xw.th = MAX(1, row * xw.ch);
-
-	XFreePixmap(xw.dpy, xw.buf);
-	xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
-			DefaultDepth(xw.dpy, xw.scr));
-	XftDrawChange(xw.draw, xw.buf);
-	xclear(0, 0, xw.w, xw.h);
-}
-
-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[LEN(dc.col)]; ++cp)
-			XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
-	}
-
-	for (i = 0; i < LEN(dc.col); i++)
-		if (!xloadcolor(i, NULL, &dc.col[i])) {
-			if (colorname[i])
-				die("Could not allocate color '%s'\n", colorname[i]);
-			else
-				die("Could not allocate color %d\n", i);
-		}
-	loaded = 1;
-}
-
-int
-xsetcolorname(int x, const char *name)
-{
-	Color ncolor;
-
-	if (!BETWEEN(x, 0, LEN(dc.col)))
-		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 = NULL;
-
-	sizeh = XAllocSizeHints();
-
-	sizeh->flags = PSize | PResizeInc | PBaseSize;
-	sizeh->height = xw.h;
-	sizeh->width = xw.w;
-	sizeh->height_inc = xw.ch;
-	sizeh->width_inc = xw.cw;
-	sizeh->base_height = 2 * borderpx;
-	sizeh->base_width = 2 * borderpx;
-	if (xw.isfixed) {
-		sizeh->flags |= PMaxSize | PMinSize;
-		sizeh->min_width = sizeh->max_width = xw.w;
-		sizeh->min_height = sizeh->max_height = xw.h;
-	}
-	if (xw.gm & (XValue|YValue)) {
-		sizeh->flags |= USPosition | PWinGravity;
-		sizeh->x = xw.l;
-		sizeh->y = xw.t;
-		sizeh->win_gravity = xgeommasktogravity(xw.gm);
-	}
-
-	XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm,
-			&class);
-	XFree(sizeh);
-}
-
-int
-xgeommasktogravity(int mask)
-{
-	switch (mask & (XNegative|YNegative)) {
-	case 0:
-		return NorthWestGravity;
-	case XNegative:
-		return NorthEastGravity;
-	case YNegative:
-		return SouthWestGravity;
-	}
-
-	return SouthEastGravity;
-}
-
-int
-xloadfont(Font *f, FcPattern *pattern)
-{
-	FcPattern *configured;
-	FcPattern *match;
-	FcResult result;
-	XGlyphInfo extents;
-	int wantattr, haveattr;
-
-	/*
-	 * Manually configure instead of calling XftMatchFont
-	 * so that we can use the configured pattern for
-	 * "missing glyph" lookups.
-	 */
-	configured = FcPatternDuplicate(pattern);
-	if (!configured)
-		return 1;
-
-	FcConfigSubstitute(NULL, configured, FcMatchPattern);
-	XftDefaultSubstitute(xw.dpy, xw.scr, configured);
-
-	match = FcFontMatch(NULL, configured, &result);
-	if (!match) {
-		FcPatternDestroy(configured);
-		return 1;
-	}
-
-	if (!(f->match = XftFontOpenPattern(xw.dpy, match))) {
-		FcPatternDestroy(configured);
-		FcPatternDestroy(match);
-		return 1;
-	}
-
-	if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) ==
-	    XftResultMatch)) {
-		/*
-		 * Check if xft was unable to find a font with the appropriate
-		 * slant but gave us one anyway. Try to mitigate.
-		 */
-		if ((XftPatternGetInteger(f->match->pattern, "slant", 0,
-		    &haveattr) != XftResultMatch) || haveattr < wantattr) {
-			f->badslant = 1;
-			fputs("st: font slant does not match\n", stderr);
-		}
-	}
-
-	if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) ==
-	    XftResultMatch)) {
-		if ((XftPatternGetInteger(f->match->pattern, "weight", 0,
-		    &haveattr) != XftResultMatch) || haveattr != wantattr) {
-			f->badweight = 1;
-			fputs("st: font weight does not match\n", stderr);
-		}
-	}
-
-	XftTextExtentsUtf8(xw.dpy, f->match,
-		(const FcChar8 *) ascii_printable,
-		strlen(ascii_printable), &extents);
-
-	f->set = NULL;
-	f->pattern = configured;
-
-	f->ascent = f->match->ascent;
-	f->descent = f->match->descent;
-	f->lbearing = 0;
-	f->rbearing = f->match->max_advance_width;
-
-	f->height = f->ascent + f->descent;
-	f->width = DIVCEIL(extents.xOff, strlen(ascii_printable));
-
-	return 0;
-}
-
-void
-xloadfonts(char *fontstr, double fontsize)
-{
-	FcPattern *pattern;
-	double fontval;
-	float ceilf(float);
-
-	if (fontstr[0] == '-') {
-		pattern = XftXlfdParse(fontstr, False, False);
-	} else {
-		pattern = FcNameParse((FcChar8 *)fontstr);
-	}
-
-	if (!pattern)
-		die("st: can't open font %s\n", fontstr);
-
-	if (fontsize > 1) {
-		FcPatternDel(pattern, FC_PIXEL_SIZE);
-		FcPatternDel(pattern, FC_SIZE);
-		FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize);
-		usedfontsize = fontsize;
-	} else {
-		if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) ==
-				FcResultMatch) {
-			usedfontsize = fontval;
-		} else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) ==
-				FcResultMatch) {
-			usedfontsize = -1;
-		} else {
-			/*
-			 * Default font size is 12, if none given. This is to
-			 * have a known usedfontsize value.
-			 */
-			FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12);
-			usedfontsize = 12;
-		}
-		defaultfontsize = usedfontsize;
-	}
-
-	if (xloadfont(&dc.font, pattern))
-		die("st: can't open font %s\n", fontstr);
-
-	if (usedfontsize < 0) {
-		FcPatternGetDouble(dc.font.match->pattern,
-		                   FC_PIXEL_SIZE, 0, &fontval);
-		usedfontsize = fontval;
-		if (fontsize == 0)
-			defaultfontsize = fontval;
-	}
-
-	/* Setting character width and height. */
-	xw.cw = ceilf(dc.font.width * cwscale);
-	xw.ch = ceilf(dc.font.height * chscale);
-
-	FcPatternDel(pattern, FC_SLANT);
-	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
-	if (xloadfont(&dc.ifont, pattern))
-		die("st: can't open font %s\n", fontstr);
-
-	FcPatternDel(pattern, FC_WEIGHT);
-	FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
-	if (xloadfont(&dc.ibfont, pattern))
-		die("st: can't open font %s\n", fontstr);
-
-	FcPatternDel(pattern, FC_SLANT);
-	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
-	if (xloadfont(&dc.bfont, pattern))
-		die("st: can't open font %s\n", fontstr);
-
-	FcPatternDestroy(pattern);
-}
-
-void
-xunloadfont(Font *f)
-{
-	XftFontClose(xw.dpy, f->match);
-	FcPatternDestroy(f->pattern);
-	if (f->set)
-		FcFontSetDestroy(f->set);
-}
-
-void
-xunloadfonts(void)
-{
-	/* Free the loaded fonts in the font cache.  */
-	while (frclen > 0)
-		XftFontClose(xw.dpy, frc[--frclen].font);
-
-	xunloadfont(&dc.font);
-	xunloadfont(&dc.bfont);
-	xunloadfont(&dc.ifont);
-	xunloadfont(&dc.ibfont);
-}
-
-void
-xzoom(const Arg *arg)
+zoom(const Arg *arg)
 {
 	Arg larg;
 
 	larg.f = usedfontsize + arg->f;
-	xzoomabs(&larg);
+	zoomabs(&larg);
 }
 
 void
-xzoomabs(const Arg *arg)
+zoomabs(const Arg *arg)
 {
 	xunloadfonts();
 	xloadfonts(usedfont, arg->f);
@@ -3558,520 +2536,18 @@ xzoomabs(const Arg *arg)
 }
 
 void
-xzoomreset(const Arg *arg)
+zoomreset(const Arg *arg)
 {
 	Arg larg;
 
 	if (defaultfontsize > 0) {
 		larg.f = defaultfontsize;
-		xzoomabs(&larg);
+		zoomabs(&larg);
 	}
 }
 
 void
-xinit(void)
-{
-	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 */
-	xw.w = 2 * borderpx + term.col * xw.cw;
-	xw.h = 2 * borderpx + term.row * xw.ch;
-	if (xw.gm & XNegative)
-		xw.l += DisplayWidth(xw.dpy, xw.scr) - xw.w - 2;
-	if (xw.gm & YNegative)
-		xw.t += DisplayHeight(xw.dpy, xw.scr) - xw.h - 2;
-
-	/* Events */
-	xw.attrs.background_pixel = dc.col[defaultbg].pixel;
-	xw.attrs.border_pixel = dc.col[defaultbg].pixel;
-	xw.attrs.bit_gravity = NorthWestGravity;
-	xw.attrs.event_mask = FocusChangeMask | KeyPressMask
-		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
-		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
-	xw.attrs.colormap = xw.cmap;
-
-	if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
-		parent = XRootWindow(xw.dpy, xw.scr);
-	xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
-			xw.w, xw.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, xw.w, xw.h,
-			DefaultDepth(xw.dpy, xw.scr));
-	XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
-	XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
-
-	/* Xft rendering context */
-	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-
-	/* input methods */
-	if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
-		XSetLocaleModifiers("@im=local");
-		if ((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
-			XSetLocaleModifiers("@im=");
-			if ((xw.xim = XOpenIM(xw.dpy,
-					NULL, NULL, NULL)) == NULL) {
-				die("XOpenIM failed. Could not open input"
-					" device.\n");
-			}
-		}
-	}
-	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
-					   | XIMStatusNothing, XNClientWindow, xw.win,
-					   XNFocusWindow, xw.win, NULL);
-	if (xw.xic == NULL)
-		die("XCreateIC failed. Could not obtain input method.\n");
-
-	/* white cursor, black outline */
-	cursor = XCreateFontCursor(xw.dpy, mouseshape);
-	XDefineCursor(xw.dpy, xw.win, cursor);
-
-	if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) {
-		xmousefg.red   = 0xffff;
-		xmousefg.green = 0xffff;
-		xmousefg.blue  = 0xffff;
-	}
-
-	if (XParseColor(xw.dpy, xw.cmap, colorname[mousebg], &xmousebg) == 0) {
-		xmousebg.red   = 0x0000;
-		xmousebg.green = 0x0000;
-		xmousebg.blue  = 0x0000;
-	}
-
-	XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg);
-
-	xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
-	xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
-	xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False);
-	XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
-
-	xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False);
-	XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
-			PropModeReplace, (uchar *)&thispid, 1);
-
-	xresettitle();
-	XMapWindow(xw.dpy, xw.win);
-	xhints();
-	XSync(xw.dpy, False);
-}
-
-int
-xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
-{
-	float winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, xp, yp;
-	ushort mode, prevmode = USHRT_MAX;
-	Font *font = &dc.font;
-	int frcflags = FRC_NORMAL;
-	float runewidth = xw.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 = xw.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f);
-			if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
-				font = &dc.ibfont;
-				frcflags = FRC_ITALICBOLD;
-			} else if (mode & ATTR_ITALIC) {
-				font = &dc.ifont;
-				frcflags = FRC_ITALIC;
-			} else if (mode & ATTR_BOLD) {
-				font = &dc.bfont;
-				frcflags = FRC_BOLD;
-			}
-			yp = winy + font->ascent;
-		}
-
-		/* Lookup character index with default font. */
-		glyphidx = XftCharIndex(xw.dpy, font->match, rune);
-		if (glyphidx) {
-			specs[numspecs].font = font->match;
-			specs[numspecs].glyph = glyphidx;
-			specs[numspecs].x = (short)xp;
-			specs[numspecs].y = (short)yp;
-			xp += runewidth;
-			numspecs++;
-			continue;
-		}
-
-		/* Fallback on font cache, search the font cache for match. */
-		for (f = 0; f < frclen; f++) {
-			glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune);
-			/* Everything correct. */
-			if (glyphidx && frc[f].flags == frcflags)
-				break;
-			/* We got a default font for a not found glyph. */
-			if (!glyphidx && frc[f].flags == frcflags
-					&& frc[f].unicodep == rune) {
-				break;
-			}
-		}
-
-		/* Nothing was found. Use fontconfig to find matching font. */
-		if (f >= frclen) {
-			if (!font->set)
-				font->set = FcFontSort(0, font->pattern,
-				                       1, 0, &fcres);
-			fcsets[0] = font->set;
-
-			/*
-			 * Nothing was found in the cache. Now use
-			 * some dozen of Fontconfig calls to get the
-			 * font for one single character.
-			 *
-			 * Xft and fontconfig are design failures.
-			 */
-			fcpattern = FcPatternDuplicate(font->pattern);
-			fccharset = FcCharSetCreate();
-
-			FcCharSetAddChar(fccharset, rune);
-			FcPatternAddCharSet(fcpattern, FC_CHARSET,
-					fccharset);
-			FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
-
-			FcConfigSubstitute(0, fcpattern,
-					FcMatchPattern);
-			FcDefaultSubstitute(fcpattern);
-
-			fontpattern = FcFontSetMatch(0, fcsets, 1,
-					fcpattern, &fcres);
-
-			/*
-			 * Overwrite or create the new cache entry.
-			 */
-			if (frclen >= LEN(frc)) {
-				frclen = LEN(frc) - 1;
-				XftFontClose(xw.dpy, frc[frclen].font);
-				frc[frclen].unicodep = 0;
-			}
-
-			frc[frclen].font = XftFontOpenPattern(xw.dpy,
-					fontpattern);
-			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 * xw.cw, winy = borderpx + y * xw.ch,
-	    width = charlen * xw.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_REVERSE) {
-		temp = fg;
-		fg = bg;
-		bg = temp;
-	}
-
-	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;
-		XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg);
-		fg = &revfg;
-	}
-
-	if (base.mode & ATTR_BLINK && term.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 + xw.ch + ((y >= term.row-1)? xw.h : 0));
-	}
-	if (x + charlen >= term.col) {
-		xclear(winx + width, (y == 0)? 0 : winy, xw.w,
-			((y >= term.row-1)? xw.h : (winy + xw.ch)));
-	}
-	if (y == 0)
-		xclear(winx, 0, winx + width, borderpx);
-	if (y == term.row-1)
-		xclear(winx, winy + xw.ch, winx + width, xw.h);
-
-	/* Clean up the region we want to draw to. */
-	XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch);
-
-	/* Set the clip region because Xft is sometimes dirty. */
-	r.x = 0;
-	r.y = 0;
-	r.height = xw.ch;
-	r.width = width;
-	XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
-
-	/* Render the glyphs. */
-	XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
-
-	/* Render underline and strikethrough. */
-	if (base.mode & ATTR_UNDERLINE) {
-		XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
-				width, 1);
-	}
-
-	if (base.mode & ATTR_STRUCK) {
-		XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3,
-				width, 1);
-	}
-
-	/* Reset clip to none. */
-	XftDrawSetClip(xw.draw, 0);
-}
-
-void
-xdrawglyph(Glyph g, int x, int y)
-{
-	int numspecs;
-	XftGlyphFontSpec spec;
-
-	numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
-	xdrawglyphfontspecs(&spec, g, numspecs, x, y);
-}
-
-void
-xdrawcursor(void)
-{
-	static int oldx = 0, oldy = 0;
-	int curx;
-	Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og;
-	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
-	Color drawcol;
-
-	LIMIT(oldx, 0, term.col-1);
-	LIMIT(oldy, 0, term.row-1);
-
-	curx = term.c.x;
-
-	/* adjust position if in dummy */
-	if (term.line[oldy][oldx].mode & ATTR_WDUMMY)
-		oldx--;
-	if (term.line[term.c.y][curx].mode & ATTR_WDUMMY)
-		curx--;
-
-	/* remove the old cursor */
-	og = term.line[oldy][oldx];
-	if (ena_sel && selected(oldx, oldy))
-		og.mode ^= ATTR_REVERSE;
-	xdrawglyph(og, oldx, oldy);
-
-	g.u = term.line[term.c.y][term.c.x].u;
-
-	/*
-	 * Select the right color for the right mode.
-	 */
-	if (IS_SET(MODE_REVERSE)) {
-		g.mode |= ATTR_REVERSE;
-		g.bg = defaultfg;
-		if (ena_sel && selected(term.c.x, term.c.y)) {
-			drawcol = dc.col[defaultcs];
-			g.fg = defaultrcs;
-		} else {
-			drawcol = dc.col[defaultrcs];
-			g.fg = defaultcs;
-		}
-	} else {
-		if (ena_sel && selected(term.c.x, term.c.y)) {
-			drawcol = dc.col[defaultrcs];
-			g.fg = defaultfg;
-			g.bg = defaultrcs;
-		} else {
-			drawcol = dc.col[defaultcs];
-		}
-	}
-
-	if (IS_SET(MODE_HIDE))
-		return;
-
-	/* draw the new one */
-	if (xw.state & WIN_FOCUSED) {
-		switch (xw.cursor) {
-		case 7: /* st extension: snowman */
-			utf8decode("☃", &g.u, UTF_SIZ);
-		case 0: /* Blinking Block */
-		case 1: /* Blinking Block (Default) */
-		case 2: /* Steady Block */
-			g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE;
-			xdrawglyph(g, term.c.x, term.c.y);
-			break;
-		case 3: /* Blinking Underline */
-		case 4: /* Steady Underline */
-			XftDrawRect(xw.draw, &drawcol,
-					borderpx + curx * xw.cw,
-					borderpx + (term.c.y + 1) * xw.ch - \
-						cursorthickness,
-					xw.cw, cursorthickness);
-			break;
-		case 5: /* Blinking bar */
-		case 6: /* Steady bar */
-			XftDrawRect(xw.draw, &drawcol,
-					borderpx + curx * xw.cw,
-					borderpx + term.c.y * xw.ch,
-					cursorthickness, xw.ch);
-			break;
-		}
-	} else {
-		XftDrawRect(xw.draw, &drawcol,
-				borderpx + curx * xw.cw,
-				borderpx + term.c.y * xw.ch,
-				xw.cw - 1, 1);
-		XftDrawRect(xw.draw, &drawcol,
-				borderpx + curx * xw.cw,
-				borderpx + term.c.y * xw.ch,
-				1, xw.ch - 1);
-		XftDrawRect(xw.draw, &drawcol,
-				borderpx + (curx + 1) * xw.cw - 1,
-				borderpx + term.c.y * xw.ch,
-				1, xw.ch - 1);
-		XftDrawRect(xw.draw, &drawcol,
-				borderpx + curx * xw.cw,
-				borderpx + (term.c.y + 1) * xw.ch - 1,
-				xw.cw, 1);
-	}
-	oldx = curx, oldy = term.c.y;
-}
-
-
-void
-xsettitle(char *p)
-{
-	XTextProperty prop;
-
-	Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
-			&prop);
-	XSetWMName(xw.dpy, xw.win, &prop);
-	XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
-	XFree(prop.value);
-}
-
-void
-xresettitle(void)
+resettitle(void)
 {
 	xsettitle(opt_title ? opt_title : "st");
 }
@@ -4083,121 +2559,6 @@ redraw(void)
 	draw();
 }
 
-void
-draw(void)
-{
-	drawregion(0, 0, term.col, term.row);
-	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
-			xw.h, 0, 0);
-	XSetForeground(xw.dpy, dc.gc,
-			dc.col[IS_SET(MODE_REVERSE)?
-				defaultfg : defaultbg].pixel);
-}
-
-void
-drawregion(int x1, int y1, int x2, int y2)
-{
-	int i, x, y, ox, numspecs;
-	Glyph base, new;
-	XftGlyphFontSpec *specs;
-	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
-
-	if (!(xw.state & WIN_VISIBLE))
-		return;
-
-	for (y = y1; y < y2; y++) {
-		if (!term.dirty[y])
-			continue;
-
-		term.dirty[y] = 0;
-
-		specs = term.specbuf;
-		numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y);
-
-		i = ox = 0;
-		for (x = x1; x < x2 && i < numspecs; x++) {
-			new = term.line[y][x];
-			if (new.mode == ATTR_WDUMMY)
-				continue;
-			if (ena_sel && selected(x, y))
-				new.mode ^= ATTR_REVERSE;
-			if (i > 0 && ATTRCMP(base, new)) {
-				xdrawglyphfontspecs(specs, base, i, ox, y);
-				specs += i;
-				numspecs -= i;
-				i = 0;
-			}
-			if (i == 0) {
-				ox = x;
-				base = new;
-			}
-			i++;
-		}
-		if (i > 0)
-			xdrawglyphfontspecs(specs, base, i, ox, y);
-	}
-	xdrawcursor();
-}
-
-void
-expose(XEvent *ev)
-{
-	redraw();
-}
-
-void
-visibility(XEvent *ev)
-{
-	XVisibilityEvent *e = &ev->xvisibility;
-
-	MODBIT(xw.state, e->state != VisibilityFullyObscured, WIN_VISIBLE);
-}
-
-void
-unmap(XEvent *ev)
-{
-	xw.state &= ~WIN_VISIBLE;
-}
-
-void
-xsetpointermotion(int set)
-{
-	MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
-	XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
-}
-
-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
-focus(XEvent *ev)
-{
-	XFocusChangeEvent *e = &ev->xfocus;
-
-	if (e->mode == NotifyGrab)
-		return;
-
-	if (ev->type == FocusIn) {
-		XSetICFocus(xw.xic);
-		xw.state |= WIN_FOCUSED;
-		xseturgency(0);
-		if (IS_SET(MODE_FOCUS))
-			ttywrite("\033[I", 3);
-	} else {
-		XUnsetICFocus(xw.xic);
-		xw.state &= ~WIN_FOCUSED;
-		if (IS_SET(MODE_FOCUS))
-			ttywrite("\033[O", 3);
-	}
-}
-
 int
 match(uint mask, uint state)
 {
@@ -4250,211 +2611,23 @@ kmap(KeySym k, uint state)
 	return NULL;
 }
 
-void
-kpress(XEvent *ev)
-{
-	XKeyEvent *e = &ev->xkey;
-	KeySym ksym;
-	char buf[32], *customkey;
-	int len;
-	Rune c;
-	Status status;
-	Shortcut *bp;
-
-	if (IS_SET(MODE_KBDLOCK))
-		return;
-
-	len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
-	/* 1. shortcuts */
-	for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
-		if (ksym == bp->keysym && match(bp->mod, e->state)) {
-			bp->func(&(bp->arg));
-			return;
-		}
-	}
-
-	/* 2. custom keys from config.h */
-	if ((customkey = kmap(ksym, e->state))) {
-		ttysend(customkey, strlen(customkey));
-		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;
-		}
-	}
-	ttysend(buf, len);
-}
-
-
-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) {
-			xw.state |= WIN_FOCUSED;
-			xseturgency(0);
-		} else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
-			xw.state &= ~WIN_FOCUSED;
-		}
-	} else if (e->xclient.data.l[0] == xw.wmdeletewin) {
-		/* Send SIGHUP to shell */
-		kill(pid, SIGHUP);
-		exit(0);
-	}
-}
-
 void
 cresize(int width, int height)
 {
 	int col, row;
 
 	if (width != 0)
-		xw.w = width;
+		win.w = width;
 	if (height != 0)
-		xw.h = height;
+		win.h = height;
 
-	col = (xw.w - 2 * borderpx) / xw.cw;
-	row = (xw.h - 2 * borderpx) / xw.ch;
+	col = (win.w - 2 * borderpx) / win.cw;
+	row = (win.h - 2 * borderpx) / win.ch;
 
 	tresize(col, row);
 	xresize(col, row);
 }
 
-void
-resize(XEvent *e)
-{
-	if (e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
-		return;
-
-	cresize(e->xconfigure.width, e->xconfigure.height);
-	ttyresize();
-}
-
-void
-run(void)
-{
-	XEvent ev;
-	int w = xw.w, h = xw.h;
-	fd_set rfd;
-	int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
-	struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
-	long deltatime;
-
-	/* Waiting for window mapping */
-	do {
-		XNextEvent(xw.dpy, &ev);
-		/*
-		 * This XFilterEvent call is required because of XOpenIM. It
-		 * does filter out the key event and some client message for
-		 * the input method too.
-		 */
-		if (XFilterEvent(&ev, None))
-			continue;
-		if (ev.type == ConfigureNotify) {
-			w = ev.xconfigure.width;
-			h = ev.xconfigure.height;
-		}
-	} while (ev.type != MapNotify);
-
-	cresize(w, h);
-	ttynew();
-	ttyresize();
-
-	clock_gettime(CLOCK_MONOTONIC, &last);
-	lastblink = last;
-
-	for (xev = actionfps;;) {
-		FD_ZERO(&rfd);
-		FD_SET(cmdfd, &rfd);
-		FD_SET(xfd, &rfd);
-
-		if (pselect(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
-			if (errno == EINTR)
-				continue;
-			die("select failed: %s\n", strerror(errno));
-		}
-		if (FD_ISSET(cmdfd, &rfd)) {
-			ttyread();
-			if (blinktimeout) {
-				blinkset = tattrset(ATTR_BLINK);
-				if (!blinkset)
-					MODBIT(term.mode, 0, MODE_BLINK);
-			}
-		}
-
-		if (FD_ISSET(xfd, &rfd))
-			xev = actionfps;
-
-		clock_gettime(CLOCK_MONOTONIC, &now);
-		drawtimeout.tv_sec = 0;
-		drawtimeout.tv_nsec =  (1000 * 1E6)/ xfps;
-		tv = &drawtimeout;
-
-		dodraw = 0;
-		if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
-			tsetdirtattr(ATTR_BLINK);
-			term.mode ^= MODE_BLINK;
-			lastblink = now;
-			dodraw = 1;
-		}
-		deltatime = TIMEDIFF(now, last);
-		if (deltatime > 1000 / (xev ? xfps : actionfps)) {
-			dodraw = 1;
-			last = now;
-		}
-
-		if (dodraw) {
-			while (XPending(xw.dpy)) {
-				XNextEvent(xw.dpy, &ev);
-				if (XFilterEvent(&ev, None))
-					continue;
-				if (handler[ev.type])
-					(handler[ev.type])(&ev);
-			}
-
-			draw();
-			XFlush(xw.dpy);
-
-			if (xev && !FD_ISSET(xfd, &rfd))
-				xev--;
-			if (!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
-				if (blinkset) {
-					if (TIMEDIFF(now, lastblink) \
-							> blinktimeout) {
-						drawtimeout.tv_nsec = 1000;
-					} else {
-						drawtimeout.tv_nsec = (1E6 * \
-							(blinktimeout - \
-							TIMEDIFF(now,
-								lastblink)));
-					}
-					drawtimeout.tv_sec = \
-					    drawtimeout.tv_nsec / 1E9;
-					drawtimeout.tv_nsec %= (long)1E9;
-				} else {
-					tv = NULL;
-				}
-			}
-		}
-	}
-}
-
 void
 usage(void)
 {
@@ -4467,72 +2640,3 @@ usage(void)
 	    "          [-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;
-	xw.cursor = cursorshape;
-
-	ARGBEGIN {
-	case 'a':
-		allowaltscreen = 0;
-		break;
-	case 'c':
-		opt_class = EARGF(usage());
-		break;
-	case 'e':
-		if (argc > 0)
-			--argc, ++argv;
-		goto run;
-	case 'f':
-		opt_font = EARGF(usage());
-		break;
-	case 'g':
-		xw.gm = XParseGeometry(EARGF(usage()),
-				&xw.l, &xw.t, &cols, &rows);
-		break;
-	case 'i':
-		xw.isfixed = 1;
-		break;
-	case 'o':
-		opt_io = EARGF(usage());
-		break;
-	case 'l':
-		opt_line = EARGF(usage());
-		break;
-	case 'n':
-		opt_name = EARGF(usage());
-		break;
-	case 't':
-	case 'T':
-		opt_title = EARGF(usage());
-		break;
-	case 'w':
-		opt_embed = EARGF(usage());
-		break;
-	case 'v':
-		die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0);
-		break;
-	default:
-		usage();
-	} ARGEND;
-
-run:
-	if (argc > 0) {
-		/* eat all remaining arguments */
-		opt_cmd = argv;
-		if (!opt_title && !opt_line)
-			opt_title = basename(xstrdup(argv[0]));
-	}
-	setlocale(LC_CTYPE, "");
-	XSetLocaleModifiers("");
-	tnew(MAX(cols, 1), MAX(rows, 1));
-	xinit();
-	selinit();
-	run();
-
-	return 0;
-}
-
diff --git a/st.h b/st.h
new file mode 100644
index 0000000..44d4938
--- /dev/null
+++ b/st.h
@@ -0,0 +1,272 @@
+/* See LICENSE for license details. */
+
+/* Arbitrary sizes */
+#define UTF_SIZ       4
+
+/* 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 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 IS_SET(flag)		((term.mode & (flag)) != 0)
+#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 term_mode {
+	MODE_WRAP        = 1 << 0,
+	MODE_INSERT      = 1 << 1,
+	MODE_APPKEYPAD   = 1 << 2,
+	MODE_ALTSCREEN   = 1 << 3,
+	MODE_CRLF        = 1 << 4,
+	MODE_MOUSEBTN    = 1 << 5,
+	MODE_MOUSEMOTION = 1 << 6,
+	MODE_REVERSE     = 1 << 7,
+	MODE_KBDLOCK     = 1 << 8,
+	MODE_HIDE        = 1 << 9,
+	MODE_ECHO        = 1 << 10,
+	MODE_APPCURSOR   = 1 << 11,
+	MODE_MOUSESGR    = 1 << 12,
+	MODE_8BIT        = 1 << 13,
+	MODE_BLINK       = 1 << 14,
+	MODE_FBLINK      = 1 << 15,
+	MODE_FOCUS       = 1 << 16,
+	MODE_MOUSEX10    = 1 << 17,
+	MODE_MOUSEMANY   = 1 << 18,
+	MODE_BRCKTPASTE  = 1 << 19,
+	MODE_PRINT       = 1 << 20,
+	MODE_UTF8        = 1 << 21,
+	MODE_SIXEL       = 1 << 22,
+	MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
+	                  |MODE_MOUSEMANY,
+};
+
+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
+};
+
+enum window_state {
+	WIN_VISIBLE = 1,
+	WIN_FOCUSED = 2
+};
+
+typedef unsigned char uchar;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+typedef unsigned short ushort;
+
+typedef uint_least32_t Rune;
+
+typedef struct {
+	Rune u;           /* character code */
+	ushort mode;      /* attribute flags */
+	uint32_t fg;      /* foreground  */
+	uint32_t bg;      /* background  */
+} Glyph;
+
+typedef Glyph *Line;
+
+typedef struct {
+	Glyph attr; /* current char attributes */
+	int x;
+	int y;
+	char state;
+} TCursor;
+
+/* 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 */
+	GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
+	TCursor c;    /* cursor */
+	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 numlock; /* lock numbers in keyboard */
+	int *tabs;
+} Term;
+
+/* 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  */
+	char state; /* focus, redraw, visible */
+	int cursor; /* cursor style */
+} TermWindow;
+
+typedef struct {
+	uint b;
+	uint mask;
+	char *s;
+} MouseShortcut;
+
+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;
+
+	char *primary, *clipboard;
+	int alt;
+	struct timespec tclick1;
+	struct timespec tclick2;
+
+	//Atom xtarget;
+} Selection;
+
+typedef union {
+	int i;
+	uint ui;
+	float f;
+	const void *v;
+} Arg;
+
+typedef struct {
+	uint mod;
+	KeySym keysym;
+	void (*func)(const Arg *);
+	const Arg arg;
+} Shortcut;
+
+void die(const char *, ...);
+void redraw(void);
+
+int tattrset(int);
+void tnew(int, int);
+void tsetdirt(int, int);
+void tsetdirtattr(int);
+int match(uint, uint);
+void ttynew(void);
+size_t ttyread(void);
+void ttyresize(void);
+void ttysend(char *, size_t);
+void ttywrite(const char *, size_t);
+
+void resettitle(void);
+
+char *kmap(KeySym, uint);
+void cresize(int, int);
+void selclear(void);
+
+void selinit(void);
+void selnormalize(void);
+int selected(int, int);
+char *getsel(void);
+int x2col(int);
+int y2row(int);
+
+size_t utf8decode(char *, Rune *, size_t);
+size_t utf8encode(Rune, char *);
+
+void *xmalloc(size_t);
+char *xstrdup(char *);
+
+void usage(void);
+
+/* Globals */
+extern TermWindow win;
+extern Term term;
+extern Selection sel;
+extern int cmdfd;
+extern pid_t pid;
+extern char **opt_cmd;
+extern char *opt_class;
+extern char *opt_embed;
+extern char *opt_font;
+extern char *opt_io;
+extern char *opt_line;
+extern char *opt_name;
+extern char *opt_title;
+extern int oldbutton;
+
+extern char *usedfont;
+extern double usedfontsize;
+extern double defaultfontsize;
+
+/* config.h globals */
+extern char font[];
+extern int borderpx;
+extern float cwscale;
+extern float chscale;
+extern unsigned int doubleclicktimeout;
+extern unsigned int tripleclicktimeout;
+extern int allowaltscreen;
+extern unsigned int xfps;
+extern unsigned int actionfps;
+extern unsigned int cursorthickness;
+extern unsigned int blinktimeout;
+extern char termname[];
+extern const char *colorname[];
+extern size_t colornamelen;
+extern unsigned int defaultfg;
+extern unsigned int defaultbg;
+extern unsigned int defaultcs;
+extern unsigned int defaultrcs;
+extern unsigned int cursorshape;
+extern unsigned int cols;
+extern unsigned int rows;
+extern unsigned int mouseshape;
+extern unsigned int mousefg;
+extern unsigned int mousebg;
+extern unsigned int defaultattr;
+extern MouseShortcut mshortcuts[];
+extern size_t mshortcutslen;
+extern Shortcut shortcuts[];
+extern size_t shortcutslen;
+extern uint forceselmod;
+extern uint selmasks[];
+extern size_t selmaskslen;
+extern char ascii_printable[];
diff --git a/win.h b/win.h
new file mode 100644
index 0000000..d684797
--- /dev/null
+++ b/win.h
@@ -0,0 +1,29 @@
+/* See LICENSE for license details. */
+
+/* X modifiers */
+#define XK_ANY_MOD    UINT_MAX
+#define XK_NO_MOD     0
+#define XK_SWITCH_MOD (1<<13)
+
+typedef XftGlyphFontSpec GlyphFontSpec;
+
+void draw(void);
+void drawregion(int, int, int, int);
+void run(void);
+
+void xbell(int);
+void xclipcopy(void);
+void xclippaste(void);
+void xhints(void);
+void xinit(void);
+void xloadcols(void);
+int xsetcolorname(int, const char *);
+void xloadfonts(char *, double);
+void xsetenv(void);
+void xsettitle(char *);
+void xsetpointermotion(int);
+void xseturgency(int);
+void xunloadfonts(void);
+void xresize(int, int);
+void xselpaste(void);
+unsigned long xwinid(void);
diff --git a/x.c b/x.c
new file mode 100644
index 0000000..6474a01
--- /dev/null
+++ b/x.c
@@ -0,0 +1,1766 @@
+/* See LICENSE for license details. */
+#include <errno.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/select.h>
+#include <time.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+#include <X11/Xft/Xft.h>
+#include <X11/XKBlib.h>
+
+#include "arg.h"
+
+#define Glyph Glyph_
+#define Font Font_
+
+#include "win.h"
+#include "st.h"
+
+/* XEMBED messages */
+#define XEMBED_FOCUS_IN  4
+#define XEMBED_FOCUS_OUT 5
+
+/* macros */
+#define TRUERED(x)		(((x) & 0xff0000) >> 8)
+#define TRUEGREEN(x)		(((x) & 0xff00))
+#define TRUEBLUE(x)		(((x) & 0xff) << 8)
+
+typedef XftDraw *Draw;
+typedef XftColor Color;
+
+/* Purely graphic info */
+typedef struct {
+	Display *dpy;
+	Colormap cmap;
+	Window win;
+	Drawable buf;
+	Atom xembed, wmdeletewin, netwmname, netwmpid;
+	XIM xim;
+	XIC xic;
+	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;
+} XSelection;
+
+/* Font structure */
+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 void xdrawcursor(void);
+static int xgeommasktogravity(int);
+static int xloadfont(Font *, FcPattern *);
+static void xsetsel(char *, Time);
+static void xunloadfont(Font *);
+
+static void expose(XEvent *);
+static void visibility(XEvent *);
+static void unmap(XEvent *);
+static void kpress(XEvent *);
+static void cmessage(XEvent *);
+static void resize(XEvent *);
+static void focus(XEvent *);
+static void brelease(XEvent *);
+static void bpress(XEvent *);
+static void bmotion(XEvent *);
+static void propnotify(XEvent *);
+static void selnotify(XEvent *);
+static void selclear_(XEvent *);
+static void selrequest(XEvent *);
+
+static void selcopy(Time);
+static void getbuttoninfo(XEvent *);
+static void mousereport(XEvent *);
+
+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;
+
+/* Font Ring Cache */
+enum {
+	FRC_NORMAL,
+	FRC_ITALIC,
+	FRC_BOLD,
+	FRC_ITALICBOLD
+};
+
+typedef struct {
+	XftFont *font;
+	int flags;
+	Rune unicodep;
+} Fontcache;
+
+/* Fontcache is an array now. A new font will be appended to the array. */
+static Fontcache frc[16];
+static int frclen = 0;
+
+void
+getbuttoninfo(XEvent *e)
+{
+	int type;
+	uint state = e->xbutton.state & ~(Button1Mask | forceselmod);
+
+	sel.alt = IS_SET(MODE_ALTSCREEN);
+
+	sel.oe.x = x2col(e->xbutton.x);
+	sel.oe.y = y2row(e->xbutton.y);
+	selnormalize();
+
+	sel.type = SEL_REGULAR;
+	for (type = 1; type < selmaskslen; ++type) {
+		if (match(selmasks[type], state)) {
+			sel.type = type;
+			break;
+		}
+	}
+}
+
+void
+mousereport(XEvent *e)
+{
+	int x = x2col(e->xbutton.x), y = y2row(e->xbutton.y),
+	    button = e->xbutton.button, state = e->xbutton.state,
+	    len;
+	char buf[40];
+	static int ox, oy;
+
+	/* from urxvt */
+	if (e->xbutton.type == MotionNotify) {
+		if (x == ox && y == oy)
+			return;
+		if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
+			return;
+		/* MOUSE_MOTION: no reporting if no button is pressed */
+		if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
+			return;
+
+		button = oldbutton + 32;
+		ox = x;
+		oy = y;
+	} else {
+		if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
+			button = 3;
+		} else {
+			button -= Button1;
+			if (button >= 3)
+				button += 64 - 3;
+		}
+		if (e->xbutton.type == ButtonPress) {
+			oldbutton = button;
+			ox = x;
+			oy = y;
+		} else if (e->xbutton.type == ButtonRelease) {
+			oldbutton = 3;
+			/* MODE_MOUSEX10: no button release reporting */
+			if (IS_SET(MODE_MOUSEX10))
+				return;
+			if (button == 64 || button == 65)
+				return;
+		}
+	}
+
+	if (!IS_SET(MODE_MOUSEX10)) {
+		button += ((state & ShiftMask  ) ? 4  : 0)
+			+ ((state & Mod4Mask   ) ? 8  : 0)
+			+ ((state & ControlMask) ? 16 : 0);
+	}
+
+	if (IS_SET(MODE_MOUSESGR)) {
+		len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
+				button, x+1, y+1,
+				e->xbutton.type == ButtonRelease ? 'm' : 'M');
+	} else if (x < 223 && y < 223) {
+		len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
+				32+button, 32+x+1, 32+y+1);
+	} else {
+		return;
+	}
+
+	ttywrite(buf, len);
+}
+
+void
+bpress(XEvent *e)
+{
+	struct timespec now;
+	MouseShortcut *ms;
+
+	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+		mousereport(e);
+		return;
+	}
+
+	for (ms = mshortcuts; ms < mshortcuts + mshortcutslen; ms++) {
+		if (e->xbutton.button == ms->b
+				&& match(ms->mask, e->xbutton.state)) {
+			ttysend(ms->s, strlen(ms->s));
+			return;
+		}
+	}
+
+	if (e->xbutton.button == Button1) {
+		clock_gettime(CLOCK_MONOTONIC, &now);
+
+		/* Clear previous selection, logically and visually. */
+		selclear_(NULL);
+		sel.mode = SEL_EMPTY;
+		sel.type = SEL_REGULAR;
+		sel.oe.x = sel.ob.x = x2col(e->xbutton.x);
+		sel.oe.y = sel.ob.y = y2row(e->xbutton.y);
+
+		/*
+		 * If the user clicks below predefined timeouts specific
+		 * snapping behaviour is exposed.
+		 */
+		if (TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) {
+			sel.snap = SNAP_LINE;
+		} else if (TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) {
+			sel.snap = SNAP_WORD;
+		} else {
+			sel.snap = 0;
+		}
+		selnormalize();
+
+		if (sel.snap != 0)
+			sel.mode = SEL_READY;
+		tsetdirt(sel.nb.y, sel.ne.y);
+		sel.tclick2 = sel.tclick1;
+		sel.tclick1 = now;
+	}
+}
+
+void
+selcopy(Time t)
+{
+	xsetsel(getsel(), t);
+}
+
+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;
+
+	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;
+	} else {
+		return;
+	}
+	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);
+		ttysend((char *)data, nitems * format / 8);
+		if (IS_SET(MODE_BRCKTPASTE) && rem == 0)
+			ttywrite("\033[201~", 6);
+		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
+xselpaste(void)
+{
+	XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY,
+			xw.win, CurrentTime);
+}
+
+void
+xclipcopy(void)
+{
+	Atom clipboard;
+
+	if (sel.clipboard != NULL)
+		free(sel.clipboard);
+
+	if (sel.primary != NULL) {
+		sel.clipboard = xstrdup(sel.primary);
+		clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+		XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
+	}
+}
+
+void
+xclippaste(void)
+{
+	Atom clipboard;
+
+	clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+	XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard,
+			xw.win, CurrentTime);
+}
+
+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 = sel.primary;
+		} else if (xsre->selection == clipboard) {
+			seltext = sel.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
+xsetsel(char *str, Time t)
+{
+	free(sel.primary);
+	sel.primary = str;
+
+	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
+	if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
+		selclear_(NULL);
+}
+
+void
+brelease(XEvent *e)
+{
+	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+		mousereport(e);
+		return;
+	}
+
+	if (e->xbutton.button == Button2) {
+		xselpaste();
+	} else if (e->xbutton.button == Button1) {
+		if (sel.mode == SEL_READY) {
+			getbuttoninfo(e);
+			selcopy(e->xbutton.time);
+		} else
+			selclear_(NULL);
+		sel.mode = SEL_IDLE;
+		tsetdirt(sel.nb.y, sel.ne.y);
+	}
+}
+
+void
+bmotion(XEvent *e)
+{
+	int oldey, oldex, oldsby, oldsey;
+
+	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+		mousereport(e);
+		return;
+	}
+
+	if (!sel.mode)
+		return;
+
+	sel.mode = SEL_READY;
+	oldey = sel.oe.y;
+	oldex = sel.oe.x;
+	oldsby = sel.nb.y;
+	oldsey = sel.ne.y;
+	getbuttoninfo(e);
+
+	if (oldey != sel.oe.y || oldex != sel.oe.x)
+		tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
+}
+
+void
+xresize(int col, int row)
+{
+	win.tw = MAX(1, col * win.cw);
+	win.th = MAX(1, row * win.ch);
+
+	XFreePixmap(xw.dpy, xw.buf);
+	xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
+			DefaultDepth(xw.dpy, xw.scr));
+	XftDrawChange(xw.draw, xw.buf);
+	xclear(0, 0, win.w, win.h);
+}
+
+ushort
+sixd_to_16bit(int x)
+{
+	return x == 0 ? 0 : 0x3737 + 0x2828 * x;
+}
+
+int
+xloadcolor(int i, const char *name, Color *ncolor)
+{
+	XRenderColor color = { .alpha = 0xffff };
+
+	if (!name) {
+		if (BETWEEN(i, 16, 255)) { /* 256 color */
+			if (i < 6*6*6+16) { /* same colors as xterm */
+				color.red   = sixd_to_16bit( ((i-16)/36)%6 );
+				color.green = sixd_to_16bit( ((i-16)/6) %6 );
+				color.blue  = sixd_to_16bit( ((i-16)/1) %6 );
+			} else { /* greyscale */
+				color.red = 0x0808 + 0x0a0a * (i - (6*6*6+16));
+				color.green = color.blue = color.red;
+			}
+			return XftColorAllocValue(xw.dpy, xw.vis,
+			                          xw.cmap, &color, ncolor);
+		} else
+			name = colorname[i];
+	}
+
+	return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
+}
+
+void
+xloadcols(void)
+{
+	int i;
+	static int loaded;
+	Color *cp;
+
+	dc.collen = MAX(colornamelen, 256);
+	dc.col = xmalloc(dc.collen * sizeof(Color));
+
+	if (loaded) {
+		for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp)
+			XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
+	}
+
+	for (i = 0; i < dc.collen; i++)
+		if (!xloadcolor(i, NULL, &dc.col[i])) {
+			if (colorname[i])
+				die("Could not allocate color '%s'\n", colorname[i]);
+			else
+				die("Could not allocate color %d\n", i);
+		}
+	loaded = 1;
+}
+
+int
+xsetcolorname(int x, const char *name)
+{
+	Color ncolor;
+
+	if (!BETWEEN(x, 0, dc.collen))
+		return 1;
+
+
+	if (!xloadcolor(x, name, &ncolor))
+		return 1;
+
+	XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
+	dc.col[x] = ncolor;
+
+	return 0;
+}
+
+/*
+ * Absolute coordinates.
+ */
+void
+xclear(int x1, int y1, int x2, int y2)
+{
+	XftDrawRect(xw.draw,
+			&dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg],
+			x1, y1, x2-x1, y2-y1);
+}
+
+void
+xhints(void)
+{
+	XClassHint class = {opt_name ? opt_name : termname,
+	                    opt_class ? opt_class : termname};
+	XWMHints wm = {.flags = InputHint, .input = 1};
+	XSizeHints *sizeh = NULL;
+
+	sizeh = XAllocSizeHints();
+
+	sizeh->flags = PSize | PResizeInc | PBaseSize;
+	sizeh->height = win.h;
+	sizeh->width = win.w;
+	sizeh->height_inc = win.ch;
+	sizeh->width_inc = win.cw;
+	sizeh->base_height = 2 * borderpx;
+	sizeh->base_width = 2 * borderpx;
+	if (xw.isfixed) {
+		sizeh->flags |= PMaxSize | PMinSize;
+		sizeh->min_width = sizeh->max_width = win.w;
+		sizeh->min_height = sizeh->max_height = win.h;
+	}
+	if (xw.gm & (XValue|YValue)) {
+		sizeh->flags |= USPosition | PWinGravity;
+		sizeh->x = xw.l;
+		sizeh->y = xw.t;
+		sizeh->win_gravity = xgeommasktogravity(xw.gm);
+	}
+
+	XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm,
+			&class);
+	XFree(sizeh);
+}
+
+int
+xgeommasktogravity(int mask)
+{
+	switch (mask & (XNegative|YNegative)) {
+	case 0:
+		return NorthWestGravity;
+	case XNegative:
+		return NorthEastGravity;
+	case YNegative:
+		return SouthWestGravity;
+	}
+
+	return SouthEastGravity;
+}
+
+int
+xloadfont(Font *f, FcPattern *pattern)
+{
+	FcPattern *configured;
+	FcPattern *match;
+	FcResult result;
+	XGlyphInfo extents;
+	int wantattr, haveattr;
+
+	/*
+	 * Manually configure instead of calling XftMatchFont
+	 * so that we can use the configured pattern for
+	 * "missing glyph" lookups.
+	 */
+	configured = FcPatternDuplicate(pattern);
+	if (!configured)
+		return 1;
+
+	FcConfigSubstitute(NULL, configured, FcMatchPattern);
+	XftDefaultSubstitute(xw.dpy, xw.scr, configured);
+
+	match = FcFontMatch(NULL, configured, &result);
+	if (!match) {
+		FcPatternDestroy(configured);
+		return 1;
+	}
+
+	if (!(f->match = XftFontOpenPattern(xw.dpy, match))) {
+		FcPatternDestroy(configured);
+		FcPatternDestroy(match);
+		return 1;
+	}
+
+	if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) ==
+	    XftResultMatch)) {
+		/*
+		 * Check if xft was unable to find a font with the appropriate
+		 * slant but gave us one anyway. Try to mitigate.
+		 */
+		if ((XftPatternGetInteger(f->match->pattern, "slant", 0,
+		    &haveattr) != XftResultMatch) || haveattr < wantattr) {
+			f->badslant = 1;
+			fputs("st: font slant does not match\n", stderr);
+		}
+	}
+
+	if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) ==
+	    XftResultMatch)) {
+		if ((XftPatternGetInteger(f->match->pattern, "weight", 0,
+		    &haveattr) != XftResultMatch) || haveattr != wantattr) {
+			f->badweight = 1;
+			fputs("st: font weight does not match\n", stderr);
+		}
+	}
+
+	XftTextExtentsUtf8(xw.dpy, f->match,
+		(const FcChar8 *) ascii_printable,
+		strlen(ascii_printable), &extents);
+
+	f->set = NULL;
+	f->pattern = configured;
+
+	f->ascent = f->match->ascent;
+	f->descent = f->match->descent;
+	f->lbearing = 0;
+	f->rbearing = f->match->max_advance_width;
+
+	f->height = f->ascent + f->descent;
+	f->width = DIVCEIL(extents.xOff, strlen(ascii_printable));
+
+	return 0;
+}
+
+void
+xloadfonts(char *fontstr, double fontsize)
+{
+	FcPattern *pattern;
+	double fontval;
+	float ceilf(float);
+
+	if (fontstr[0] == '-') {
+		pattern = XftXlfdParse(fontstr, False, False);
+	} else {
+		pattern = FcNameParse((FcChar8 *)fontstr);
+	}
+
+	if (!pattern)
+		die("st: can't open font %s\n", fontstr);
+
+	if (fontsize > 1) {
+		FcPatternDel(pattern, FC_PIXEL_SIZE);
+		FcPatternDel(pattern, FC_SIZE);
+		FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize);
+		usedfontsize = fontsize;
+	} else {
+		if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) ==
+				FcResultMatch) {
+			usedfontsize = fontval;
+		} else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) ==
+				FcResultMatch) {
+			usedfontsize = -1;
+		} else {
+			/*
+			 * Default font size is 12, if none given. This is to
+			 * have a known usedfontsize value.
+			 */
+			FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12);
+			usedfontsize = 12;
+		}
+		defaultfontsize = usedfontsize;
+	}
+
+	if (xloadfont(&dc.font, pattern))
+		die("st: can't open font %s\n", fontstr);
+
+	if (usedfontsize < 0) {
+		FcPatternGetDouble(dc.font.match->pattern,
+		                   FC_PIXEL_SIZE, 0, &fontval);
+		usedfontsize = fontval;
+		if (fontsize == 0)
+			defaultfontsize = fontval;
+	}
+
+	/* Setting character width and height. */
+	win.cw = ceilf(dc.font.width * cwscale);
+	win.ch = ceilf(dc.font.height * chscale);
+
+	FcPatternDel(pattern, FC_SLANT);
+	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+	if (xloadfont(&dc.ifont, pattern))
+		die("st: can't open font %s\n", fontstr);
+
+	FcPatternDel(pattern, FC_WEIGHT);
+	FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
+	if (xloadfont(&dc.ibfont, pattern))
+		die("st: can't open font %s\n", fontstr);
+
+	FcPatternDel(pattern, FC_SLANT);
+	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
+	if (xloadfont(&dc.bfont, pattern))
+		die("st: can't open font %s\n", fontstr);
+
+	FcPatternDestroy(pattern);
+}
+
+void
+xunloadfont(Font *f)
+{
+	XftFontClose(xw.dpy, f->match);
+	FcPatternDestroy(f->pattern);
+	if (f->set)
+		FcFontSetDestroy(f->set);
+}
+
+void
+xunloadfonts(void)
+{
+	/* Free the loaded fonts in the font cache.  */
+	while (frclen > 0)
+		XftFontClose(xw.dpy, frc[--frclen].font);
+
+	xunloadfont(&dc.font);
+	xunloadfont(&dc.bfont);
+	xunloadfont(&dc.ifont);
+	xunloadfont(&dc.ibfont);
+}
+
+void
+xinit(void)
+{
+	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 + term.col * win.cw;
+	win.h = 2 * borderpx + term.row * win.ch;
+	if (xw.gm & XNegative)
+		xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
+	if (xw.gm & YNegative)
+		xw.t += DisplayHeight(xw.dpy, xw.scr) - win.h - 2;
+
+	/* Events */
+	xw.attrs.background_pixel = dc.col[defaultbg].pixel;
+	xw.attrs.border_pixel = dc.col[defaultbg].pixel;
+	xw.attrs.bit_gravity = NorthWestGravity;
+	xw.attrs.event_mask = FocusChangeMask | KeyPressMask
+		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
+		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
+	xw.attrs.colormap = xw.cmap;
+
+	if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
+		parent = XRootWindow(xw.dpy, xw.scr);
+	xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
+			win.w, win.h, 0, 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);
+
+	/* Xft rendering context */
+	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
+
+	/* input methods */
+	if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+		XSetLocaleModifiers("@im=local");
+		if ((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+			XSetLocaleModifiers("@im=");
+			if ((xw.xim = XOpenIM(xw.dpy,
+					NULL, NULL, NULL)) == NULL) {
+				die("XOpenIM failed. Could not open input"
+					" device.\n");
+			}
+		}
+	}
+	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
+					   | XIMStatusNothing, XNClientWindow, xw.win,
+					   XNFocusWindow, xw.win, NULL);
+	if (xw.xic == NULL)
+		die("XCreateIC failed. Could not obtain input method.\n");
+
+	/* white cursor, black outline */
+	cursor = XCreateFontCursor(xw.dpy, mouseshape);
+	XDefineCursor(xw.dpy, xw.win, cursor);
+
+	if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) {
+		xmousefg.red   = 0xffff;
+		xmousefg.green = 0xffff;
+		xmousefg.blue  = 0xffff;
+	}
+
+	if (XParseColor(xw.dpy, xw.cmap, colorname[mousebg], &xmousebg) == 0) {
+		xmousebg.red   = 0x0000;
+		xmousebg.green = 0x0000;
+		xmousebg.blue  = 0x0000;
+	}
+
+	XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg);
+
+	xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
+	xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
+	xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False);
+	XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
+
+	xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False);
+	XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
+			PropModeReplace, (uchar *)&thispid, 1);
+
+	resettitle();
+	XMapWindow(xw.dpy, xw.win);
+	xhints();
+	XSync(xw.dpy, False);
+
+	xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
+	if (xsel.xtarget == None)
+		xsel.xtarget = XA_STRING;
+}
+
+int
+xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
+{
+	float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp;
+	ushort mode, prevmode = USHRT_MAX;
+	Font *font = &dc.font;
+	int frcflags = FRC_NORMAL;
+	float runewidth = win.cw;
+	Rune rune;
+	FT_UInt glyphidx;
+	FcResult fcres;
+	FcPattern *fcpattern, *fontpattern;
+	FcFontSet *fcsets[] = { NULL };
+	FcCharSet *fccharset;
+	int i, f, numspecs = 0;
+
+	for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
+		/* Fetch rune and mode for current glyph. */
+		rune = glyphs[i].u;
+		mode = glyphs[i].mode;
+
+		/* Skip dummy wide-character spacing. */
+		if (mode == ATTR_WDUMMY)
+			continue;
+
+		/* Determine font for glyph if different from previous glyph. */
+		if (prevmode != mode) {
+			prevmode = mode;
+			font = &dc.font;
+			frcflags = FRC_NORMAL;
+			runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f);
+			if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
+				font = &dc.ibfont;
+				frcflags = FRC_ITALICBOLD;
+			} else if (mode & ATTR_ITALIC) {
+				font = &dc.ifont;
+				frcflags = FRC_ITALIC;
+			} else if (mode & ATTR_BOLD) {
+				font = &dc.bfont;
+				frcflags = FRC_BOLD;
+			}
+			yp = winy + font->ascent;
+		}
+
+		/* Lookup character index with default font. */
+		glyphidx = XftCharIndex(xw.dpy, font->match, rune);
+		if (glyphidx) {
+			specs[numspecs].font = font->match;
+			specs[numspecs].glyph = glyphidx;
+			specs[numspecs].x = (short)xp;
+			specs[numspecs].y = (short)yp;
+			xp += runewidth;
+			numspecs++;
+			continue;
+		}
+
+		/* Fallback on font cache, search the font cache for match. */
+		for (f = 0; f < frclen; f++) {
+			glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune);
+			/* Everything correct. */
+			if (glyphidx && frc[f].flags == frcflags)
+				break;
+			/* We got a default font for a not found glyph. */
+			if (!glyphidx && frc[f].flags == frcflags
+					&& frc[f].unicodep == rune) {
+				break;
+			}
+		}
+
+		/* Nothing was found. Use fontconfig to find matching font. */
+		if (f >= frclen) {
+			if (!font->set)
+				font->set = FcFontSort(0, font->pattern,
+				                       1, 0, &fcres);
+			fcsets[0] = font->set;
+
+			/*
+			 * Nothing was found in the cache. Now use
+			 * some dozen of Fontconfig calls to get the
+			 * font for one single character.
+			 *
+			 * Xft and fontconfig are design failures.
+			 */
+			fcpattern = FcPatternDuplicate(font->pattern);
+			fccharset = FcCharSetCreate();
+
+			FcCharSetAddChar(fccharset, rune);
+			FcPatternAddCharSet(fcpattern, FC_CHARSET,
+					fccharset);
+			FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
+
+			FcConfigSubstitute(0, fcpattern,
+					FcMatchPattern);
+			FcDefaultSubstitute(fcpattern);
+
+			fontpattern = FcFontSetMatch(0, fcsets, 1,
+					fcpattern, &fcres);
+
+			/*
+			 * Overwrite or create the new cache entry.
+			 */
+			if (frclen >= LEN(frc)) {
+				frclen = LEN(frc) - 1;
+				XftFontClose(xw.dpy, frc[frclen].font);
+				frc[frclen].unicodep = 0;
+			}
+
+			frc[frclen].font = XftFontOpenPattern(xw.dpy,
+					fontpattern);
+			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_REVERSE) {
+		temp = fg;
+		fg = bg;
+		bg = temp;
+	}
+
+	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;
+		XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg);
+		fg = &revfg;
+	}
+
+	if (base.mode & ATTR_BLINK && term.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 + ((y >= term.row-1)? win.h : 0));
+	}
+	if (x + charlen >= term.col) {
+		xclear(winx + width, (y == 0)? 0 : winy, win.w,
+			((y >= term.row-1)? win.h : (winy + win.ch)));
+	}
+	if (y == 0)
+		xclear(winx, 0, winx + width, borderpx);
+	if (y == term.row-1)
+		xclear(winx, winy + win.ch, winx + width, win.h);
+
+	/* Clean up the region we want to draw to. */
+	XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
+
+	/* Set the clip region because Xft is sometimes dirty. */
+	r.x = 0;
+	r.y = 0;
+	r.height = win.ch;
+	r.width = width;
+	XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
+
+	/* Render the glyphs. */
+	XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
+
+	/* Render underline and strikethrough. */
+	if (base.mode & ATTR_UNDERLINE) {
+		XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
+				width, 1);
+	}
+
+	if (base.mode & ATTR_STRUCK) {
+		XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3,
+				width, 1);
+	}
+
+	/* Reset clip to none. */
+	XftDrawSetClip(xw.draw, 0);
+}
+
+void
+xdrawglyph(Glyph g, int x, int y)
+{
+	int numspecs;
+	XftGlyphFontSpec spec;
+
+	numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
+	xdrawglyphfontspecs(&spec, g, numspecs, x, y);
+}
+
+void
+xdrawcursor(void)
+{
+	static int oldx = 0, oldy = 0;
+	int curx;
+	Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og;
+	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
+	Color drawcol;
+
+	LIMIT(oldx, 0, term.col-1);
+	LIMIT(oldy, 0, term.row-1);
+
+	curx = term.c.x;
+
+	/* adjust position if in dummy */
+	if (term.line[oldy][oldx].mode & ATTR_WDUMMY)
+		oldx--;
+	if (term.line[term.c.y][curx].mode & ATTR_WDUMMY)
+		curx--;
+
+	/* remove the old cursor */
+	og = term.line[oldy][oldx];
+	if (ena_sel && selected(oldx, oldy))
+		og.mode ^= ATTR_REVERSE;
+	xdrawglyph(og, oldx, oldy);
+
+	g.u = term.line[term.c.y][term.c.x].u;
+
+	/*
+	 * Select the right color for the right mode.
+	 */
+	if (IS_SET(MODE_REVERSE)) {
+		g.mode |= ATTR_REVERSE;
+		g.bg = defaultfg;
+		if (ena_sel && selected(term.c.x, term.c.y)) {
+			drawcol = dc.col[defaultcs];
+			g.fg = defaultrcs;
+		} else {
+			drawcol = dc.col[defaultrcs];
+			g.fg = defaultcs;
+		}
+	} else {
+		if (ena_sel && selected(term.c.x, term.c.y)) {
+			drawcol = dc.col[defaultrcs];
+			g.fg = defaultfg;
+			g.bg = defaultrcs;
+		} else {
+			drawcol = dc.col[defaultcs];
+		}
+	}
+
+	if (IS_SET(MODE_HIDE))
+		return;
+
+	/* draw the new one */
+	if (win.state & WIN_FOCUSED) {
+		switch (win.cursor) {
+		case 7: /* st extension: snowman */
+			utf8decode("☃", &g.u, UTF_SIZ);
+		case 0: /* Blinking Block */
+		case 1: /* Blinking Block (Default) */
+		case 2: /* Steady Block */
+			g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE;
+			xdrawglyph(g, term.c.x, term.c.y);
+			break;
+		case 3: /* Blinking Underline */
+		case 4: /* Steady Underline */
+			XftDrawRect(xw.draw, &drawcol,
+					borderpx + curx * win.cw,
+					borderpx + (term.c.y + 1) * win.ch - \
+						cursorthickness,
+					win.cw, cursorthickness);
+			break;
+		case 5: /* Blinking bar */
+		case 6: /* Steady bar */
+			XftDrawRect(xw.draw, &drawcol,
+					borderpx + curx * win.cw,
+					borderpx + term.c.y * win.ch,
+					cursorthickness, win.ch);
+			break;
+		}
+	} else {
+		XftDrawRect(xw.draw, &drawcol,
+				borderpx + curx * win.cw,
+				borderpx + term.c.y * win.ch,
+				win.cw - 1, 1);
+		XftDrawRect(xw.draw, &drawcol,
+				borderpx + curx * win.cw,
+				borderpx + term.c.y * win.ch,
+				1, win.ch - 1);
+		XftDrawRect(xw.draw, &drawcol,
+				borderpx + (curx + 1) * win.cw - 1,
+				borderpx + term.c.y * win.ch,
+				1, win.ch - 1);
+		XftDrawRect(xw.draw, &drawcol,
+				borderpx + curx * win.cw,
+				borderpx + (term.c.y + 1) * win.ch - 1,
+				win.cw, 1);
+	}
+	oldx = curx, oldy = term.c.y;
+}
+
+void
+xsetenv(void)
+{
+	char buf[sizeof(long) * 8 + 1];
+
+	snprintf(buf, sizeof(buf), "%lu", xw.win);
+	setenv("WINDOWID", buf, 1);
+}
+
+void
+xsettitle(char *p)
+{
+	XTextProperty prop;
+
+	Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
+			&prop);
+	XSetWMName(xw.dpy, xw.win, &prop);
+	XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
+	XFree(prop.value);
+}
+
+void
+draw(void)
+{
+	drawregion(0, 0, term.col, term.row);
+	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
+drawregion(int x1, int y1, int x2, int y2)
+{
+	int i, x, y, ox, numspecs;
+	Glyph base, new;
+	XftGlyphFontSpec *specs;
+	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
+
+	if (!(win.state & WIN_VISIBLE))
+		return;
+
+	for (y = y1; y < y2; y++) {
+		if (!term.dirty[y])
+			continue;
+
+		term.dirty[y] = 0;
+
+		specs = term.specbuf;
+		numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y);
+
+		i = ox = 0;
+		for (x = x1; x < x2 && i < numspecs; x++) {
+			new = term.line[y][x];
+			if (new.mode == ATTR_WDUMMY)
+				continue;
+			if (ena_sel && selected(x, y))
+				new.mode ^= ATTR_REVERSE;
+			if (i > 0 && ATTRCMP(base, new)) {
+				xdrawglyphfontspecs(specs, base, i, ox, y);
+				specs += i;
+				numspecs -= i;
+				i = 0;
+			}
+			if (i == 0) {
+				ox = x;
+				base = new;
+			}
+			i++;
+		}
+		if (i > 0)
+			xdrawglyphfontspecs(specs, base, i, ox, y);
+	}
+	xdrawcursor();
+}
+
+void
+expose(XEvent *ev)
+{
+	redraw();
+}
+
+void
+visibility(XEvent *ev)
+{
+	XVisibilityEvent *e = &ev->xvisibility;
+
+	MODBIT(win.state, e->state != VisibilityFullyObscured, WIN_VISIBLE);
+}
+
+void
+unmap(XEvent *ev)
+{
+	win.state &= ~WIN_VISIBLE;
+}
+
+void
+xsetpointermotion(int set)
+{
+	MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
+	XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
+}
+
+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(int vol)
+{
+	XkbBell(xw.dpy, xw.win, vol, (Atom)NULL);
+}
+
+unsigned long
+xwinid(void)
+{
+	return xw.win;
+}
+
+void
+focus(XEvent *ev)
+{
+	XFocusChangeEvent *e = &ev->xfocus;
+
+	if (e->mode == NotifyGrab)
+		return;
+
+	if (ev->type == FocusIn) {
+		XSetICFocus(xw.xic);
+		win.state |= WIN_FOCUSED;
+		xseturgency(0);
+		if (IS_SET(MODE_FOCUS))
+			ttywrite("\033[I", 3);
+	} else {
+		XUnsetICFocus(xw.xic);
+		win.state &= ~WIN_FOCUSED;
+		if (IS_SET(MODE_FOCUS))
+			ttywrite("\033[O", 3);
+	}
+}
+
+void
+kpress(XEvent *ev)
+{
+	XKeyEvent *e = &ev->xkey;
+	KeySym ksym;
+	char buf[32], *customkey;
+	int len;
+	Rune c;
+	Status status;
+	Shortcut *bp;
+
+	if (IS_SET(MODE_KBDLOCK))
+		return;
+
+	len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
+	/* 1. shortcuts */
+	for (bp = shortcuts; bp < shortcuts + shortcutslen; 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))) {
+		ttysend(customkey, strlen(customkey));
+		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;
+		}
+	}
+	ttysend(buf, len);
+}
+
+
+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.state |= WIN_FOCUSED;
+			xseturgency(0);
+		} else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
+			win.state &= ~WIN_FOCUSED;
+		}
+	} else if (e->xclient.data.l[0] == xw.wmdeletewin) {
+		/* Send SIGHUP to shell */
+		kill(pid, SIGHUP);
+		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);
+	ttyresize();
+}
+
+void
+run(void)
+{
+	XEvent ev;
+	int w = win.w, h = win.h;
+	fd_set rfd;
+	int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
+	struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
+	long deltatime;
+
+	/* Waiting for window mapping */
+	do {
+		XNextEvent(xw.dpy, &ev);
+		/*
+		 * This XFilterEvent call is required because of XOpenIM. It
+		 * does filter out the key event and some client message for
+		 * the input method too.
+		 */
+		if (XFilterEvent(&ev, None))
+			continue;
+		if (ev.type == ConfigureNotify) {
+			w = ev.xconfigure.width;
+			h = ev.xconfigure.height;
+		}
+	} while (ev.type != MapNotify);
+
+	cresize(w, h);
+	ttynew();
+	ttyresize();
+
+	clock_gettime(CLOCK_MONOTONIC, &last);
+	lastblink = last;
+
+	for (xev = actionfps;;) {
+		FD_ZERO(&rfd);
+		FD_SET(cmdfd, &rfd);
+		FD_SET(xfd, &rfd);
+
+		if (pselect(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
+			if (errno == EINTR)
+				continue;
+			die("select failed: %s\n", strerror(errno));
+		}
+		if (FD_ISSET(cmdfd, &rfd)) {
+			ttyread();
+			if (blinktimeout) {
+				blinkset = tattrset(ATTR_BLINK);
+				if (!blinkset)
+					MODBIT(term.mode, 0, MODE_BLINK);
+			}
+		}
+
+		if (FD_ISSET(xfd, &rfd))
+			xev = actionfps;
+
+		clock_gettime(CLOCK_MONOTONIC, &now);
+		drawtimeout.tv_sec = 0;
+		drawtimeout.tv_nsec =  (1000 * 1E6)/ xfps;
+		tv = &drawtimeout;
+
+		dodraw = 0;
+		if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
+			tsetdirtattr(ATTR_BLINK);
+			term.mode ^= MODE_BLINK;
+			lastblink = now;
+			dodraw = 1;
+		}
+		deltatime = TIMEDIFF(now, last);
+		if (deltatime > 1000 / (xev ? xfps : actionfps)) {
+			dodraw = 1;
+			last = now;
+		}
+
+		if (dodraw) {
+			while (XPending(xw.dpy)) {
+				XNextEvent(xw.dpy, &ev);
+				if (XFilterEvent(&ev, None))
+					continue;
+				if (handler[ev.type])
+					(handler[ev.type])(&ev);
+			}
+
+			draw();
+			XFlush(xw.dpy);
+
+			if (xev && !FD_ISSET(xfd, &rfd))
+				xev--;
+			if (!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
+				if (blinkset) {
+					if (TIMEDIFF(now, lastblink) \
+							> blinktimeout) {
+						drawtimeout.tv_nsec = 1000;
+					} else {
+						drawtimeout.tv_nsec = (1E6 * \
+							(blinktimeout - \
+							TIMEDIFF(now,
+								lastblink)));
+					}
+					drawtimeout.tv_sec = \
+					    drawtimeout.tv_nsec / 1E9;
+					drawtimeout.tv_nsec %= (long)1E9;
+				} else {
+					tv = NULL;
+				}
+			}
+		}
+	}
+}
+
+int
+main(int argc, char *argv[])
+{
+	xw.l = xw.t = 0;
+	xw.isfixed = False;
+	win.cursor = cursorshape;
+
+	ARGBEGIN {
+	case 'a':
+		allowaltscreen = 0;
+		break;
+	case 'c':
+		opt_class = EARGF(usage());
+		break;
+	case 'e':
+		if (argc > 0)
+			--argc, ++argv;
+		goto run;
+	case 'f':
+		opt_font = EARGF(usage());
+		break;
+	case 'g':
+		xw.gm = XParseGeometry(EARGF(usage()),
+				&xw.l, &xw.t, &cols, &rows);
+		break;
+	case 'i':
+		xw.isfixed = 1;
+		break;
+	case 'o':
+		opt_io = EARGF(usage());
+		break;
+	case 'l':
+		opt_line = EARGF(usage());
+		break;
+	case 'n':
+		opt_name = EARGF(usage());
+		break;
+	case 't':
+	case 'T':
+		opt_title = EARGF(usage());
+		break;
+	case 'w':
+		opt_embed = EARGF(usage());
+		break;
+	case 'v':
+		die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0);
+		break;
+	default:
+		usage();
+	} ARGEND;
+
+run:
+	if (argc > 0) {
+		/* eat all remaining arguments */
+		opt_cmd = argv;
+		if (!opt_title && !opt_line)
+			opt_title = basename(xstrdup(argv[0]));
+	}
+	setlocale(LC_CTYPE, "");
+	XSetLocaleModifiers("");
+	tnew(MAX(cols, 1), MAX(rows, 1));
+	xinit();
+	selinit();
+	run();
+
+	return 0;
+}

From 20f713548de451b67db3306cf8cf7b2f38fee05c Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Wed, 25 Jan 2017 19:17:38 +0100
Subject: [PATCH 0948/1146] Change default keybindings

CTRL+SHIFT is an impossible combination in the terminal world
(0x20 | x & 0x1F), so it is perfect to be used for internals
shortcuts of terminals, and being a double combination
reduces the prossibility of having comflicts.
---
 config.def.h | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/config.def.h b/config.def.h
index fd80923..877afab 100644
--- a/config.def.h
+++ b/config.def.h
@@ -162,6 +162,7 @@ MouseShortcut mshortcuts[] = {
 
 /* Internal keyboard shortcuts. */
 #define MODKEY Mod1Mask
+#define TERMMOD (ControlMask|ShiftMask)
 
 Shortcut shortcuts[] = {
 	/* mask                 keysym          function        argument */
@@ -169,15 +170,14 @@ Shortcut shortcuts[] = {
 	{ ControlMask,          XK_Print,       toggleprinter,  {.i =  0} },
 	{ ShiftMask,            XK_Print,       printscreen,    {.i =  0} },
 	{ XK_ANY_MOD,           XK_Print,       printsel,       {.i =  0} },
-	{ MODKEY|ShiftMask,     XK_Prior,       zoom,           {.f = +1} },
-	{ MODKEY|ShiftMask,     XK_Next,        zoom,           {.f = -1} },
-	{ MODKEY|ShiftMask,     XK_Home,        zoomreset,      {.f =  0} },
-	{ ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
-	{ MODKEY|ShiftMask,     XK_Insert,      clippaste,      {.i =  0} },
-	{ MODKEY|ShiftMask,     XK_C,           clipcopy,       {.i =  0} },
-	{ MODKEY|ShiftMask,     XK_V,           clippaste,      {.i =  0} },
-	{ MODKEY,               XK_Num_Lock,    numlock,        {.i =  0} },
-	{ MODKEY,               XK_Control_L,   iso14755,       {.i =  0} },
+	{ TERMMOD,              XK_Prior,       zoom,           {.f = +1} },
+	{ TERMMOD,              XK_Next,        zoom,           {.f = -1} },
+	{ TERMMOD,              XK_Home,        zoomreset,      {.f =  0} },
+	{ TERMMOD,              XK_C,           clipcopy,       {.i =  0} },
+	{ TERMMOD,              XK_V,           clippaste,      {.i =  0} },
+	{ TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
+	{ TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
+	{ TERMMOD,              XK_I,           iso14755,       {.i =  0} },
 };
 
 /*

From e7ed326d2e914a57017c9f34459824614075519b Mon Sep 17 00:00:00 2001
From: "osandov@osandov.com" <osandov@osandov.com>
Date: Sat, 18 Mar 2017 11:55:04 +0100
Subject: [PATCH 0949/1146] Support xterm Ms feature to set clipboard

This is used by, e.g., tmux.
---
 st.c    | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 st.info |  1 +
 win.h   |  1 +
 x.c     |  1 -
 4 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 1e4196e..d7bd32a 100644
--- a/st.c
+++ b/st.c
@@ -198,6 +198,8 @@ static char utf8encodebyte(Rune, size_t);
 static char *utf8strchr(char *s, Rune u);
 static size_t utf8validate(Rune *, size_t);
 
+static char *base64dec(const char *);
+
 static ssize_t xwrite(int, const char *, size_t);
 static void *xrealloc(void *, size_t);
 
@@ -369,6 +371,48 @@ utf8validate(Rune *u, size_t i)
 	return i;
 }
 
+static const char base64_digits[] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0,
+	63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, -1, 0, 0, 0, 0, 1,
+	2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+	22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+	35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+char *
+base64dec(const char *src)
+{
+	size_t in_len = strlen(src);
+	char *result, *dst;
+
+	if (in_len % 4)
+		return NULL;
+	result = dst = xmalloc(in_len / 4 * 3 + 1);
+	while (*src) {
+		int a = base64_digits[(unsigned char) *src++];
+		int b = base64_digits[(unsigned char) *src++];
+		int c = base64_digits[(unsigned char) *src++];
+		int d = base64_digits[(unsigned char) *src++];
+
+		*dst++ = (a << 2) | ((b & 0x30) >> 4);
+		if (c == -1)
+			break;
+		*dst++ = ((b & 0x0f) << 4) | ((c & 0x3c) >> 2);
+		if (d == -1)
+			break;
+		*dst++ = ((c & 0x03) << 6) | d;
+	}
+	*dst = '\0';
+	return result;
+}
+
 void
 selinit(void)
 {
@@ -1820,6 +1864,19 @@ strhandle(void)
 			if (narg > 1)
 				xsettitle(strescseq.args[1]);
 			return;
+		case 52:
+			if (narg > 2) {
+				char *dec;
+
+				dec = base64dec(strescseq.args[2]);
+				if (dec) {
+					xsetsel(dec, CurrentTime);
+					clipcopy(NULL);
+				} else {
+					fprintf(stderr, "erresc: invalid base64\n");
+				}
+			}
+			return;
 		case 4: /* color set */
 			if (narg < 3)
 				break;
diff --git a/st.info b/st.info
index 13cc8eb..0b928af 100644
--- a/st.info
+++ b/st.info
@@ -189,6 +189,7 @@ st| simpleterm,
 	Se,
 	Ss,
 	Tc,
+	Ms=\E]52;%p1%s;%p2%s\007,
 
 st-256color| simpleterm with 256 colors,
 	use=st,
diff --git a/win.h b/win.h
index d684797..428111c 100644
--- a/win.h
+++ b/win.h
@@ -27,3 +27,4 @@ void xunloadfonts(void);
 void xresize(int, int);
 void xselpaste(void);
 unsigned long xwinid(void);
+void xsetsel(char *, Time);
diff --git a/x.c b/x.c
index 6474a01..743b084 100644
--- a/x.c
+++ b/x.c
@@ -88,7 +88,6 @@ static void xclear(int, int, int, int);
 static void xdrawcursor(void);
 static int xgeommasktogravity(int);
 static int xloadfont(Font *, FcPattern *);
-static void xsetsel(char *, Time);
 static void xunloadfont(Font *);
 
 static void expose(XEvent *);

From f2bfd513b14a2aa27796670235557a550b4189db Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nils=20Reu=C3=9Fe?= <n.reusse@hxgn.net>
Date: Wed, 29 Mar 2017 18:34:12 +0200
Subject: [PATCH 0950/1146] keep some glyph modes for the cursor

st currently does not keep any mode for the cursor that was active
in the underlying glyph (e.g. italic text), the mode is always
ATTR_NULL [1].  At [2] you can find a screenshot that shows the
implications.  Other terminals (at least vte-based, such as
XFCE-terminal) keep some modes for the cursor.  I find the current
behaviour very disruptive, so here is a patch that keeps a few
(arbitrarily chosen) modes for the cursor.

[1] http://git.suckless.org/st/tree/st.c#n3963
[2] http://i.imgur.com/R2yCEaC.png
---
 x.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/x.c b/x.c
index 743b084..b7339e9 100644
--- a/x.c
+++ b/x.c
@@ -1266,6 +1266,7 @@ xdrawcursor(void)
 	Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og;
 	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 	Color drawcol;
+	unsigned attr;
 
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
@@ -1285,6 +1286,8 @@ xdrawcursor(void)
 	xdrawglyph(og, oldx, oldy);
 
 	g.u = term.line[term.c.y][term.c.x].u;
+	attr = ATTR_BOLD | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_STRUCK;
+	g.mode |= term.line[term.c.y][term.c.x].mode & attr;
 
 	/*
 	 * Select the right color for the right mode.

From 149c0d3aedffe69b625ef95868daae200941d5f5 Mon Sep 17 00:00:00 2001
From: Alexander Krotov <ilabdsf@gmail.com>
Date: Sat, 25 Mar 2017 23:02:42 +0300
Subject: [PATCH 0951/1146] Fix commented out code

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index d7bd32a..ae93ade 100644
--- a/st.c
+++ b/st.c
@@ -2537,7 +2537,7 @@ tresize(int col, int row)
 	}
 
 	/* allocate any new rows */
-	for (/* i == minrow */; i < row; i++) {
+	for (/* i = minrow */; i < row; i++) {
 		term.line[i] = xmalloc(col * sizeof(Glyph));
 		term.alt[i] = xmalloc(col * sizeof(Glyph));
 	}

From 745c40f8b07ab898d1f9d4f564881b40599bc80d Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Tue, 4 Apr 2017 17:20:55 +0200
Subject: [PATCH 0952/1146] Simplify how we keep ATTRs under cursor

Thanks to tarug0 for the suggestion/patch.
---
 x.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/x.c b/x.c
index b7339e9..fbfd350 100644
--- a/x.c
+++ b/x.c
@@ -1266,7 +1266,6 @@ xdrawcursor(void)
 	Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og;
 	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 	Color drawcol;
-	unsigned attr;
 
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
@@ -1286,8 +1285,8 @@ xdrawcursor(void)
 	xdrawglyph(og, oldx, oldy);
 
 	g.u = term.line[term.c.y][term.c.x].u;
-	attr = ATTR_BOLD | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_STRUCK;
-	g.mode |= term.line[term.c.y][term.c.x].mode & attr;
+	g.mode |= term.line[term.c.y][term.c.x].mode &
+	          (ATTR_BOLD | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_STRUCK);
 
 	/*
 	 * Select the right color for the right mode.

From 5a10aca702bf7bc9094cb4abaea6c59558740d29 Mon Sep 17 00:00:00 2001
From: "greg.reagle@umbc.edu" <greg.reagle@umbc.edu>
Date: Mon, 10 Apr 2017 18:24:03 +0200
Subject: [PATCH 0953/1146] st.1: modify man page to accurately reflect default
 keybindings

Attached.

===> 2/ (text/x-patch) [file]
	cp /mail/fs/mbox/298/2/body /usr/k0ga/0001-st.1-modify-man-page-to-accurately-reflect-default-k.patch

From 265db94b1eca5850d484f86b7db4af8e57822cfe Mon Sep 17 00:00:00 2001
From: Greg Reagle <greg.reagle@umbc.edu>
Date: Sun, 9 Apr 2017 23:05:47 -0400
Subject: [PATCH] st.1: modify man page to accurately reflect default
 keybindings
---
 st.1 | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/st.1 b/st.1
index c429dcf..bbca7e5 100644
--- a/st.1
+++ b/st.1
@@ -142,28 +142,25 @@ Print the full screen to the
 Print the selection to the
 .I iofile.
 .TP
-.B Alt-Shift-Page Up
+.B Ctrl-Shift-Page Up
 Increase font size.
 .TP
-.B Alt-Shift-Page Down
+.B Ctrl-Shift-Page Down
 Decrease font size.
 .TP
-.B Alt-Shift-Home
+.B Ctrl-Shift-Home
 Reset to default font size.
 .TP
-.B Shift-Insert
+.B Ctrl-Shift-y
 Paste from primary selection (middle mouse button).
 .TP
-.B Alt-Shift-Insert
-Paste from clipboard selection.
-.TP
-.B Alt-Shift-c
+.B Ctrl-Shift-c
 Copy the selected text to the clipboard selection.
 .TP
-.B Alt-Shift-v
+.B Ctrl-Shift-v
 Paste from the clipboard selection.
 .TP
-.B Alt-Ctrl
+.B Ctrl-Shift-i
 Launch dmenu to enter a unicode codepoint and send the corresponding glyph
 to st.
 .SH CUSTOMIZATION

From 6cb6d61525931c88971cce323f63e40451a6d365 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Sun, 28 May 2017 09:56:57 +0200
Subject: [PATCH 0954/1146] Add bold off SGR

---
 st.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.c b/st.c
index ae93ade..8d4a9f2 100644
--- a/st.c
+++ b/st.c
@@ -1402,6 +1402,9 @@ tsetattr(int *attr, int l)
 		case 9:
 			term.c.attr.mode |= ATTR_STRUCK;
 			break;
+		case 21:
+			term.c.attr.mode &= ~ATTR_BOLD;
+			break;
 		case 22:
 			term.c.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT);
 			break;

From b331da550b290d54592b7ba11242c92f5a303a48 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marc=20Andr=C3=A9=20Tanner?= <mat@brain-dump.org>
Date: Mon, 15 May 2017 12:45:41 +0200
Subject: [PATCH 0955/1146] Add color change terminfo capabilities

---
 st.info | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/st.info b/st.info
index 0b928af..4d77eae 100644
--- a/st.info
+++ b/st.info
@@ -193,9 +193,12 @@ st| simpleterm,
 
 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,
 

From fabd4602b3223666165c76c397644a081b9a97e5 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Wed, 12 Jul 2017 00:24:51 +0200
Subject: [PATCH 0956/1146] Do not obfuscate what make is doing.

Change some styling too while we're at it.
---
 Makefile  | 56 ++++++++++++++++++++++++-------------------------------
 config.mk | 16 ++++++++--------
 2 files changed, 32 insertions(+), 40 deletions(-)

diff --git a/Makefile b/Makefile
index d8595fe..f5b84a0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,63 +1,55 @@
 # st - simple terminal
 # See LICENSE file for copyright and license details.
+.POSIX:
 
 include config.mk
 
 SRC = st.c x.c
-OBJ = ${SRC:.c=.o}
+OBJ = $(SRC:.c=.o)
 
 all: options st
 
 options:
 	@echo st build options:
-	@echo "CFLAGS   = ${CFLAGS}"
-	@echo "LDFLAGS  = ${LDFLAGS}"
-	@echo "CC       = ${CC}"
+	@echo "CFLAGS  = $(CFLAGS)"
+	@echo "LDFLAGS = $(LDFLAGS)"
+	@echo "CC      = $(CC)"
 
 config.h:
 	cp config.def.h config.h
 
 .c.o:
-	@echo CC $<
-	@${CC} -c ${CFLAGS} $<
+	$(CC) $(CFLAGS) -c $<
 
 st.o: config.h st.h win.h
 x.o: arg.h st.h win.h
 
-${OBJ}: config.h config.mk
+$(OBJ): config.h config.mk
 
-st: ${OBJ}
-	@echo CC -o $@
-	@${CC} -o $@ ${OBJ} ${LDFLAGS}
+st: $(OBJ)
+	$(CC) $(LDFLAGS) -o $@ $(OBJ)
 
 clean:
-	@echo cleaning
-	@rm -f st ${OBJ} st-${VERSION}.tar.gz
+	rm -f st $(OBJ) st-$(VERSION).tar.gz
 
 dist: clean
-	@echo creating dist tarball
-	@mkdir -p st-${VERSION}
-	@cp -R LICENSE Makefile README config.mk config.def.h st.info st.1 arg.h ${SRC} st-${VERSION}
-	@tar -cf st-${VERSION}.tar st-${VERSION}
-	@gzip st-${VERSION}.tar
-	@rm -rf st-${VERSION}
+	mkdir -p st-$(VERSION)
+	cp -R LICENSE Makefile README config.mk config.def.h st.info st.1 arg.h $(SRC) st-$(VERSION)
+	tar -cf - st-$(VERSION) | gzip > st-$(VERSION).tar.gz
+	rm -rf st-$(VERSION)
 
-install: all
-	@echo installing executable file to ${DESTDIR}${PREFIX}/bin
-	@mkdir -p ${DESTDIR}${PREFIX}/bin
-	@cp -f st ${DESTDIR}${PREFIX}/bin
-	@chmod 755 ${DESTDIR}${PREFIX}/bin/st
-	@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
-	@mkdir -p ${DESTDIR}${MANPREFIX}/man1
-	@sed "s/VERSION/${VERSION}/g" < st.1 > ${DESTDIR}${MANPREFIX}/man1/st.1
-	@chmod 644 ${DESTDIR}${MANPREFIX}/man1/st.1
+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.
-	@tic -sx st.info
 
 uninstall:
-	@echo removing executable file from ${DESTDIR}${PREFIX}/bin
-	@rm -f ${DESTDIR}${PREFIX}/bin/st
-	@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
-	@rm -f ${DESTDIR}${MANPREFIX}/man1/st.1
+	rm -f $(DESTDIR)$(PREFIX)/bin/st
+	rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
 
 .PHONY: all options clean dist install uninstall
diff --git a/config.mk b/config.mk
index c84c5ee..527a64d 100644
--- a/config.mk
+++ b/config.mk
@@ -5,24 +5,24 @@ VERSION = 0.7
 
 # paths
 PREFIX = /usr/local
-MANPREFIX = ${PREFIX}/share/man
+MANPREFIX = $(PREFIX)/share/man
 
 X11INC = /usr/X11R6/include
 X11LIB = /usr/X11R6/lib
 
 # includes and libs
-INCS = -I. -I/usr/include -I${X11INC} \
+INCS = -I$(X11INC) \
        `pkg-config --cflags fontconfig` \
        `pkg-config --cflags freetype2`
-LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXft \
-       `pkg-config --libs fontconfig`  \
+LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
+       `pkg-config --libs fontconfig` \
        `pkg-config --libs freetype2`
 
 # flags
-CPPFLAGS = -DVERSION=\"${VERSION}\" -D_XOPEN_SOURCE=600
-CFLAGS += -g -std=c99 -pedantic -Wall -Wvariadic-macros -Os ${INCS} ${CPPFLAGS}
-LDFLAGS += -g ${LIBS}
+CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+CFLAGS = -g -std=c99 -pedantic -Wall -Wvariadic-macros -Os $(INCS) $(CPPFLAGS)
+LDFLAGS = -g $(LIBS)
 
 # compiler and linker
-# CC = cc
+# CC = c99
 

From d4928edba0fe2cc63b3bc13fd6dad0bcb875174e Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Wed, 12 Jul 2017 00:26:35 +0200
Subject: [PATCH 0957/1146] Let the user specify C and LD FLAGS

---
 Makefile  | 8 ++++----
 config.mk | 4 ++--
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index f5b84a0..128ee9d 100644
--- a/Makefile
+++ b/Makefile
@@ -11,15 +11,15 @@ all: options st
 
 options:
 	@echo st build options:
-	@echo "CFLAGS  = $(CFLAGS)"
-	@echo "LDFLAGS = $(LDFLAGS)"
+	@echo "CFLAGS  = $(STCFLAGS)"
+	@echo "LDFLAGS = $(STLDFLAGS)"
 	@echo "CC      = $(CC)"
 
 config.h:
 	cp config.def.h config.h
 
 .c.o:
-	$(CC) $(CFLAGS) -c $<
+	$(CC) $(STCFLAGS) -c $<
 
 st.o: config.h st.h win.h
 x.o: arg.h st.h win.h
@@ -27,7 +27,7 @@ x.o: arg.h st.h win.h
 $(OBJ): config.h config.mk
 
 st: $(OBJ)
-	$(CC) $(LDFLAGS) -o $@ $(OBJ)
+	$(CC) $(STLDFLAGS) -o $@ $(OBJ)
 
 clean:
 	rm -f st $(OBJ) st-$(VERSION).tar.gz
diff --git a/config.mk b/config.mk
index 527a64d..0aceec4 100644
--- a/config.mk
+++ b/config.mk
@@ -20,8 +20,8 @@ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
 
 # flags
 CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
-CFLAGS = -g -std=c99 -pedantic -Wall -Wvariadic-macros -Os $(INCS) $(CPPFLAGS)
-LDFLAGS = -g $(LIBS)
+STCFLAGS = $(INCS) $(CPPFLAGS) $(CFLAGS)
+STLDFLAGS = $(LIBS) $(LDFLAGS)
 
 # compiler and linker
 # CC = c99

From c0882f2ed1d7a2dd0fa2efa52157e6fc6fde3652 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Tue, 11 Jul 2017 23:03:27 +0200
Subject: [PATCH 0958/1146] Add dim/smxx/rmxx to terminfo, remove duplicate
 kich1

---
 st.info | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/st.info b/st.info
index 4d77eae..52fc617 100644
--- a/st.info
+++ b/st.info
@@ -25,6 +25,7 @@ st| simpleterm,
 	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,
@@ -142,7 +143,6 @@ st| simpleterm,
 	khome=\E[1~,
 	kil1=\E[2;5~,
 	krmir=\E[2;2~,
-	kich1=\E[2~,
 	knp=\E[6~,
 	kmous=\E[M,
 	kpp=\E[5~,
@@ -185,7 +185,10 @@ st| simpleterm,
 	tsl=\E]0;,
 	xenl,
 	vpa=\E[%i%p1%dd,
-# Tmux unofficial extensions, see TERMINFO EXTENSIONS in tmux(1)
+# XTerm extensions
+	rmxx=\E[29m,
+	smxx=\E[9m,
+# tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
 	Se,
 	Ss,
 	Tc,

From 8dacdfbab1c476063a31bc3b8d7222ac2b70ff66 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Tue, 11 Jul 2017 23:16:25 +0200
Subject: [PATCH 0959/1146] Revert "Add bold off SGR"

This reverts commit 6cb6d61525931c88971cce323f63e40451a6d365.
This wasn't a useful thing after all.
---
 st.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/st.c b/st.c
index 8d4a9f2..ae93ade 100644
--- a/st.c
+++ b/st.c
@@ -1402,9 +1402,6 @@ tsetattr(int *attr, int l)
 		case 9:
 			term.c.attr.mode |= ATTR_STRUCK;
 			break;
-		case 21:
-			term.c.attr.mode &= ~ATTR_BOLD;
-			break;
 		case 22:
 			term.c.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT);
 			break;

From 7f990328e4fec8dfaaad311cb8af2304b58c872e Mon Sep 17 00:00:00 2001
From: Anselm R Garbe <anselm@garbe.us>
Date: Sun, 23 Jul 2017 11:17:26 +0200
Subject: [PATCH 0960/1146] fixed STLDFLAG order in broken st Makefile

---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 128ee9d..c678ead 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ x.o: arg.h st.h win.h
 $(OBJ): config.h config.mk
 
 st: $(OBJ)
-	$(CC) $(STLDFLAGS) -o $@ $(OBJ)
+	$(CC) -o $@ $(OBJ) $(STLDFLAGS)
 
 clean:
 	rm -f st $(OBJ) st-$(VERSION).tar.gz

From 77c51c5a6b16387f1792e23acbcf2080f790aa25 Mon Sep 17 00:00:00 2001
From: Anselm R Garbe <anselm@garbe.us>
Date: Fri, 1 Sep 2017 09:48:24 +0200
Subject: [PATCH 0961/1146] make clipboard patch obsolete

---
 x.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/x.c b/x.c
index fbfd350..ab9593e 100644
--- a/x.c
+++ b/x.c
@@ -507,6 +507,7 @@ xsetsel(char *str, Time t)
 	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
 	if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
 		selclear_(NULL);
+	xclipcopy();
 }
 
 void

From 9c61f29bb7da237907e42875ebe7d0084e8ab1ac Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 2 Sep 2017 13:52:33 +0200
Subject: [PATCH 0962/1146] Revert "make clipboard patch obsolete"

This reverts commit 77c51c5a6b16387f1792e23acbcf2080f790aa25.

Having multiple clipboards are useful, for example for plumber scripts.
I've discussed this on IRC and it is useful to have.
---
 x.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/x.c b/x.c
index ab9593e..fbfd350 100644
--- a/x.c
+++ b/x.c
@@ -507,7 +507,6 @@ xsetsel(char *str, Time t)
 	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
 	if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
 		selclear_(NULL);
-	xclipcopy();
 }
 
 void

From 274d46ace00003d1df718b974d17642cbce167d5 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Wed, 13 Sep 2017 22:40:36 +0200
Subject: [PATCH 0963/1146] Revert "fixed STLDFLAG order in broken st Makefile"

This reverts commit 7f990328e4fec8dfaaad311cb8af2304b58c872e.

this was wrong as pointed out by k0ga:
"STLDFLAGS is about flags to the linker, for example -L
not about -l for that reason it must go before the object list".
---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index c678ead..128ee9d 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ x.o: arg.h st.h win.h
 $(OBJ): config.h config.mk
 
 st: $(OBJ)
-	$(CC) -o $@ $(OBJ) $(STLDFLAGS)
+	$(CC) $(STLDFLAGS) -o $@ $(OBJ)
 
 clean:
 	rm -f st $(OBJ) st-$(VERSION).tar.gz

From ee5cc8e903574bf629e5159334ae6b0fad6af402 Mon Sep 17 00:00:00 2001
From: "Suraj N. Kurapati" <sunaku@riseup.net>
Date: Thu, 17 Aug 2017 23:00:10 -0700
Subject: [PATCH 0964/1146] base64dec: skip non-printable characters like \r\n

Non-printable characters, such as line breaks, in a base64 encoded
string violate the "string length must be a multiple of four" rule.

This patch pads the result buffer by one extra unit of four bytes,
and skips over non-printable characters found in the input string.
---
 st.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/st.c b/st.c
index ae93ade..7c7ddff 100644
--- a/st.c
+++ b/st.c
@@ -386,6 +386,13 @@ static const char base64_digits[] = {
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
+char
+base64dec_getc(const char **src)
+{
+	while (**src && !isprint(**src)) (*src)++;
+	return *((*src)++);
+}
+
 char *
 base64dec(const char *src)
 {
@@ -393,13 +400,13 @@ base64dec(const char *src)
 	char *result, *dst;
 
 	if (in_len % 4)
-		return NULL;
+		in_len += 4 - (in_len % 4);
 	result = dst = xmalloc(in_len / 4 * 3 + 1);
 	while (*src) {
-		int a = base64_digits[(unsigned char) *src++];
-		int b = base64_digits[(unsigned char) *src++];
-		int c = base64_digits[(unsigned char) *src++];
-		int d = base64_digits[(unsigned char) *src++];
+		int a = base64_digits[(unsigned char) base64dec_getc(&src)];
+		int b = base64_digits[(unsigned char) base64dec_getc(&src)];
+		int c = base64_digits[(unsigned char) base64dec_getc(&src)];
+		int d = base64_digits[(unsigned char) base64dec_getc(&src)];
 
 		*dst++ = (a << 2) | ((b & 0x30) >> 4);
 		if (c == -1)

From b2ac91775302fa4b8ce462a6e7bcfffa93923471 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 15 Sep 2017 11:16:37 +0200
Subject: [PATCH 0965/1146] Revert "Revert "fixed STLDFLAG order in broken st
 Makefile""

This reverts commit 274d46ace00003d1df718b974d17642cbce167d5.

Sorry, the original commit was correct after all. It allows has the
correct link order and supports static-linking also.

Just a reminder: it is important to give a (brief) rationale of the
patch intentions.
---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 128ee9d..c678ead 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ x.o: arg.h st.h win.h
 $(OBJ): config.h config.mk
 
 st: $(OBJ)
-	$(CC) $(STLDFLAGS) -o $@ $(OBJ)
+	$(CC) -o $@ $(OBJ) $(STLDFLAGS)
 
 clean:
 	rm -f st $(OBJ) st-$(VERSION).tar.gz

From b1338e91ed632adbcd08388de37e46cf25326e01 Mon Sep 17 00:00:00 2001
From: Gary Allen Vollink <gary@vollink.com>
Date: Thu, 14 Sep 2017 15:30:02 -0400
Subject: [PATCH 0966/1146] Add an error for XftFontOpenPattern failure.

---
 x.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/x.c b/x.c
index fbfd350..191e5dc 100644
--- a/x.c
+++ b/x.c
@@ -1092,6 +1092,9 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
 
 			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;
 

From 0ac685fc015362e749bf82cfaa3cfe2dd9b305f0 Mon Sep 17 00:00:00 2001
From: Paride Legovini <pl@ninthfloor.org>
Date: Tue, 10 Oct 2017 17:49:38 +0200
Subject: [PATCH 0967/1146] Fix manpage typo

Signed-off-by: Paride Legovini <pl@ninthfloor.org>
---
 st.1 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.1 b/st.1
index bbca7e5..81bceff 100644
--- a/st.1
+++ b/st.1
@@ -120,7 +120,7 @@ st executes
 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 compability,
+This option is only intended for compatibility,
 and all the remaining arguments are used as a command
 even without it.
 .SH SHORTCUTS

From c1d23afa9c44cc29818c538126790ae90a64a3c5 Mon Sep 17 00:00:00 2001
From: George Ornbo <george@shapeshed.com>
Date: Wed, 20 Dec 2017 09:05:32 +0000
Subject: [PATCH 0968/1146] Fix FAQ typo

---
 FAQ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/FAQ b/FAQ
index 4defff9..921c493 100644
--- a/FAQ
+++ b/FAQ
@@ -6,7 +6,7 @@ Use the excellent tool of [utmp](http://git.suckless.org/utmp/) for this task.
 
 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 manualy run `tic -sx st.info`.
+you can manually run `tic -sx st.info`.
 
 ## Nothing works, and nothing is said about an unknown terminal!
 

From e829e13bb1a830e0cdce749ea0865cd93af1846c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benno=20F=C3=BCnfst=C3=BCck?= <benno.fuenfstueck@gmail.com>
Date: Tue, 26 Dec 2017 16:38:27 +0100
Subject: [PATCH 0969/1146] Apply ATTR_REVERSE after ATTR_FAINT

An example where the new behaviour makes more sense:

Suppose some text is formatted with ATTR_FAINT for red for the foreground, so it
is rendered in a dark red. In that case, when selected with the mouse, the
intended behaviour is that foreground and background color are swapped: so the
selection should be rendered in dark red and the text in the default background
color.

Before this patch, what happened was that the selection would be in normal red
and the text in the darkened background color, making it almost unreadable.

For an example application that uses the FAINT attribute, try dmesg from
util-linux with color support, it uses FAINT for segfault messages.
---
 x.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/x.c b/x.c
index 191e5dc..474d73b 100644
--- a/x.c
+++ b/x.c
@@ -1189,12 +1189,6 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 		}
 	}
 
-	if (base.mode & ATTR_REVERSE) {
-		temp = fg;
-		fg = bg;
-		bg = temp;
-	}
-
 	if ((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) {
 		colfg.red = fg->color.red / 2;
 		colfg.green = fg->color.green / 2;
@@ -1203,6 +1197,13 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 		fg = &revfg;
 	}
 
+
+	if (base.mode & ATTR_REVERSE) {
+		temp = fg;
+		fg = bg;
+		bg = temp;
+	}
+
 	if (base.mode & ATTR_BLINK && term.mode & MODE_BLINK)
 		fg = bg;
 

From 1f24bde82b19912c080fbb4a0b153a248cd6c6ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benno=20F=C3=BCnfst=C3=BCck?= <benno.fuenfstueck@gmail.com>
Date: Tue, 26 Dec 2017 16:23:24 +0100
Subject: [PATCH 0970/1146] Fix color with FAINT attribute

The alpha value needs to be initialized as well.
---
 x.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/x.c b/x.c
index 474d73b..c484dfc 100644
--- a/x.c
+++ b/x.c
@@ -1193,6 +1193,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 		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;
 	}

From 3e44ee5569a81ba6f06e1ecd19bf0ceb1e97f18d Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Tue, 10 Oct 2017 10:30:23 -0500
Subject: [PATCH 0971/1146] Call xsetenv() in main process instead of child

This makes xsetenv internal to x.c, and allows iso14755's external
command to use $WINDOWID instead of having to snprintf it again.  (The
same benefit will apply to the externalpipe patch.)  The xwinid function
is no longer needed.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c  | 8 ++------
 win.h | 2 --
 x.c   | 8 ++------
 3 files changed, 4 insertions(+), 14 deletions(-)

diff --git a/st.c b/st.c
index 7c7ddff..668b312 100644
--- a/st.c
+++ b/st.c
@@ -60,7 +60,7 @@ char *argv0;
 #define ISDELIM(u)		(utf8strchr(worddelimiters, u) != NULL)
 
 /* constants */
-#define ISO14755CMD		"dmenu -w %lu -p codepoint: </dev/null"
+#define ISO14755CMD		"dmenu -w \"$WINDOWID\" -p codepoint: </dev/null"
 
 enum cursor_movement {
 	CURSOR_SAVE,
@@ -706,7 +706,6 @@ execsh(void)
 	setenv("SHELL", sh, 1);
 	setenv("HOME", pw->pw_dir, 1);
 	setenv("TERM", termname, 1);
-	xsetenv();
 
 	signal(SIGCHLD, SIG_DFL);
 	signal(SIGHUP, SIG_DFL);
@@ -1993,14 +1992,11 @@ tprinter(char *s, size_t len)
 void
 iso14755(const Arg *arg)
 {
-	unsigned long id = xwinid();
-	char cmd[sizeof(ISO14755CMD) + NUMMAXLEN(id)];
 	FILE *p;
 	char *us, *e, codepoint[9], uc[UTF_SIZ];
 	unsigned long utf32;
 
-	snprintf(cmd, sizeof(cmd), ISO14755CMD, id);
-	if (!(p = popen(cmd, "r")))
+	if (!(p = popen(ISO14755CMD, "r")))
 		return;
 
 	us = fgets(codepoint, sizeof(codepoint), p);
diff --git a/win.h b/win.h
index 428111c..423c114 100644
--- a/win.h
+++ b/win.h
@@ -19,12 +19,10 @@ void xinit(void);
 void xloadcols(void);
 int xsetcolorname(int, const char *);
 void xloadfonts(char *, double);
-void xsetenv(void);
 void xsettitle(char *);
 void xsetpointermotion(int);
 void xseturgency(int);
 void xunloadfonts(void);
 void xresize(int, int);
 void xselpaste(void);
-unsigned long xwinid(void);
 void xsetsel(char *, Time);
diff --git a/x.c b/x.c
index c484dfc..df2a88c 100644
--- a/x.c
+++ b/x.c
@@ -89,6 +89,7 @@ static void xdrawcursor(void);
 static int xgeommasktogravity(int);
 static int xloadfont(Font *, FcPattern *);
 static void xunloadfont(Font *);
+static void xsetenv(void);
 
 static void expose(XEvent *);
 static void visibility(XEvent *);
@@ -1487,12 +1488,6 @@ xbell(int vol)
 	XkbBell(xw.dpy, xw.win, vol, (Atom)NULL);
 }
 
-unsigned long
-xwinid(void)
-{
-	return xw.win;
-}
-
 void
 focus(XEvent *ev)
 {
@@ -1765,6 +1760,7 @@ run:
 	XSetLocaleModifiers("");
 	tnew(MAX(cols, 1), MAX(rows, 1));
 	xinit();
+	xsetenv();
 	selinit();
 	run();
 

From 3518dba2a5fb57f601b74528ddeb67f173e4024b Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Tue, 10 Oct 2017 11:11:27 -0500
Subject: [PATCH 0972/1146] Move usage() to be with run() in x.c

run/usage/xinit are now all internal to x.c

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c  | 15 ---------------
 st.h  |  2 --
 win.h |  2 --
 x.c   | 18 ++++++++++++++++++
 4 files changed, 18 insertions(+), 19 deletions(-)

diff --git a/st.c b/st.c
index 668b312..6338510 100644
--- a/st.c
+++ b/st.c
@@ -28,8 +28,6 @@
 #include <X11/cursorfont.h>
 #include <X11/Xft/Xft.h>
 
-char *argv0;
-
 #define Glyph Glyph_
 #define Font Font_
 
@@ -2687,16 +2685,3 @@ cresize(int width, int height)
 	tresize(col, row);
 	xresize(col, row);
 }
-
-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);
-}
diff --git a/st.h b/st.h
index 44d4938..28a751d 100644
--- a/st.h
+++ b/st.h
@@ -214,8 +214,6 @@ size_t utf8encode(Rune, char *);
 void *xmalloc(size_t);
 char *xstrdup(char *);
 
-void usage(void);
-
 /* Globals */
 extern TermWindow win;
 extern Term term;
diff --git a/win.h b/win.h
index 423c114..60cecb1 100644
--- a/win.h
+++ b/win.h
@@ -9,13 +9,11 @@ typedef XftGlyphFontSpec GlyphFontSpec;
 
 void draw(void);
 void drawregion(int, int, int, int);
-void run(void);
 
 void xbell(int);
 void xclipcopy(void);
 void xclippaste(void);
 void xhints(void);
-void xinit(void);
 void xloadcols(void);
 int xsetcolorname(int, const char *);
 void xloadfonts(char *, double);
diff --git a/x.c b/x.c
index df2a88c..f660ca3 100644
--- a/x.c
+++ b/x.c
@@ -15,6 +15,7 @@
 #include <X11/Xft/Xft.h>
 #include <X11/XKBlib.h>
 
+static char *argv0;
 #include "arg.h"
 
 #define Glyph Glyph_
@@ -87,6 +88,7 @@ static void xdrawglyph(Glyph, int, int);
 static void xclear(int, int, int, int);
 static void xdrawcursor(void);
 static int xgeommasktogravity(int);
+static void xinit(void);
 static int xloadfont(Font *, FcPattern *);
 static void xunloadfont(Font *);
 static void xsetenv(void);
@@ -110,6 +112,9 @@ static void selcopy(Time);
 static void getbuttoninfo(XEvent *);
 static void mousereport(XEvent *);
 
+static void run(void);
+static void usage(void);
+
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
 	[ClientMessage] = cmessage,
@@ -1698,6 +1703,19 @@ run(void)
 	}
 }
 
+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[])
 {

From d5275012b45149a2a6e94679609aacca478221ad Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Tue, 10 Oct 2017 11:30:36 -0500
Subject: [PATCH 0973/1146] Move zoom functions into x.c

This makes x(un)loadfonts internal to x.c.  Needed to reorder includes
and move a typedef to keep the compiler happy.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c  | 36 +-----------------------------------
 st.h  |  1 +
 win.h |  7 +++----
 x.c   | 35 ++++++++++++++++++++++++++++++++++-
 4 files changed, 39 insertions(+), 40 deletions(-)

diff --git a/st.c b/st.c
index 6338510..f1f7bc1 100644
--- a/st.c
+++ b/st.c
@@ -31,8 +31,8 @@
 #define Glyph Glyph_
 #define Font Font_
 
-#include "win.h"
 #include "st.h"
+#include "win.h"
 
 #if   defined(__linux)
  #include <pty.h>
@@ -128,9 +128,6 @@ 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 printsel(const Arg *);
 static void printscreen(const Arg *) ;
 static void iso14755(const Arg *);
@@ -2573,37 +2570,6 @@ tresize(int col, int row)
 	term.c = c;
 }
 
-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);
-	ttyresize();
-	redraw();
-	xhints();
-}
-
-void
-zoomreset(const Arg *arg)
-{
-	Arg larg;
-
-	if (defaultfontsize > 0) {
-		larg.f = defaultfontsize;
-		zoomabs(&larg);
-	}
-}
-
 void
 resettitle(void)
 {
diff --git a/st.h b/st.h
index 28a751d..9ece72f 100644
--- a/st.h
+++ b/st.h
@@ -100,6 +100,7 @@ typedef struct {
 } Glyph;
 
 typedef Glyph *Line;
+typedef XftGlyphFontSpec GlyphFontSpec;
 
 typedef struct {
 	Glyph attr; /* current char attributes */
diff --git a/win.h b/win.h
index 60cecb1..ea45e60 100644
--- a/win.h
+++ b/win.h
@@ -5,8 +5,6 @@
 #define XK_NO_MOD     0
 #define XK_SWITCH_MOD (1<<13)
 
-typedef XftGlyphFontSpec GlyphFontSpec;
-
 void draw(void);
 void drawregion(int, int, int, int);
 
@@ -16,11 +14,12 @@ void xclippaste(void);
 void xhints(void);
 void xloadcols(void);
 int xsetcolorname(int, const char *);
-void xloadfonts(char *, double);
 void xsettitle(char *);
 void xsetpointermotion(int);
 void xseturgency(int);
-void xunloadfonts(void);
 void xresize(int, int);
 void xselpaste(void);
 void xsetsel(char *, Time);
+void zoom(const Arg *);
+void zoomabs(const Arg *);
+void zoomreset(const Arg *);
diff --git a/x.c b/x.c
index f660ca3..426ca28 100644
--- a/x.c
+++ b/x.c
@@ -21,8 +21,8 @@ static char *argv0;
 #define Glyph Glyph_
 #define Font Font_
 
-#include "win.h"
 #include "st.h"
+#include "win.h"
 
 /* XEMBED messages */
 #define XEMBED_FOCUS_IN  4
@@ -90,7 +90,9 @@ static void xdrawcursor(void);
 static int xgeommasktogravity(int);
 static void xinit(void);
 static int xloadfont(Font *, FcPattern *);
+static void xloadfonts(char *, double);
 static void xunloadfont(Font *);
+static void xunloadfonts(void);
 static void xsetenv(void);
 
 static void expose(XEvent *);
@@ -164,6 +166,37 @@ typedef struct {
 static Fontcache frc[16];
 static int frclen = 0;
 
+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);
+	ttyresize();
+	redraw();
+	xhints();
+}
+
+void
+zoomreset(const Arg *arg)
+{
+	Arg larg;
+
+	if (defaultfontsize > 0) {
+		larg.f = defaultfontsize;
+		zoomabs(&larg);
+	}
+}
+
 void
 getbuttoninfo(XEvent *e)
 {

From 626b0ae40c71b6c1e02ece79bf033432647381a6 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Tue, 10 Oct 2017 12:01:18 -0500
Subject: [PATCH 0974/1146] Move window urgency handling entirely into x.c

This allows us to make xseturgency internal.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 config.def.h | 2 +-
 st.c         | 5 +----
 st.h         | 1 +
 win.h        | 3 +--
 x.c          | 8 ++++++--
 5 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/config.def.h b/config.def.h
index 877afab..dd94be2 100644
--- a/config.def.h
+++ b/config.def.h
@@ -60,7 +60,7 @@ unsigned int cursorthickness = 2;
  * bell volume. It must be a value between -100 and 100. Use 0 for disabling
  * it
  */
-static int bellvolume = 0;
+int bellvolume = 0;
 
 /* default TERM value */
 char termname[] = "st-256color";
diff --git a/st.c b/st.c
index f1f7bc1..df43fac 100644
--- a/st.c
+++ b/st.c
@@ -2176,10 +2176,7 @@ tcontrolcode(uchar ascii)
 			/* backwards compatibility to xterm */
 			strhandle();
 		} else {
-			if (!(win.state & WIN_FOCUSED))
-				xseturgency(1);
-			if (bellvolume)
-				xbell(bellvolume);
+			xbell();
 		}
 		break;
 	case '\033': /* ESC */
diff --git a/st.h b/st.h
index 9ece72f..ad94351 100644
--- a/st.h
+++ b/st.h
@@ -246,6 +246,7 @@ extern int allowaltscreen;
 extern unsigned int xfps;
 extern unsigned int actionfps;
 extern unsigned int cursorthickness;
+extern int bellvolume;
 extern unsigned int blinktimeout;
 extern char termname[];
 extern const char *colorname[];
diff --git a/win.h b/win.h
index ea45e60..dee0b7f 100644
--- a/win.h
+++ b/win.h
@@ -8,7 +8,7 @@
 void draw(void);
 void drawregion(int, int, int, int);
 
-void xbell(int);
+void xbell(void);
 void xclipcopy(void);
 void xclippaste(void);
 void xhints(void);
@@ -16,7 +16,6 @@ void xloadcols(void);
 int xsetcolorname(int, const char *);
 void xsettitle(char *);
 void xsetpointermotion(int);
-void xseturgency(int);
 void xresize(int, int);
 void xselpaste(void);
 void xsetsel(char *, Time);
diff --git a/x.c b/x.c
index 426ca28..5b3c97b 100644
--- a/x.c
+++ b/x.c
@@ -94,6 +94,7 @@ static void xloadfonts(char *, double);
 static void xunloadfont(Font *);
 static void xunloadfonts(void);
 static void xsetenv(void);
+static void xseturgency(int);
 
 static void expose(XEvent *);
 static void visibility(XEvent *);
@@ -1521,9 +1522,12 @@ xseturgency(int add)
 }
 
 void
-xbell(int vol)
+xbell(void)
 {
-	XkbBell(xw.dpy, xw.win, vol, (Atom)NULL);
+	if (!(win.state & WIN_FOCUSED))
+		xseturgency(1);
+	if (bellvolume)
+		XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL);
 }
 
 void

From a09138afa57adb4b76dba8ca72dc7ee2642a5c8d Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Tue, 10 Oct 2017 12:17:25 -0500
Subject: [PATCH 0975/1146] Move font/fontspec variables into x.c and XWindow

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c | 11 -----------
 st.h |  8 ++------
 x.c  | 18 +++++++++++++-----
 3 files changed, 15 insertions(+), 22 deletions(-)

diff --git a/st.c b/st.c
index df43fac..540b487 100644
--- a/st.c
+++ b/st.c
@@ -28,9 +28,6 @@
 #include <X11/cursorfont.h>
 #include <X11/Xft/Xft.h>
 
-#define Glyph Glyph_
-#define Font Font_
-
 #include "st.h"
 #include "win.h"
 
@@ -196,7 +193,6 @@ static size_t utf8validate(Rune *, size_t);
 static char *base64dec(const char *);
 
 static ssize_t xwrite(int, const char *, size_t);
-static void *xrealloc(void *, size_t);
 
 /* Globals */
 TermWindow win;
@@ -218,10 +214,6 @@ static CSIEscape csiescseq;
 static STREscape strescseq;
 static int iofd = 1;
 
-char *usedfont = NULL;
-double usedfontsize = 0;
-double defaultfontsize = 0;
-
 static uchar utfbyte[UTF_SIZ + 1] = {0x80,    0, 0xC0, 0xE0, 0xF0};
 static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
 static Rune utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  0x10000};
@@ -2516,9 +2508,6 @@ tresize(int col, int row)
 		free(term.alt[i]);
 	}
 
-	/* resize to new width */
-	term.specbuf = xrealloc(term.specbuf, col * sizeof(GlyphFontSpec));
-
 	/* resize to new height */
 	term.line = xrealloc(term.line, row * sizeof(Line));
 	term.alt  = xrealloc(term.alt,  row * sizeof(Line));
diff --git a/st.h b/st.h
index ad94351..2199c13 100644
--- a/st.h
+++ b/st.h
@@ -92,6 +92,7 @@ typedef unsigned short ushort;
 
 typedef uint_least32_t Rune;
 
+#define Glyph Glyph_
 typedef struct {
 	Rune u;           /* character code */
 	ushort mode;      /* attribute flags */
@@ -100,7 +101,6 @@ typedef struct {
 } Glyph;
 
 typedef Glyph *Line;
-typedef XftGlyphFontSpec GlyphFontSpec;
 
 typedef struct {
 	Glyph attr; /* current char attributes */
@@ -116,7 +116,6 @@ typedef struct {
 	Line *line;   /* screen */
 	Line *alt;    /* alternate screen */
 	int *dirty;  /* dirtyness of lines */
-	GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
 	TCursor c;    /* cursor */
 	int top;      /* top    scroll limit */
 	int bot;      /* bottom scroll limit */
@@ -213,6 +212,7 @@ size_t utf8decode(char *, Rune *, size_t);
 size_t utf8encode(Rune, char *);
 
 void *xmalloc(size_t);
+void *xrealloc(void *, size_t);
 char *xstrdup(char *);
 
 /* Globals */
@@ -231,10 +231,6 @@ extern char *opt_name;
 extern char *opt_title;
 extern int oldbutton;
 
-extern char *usedfont;
-extern double usedfontsize;
-extern double defaultfontsize;
-
 /* config.h globals */
 extern char font[];
 extern int borderpx;
diff --git a/x.c b/x.c
index 5b3c97b..186e408 100644
--- a/x.c
+++ b/x.c
@@ -17,10 +17,6 @@
 
 static char *argv0;
 #include "arg.h"
-
-#define Glyph Glyph_
-#define Font Font_
-
 #include "st.h"
 #include "win.h"
 
@@ -35,6 +31,7 @@ static char *argv0;
 
 typedef XftDraw *Draw;
 typedef XftColor Color;
+typedef XftGlyphFontSpec GlyphFontSpec;
 
 /* Purely graphic info */
 typedef struct {
@@ -42,6 +39,7 @@ typedef struct {
 	Colormap cmap;
 	Window win;
 	Drawable buf;
+	GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
 	Atom xembed, wmdeletewin, netwmname, netwmpid;
 	XIM xim;
 	XIC xic;
@@ -59,6 +57,7 @@ typedef struct {
 } XSelection;
 
 /* Font structure */
+#define Font Font_
 typedef struct {
 	int height;
 	int width;
@@ -166,6 +165,9 @@ typedef struct {
 /* Fontcache is an array now. A new font will be appended to the array. */
 static Fontcache frc[16];
 static int frclen = 0;
+static char *usedfont = NULL;
+static double usedfontsize = 0;
+static double defaultfontsize = 0;
 
 void
 zoom(const Arg *arg)
@@ -605,6 +607,9 @@ xresize(int col, int row)
 			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
@@ -965,6 +970,9 @@ xinit(void)
 	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(term.col * sizeof(GlyphFontSpec));
+
 	/* Xft rendering context */
 	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
 
@@ -1456,7 +1464,7 @@ drawregion(int x1, int y1, int x2, int y2)
 
 		term.dirty[y] = 0;
 
-		specs = term.specbuf;
+		specs = xw.specbuf;
 		numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y);
 
 		i = ox = 0;

From a8314643b1aeaa2187dad71dc5748aaac1760c1b Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Tue, 10 Oct 2017 12:46:53 -0500
Subject: [PATCH 0976/1146] Move window-manipulating functions into x.c

xresize is now internal to x.c

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c  | 36 ------------------------------------
 st.h  |  9 +--------
 win.h |  1 -
 x.c   | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 45 insertions(+), 46 deletions(-)

diff --git a/st.c b/st.c
index 540b487..75c191d 100644
--- a/st.c
+++ b/st.c
@@ -165,7 +165,6 @@ static void tnewline(int);
 static void tputtab(int);
 static void tputc(Rune);
 static void treset(void);
-static void tresize(int, int);
 static void tscrollup(int, int);
 static void tscrolldown(int, int);
 static void tsetattr(int *, int);
@@ -419,24 +418,6 @@ selinit(void)
 	sel.clipboard = NULL;
 }
 
-int
-x2col(int x)
-{
-	x -= borderpx;
-	x /= win.cw;
-
-	return LIMIT(x, 0, term.col-1);
-}
-
-int
-y2row(int y)
-{
-	y -= borderpx;
-	y /= win.ch;
-
-	return LIMIT(y, 0, term.row-1);
-}
-
 int
 tlinelen(int y)
 {
@@ -2620,20 +2601,3 @@ kmap(KeySym k, uint state)
 
 	return NULL;
 }
-
-void
-cresize(int width, int height)
-{
-	int col, row;
-
-	if (width != 0)
-		win.w = width;
-	if (height != 0)
-		win.h = height;
-
-	col = (win.w - 2 * borderpx) / win.cw;
-	row = (win.h - 2 * borderpx) / win.ch;
-
-	tresize(col, row);
-	xresize(col, row);
-}
diff --git a/st.h b/st.h
index 2199c13..5d44411 100644
--- a/st.h
+++ b/st.h
@@ -80,11 +80,6 @@ enum selection_snap {
 	SNAP_LINE = 2
 };
 
-enum window_state {
-	WIN_VISIBLE = 1,
-	WIN_FOCUSED = 2
-};
-
 typedef unsigned char uchar;
 typedef unsigned int uint;
 typedef unsigned long ulong;
@@ -186,6 +181,7 @@ void redraw(void);
 
 int tattrset(int);
 void tnew(int, int);
+void tresize(int, int);
 void tsetdirt(int, int);
 void tsetdirtattr(int);
 int match(uint, uint);
@@ -198,15 +194,12 @@ void ttywrite(const char *, size_t);
 void resettitle(void);
 
 char *kmap(KeySym, uint);
-void cresize(int, int);
 void selclear(void);
 
 void selinit(void);
 void selnormalize(void);
 int selected(int, int);
 char *getsel(void);
-int x2col(int);
-int y2row(int);
 
 size_t utf8decode(char *, Rune *, size_t);
 size_t utf8encode(Rune, char *);
diff --git a/win.h b/win.h
index dee0b7f..00113c5 100644
--- a/win.h
+++ b/win.h
@@ -16,7 +16,6 @@ void xloadcols(void);
 int xsetcolorname(int, const char *);
 void xsettitle(char *);
 void xsetpointermotion(int);
-void xresize(int, int);
 void xselpaste(void);
 void xsetsel(char *, Time);
 void zoom(const Arg *);
diff --git a/x.c b/x.c
index 186e408..01ef1b0 100644
--- a/x.c
+++ b/x.c
@@ -88,12 +88,16 @@ static void xclear(int, int, int, int);
 static void xdrawcursor(void);
 static int xgeommasktogravity(int);
 static void xinit(void);
+static void cresize(int, int);
+static void xresize(int, int);
 static int xloadfont(Font *, FcPattern *);
 static void xloadfonts(char *, double);
 static void xunloadfont(Font *);
 static void xunloadfonts(void);
 static void xsetenv(void);
 static void xseturgency(int);
+static int x2col(int);
+static int y2row(int);
 
 static void expose(XEvent *);
 static void visibility(XEvent *);
@@ -109,7 +113,6 @@ static void propnotify(XEvent *);
 static void selnotify(XEvent *);
 static void selclear_(XEvent *);
 static void selrequest(XEvent *);
-
 static void selcopy(Time);
 static void getbuttoninfo(XEvent *);
 static void mousereport(XEvent *);
@@ -148,6 +151,11 @@ static DC dc;
 static XWindow xw;
 static XSelection xsel;
 
+enum window_state {
+	WIN_VISIBLE = 1,
+	WIN_FOCUSED = 2
+};
+
 /* Font Ring Cache */
 enum {
 	FRC_NORMAL,
@@ -200,6 +208,24 @@ zoomreset(const Arg *arg)
 	}
 }
 
+int
+x2col(int x)
+{
+	x -= borderpx;
+	x /= win.cw;
+
+	return LIMIT(x, 0, term.col-1);
+}
+
+int
+y2row(int y)
+{
+	y -= borderpx;
+	y /= win.ch;
+
+	return LIMIT(y, 0, term.row-1);
+}
+
 void
 getbuttoninfo(XEvent *e)
 {
@@ -596,6 +622,23 @@ bmotion(XEvent *e)
 		tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
 }
 
+void
+cresize(int width, int height)
+{
+	int col, row;
+
+	if (width != 0)
+		win.w = width;
+	if (height != 0)
+		win.h = height;
+
+	col = (win.w - 2 * borderpx) / win.cw;
+	row = (win.h - 2 * borderpx) / win.ch;
+
+	tresize(col, row);
+	xresize(col, row);
+}
+
 void
 xresize(int col, int row)
 {

From dbe8676d7d69651132bde2b6d9ec3787cbbc552a Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Tue, 10 Oct 2017 15:51:23 -0500
Subject: [PATCH 0977/1146] Pass new dimensions into ttyresize

This removes another reference to TermWindow from st.c.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c | 6 +++---
 st.h | 2 +-
 x.c  | 6 +++---
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index 75c191d..839dc94 100644
--- a/st.c
+++ b/st.c
@@ -905,14 +905,14 @@ ttysend(char *s, size_t n)
 }
 
 void
-ttyresize(void)
+ttyresize(int tw, int th)
 {
 	struct winsize w;
 
 	w.ws_row = term.row;
 	w.ws_col = term.col;
-	w.ws_xpixel = win.tw;
-	w.ws_ypixel = win.th;
+	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));
 }
diff --git a/st.h b/st.h
index 5d44411..372462d 100644
--- a/st.h
+++ b/st.h
@@ -187,7 +187,7 @@ void tsetdirtattr(int);
 int match(uint, uint);
 void ttynew(void);
 size_t ttyread(void);
-void ttyresize(void);
+void ttyresize(int, int);
 void ttysend(char *, size_t);
 void ttywrite(const char *, size_t);
 
diff --git a/x.c b/x.c
index 01ef1b0..1b656ac 100644
--- a/x.c
+++ b/x.c
@@ -192,7 +192,7 @@ zoomabs(const Arg *arg)
 	xunloadfonts();
 	xloadfonts(usedfont, arg->f);
 	cresize(0, 0);
-	ttyresize();
+	ttyresize(win.tw, win.th);
 	redraw();
 	xhints();
 }
@@ -1679,7 +1679,7 @@ resize(XEvent *e)
 		return;
 
 	cresize(e->xconfigure.width, e->xconfigure.height);
-	ttyresize();
+	ttyresize(win.tw, win.th);
 }
 
 void
@@ -1710,7 +1710,7 @@ run(void)
 
 	cresize(w, h);
 	ttynew();
-	ttyresize();
+	ttyresize(win.tw, win.th);
 
 	clock_gettime(CLOCK_MONOTONIC, &last);
 	lastblink = last;

From ed132e11271d18a5d8aa163096bc6192c694bc47 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Wed, 11 Oct 2017 08:47:14 -0500
Subject: [PATCH 0978/1146] Move key-matching functions into x.c

Modifiers and keysyms are specific to X, and the functions match and
kmap are only used in x.c.  Needed to global-ize the key arrays and
lengths from config.h (for now).

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 config.def.h |  6 +++---
 st.c         | 58 ++--------------------------------------------------
 st.h         | 18 +++++++++++++---
 x.c          | 48 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 68 insertions(+), 62 deletions(-)

diff --git a/config.def.h b/config.def.h
index dd94be2..18cb31c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -209,13 +209,13 @@ Shortcut shortcuts[] = {
  * 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 };
+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;
+uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
 
 /*
  * Override mouse-select while mask is active (when MODE_MOUSE is set).
@@ -228,7 +228,7 @@ uint forceselmod = ShiftMask;
  * This is the huge key array which defines all compatibility to the Linux
  * world. Please decide about changes wisely.
  */
-static Key key[] = {
+Key key[] = {
 	/* keysym           mask            string      appkey appcursor crlf */
 	{ XK_KP_Home,       ShiftMask,      "\033[2J",       0,   -1,    0},
 	{ XK_KP_Home,       ShiftMask,      "\033[1;2H",     0,   +1,    0},
diff --git a/st.c b/st.c
index 839dc94..1a8fa1f 100644
--- a/st.c
+++ b/st.c
@@ -110,16 +110,6 @@ typedef struct {
 	int narg;              /* nb of args */
 } STREscape;
 
-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 */
-	signed char crlf;      /* crlf mode          */
-} Key;
-
 /* function definitions used in config.h */
 static void clipcopy(const Arg *);
 static void clippaste(const Arg *);
@@ -223,6 +213,8 @@ size_t colornamelen = LEN(colorname);
 size_t mshortcutslen = LEN(mshortcuts);
 size_t shortcutslen = LEN(shortcuts);
 size_t selmaskslen = LEN(selmasks);
+size_t keyslen = LEN(key);
+size_t mappedkeyslen = LEN(mappedkeys);
 
 ssize_t
 xwrite(int fd, const char *s, size_t len)
@@ -2550,54 +2542,8 @@ redraw(void)
 	draw();
 }
 
-int
-match(uint mask, uint state)
-{
-	return mask == XK_ANY_MOD || mask == (state & ~ignoremod);
-}
-
 void
 numlock(const Arg *dummy)
 {
 	term.numlock ^= 1;
 }
-
-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 (term.numlock && kp->appkey == 2)
-			continue;
-
-		if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0)
-			continue;
-
-		if (IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0)
-			continue;
-
-		return kp->s;
-	}
-
-	return NULL;
-}
diff --git a/st.h b/st.h
index 372462d..c255b7c 100644
--- a/st.h
+++ b/st.h
@@ -176,6 +176,16 @@ typedef struct {
 	const Arg arg;
 } Shortcut;
 
+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 */
+	signed char crlf;      /* crlf mode          */
+} Key;
+
 void die(const char *, ...);
 void redraw(void);
 
@@ -184,7 +194,6 @@ void tnew(int, int);
 void tresize(int, int);
 void tsetdirt(int, int);
 void tsetdirtattr(int);
-int match(uint, uint);
 void ttynew(void);
 size_t ttyread(void);
 void ttyresize(int, int);
@@ -193,9 +202,7 @@ void ttywrite(const char *, size_t);
 
 void resettitle(void);
 
-char *kmap(KeySym, uint);
 void selclear(void);
-
 void selinit(void);
 void selnormalize(void);
 int selected(int, int);
@@ -255,7 +262,12 @@ extern MouseShortcut mshortcuts[];
 extern size_t mshortcutslen;
 extern Shortcut shortcuts[];
 extern size_t shortcutslen;
+extern KeySym mappedkeys[];
+extern size_t mappedkeyslen;
+extern uint ignoremod;
 extern uint forceselmod;
+extern Key key[];
+extern size_t keyslen;
 extern uint selmasks[];
 extern size_t selmaskslen;
 extern char ascii_printable[];
diff --git a/x.c b/x.c
index 1b656ac..371a467 100644
--- a/x.c
+++ b/x.c
@@ -116,6 +116,8 @@ static void selrequest(XEvent *);
 static void selcopy(Time);
 static void getbuttoninfo(XEvent *);
 static void mousereport(XEvent *);
+static char *kmap(KeySym, uint);
+static int match(uint, uint);
 
 static void run(void);
 static void usage(void);
@@ -1603,6 +1605,52 @@ focus(XEvent *ev)
 	}
 }
 
+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 < mappedkeyslen; i++) {
+		if (mappedkeys[i] == k)
+			break;
+	}
+	if (i == mappedkeyslen) {
+		if ((k & 0xFFFF) < 0xFD00)
+			return NULL;
+	}
+
+	for (kp = key; kp < key + keyslen; 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 (term.numlock && kp->appkey == 2)
+			continue;
+
+		if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0)
+			continue;
+
+		if (IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0)
+			continue;
+
+		return kp->s;
+	}
+
+	return NULL;
+}
+
 void
 kpress(XEvent *ev)
 {

From 69e32a61df15787c410a48eaa10a89240c36257d Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Thu, 12 Oct 2017 22:25:49 -0500
Subject: [PATCH 0979/1146] Move opt_* into same file as main()/run()

This commit is purely about reducing externs and LOC.  If the main and
run functions ever move elsewhere (which will probably make sense
eventually), these should come along with them.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c | 50 ++++++++++++++++++++------------------------------
 st.h | 11 ++---------
 x.c  | 12 +++++++++++-
 3 files changed, 33 insertions(+), 40 deletions(-)

diff --git a/st.c b/st.c
index 1a8fa1f..58f7941 100644
--- a/st.c
+++ b/st.c
@@ -48,7 +48,6 @@
 
 /* macros */
 #define NUMMAXLEN(x)		((int)(sizeof(x) * 2.56 + 0.5) + 1)
-#define DEFAULT(a, b)		(a) = (a) ? (a) : (b)
 #define ISCONTROLC0(c)		(BETWEEN(c, 0, 0x1f) || (c) == '\177')
 #define ISCONTROLC1(c)		(BETWEEN(c, 0x80, 0x9f))
 #define ISCONTROL(c)		(ISCONTROLC0(c) || ISCONTROLC1(c))
@@ -124,8 +123,8 @@ static void sendbreak(const Arg *);
 /* config.h for applying patches and the configuration. */
 #include "config.h"
 
-static void execsh(void);
-static void stty(void);
+static void execsh(char **);
+static void stty(char **);
 static void sigchld(int);
 
 static void csidump(void);
@@ -189,14 +188,6 @@ Term term;
 Selection sel;
 int cmdfd;
 pid_t pid;
-char **opt_cmd  = NULL;
-char *opt_class = NULL;
-char *opt_embed = NULL;
-char *opt_font  = NULL;
-char *opt_io    = NULL;
-char *opt_line  = NULL;
-char *opt_name  = NULL;
-char *opt_title = NULL;
 int oldbutton   = 3; /* button event on startup: 3 = release */
 
 static CSIEscape csiescseq;
@@ -634,9 +625,9 @@ die(const char *errstr, ...)
 }
 
 void
-execsh(void)
+execsh(char **args)
 {
-	char **args, *sh, *prog;
+	char *sh, *prog;
 	const struct passwd *pw;
 
 	errno = 0;
@@ -650,13 +641,13 @@ execsh(void)
 	if ((sh = getenv("SHELL")) == NULL)
 		sh = (pw->pw_shell[0]) ? pw->pw_shell : shell;
 
-	if (opt_cmd)
-		prog = opt_cmd[0];
+	if (args)
+		prog = args[0];
 	else if (utmp)
 		prog = utmp;
 	else
 		prog = sh;
-	args = (opt_cmd) ? opt_cmd : (char *[]) {prog, NULL};
+	DEFAULT(args, ((char *[]) {prog, NULL}));
 
 	unsetenv("COLUMNS");
 	unsetenv("LINES");
@@ -697,7 +688,7 @@ sigchld(int a)
 
 
 void
-stty(void)
+stty(char **args)
 {
 	char cmd[_POSIX_ARG_MAX], **p, *q, *s;
 	size_t n, siz;
@@ -707,7 +698,7 @@ stty(void)
 	memcpy(cmd, stty_args, n);
 	q = cmd + n;
 	siz = sizeof(cmd) - n;
-	for (p = opt_cmd; p && (s = *p); ++p) {
+	for (p = args; p && (s = *p); ++p) {
 		if ((n = strlen(s)) > siz-1)
 			die("stty parameter length too long\n");
 		*q++ = ' ';
@@ -721,26 +712,26 @@ stty(void)
 }
 
 void
-ttynew(void)
+ttynew(char *line, char *out, char **args)
 {
 	int m, s;
 	struct winsize w = {term.row, term.col, 0, 0};
 
-	if (opt_io) {
+	if (out) {
 		term.mode |= MODE_PRINT;
-		iofd = (!strcmp(opt_io, "-")) ?
-			  1 : open(opt_io, O_WRONLY | O_CREAT, 0666);
+		iofd = (!strcmp(out, "-")) ?
+			  1 : open(out, O_WRONLY | O_CREAT, 0666);
 		if (iofd < 0) {
 			fprintf(stderr, "Error opening %s:%s\n",
-				opt_io, strerror(errno));
+				out, strerror(errno));
 		}
 	}
 
-	if (opt_line) {
-		if ((cmdfd = open(opt_line, O_RDWR)) < 0)
+	if (line) {
+		if ((cmdfd = open(line, O_RDWR)) < 0)
 			die("open line failed: %s\n", strerror(errno));
 		dup2(cmdfd, 0);
-		stty();
+		stty(args);
 		return;
 	}
 
@@ -762,7 +753,7 @@ ttynew(void)
 			die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
 		close(s);
 		close(m);
-		execsh();
+		execsh(args);
 		break;
 	default:
 		close(s);
@@ -1942,8 +1933,7 @@ void
 tprinter(char *s, size_t len)
 {
 	if (iofd != -1 && xwrite(iofd, s, len) < 0) {
-		fprintf(stderr, "Error writing in %s:%s\n",
-			opt_io, strerror(errno));
+		perror("Error writing to output file");
 		close(iofd);
 		iofd = -1;
 	}
@@ -2532,7 +2522,7 @@ tresize(int col, int row)
 void
 resettitle(void)
 {
-	xsettitle(opt_title ? opt_title : "st");
+	xsettitle(NULL);
 }
 
 void
diff --git a/st.h b/st.h
index c255b7c..09473c2 100644
--- a/st.h
+++ b/st.h
@@ -9,6 +9,7 @@
 #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)
@@ -194,7 +195,7 @@ void tnew(int, int);
 void tresize(int, int);
 void tsetdirt(int, int);
 void tsetdirtattr(int);
-void ttynew(void);
+void ttynew(char *, char *, char **);
 size_t ttyread(void);
 void ttyresize(int, int);
 void ttysend(char *, size_t);
@@ -221,14 +222,6 @@ extern Term term;
 extern Selection sel;
 extern int cmdfd;
 extern pid_t pid;
-extern char **opt_cmd;
-extern char *opt_class;
-extern char *opt_embed;
-extern char *opt_font;
-extern char *opt_io;
-extern char *opt_line;
-extern char *opt_name;
-extern char *opt_title;
 extern int oldbutton;
 
 /* config.h globals */
diff --git a/x.c b/x.c
index 371a467..e267961 100644
--- a/x.c
+++ b/x.c
@@ -179,6 +179,15 @@ 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;
+
 void
 zoom(const Arg *arg)
 {
@@ -1473,6 +1482,7 @@ void
 xsettitle(char *p)
 {
 	XTextProperty prop;
+	DEFAULT(p, "st");
 
 	Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
 			&prop);
@@ -1757,7 +1767,7 @@ run(void)
 	} while (ev.type != MapNotify);
 
 	cresize(w, h);
-	ttynew();
+	ttynew(opt_line, opt_io, opt_cmd);
 	ttyresize(win.tw, win.th);
 
 	clock_gettime(CLOCK_MONOTONIC, &last);

From 32d3b1d00f66eda4f5446f3b32cabed2c9a77a40 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Sun, 15 Oct 2017 20:35:48 -0500
Subject: [PATCH 0980/1146] Factor out equivalent code from ttyread/ttysend

The echo-to-terminal portions of ttyread and ttysend were actually doing
the same thing.  New function twrite() now handles this.  The parameter
show_ctrl determines whether control characters are shown as "^A".  This
was the only difference between tputc and techo, and techo is now unused
and removed.

(This commit should not change st's behaviour.)

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c | 101 +++++++++++++++++++++++------------------------------------
 st.h |   2 +-
 2 files changed, 41 insertions(+), 62 deletions(-)

diff --git a/st.c b/st.c
index 58f7941..641f896 100644
--- a/st.c
+++ b/st.c
@@ -161,8 +161,8 @@ static void tsetchar(Rune, Glyph *, int, int);
 static void tsetscroll(int, int);
 static void tswapscreen(void);
 static void tsetmode(int, int, int *, int);
+static int twrite(const char *, int, int);
 static void tfulldirt(void);
-static void techo(Rune);
 static void tcontrolcode(uchar );
 static void tdectest(char );
 static void tdefutf8(char);
@@ -254,7 +254,7 @@ xstrdup(char *s)
 }
 
 size_t
-utf8decode(char *c, Rune *u, size_t clen)
+utf8decode(const char *c, Rune *u, size_t clen)
 {
 	size_t i, j, len, type;
 	Rune udecoded;
@@ -768,38 +768,19 @@ ttyread(void)
 {
 	static char buf[BUFSIZ];
 	static int buflen = 0;
-	char *ptr;
-	int charsize; /* size of utf8 char in bytes */
-	Rune unicodep;
+	int written;
 	int ret;
 
 	/* append read bytes to unprocessed bytes */
 	if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
 		die("Couldn't read from shell: %s\n", strerror(errno));
-
 	buflen += ret;
-	ptr = buf;
 
-	for (;;) {
-		if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
-			/* process a complete utf8 char */
-			charsize = utf8decode(ptr, &unicodep, buflen);
-			if (charsize == 0)
-				break;
-			tputc(unicodep);
-			ptr += charsize;
-			buflen -= charsize;
-
-		} else {
-			if (buflen <= 0)
-				break;
-			tputc(*ptr++ & 0xFF);
-			buflen--;
-		}
-	}
+	written = twrite(buf, buflen, 0);
+	buflen -= written;
 	/* keep any uncomplete utf8 char for the next call */
 	if (buflen > 0)
-		memmove(buf, ptr, buflen);
+		memmove(buf, buf + written, buflen);
 
 	return ret;
 }
@@ -864,27 +845,9 @@ write_error:
 void
 ttysend(char *s, size_t n)
 {
-	int len;
-	char *t, *lim;
-	Rune u;
-
 	ttywrite(s, n);
-	if (!IS_SET(MODE_ECHO))
-		return;
-
-	lim = &s[n];
-	for (t = s; t < lim; t += len) {
-		if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
-			len = utf8decode(t, &u, n);
-		} else {
-			u = *t & 0xFF;
-			len = 1;
-		}
-		if (len <= 0)
-			break;
-		techo(u);
-		n -= len;
-	}
+	if (IS_SET(MODE_ECHO))
+		twrite(s, n, 1);
 }
 
 void
@@ -2031,22 +1994,6 @@ tputtab(int n)
 	term.c.x = LIMIT(x, 0, term.col-1);
 }
 
-void
-techo(Rune u)
-{
-	if (ISCONTROL(u)) { /* control code */
-		if (u & 0x80) {
-			u &= 0x7f;
-			tputc('^');
-			tputc('[');
-		} else if (u != '\n' && u != '\r' && u != '\t') {
-			u ^= 0x40;
-			tputc('^');
-		}
-	}
-	tputc(u);
-}
-
 void
 tdefutf8(char ascii)
 {
@@ -2437,6 +2384,38 @@ check_control_code:
 	}
 }
 
+int
+twrite(const char *buf, int buflen, int show_ctrl)
+{
+	int charsize;
+	Rune u;
+	int n;
+
+	for (n = 0; n < buflen; n += charsize) {
+		if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
+			/* process a complete utf8 char */
+			charsize = utf8decode(buf + n, &u, buflen - n);
+			if (charsize == 0)
+				break;
+		} else {
+			u = buf[n] & 0xFF;
+			charsize = 1;
+		}
+		if (show_ctrl && ISCONTROL(u)) {
+			if (u & 0x80) {
+				u &= 0x7f;
+				tputc('^');
+				tputc('[');
+			} else if (u != '\n' && u != '\r' && u != '\t') {
+				u ^= 0x40;
+				tputc('^');
+			}
+		}
+		tputc(u);
+	}
+	return n;
+}
+
 void
 tresize(int col, int row)
 {
diff --git a/st.h b/st.h
index 09473c2..3d9b6e7 100644
--- a/st.h
+++ b/st.h
@@ -209,7 +209,7 @@ void selnormalize(void);
 int selected(int, int);
 char *getsel(void);
 
-size_t utf8decode(char *, Rune *, size_t);
+size_t utf8decode(const char *, Rune *, size_t);
 size_t utf8encode(Rune, char *);
 
 void *xmalloc(size_t);

From 65976c1a29f2945c3cfb6af74cd6440cf193021d Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Tue, 17 Oct 2017 15:21:04 -0500
Subject: [PATCH 0981/1146] Move config.h include from st.c to x.c

config.h includes references to KeySyms and other X stuff.  Until we
come up with a cleaner way to separate configuration, it is simpler
(leads to more code removal) to have this here.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 config.def.h | 73 ++++++++++++++++++++++++++--------------------------
 st.c         | 47 +++------------------------------
 st.h         | 50 ++++++++++-------------------------
 win.h        |  3 ---
 x.c          | 37 ++++++++++++++++++++++++++
 5 files changed, 91 insertions(+), 119 deletions(-)

diff --git a/config.def.h b/config.def.h
index 18cb31c..1c181ab 100644
--- a/config.def.h
+++ b/config.def.h
@@ -5,8 +5,8 @@
  *
  * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
  */
-char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
-int borderpx = 2;
+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:
@@ -16,54 +16,54 @@ int borderpx = 2;
  * 4: value of shell in /etc/passwd
  * 5: value of shell in config.h
  */
-static char shell[] = "/bin/sh";
-static char *utmp = NULL;
-static char stty_args[] = "stty raw pass8 nl -echo -iexten -cstopb 38400";
+char *shell = "/bin/sh";
+char *utmp = NULL;
+char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
 
 /* identification sequence returned in DA and DECID */
-static char vtiden[] = "\033[?6c";
+char *vtiden = "\033[?6c";
 
 /* Kerning / character bounding-box multipliers */
-float cwscale = 1.0;
-float chscale = 1.0;
+static float cwscale = 1.0;
+static float chscale = 1.0;
 
 /*
  * word delimiter string
  *
  * More advanced example: " `'\"()[]{}"
  */
-static char worddelimiters[] = " ";
+char *worddelimiters = " ";
 
 /* selection timeouts (in milliseconds) */
-unsigned int doubleclicktimeout = 300;
-unsigned int tripleclicktimeout = 600;
+static unsigned int doubleclicktimeout = 300;
+static unsigned int tripleclicktimeout = 600;
 
 /* alt screens */
 int allowaltscreen = 1;
 
 /* frames per second st should at maximum draw to the screen */
-unsigned int xfps = 120;
-unsigned int actionfps = 30;
+static unsigned int xfps = 120;
+static unsigned int actionfps = 30;
 
 /*
  * blinking timeout (set to 0 to disable blinking) for the terminal blinking
  * attribute.
  */
-unsigned int blinktimeout = 800;
+static unsigned int blinktimeout = 800;
 
 /*
  * thickness of underline and bar cursors
  */
-unsigned int cursorthickness = 2;
+static unsigned int cursorthickness = 2;
 
 /*
  * bell volume. It must be a value between -100 and 100. Use 0 for disabling
  * it
  */
-int bellvolume = 0;
+static int bellvolume = 0;
 
 /* default TERM value */
-char termname[] = "st-256color";
+char *termname = "st-256color";
 
 /*
  * spaces per tab
@@ -80,10 +80,10 @@ char termname[] = "st-256color";
  *
  *	stty tabs
  */
-static unsigned int tabspaces = 8;
+unsigned int tabspaces = 8;
 
 /* Terminal colors (16 first used in escape sequence) */
-const char *colorname[] = {
+static const char *colorname[] = {
 	/* 8 normal colors */
 	"black",
 	"red3",
@@ -118,8 +118,8 @@ const char *colorname[] = {
  */
 unsigned int defaultfg = 7;
 unsigned int defaultbg = 0;
-unsigned int defaultcs = 256;
-unsigned int defaultrcs = 257;
+static unsigned int defaultcs = 256;
+static unsigned int defaultrcs = 257;
 
 /*
  * Default shape of cursor
@@ -128,33 +128,33 @@ unsigned int defaultrcs = 257;
  * 6: Bar ("|")
  * 7: Snowman ("☃")
  */
-unsigned int cursorshape = 2;
+static unsigned int cursorshape = 2;
 
 /*
  * Default columns and rows numbers
  */
 
-unsigned int cols = 80;
-unsigned int rows = 24;
+static unsigned int cols = 80;
+static unsigned int rows = 24;
 
 /*
  * Default colour and shape of the mouse cursor
  */
-unsigned int mouseshape = XC_xterm;
-unsigned int mousefg = 7;
-unsigned int mousebg = 0;
+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.
  */
-unsigned int defaultattr = 11;
+static unsigned int defaultattr = 11;
 
 /*
  * Internal mouse shortcuts.
  * Beware that overloading Button1 will disable the selection.
  */
-MouseShortcut mshortcuts[] = {
+static MouseShortcut mshortcuts[] = {
 	/* button               mask            string */
 	{ Button4,              XK_ANY_MOD,     "\031" },
 	{ Button5,              XK_ANY_MOD,     "\005" },
@@ -164,7 +164,7 @@ MouseShortcut mshortcuts[] = {
 #define MODKEY Mod1Mask
 #define TERMMOD (ControlMask|ShiftMask)
 
-Shortcut shortcuts[] = {
+static Shortcut shortcuts[] = {
 	/* mask                 keysym          function        argument */
 	{ XK_ANY_MOD,           XK_Break,       sendbreak,      {.i =  0} },
 	{ ControlMask,          XK_Print,       toggleprinter,  {.i =  0} },
@@ -209,26 +209,26 @@ Shortcut shortcuts[] = {
  * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
  * to be mapped below, add them to this array.
  */
-KeySym mappedkeys[] = { -1 };
+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.
  */
-uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
+static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
 
 /*
  * Override mouse-select while mask is active (when MODE_MOUSE is set).
  * Note that if you want to use ShiftMask with selmasks, set this to an other
  * modifier, set to 0 to not use it.
  */
-uint forceselmod = ShiftMask;
+static uint forceselmod = ShiftMask;
 
 /*
  * This is the huge key array which defines all compatibility to the Linux
  * world. Please decide about changes wisely.
  */
-Key key[] = {
+static Key key[] = {
 	/* keysym           mask            string      appkey appcursor crlf */
 	{ XK_KP_Home,       ShiftMask,      "\033[2J",       0,   -1,    0},
 	{ XK_KP_Home,       ShiftMask,      "\033[1;2H",     0,   +1,    0},
@@ -451,7 +451,7 @@ Key key[] = {
  * ButtonRelease and MotionNotify.
  * If no match is found, regular selection is used.
  */
-uint selmasks[] = {
+static uint selmasks[] = {
 	[SEL_RECTANGULAR] = Mod1Mask,
 };
 
@@ -459,8 +459,7 @@ uint selmasks[] = {
  * Printable characters in ASCII, used to estimate the advance width
  * of single wide characters.
  */
-char ascii_printable[] =
+static char ascii_printable[] =
 	" !\"#$%&'()*+,-./0123456789:;<=>?"
 	"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
 	"`abcdefghijklmnopqrstuvwxyz{|}~";
-
diff --git a/st.c b/st.c
index 641f896..ec747cc 100644
--- a/st.c
+++ b/st.c
@@ -109,19 +109,6 @@ typedef struct {
 	int narg;              /* nb of args */
 } STREscape;
 
-/* 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 printsel(const Arg *);
-static void printscreen(const Arg *) ;
-static void iso14755(const Arg *);
-static void toggleprinter(const Arg *);
-static void sendbreak(const Arg *);
-
-/* config.h for applying patches and the configuration. */
-#include "config.h"
 
 static void execsh(char **);
 static void stty(char **);
@@ -199,14 +186,6 @@ static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
 static Rune utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  0x10000};
 static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
 
-/* config.h array lengths */
-size_t colornamelen = LEN(colorname);
-size_t mshortcutslen = LEN(mshortcuts);
-size_t shortcutslen = LEN(shortcuts);
-size_t selmaskslen = LEN(selmasks);
-size_t keyslen = LEN(key);
-size_t mappedkeyslen = LEN(mappedkeys);
-
 ssize_t
 xwrite(int fd, const char *s, size_t len)
 {
@@ -585,24 +564,6 @@ getsel(void)
 	return str;
 }
 
-void
-selpaste(const Arg *dummy)
-{
-	xselpaste();
-}
-
-void
-clipcopy(const Arg *dummy)
-{
-	xclipcopy();
-}
-
-void
-clippaste(const Arg *dummy)
-{
-	xclippaste();
-}
-
 void
 selclear(void)
 {
@@ -1572,7 +1533,7 @@ csihandle(void)
 		break;
 	case 'c': /* DA -- Device Attributes */
 		if (csiescseq.arg[0] == 0)
-			ttywrite(vtiden, sizeof(vtiden) - 1);
+			ttywrite(vtiden, strlen(vtiden));
 		break;
 	case 'C': /* CUF -- Cursor <n> Forward */
 	case 'a': /* HPR -- Cursor <n> Forward */
@@ -1791,7 +1752,7 @@ strhandle(void)
 				dec = base64dec(strescseq.args[2]);
 				if (dec) {
 					xsetsel(dec, CurrentTime);
-					clipcopy(NULL);
+					xclipcopy();
 				} else {
 					fprintf(stderr, "erresc: invalid base64\n");
 				}
@@ -2134,7 +2095,7 @@ tcontrolcode(uchar ascii)
 	case 0x99:   /* TODO: SGCI */
 		break;
 	case 0x9a:   /* DECID -- Identify Terminal */
-		ttywrite(vtiden, sizeof(vtiden) - 1);
+		ttywrite(vtiden, strlen(vtiden));
 		break;
 	case 0x9b:   /* TODO: CSI */
 	case 0x9c:   /* TODO: ST */
@@ -2206,7 +2167,7 @@ eschandle(uchar ascii)
 		}
 		break;
 	case 'Z': /* DECID -- Identify Terminal */
-		ttywrite(vtiden, sizeof(vtiden) - 1);
+		ttywrite(vtiden, strlen(vtiden));
 		break;
 	case 'c': /* RIS -- Reset to inital state */
 		treset();
diff --git a/st.h b/st.h
index 3d9b6e7..9314607 100644
--- a/st.h
+++ b/st.h
@@ -190,6 +190,13 @@ typedef struct {
 void die(const char *, ...);
 void redraw(void);
 
+void iso14755(const Arg *);
+void numlock(const Arg *);
+void printscreen(const Arg *);
+void printsel(const Arg *);
+void sendbreak(const Arg *);
+void toggleprinter(const Arg *);
+
 int tattrset(int);
 void tnew(int, int);
 void tresize(int, int);
@@ -225,42 +232,13 @@ extern pid_t pid;
 extern int oldbutton;
 
 /* config.h globals */
-extern char font[];
-extern int borderpx;
-extern float cwscale;
-extern float chscale;
-extern unsigned int doubleclicktimeout;
-extern unsigned int tripleclicktimeout;
+extern char *shell;
+extern char *utmp;
+extern char *stty_args;
+extern char *vtiden;
+extern char *worddelimiters;
 extern int allowaltscreen;
-extern unsigned int xfps;
-extern unsigned int actionfps;
-extern unsigned int cursorthickness;
-extern int bellvolume;
-extern unsigned int blinktimeout;
-extern char termname[];
-extern const char *colorname[];
-extern size_t colornamelen;
+extern char *termname;
+extern unsigned int tabspaces;
 extern unsigned int defaultfg;
 extern unsigned int defaultbg;
-extern unsigned int defaultcs;
-extern unsigned int defaultrcs;
-extern unsigned int cursorshape;
-extern unsigned int cols;
-extern unsigned int rows;
-extern unsigned int mouseshape;
-extern unsigned int mousefg;
-extern unsigned int mousebg;
-extern unsigned int defaultattr;
-extern MouseShortcut mshortcuts[];
-extern size_t mshortcutslen;
-extern Shortcut shortcuts[];
-extern size_t shortcutslen;
-extern KeySym mappedkeys[];
-extern size_t mappedkeyslen;
-extern uint ignoremod;
-extern uint forceselmod;
-extern Key key[];
-extern size_t keyslen;
-extern uint selmasks[];
-extern size_t selmaskslen;
-extern char ascii_printable[];
diff --git a/win.h b/win.h
index 00113c5..b7022ec 100644
--- a/win.h
+++ b/win.h
@@ -18,6 +18,3 @@ void xsettitle(char *);
 void xsetpointermotion(int);
 void xselpaste(void);
 void xsetsel(char *, Time);
-void zoom(const Arg *);
-void zoomabs(const Arg *);
-void zoomreset(const Arg *);
diff --git a/x.c b/x.c
index e267961..cb8c351 100644
--- a/x.c
+++ b/x.c
@@ -20,6 +20,25 @@ static char *argv0;
 #include "st.h"
 #include "win.h"
 
+/* function definitions used in config.h */
+static void clipcopy(const Arg *);
+static void clippaste(const Arg *);
+static void selpaste(const Arg *);
+static void zoom(const Arg *);
+static void zoomabs(const Arg *);
+static void zoomreset(const Arg *);
+
+/* config.h for applying patches and the configuration. */
+#include "config.h"
+
+/* config.h array lengths */
+size_t colornamelen = LEN(colorname);
+size_t mshortcutslen = LEN(mshortcuts);
+size_t shortcutslen = LEN(shortcuts);
+size_t selmaskslen = LEN(selmasks);
+size_t keyslen = LEN(key);
+size_t mappedkeyslen = LEN(mappedkeys);
+
 /* XEMBED messages */
 #define XEMBED_FOCUS_IN  4
 #define XEMBED_FOCUS_OUT 5
@@ -188,6 +207,24 @@ static char *opt_line  = NULL;
 static char *opt_name  = NULL;
 static char *opt_title = NULL;
 
+void
+clipcopy(const Arg *dummy)
+{
+	xclipcopy();
+}
+
+void
+clippaste(const Arg *dummy)
+{
+	xclippaste();
+}
+
+void
+selpaste(const Arg *dummy)
+{
+	xselpaste();
+}
+
 void
 zoom(const Arg *arg)
 {

From 428f01969aaf48ffa2983746c0a397bcc8946799 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Tue, 17 Oct 2017 15:43:32 -0500
Subject: [PATCH 0982/1146] Inline clipboard functions

No need to keep a function that only calls another function in the same
file.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 win.h |  2 --
 x.c   | 50 +++++++++++++++++++-------------------------------
 2 files changed, 19 insertions(+), 33 deletions(-)

diff --git a/win.h b/win.h
index b7022ec..beb458d 100644
--- a/win.h
+++ b/win.h
@@ -10,11 +10,9 @@ void drawregion(int, int, int, int);
 
 void xbell(void);
 void xclipcopy(void);
-void xclippaste(void);
 void xhints(void);
 void xloadcols(void);
 int xsetcolorname(int, const char *);
 void xsettitle(char *);
 void xsetpointermotion(int);
-void xselpaste(void);
 void xsetsel(char *, Time);
diff --git a/x.c b/x.c
index cb8c351..46356fe 100644
--- a/x.c
+++ b/x.c
@@ -210,19 +210,33 @@ static char *opt_title = NULL;
 void
 clipcopy(const Arg *dummy)
 {
-	xclipcopy();
+	Atom clipboard;
+
+	if (sel.clipboard != NULL)
+		free(sel.clipboard);
+
+	if (sel.primary != NULL) {
+		sel.clipboard = xstrdup(sel.primary);
+		clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+		XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
+	}
 }
 
 void
 clippaste(const Arg *dummy)
 {
-	xclippaste();
+	Atom clipboard;
+
+	clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+	XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard,
+			xw.win, CurrentTime);
 }
 
 void
 selpaste(const Arg *dummy)
 {
-	xselpaste();
+	XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY,
+			xw.win, CurrentTime);
 }
 
 void
@@ -518,36 +532,10 @@ selnotify(XEvent *e)
 	XDeleteProperty(xw.dpy, xw.win, (int)property);
 }
 
-void
-xselpaste(void)
-{
-	XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY,
-			xw.win, CurrentTime);
-}
-
 void
 xclipcopy(void)
 {
-	Atom clipboard;
-
-	if (sel.clipboard != NULL)
-		free(sel.clipboard);
-
-	if (sel.primary != NULL) {
-		sel.clipboard = xstrdup(sel.primary);
-		clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
-		XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
-	}
-}
-
-void
-xclippaste(void)
-{
-	Atom clipboard;
-
-	clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
-	XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard,
-			xw.win, CurrentTime);
+	clipcopy(NULL);
 }
 
 void
@@ -634,7 +622,7 @@ brelease(XEvent *e)
 	}
 
 	if (e->xbutton.button == Button2) {
-		xselpaste();
+		selpaste(NULL);
 	} else if (e->xbutton.button == Button1) {
 		if (sel.mode == SEL_READY) {
 			getbuttoninfo(e);

From 75c9a0ee1d232a1a177746d97a13cf92b03da44a Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Tue, 17 Oct 2017 15:46:31 -0500
Subject: [PATCH 0983/1146] Remove unneeded array-length variables

These were only used in x.c, which now has direct visibility of the
config.h arrays.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 x.c | 22 +++++++---------------
 1 file changed, 7 insertions(+), 15 deletions(-)

diff --git a/x.c b/x.c
index 46356fe..03555d1 100644
--- a/x.c
+++ b/x.c
@@ -31,14 +31,6 @@ static void zoomreset(const Arg *);
 /* config.h for applying patches and the configuration. */
 #include "config.h"
 
-/* config.h array lengths */
-size_t colornamelen = LEN(colorname);
-size_t mshortcutslen = LEN(mshortcuts);
-size_t shortcutslen = LEN(shortcuts);
-size_t selmaskslen = LEN(selmasks);
-size_t keyslen = LEN(key);
-size_t mappedkeyslen = LEN(mappedkeys);
-
 /* XEMBED messages */
 #define XEMBED_FOCUS_IN  4
 #define XEMBED_FOCUS_OUT 5
@@ -301,7 +293,7 @@ getbuttoninfo(XEvent *e)
 	selnormalize();
 
 	sel.type = SEL_REGULAR;
-	for (type = 1; type < selmaskslen; ++type) {
+	for (type = 1; type < LEN(selmasks); ++type) {
 		if (match(selmasks[type], state)) {
 			sel.type = type;
 			break;
@@ -384,7 +376,7 @@ bpress(XEvent *e)
 		return;
 	}
 
-	for (ms = mshortcuts; ms < mshortcuts + mshortcutslen; ms++) {
+	for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
 		if (e->xbutton.button == ms->b
 				&& match(ms->mask, e->xbutton.state)) {
 			ttysend(ms->s, strlen(ms->s));
@@ -728,7 +720,7 @@ xloadcols(void)
 	static int loaded;
 	Color *cp;
 
-	dc.collen = MAX(colornamelen, 256);
+	dc.collen = MAX(LEN(colorname), 256);
 	dc.col = xmalloc(dc.collen * sizeof(Color));
 
 	if (loaded) {
@@ -1653,16 +1645,16 @@ kmap(KeySym k, uint state)
 	int i;
 
 	/* Check for mapped keys out of X11 function keys. */
-	for (i = 0; i < mappedkeyslen; i++) {
+	for (i = 0; i < LEN(mappedkeys); i++) {
 		if (mappedkeys[i] == k)
 			break;
 	}
-	if (i == mappedkeyslen) {
+	if (i == LEN(mappedkeys)) {
 		if ((k & 0xFFFF) < 0xFD00)
 			return NULL;
 	}
 
-	for (kp = key; kp < key + keyslen; kp++) {
+	for (kp = key; kp < key + LEN(key); kp++) {
 		if (kp->k != k)
 			continue;
 
@@ -1702,7 +1694,7 @@ kpress(XEvent *ev)
 
 	len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
 	/* 1. shortcuts */
-	for (bp = shortcuts; bp < shortcuts + shortcutslen; bp++) {
+	for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
 		if (ksym == bp->keysym && match(bp->mod, e->state)) {
 			bp->func(&(bp->arg));
 			return;

From 416dd257274fd334be082b1138338adffa3e2d5e Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Tue, 17 Oct 2017 16:46:26 -0500
Subject: [PATCH 0984/1146] Move X-related config.h types into x.c

No need to expose Shortcut, MouseShortcut, and Key anymore.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.h | 23 -----------------------
 x.c  | 24 ++++++++++++++++++++++++
 2 files changed, 24 insertions(+), 23 deletions(-)

diff --git a/st.h b/st.h
index 9314607..71c79f4 100644
--- a/st.h
+++ b/st.h
@@ -134,12 +134,6 @@ typedef struct {
 	int cursor; /* cursor style */
 } TermWindow;
 
-typedef struct {
-	uint b;
-	uint mask;
-	char *s;
-} MouseShortcut;
-
 typedef struct {
 	int mode;
 	int type;
@@ -170,23 +164,6 @@ typedef union {
 	const void *v;
 } Arg;
 
-typedef struct {
-	uint mod;
-	KeySym keysym;
-	void (*func)(const Arg *);
-	const Arg arg;
-} Shortcut;
-
-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 */
-	signed char crlf;      /* crlf mode          */
-} Key;
-
 void die(const char *, ...);
 void redraw(void);
 
diff --git a/x.c b/x.c
index 03555d1..24f6991 100644
--- a/x.c
+++ b/x.c
@@ -20,6 +20,30 @@ static char *argv0;
 #include "st.h"
 #include "win.h"
 
+/* types used in config.h */
+typedef struct {
+	uint mod;
+	KeySym keysym;
+	void (*func)(const Arg *);
+	const Arg arg;
+} Shortcut;
+
+typedef struct {
+	uint b;
+	uint mask;
+	char *s;
+} MouseShortcut;
+
+typedef struct {
+	KeySym k;
+	uint mask;
+	char *s;
+	/* three valued logic variables: 0 indifferent, 1 on, -1 off */
+	signed char appkey;    /* application keypad */
+	signed char appcursor; /* application cursor */
+	signed char crlf;      /* crlf mode          */
+} Key;
+
 /* function definitions used in config.h */
 static void clipcopy(const Arg *);
 static void clippaste(const Arg *);

From 323d38da20c8a1d295ab1dbc0fc7ce947ef824e1 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Mon, 6 Nov 2017 17:57:45 -0600
Subject: [PATCH 0985/1146] Make win variable internal to x.c

There was only a single reference to the `win` variable in st.c, so
exporting that to x.c allows us to rid ourselves of another extern.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c  |  6 +-----
 st.h  |  1 -
 win.h |  1 +
 x.c   | 11 +++++++++++
 4 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index ec747cc..fdf697b 100644
--- a/st.c
+++ b/st.c
@@ -170,7 +170,6 @@ static char *base64dec(const char *);
 static ssize_t xwrite(int, const char *, size_t);
 
 /* Globals */
-TermWindow win;
 Term term;
 Selection sel;
 int cmdfd;
@@ -1683,11 +1682,8 @@ csihandle(void)
 	case ' ':
 		switch (csiescseq.mode[1]) {
 		case 'q': /* DECSCUSR -- Set Cursor Style */
-			DEFAULT(csiescseq.arg[0], 1);
-			if (!BETWEEN(csiescseq.arg[0], 0, 6)) {
+			if (xsetcursor(csiescseq.arg[0]))
 				goto unknown;
-			}
-			win.cursor = csiescseq.arg[0];
 			break;
 		default:
 			goto unknown;
diff --git a/st.h b/st.h
index 71c79f4..8637d35 100644
--- a/st.h
+++ b/st.h
@@ -201,7 +201,6 @@ void *xrealloc(void *, size_t);
 char *xstrdup(char *);
 
 /* Globals */
-extern TermWindow win;
 extern Term term;
 extern Selection sel;
 extern int cmdfd;
diff --git a/win.h b/win.h
index beb458d..c6a5337 100644
--- a/win.h
+++ b/win.h
@@ -14,5 +14,6 @@ void xhints(void);
 void xloadcols(void);
 int xsetcolorname(int, const char *);
 void xsettitle(char *);
+int xsetcursor(int);
 void xsetpointermotion(int);
 void xsetsel(char *, Time);
diff --git a/x.c b/x.c
index 24f6991..04e2e05 100644
--- a/x.c
+++ b/x.c
@@ -187,6 +187,7 @@ static void (*handler[LASTEvent])(XEvent *) = {
 static DC dc;
 static XWindow xw;
 static XSelection xsel;
+static TermWindow win;
 
 enum window_state {
 	WIN_VISIBLE = 1,
@@ -1615,6 +1616,16 @@ xsetpointermotion(int set)
 	XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
 }
 
+int
+xsetcursor(int cursor)
+{
+	DEFAULT(cursor, 1);
+	if (!BETWEEN(cursor, 0, 6))
+		return 1;
+	win.cursor = cursor;
+	return 0;
+}
+
 void
 xseturgency(int add)
 {

From 3bb900cd6c1c7a5364bd79bce63fdd8711bc878b Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Mon, 6 Nov 2017 18:25:58 -0600
Subject: [PATCH 0986/1146] Remove Time argument from xsetsel

This is an X type and should be internal to x.c.

The selcopy() function was a single line and only used in one place, so
it was inlined to reduce LOC.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c  |  2 +-
 win.h |  2 +-
 x.c   | 18 +++++++++---------
 3 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/st.c b/st.c
index fdf697b..bcb6473 100644
--- a/st.c
+++ b/st.c
@@ -1747,7 +1747,7 @@ strhandle(void)
 
 				dec = base64dec(strescseq.args[2]);
 				if (dec) {
-					xsetsel(dec, CurrentTime);
+					xsetsel(dec);
 					xclipcopy();
 				} else {
 					fprintf(stderr, "erresc: invalid base64\n");
diff --git a/win.h b/win.h
index c6a5337..f95a679 100644
--- a/win.h
+++ b/win.h
@@ -16,4 +16,4 @@ int xsetcolorname(int, const char *);
 void xsettitle(char *);
 int xsetcursor(int);
 void xsetpointermotion(int);
-void xsetsel(char *, Time);
+void xsetsel(char *);
diff --git a/x.c b/x.c
index 04e2e05..a332ac9 100644
--- a/x.c
+++ b/x.c
@@ -148,7 +148,7 @@ static void propnotify(XEvent *);
 static void selnotify(XEvent *);
 static void selclear_(XEvent *);
 static void selrequest(XEvent *);
-static void selcopy(Time);
+static void setsel(char *, Time);
 static void getbuttoninfo(XEvent *);
 static void mousereport(XEvent *);
 static char *kmap(KeySym, uint);
@@ -440,12 +440,6 @@ bpress(XEvent *e)
 	}
 }
 
-void
-selcopy(Time t)
-{
-	xsetsel(getsel(), t);
-}
-
 void
 propnotify(XEvent *e)
 {
@@ -620,7 +614,7 @@ selrequest(XEvent *e)
 }
 
 void
-xsetsel(char *str, Time t)
+setsel(char *str, Time t)
 {
 	free(sel.primary);
 	sel.primary = str;
@@ -630,6 +624,12 @@ xsetsel(char *str, Time t)
 		selclear_(NULL);
 }
 
+void
+xsetsel(char *str)
+{
+	setsel(str, CurrentTime);
+}
+
 void
 brelease(XEvent *e)
 {
@@ -643,7 +643,7 @@ brelease(XEvent *e)
 	} else if (e->xbutton.button == Button1) {
 		if (sel.mode == SEL_READY) {
 			getbuttoninfo(e);
-			selcopy(e->xbutton.time);
+			setsel(getsel(), e->xbutton.time);
 		} else
 			selclear_(NULL);
 		sel.mode = SEL_IDLE;

From 8b564c1a3f51c08e64c2f589852a02b8595d44ca Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Mon, 6 Nov 2017 18:30:45 -0600
Subject: [PATCH 0987/1146] Remove X and fontconfig from st.c

None of the X-related includes are needed any longer.  In addition, move
the X modifier defines into x.c, as they are not used outside.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c  | 5 -----
 win.h | 5 -----
 x.c   | 5 +++++
 3 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/st.c b/st.c
index bcb6473..9cfa547 100644
--- a/st.c
+++ b/st.c
@@ -21,13 +21,8 @@
 #include <time.h>
 #include <unistd.h>
 #include <libgen.h>
-#include <fontconfig/fontconfig.h>
 #include <wchar.h>
 
-/* X11 */
-#include <X11/cursorfont.h>
-#include <X11/Xft/Xft.h>
-
 #include "st.h"
 #include "win.h"
 
diff --git a/win.h b/win.h
index f95a679..123662e 100644
--- a/win.h
+++ b/win.h
@@ -1,10 +1,5 @@
 /* See LICENSE for license details. */
 
-/* X modifiers */
-#define XK_ANY_MOD    UINT_MAX
-#define XK_NO_MOD     0
-#define XK_SWITCH_MOD (1<<13)
-
 void draw(void);
 void drawregion(int, int, int, int);
 
diff --git a/x.c b/x.c
index a332ac9..e5b236d 100644
--- a/x.c
+++ b/x.c
@@ -44,6 +44,11 @@ typedef struct {
 	signed char crlf;      /* crlf mode          */
 } Key;
 
+/* X modifiers */
+#define XK_ANY_MOD    UINT_MAX
+#define XK_NO_MOD     0
+#define XK_SWITCH_MOD (1<<13)
+
 /* function definitions used in config.h */
 static void clipcopy(const Arg *);
 static void clippaste(const Arg *);

From d84f3f4bd15e7d65fc0334cf7d62913c901bad00 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Wed, 21 Feb 2018 22:28:41 -0600
Subject: [PATCH 0988/1146] Rely on ttyresize to set tty size

This removes ttynew's dependency on cresize being called first, and then
allows us to absorb the ttyresize call into cresize (which always
precedes it).

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c | 3 +--
 x.c  | 6 ++----
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/st.c b/st.c
index 9cfa547..dae7b91 100644
--- a/st.c
+++ b/st.c
@@ -670,7 +670,6 @@ void
 ttynew(char *line, char *out, char **args)
 {
 	int m, s;
-	struct winsize w = {term.row, term.col, 0, 0};
 
 	if (out) {
 		term.mode |= MODE_PRINT;
@@ -691,7 +690,7 @@ ttynew(char *line, char *out, char **args)
 	}
 
 	/* seems to work fine on linux, openbsd and freebsd */
-	if (openpty(&m, &s, NULL, NULL, &w) < 0)
+	if (openpty(&m, &s, NULL, NULL, NULL) < 0)
 		die("openpty failed: %s\n", strerror(errno));
 
 	switch (pid = fork()) {
diff --git a/x.c b/x.c
index e5b236d..7bfa1b7 100644
--- a/x.c
+++ b/x.c
@@ -276,7 +276,6 @@ zoomabs(const Arg *arg)
 	xunloadfonts();
 	xloadfonts(usedfont, arg->f);
 	cresize(0, 0);
-	ttyresize(win.tw, win.th);
 	redraw();
 	xhints();
 }
@@ -695,6 +694,7 @@ cresize(int width, int height)
 
 	tresize(col, row);
 	xresize(col, row);
+	ttyresize(win.tw, win.th);
 }
 
 void
@@ -1794,7 +1794,6 @@ resize(XEvent *e)
 		return;
 
 	cresize(e->xconfigure.width, e->xconfigure.height);
-	ttyresize(win.tw, win.th);
 }
 
 void
@@ -1823,9 +1822,8 @@ run(void)
 		}
 	} while (ev.type != MapNotify);
 
-	cresize(w, h);
 	ttynew(opt_line, opt_io, opt_cmd);
-	ttyresize(win.tw, win.th);
+	cresize(w, h);
 
 	clock_gettime(CLOCK_MONOTONIC, &last);
 	lastblink = last;

From 138caf294ea4d7968df36ead9d5ff5fc49f6215f Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Wed, 21 Feb 2018 22:48:28 -0600
Subject: [PATCH 0989/1146] Have selected() check whether selection exists

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c |  3 ++-
 x.c  | 10 ++++------
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/st.c b/st.c
index dae7b91..d4dfe6e 100644
--- a/st.c
+++ b/st.c
@@ -419,7 +419,8 @@ selnormalize(void)
 int
 selected(int x, int y)
 {
-	if (sel.mode == SEL_EMPTY)
+	if (sel.mode == SEL_EMPTY || sel.ob.x == -1 ||
+			sel.alt != IS_SET(MODE_ALTSCREEN))
 		return 0;
 
 	if (sel.type == SEL_RECTANGULAR)
diff --git a/x.c b/x.c
index 7bfa1b7..e3e5451 100644
--- a/x.c
+++ b/x.c
@@ -1418,7 +1418,6 @@ xdrawcursor(void)
 	static int oldx = 0, oldy = 0;
 	int curx;
 	Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og;
-	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 	Color drawcol;
 
 	LIMIT(oldx, 0, term.col-1);
@@ -1434,7 +1433,7 @@ xdrawcursor(void)
 
 	/* remove the old cursor */
 	og = term.line[oldy][oldx];
-	if (ena_sel && selected(oldx, oldy))
+	if (selected(oldx, oldy))
 		og.mode ^= ATTR_REVERSE;
 	xdrawglyph(og, oldx, oldy);
 
@@ -1448,7 +1447,7 @@ xdrawcursor(void)
 	if (IS_SET(MODE_REVERSE)) {
 		g.mode |= ATTR_REVERSE;
 		g.bg = defaultfg;
-		if (ena_sel && selected(term.c.x, term.c.y)) {
+		if (selected(term.c.x, term.c.y)) {
 			drawcol = dc.col[defaultcs];
 			g.fg = defaultrcs;
 		} else {
@@ -1456,7 +1455,7 @@ xdrawcursor(void)
 			g.fg = defaultcs;
 		}
 	} else {
-		if (ena_sel && selected(term.c.x, term.c.y)) {
+		if (selected(term.c.x, term.c.y)) {
 			drawcol = dc.col[defaultrcs];
 			g.fg = defaultfg;
 			g.bg = defaultrcs;
@@ -1555,7 +1554,6 @@ drawregion(int x1, int y1, int x2, int y2)
 	int i, x, y, ox, numspecs;
 	Glyph base, new;
 	XftGlyphFontSpec *specs;
-	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 
 	if (!(win.state & WIN_VISIBLE))
 		return;
@@ -1574,7 +1572,7 @@ drawregion(int x1, int y1, int x2, int y2)
 			new = term.line[y][x];
 			if (new.mode == ATTR_WDUMMY)
 				continue;
-			if (ena_sel && selected(x, y))
+			if (selected(x, y))
 				new.mode ^= ATTR_REVERSE;
 			if (i > 0 && ATTRCMP(base, new)) {
 				xdrawglyphfontspecs(specs, base, i, ox, y);

From 5683b1f80c5ac274adf98517ce2217b4d4896243 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Wed, 21 Feb 2018 22:56:02 -0600
Subject: [PATCH 0990/1146] Move X-specific selection info into XSelection

Data about PRIMARY/CLIPBOARD and clicks are part of the front-end, not
the terminal.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c |  4 ----
 st.h |  5 -----
 x.c  | 31 +++++++++++++++++++------------
 3 files changed, 19 insertions(+), 21 deletions(-)

diff --git a/st.c b/st.c
index d4dfe6e..ea0726c 100644
--- a/st.c
+++ b/st.c
@@ -365,13 +365,9 @@ base64dec(const char *src)
 void
 selinit(void)
 {
-	clock_gettime(CLOCK_MONOTONIC, &sel.tclick1);
-	clock_gettime(CLOCK_MONOTONIC, &sel.tclick2);
 	sel.mode = SEL_IDLE;
 	sel.snap = 0;
 	sel.ob.x = -1;
-	sel.primary = NULL;
-	sel.clipboard = NULL;
 }
 
 int
diff --git a/st.h b/st.h
index 8637d35..79dd47e 100644
--- a/st.h
+++ b/st.h
@@ -149,12 +149,7 @@ typedef struct {
 		int x, y;
 	} nb, ne, ob, oe;
 
-	char *primary, *clipboard;
 	int alt;
-	struct timespec tclick1;
-	struct timespec tclick2;
-
-	//Atom xtarget;
 } Selection;
 
 typedef union {
diff --git a/x.c b/x.c
index e3e5451..9f506b1 100644
--- a/x.c
+++ b/x.c
@@ -94,6 +94,9 @@ typedef struct {
 
 typedef struct {
 	Atom xtarget;
+	char *primary, *clipboard;
+	struct timespec tclick1;
+	struct timespec tclick2;
 } XSelection;
 
 /* Font structure */
@@ -234,11 +237,11 @@ clipcopy(const Arg *dummy)
 {
 	Atom clipboard;
 
-	if (sel.clipboard != NULL)
-		free(sel.clipboard);
+	if (xsel.clipboard != NULL)
+		free(xsel.clipboard);
 
-	if (sel.primary != NULL) {
-		sel.clipboard = xstrdup(sel.primary);
+	if (xsel.primary != NULL) {
+		xsel.clipboard = xstrdup(xsel.primary);
 		clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
 		XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
 	}
@@ -427,9 +430,9 @@ bpress(XEvent *e)
 		 * If the user clicks below predefined timeouts specific
 		 * snapping behaviour is exposed.
 		 */
-		if (TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) {
+		if (TIMEDIFF(now, xsel.tclick2) <= tripleclicktimeout) {
 			sel.snap = SNAP_LINE;
-		} else if (TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) {
+		} else if (TIMEDIFF(now, xsel.tclick1) <= doubleclicktimeout) {
 			sel.snap = SNAP_WORD;
 		} else {
 			sel.snap = 0;
@@ -439,8 +442,8 @@ bpress(XEvent *e)
 		if (sel.snap != 0)
 			sel.mode = SEL_READY;
 		tsetdirt(sel.nb.y, sel.ne.y);
-		sel.tclick2 = sel.tclick1;
-		sel.tclick1 = now;
+		xsel.tclick2 = xsel.tclick1;
+		xsel.tclick1 = now;
 	}
 }
 
@@ -594,9 +597,9 @@ selrequest(XEvent *e)
 		 */
 		clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
 		if (xsre->selection == XA_PRIMARY) {
-			seltext = sel.primary;
+			seltext = xsel.primary;
 		} else if (xsre->selection == clipboard) {
-			seltext = sel.clipboard;
+			seltext = xsel.clipboard;
 		} else {
 			fprintf(stderr,
 				"Unhandled clipboard selection 0x%lx\n",
@@ -620,8 +623,8 @@ selrequest(XEvent *e)
 void
 setsel(char *str, Time t)
 {
-	free(sel.primary);
-	sel.primary = str;
+	free(xsel.primary);
+	xsel.primary = str;
 
 	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
 	if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
@@ -1127,6 +1130,10 @@ xinit(void)
 	xhints();
 	XSync(xw.dpy, False);
 
+	clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1);
+	clock_gettime(CLOCK_MONOTONIC, &xsel.tclick2);
+	xsel.primary = NULL;
+	xsel.clipboard = NULL;
 	xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
 	if (xsel.xtarget == None)
 		xsel.xtarget = XA_STRING;

From bcb5d3adbe57ead05a829e5144c2ba1dc465865f Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Wed, 21 Feb 2018 23:29:41 -0600
Subject: [PATCH 0991/1146] Move terminal-related selection logic into st.c

The front-end determines information about mouse clicks and motion, and
the terminal handles the actual selection start/extend/dirty logic by
row and column.

While we're in the neighborhood, we'll also rename getbuttoninfo() to
mousesel() which is, at least, less wrong.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c | 37 +++++++++++++++++++++++++++++++++++++
 st.h |  3 ++-
 x.c  | 55 +++++++++++++++----------------------------------------
 3 files changed, 54 insertions(+), 41 deletions(-)

diff --git a/st.c b/st.c
index ea0726c..21cba9e 100644
--- a/st.c
+++ b/st.c
@@ -140,6 +140,7 @@ static void tscrollup(int, int);
 static void tscrolldown(int, int);
 static void tsetattr(int *, int);
 static void tsetchar(Rune, Glyph *, int, int);
+static void tsetdirt(int, int);
 static void tsetscroll(int, int);
 static void tswapscreen(void);
 static void tsetmode(int, int, int *, int);
@@ -384,6 +385,42 @@ tlinelen(int y)
 	return i;
 }
 
+void
+selstart(int col, int row, int snap)
+{
+	selclear();
+	sel.mode = SEL_EMPTY;
+	sel.type = SEL_REGULAR;
+	sel.snap = snap;
+	sel.oe.x = sel.ob.x = col;
+	sel.oe.y = sel.ob.y = row;
+	selnormalize();
+
+	if (sel.snap != 0)
+		sel.mode = SEL_READY;
+	tsetdirt(sel.nb.y, sel.ne.y);
+}
+
+void
+selextend(int col, int row, int type)
+{
+	int oldey, oldex, oldsby, oldsey, oldtype;
+	oldey = sel.oe.y;
+	oldex = sel.oe.x;
+	oldsby = sel.nb.y;
+	oldsey = sel.ne.y;
+	oldtype = sel.type;
+
+	sel.alt = IS_SET(MODE_ALTSCREEN);
+	sel.oe.x = col;
+	sel.oe.y = row;
+	selnormalize();
+	sel.type = type;
+
+	if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type)
+		tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
+}
+
 void
 selnormalize(void)
 {
diff --git a/st.h b/st.h
index 79dd47e..c5ff5cf 100644
--- a/st.h
+++ b/st.h
@@ -172,7 +172,6 @@ void toggleprinter(const Arg *);
 int tattrset(int);
 void tnew(int, int);
 void tresize(int, int);
-void tsetdirt(int, int);
 void tsetdirtattr(int);
 void ttynew(char *, char *, char **);
 size_t ttyread(void);
@@ -184,6 +183,8 @@ void resettitle(void);
 
 void selclear(void);
 void selinit(void);
+void selstart(int, int, int);
+void selextend(int, int, int);
 void selnormalize(void);
 int selected(int, int);
 char *getsel(void);
diff --git a/x.c b/x.c
index 9f506b1..ddae6b6 100644
--- a/x.c
+++ b/x.c
@@ -157,7 +157,7 @@ static void selnotify(XEvent *);
 static void selclear_(XEvent *);
 static void selrequest(XEvent *);
 static void setsel(char *, Time);
-static void getbuttoninfo(XEvent *);
+static void mousesel(XEvent *);
 static void mousereport(XEvent *);
 static char *kmap(KeySym, uint);
 static int match(uint, uint);
@@ -313,24 +313,19 @@ y2row(int y)
 }
 
 void
-getbuttoninfo(XEvent *e)
+mousesel(XEvent *e)
 {
-	int type;
+	int type, seltype = SEL_REGULAR;
 	uint state = e->xbutton.state & ~(Button1Mask | forceselmod);
 
-	sel.alt = IS_SET(MODE_ALTSCREEN);
-
-	sel.oe.x = x2col(e->xbutton.x);
-	sel.oe.y = y2row(e->xbutton.y);
-	selnormalize();
-
-	sel.type = SEL_REGULAR;
 	for (type = 1; type < LEN(selmasks); ++type) {
 		if (match(selmasks[type], state)) {
-			sel.type = type;
+			seltype = type;
 			break;
 		}
 	}
+
+	selextend(x2col(e->xbutton.x), y2row(e->xbutton.y), seltype);
 }
 
 void
@@ -402,6 +397,7 @@ bpress(XEvent *e)
 {
 	struct timespec now;
 	MouseShortcut *ms;
+	int snap;
 
 	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);
@@ -417,33 +413,22 @@ bpress(XEvent *e)
 	}
 
 	if (e->xbutton.button == Button1) {
-		clock_gettime(CLOCK_MONOTONIC, &now);
-
-		/* Clear previous selection, logically and visually. */
-		selclear_(NULL);
-		sel.mode = SEL_EMPTY;
-		sel.type = SEL_REGULAR;
-		sel.oe.x = sel.ob.x = x2col(e->xbutton.x);
-		sel.oe.y = sel.ob.y = y2row(e->xbutton.y);
-
 		/*
 		 * If the user clicks below predefined timeouts specific
 		 * snapping behaviour is exposed.
 		 */
+		clock_gettime(CLOCK_MONOTONIC, &now);
 		if (TIMEDIFF(now, xsel.tclick2) <= tripleclicktimeout) {
-			sel.snap = SNAP_LINE;
+			snap = SNAP_LINE;
 		} else if (TIMEDIFF(now, xsel.tclick1) <= doubleclicktimeout) {
-			sel.snap = SNAP_WORD;
+			snap = SNAP_WORD;
 		} else {
-			sel.snap = 0;
+			snap = 0;
 		}
-		selnormalize();
-
-		if (sel.snap != 0)
-			sel.mode = SEL_READY;
-		tsetdirt(sel.nb.y, sel.ne.y);
 		xsel.tclick2 = xsel.tclick1;
 		xsel.tclick1 = now;
+
+		selstart(x2col(e->xbutton.x), y2row(e->xbutton.y), snap);
 	}
 }
 
@@ -649,20 +634,17 @@ brelease(XEvent *e)
 		selpaste(NULL);
 	} else if (e->xbutton.button == Button1) {
 		if (sel.mode == SEL_READY) {
-			getbuttoninfo(e);
+			mousesel(e);
 			setsel(getsel(), e->xbutton.time);
 		} else
 			selclear_(NULL);
 		sel.mode = SEL_IDLE;
-		tsetdirt(sel.nb.y, sel.ne.y);
 	}
 }
 
 void
 bmotion(XEvent *e)
 {
-	int oldey, oldex, oldsby, oldsey;
-
 	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);
 		return;
@@ -672,14 +654,7 @@ bmotion(XEvent *e)
 		return;
 
 	sel.mode = SEL_READY;
-	oldey = sel.oe.y;
-	oldex = sel.oe.x;
-	oldsby = sel.nb.y;
-	oldsey = sel.ne.y;
-	getbuttoninfo(e);
-
-	if (oldey != sel.oe.y || oldex != sel.oe.x)
-		tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
+	mousesel(e);
 }
 
 void

From cfc7acdfd923924ae150a32061fb95987697b159 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Wed, 21 Feb 2018 23:54:29 -0600
Subject: [PATCH 0992/1146] Move remaining selection mode logic into selextend

The "done" parameter indicates a change which finalizes the selection
(e.g. a mouse button release as opposed to motion).

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c | 14 ++++++++++++--
 st.h |  3 +--
 x.c  | 27 +++++++++------------------
 3 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/st.c b/st.c
index 21cba9e..b7e215e 100644
--- a/st.c
+++ b/st.c
@@ -167,11 +167,11 @@ static ssize_t xwrite(int, const char *, size_t);
 
 /* Globals */
 Term term;
-Selection sel;
 int cmdfd;
 pid_t pid;
 int oldbutton   = 3; /* button event on startup: 3 = release */
 
+static Selection sel;
 static CSIEscape csiescseq;
 static STREscape strescseq;
 static int iofd = 1;
@@ -402,9 +402,17 @@ selstart(int col, int row, int snap)
 }
 
 void
-selextend(int col, int row, int type)
+selextend(int col, int row, int type, int done)
 {
 	int oldey, oldex, oldsby, oldsey, oldtype;
+
+	if (!sel.mode)
+		return;
+	if (done && sel.mode == SEL_EMPTY) {
+		selclear();
+		return;
+	}
+
 	oldey = sel.oe.y;
 	oldex = sel.oe.x;
 	oldsby = sel.nb.y;
@@ -419,6 +427,8 @@ selextend(int col, int row, int type)
 
 	if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type)
 		tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
+
+	sel.mode = done ? SEL_IDLE : SEL_READY;
 }
 
 void
diff --git a/st.h b/st.h
index c5ff5cf..a34e31c 100644
--- a/st.h
+++ b/st.h
@@ -184,7 +184,7 @@ void resettitle(void);
 void selclear(void);
 void selinit(void);
 void selstart(int, int, int);
-void selextend(int, int, int);
+void selextend(int, int, int, int);
 void selnormalize(void);
 int selected(int, int);
 char *getsel(void);
@@ -198,7 +198,6 @@ char *xstrdup(char *);
 
 /* Globals */
 extern Term term;
-extern Selection sel;
 extern int cmdfd;
 extern pid_t pid;
 extern int oldbutton;
diff --git a/x.c b/x.c
index ddae6b6..a7f619e 100644
--- a/x.c
+++ b/x.c
@@ -157,7 +157,7 @@ static void selnotify(XEvent *);
 static void selclear_(XEvent *);
 static void selrequest(XEvent *);
 static void setsel(char *, Time);
-static void mousesel(XEvent *);
+static void mousesel(XEvent *, int);
 static void mousereport(XEvent *);
 static char *kmap(KeySym, uint);
 static int match(uint, uint);
@@ -313,7 +313,7 @@ y2row(int y)
 }
 
 void
-mousesel(XEvent *e)
+mousesel(XEvent *e, int done)
 {
 	int type, seltype = SEL_REGULAR;
 	uint state = e->xbutton.state & ~(Button1Mask | forceselmod);
@@ -324,8 +324,9 @@ mousesel(XEvent *e)
 			break;
 		}
 	}
-
-	selextend(x2col(e->xbutton.x), y2row(e->xbutton.y), seltype);
+	selextend(x2col(e->xbutton.x), y2row(e->xbutton.y), seltype, done);
+	if (done)
+		setsel(getsel(), e->xbutton.time);
 }
 
 void
@@ -630,16 +631,10 @@ brelease(XEvent *e)
 		return;
 	}
 
-	if (e->xbutton.button == Button2) {
+	if (e->xbutton.button == Button2)
 		selpaste(NULL);
-	} else if (e->xbutton.button == Button1) {
-		if (sel.mode == SEL_READY) {
-			mousesel(e);
-			setsel(getsel(), e->xbutton.time);
-		} else
-			selclear_(NULL);
-		sel.mode = SEL_IDLE;
-	}
+	else if (e->xbutton.button == Button1)
+		mousesel(e, 1);
 }
 
 void
@@ -650,11 +645,7 @@ bmotion(XEvent *e)
 		return;
 	}
 
-	if (!sel.mode)
-		return;
-
-	sel.mode = SEL_READY;
-	mousesel(e);
+	mousesel(e, 0);
 }
 
 void

From 52d6fb1ab1f7d41839edebb63c3408578cd44e3c Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Thu, 22 Feb 2018 00:42:23 -0600
Subject: [PATCH 0993/1146] Move terminal echo logic into st.c

The only thing differentiating ttywrite and ttysend was the potential
for echo; make this a parameter and remove ttysend.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c | 23 +++++++++--------------
 st.h |  3 +--
 x.c  | 18 +++++++++---------
 3 files changed, 19 insertions(+), 25 deletions(-)

diff --git a/st.c b/st.c
index b7e215e..7d546da 100644
--- a/st.c
+++ b/st.c
@@ -784,12 +784,15 @@ ttyread(void)
 }
 
 void
-ttywrite(const char *s, size_t n)
+ttywrite(const char *s, size_t n, int may_echo)
 {
 	fd_set wfd, rfd;
 	ssize_t r;
 	size_t lim = 256;
 
+	if (may_echo && IS_SET(MODE_ECHO))
+		twrite(s, n, 1);
+
 	/*
 	 * 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
@@ -840,14 +843,6 @@ write_error:
 	die("write error on tty: %s\n", strerror(errno));
 }
 
-void
-ttysend(char *s, size_t n)
-{
-	ttywrite(s, n);
-	if (IS_SET(MODE_ECHO))
-		twrite(s, n, 1);
-}
-
 void
 ttyresize(int tw, int th)
 {
@@ -1570,7 +1565,7 @@ csihandle(void)
 		break;
 	case 'c': /* DA -- Device Attributes */
 		if (csiescseq.arg[0] == 0)
-			ttywrite(vtiden, strlen(vtiden));
+			ttywrite(vtiden, strlen(vtiden), 0);
 		break;
 	case 'C': /* CUF -- Cursor <n> Forward */
 	case 'a': /* HPR -- Cursor <n> Forward */
@@ -1698,7 +1693,7 @@ csihandle(void)
 		if (csiescseq.arg[0] == 6) {
 			len = snprintf(buf, sizeof(buf),"\033[%i;%iR",
 					term.c.y+1, term.c.x+1);
-			ttywrite(buf, len);
+			ttywrite(buf, len, 0);
 		}
 		break;
 	case 'r': /* DECSTBM -- Set Scrolling Region */
@@ -1916,7 +1911,7 @@ iso14755(const Arg *arg)
 	    (*e != '\n' && *e != '\0'))
 		return;
 
-	ttysend(uc, utf8encode(utf32, uc));
+	ttywrite(uc, utf8encode(utf32, uc), 1);
 }
 
 void
@@ -2129,7 +2124,7 @@ tcontrolcode(uchar ascii)
 	case 0x99:   /* TODO: SGCI */
 		break;
 	case 0x9a:   /* DECID -- Identify Terminal */
-		ttywrite(vtiden, strlen(vtiden));
+		ttywrite(vtiden, strlen(vtiden), 0);
 		break;
 	case 0x9b:   /* TODO: CSI */
 	case 0x9c:   /* TODO: ST */
@@ -2201,7 +2196,7 @@ eschandle(uchar ascii)
 		}
 		break;
 	case 'Z': /* DECID -- Identify Terminal */
-		ttywrite(vtiden, strlen(vtiden));
+		ttywrite(vtiden, strlen(vtiden), 0);
 		break;
 	case 'c': /* RIS -- Reset to inital state */
 		treset();
diff --git a/st.h b/st.h
index a34e31c..d7738a0 100644
--- a/st.h
+++ b/st.h
@@ -176,8 +176,7 @@ void tsetdirtattr(int);
 void ttynew(char *, char *, char **);
 size_t ttyread(void);
 void ttyresize(int, int);
-void ttysend(char *, size_t);
-void ttywrite(const char *, size_t);
+void ttywrite(const char *, size_t, int);
 
 void resettitle(void);
 
diff --git a/x.c b/x.c
index a7f619e..49a22e4 100644
--- a/x.c
+++ b/x.c
@@ -390,7 +390,7 @@ mousereport(XEvent *e)
 		return;
 	}
 
-	ttywrite(buf, len);
+	ttywrite(buf, len, 0);
 }
 
 void
@@ -408,7 +408,7 @@ bpress(XEvent *e)
 	for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
 		if (e->xbutton.button == ms->b
 				&& match(ms->mask, e->xbutton.state)) {
-			ttysend(ms->s, strlen(ms->s));
+			ttywrite(ms->s, strlen(ms->s), 1);
 			return;
 		}
 	}
@@ -520,10 +520,10 @@ selnotify(XEvent *e)
 		}
 
 		if (IS_SET(MODE_BRCKTPASTE) && ofs == 0)
-			ttywrite("\033[200~", 6);
-		ttysend((char *)data, nitems * format / 8);
+			ttywrite("\033[200~", 6, 0);
+		ttywrite((char *)data, nitems * format / 8, 1);
 		if (IS_SET(MODE_BRCKTPASTE) && rem == 0)
-			ttywrite("\033[201~", 6);
+			ttywrite("\033[201~", 6, 0);
 		XFree(data);
 		/* number of 32-bit chunks returned */
 		ofs += nitems * format / 32;
@@ -1634,12 +1634,12 @@ focus(XEvent *ev)
 		win.state |= WIN_FOCUSED;
 		xseturgency(0);
 		if (IS_SET(MODE_FOCUS))
-			ttywrite("\033[I", 3);
+			ttywrite("\033[I", 3, 0);
 	} else {
 		XUnsetICFocus(xw.xic);
 		win.state &= ~WIN_FOCUSED;
 		if (IS_SET(MODE_FOCUS))
-			ttywrite("\033[O", 3);
+			ttywrite("\033[O", 3, 0);
 	}
 }
 
@@ -1714,7 +1714,7 @@ kpress(XEvent *ev)
 
 	/* 2. custom keys from config.h */
 	if ((customkey = kmap(ksym, e->state))) {
-		ttysend(customkey, strlen(customkey));
+		ttywrite(customkey, strlen(customkey), 1);
 		return;
 	}
 
@@ -1733,7 +1733,7 @@ kpress(XEvent *ev)
 			len = 2;
 		}
 	}
-	ttysend(buf, len);
+	ttywrite(buf, len, 1);
 }
 
 

From 33201ac65f74e45b4fa60822ba9a538c3cfa9b25 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Thu, 22 Feb 2018 01:05:12 -0600
Subject: [PATCH 0994/1146] Move CRLF input processing into ttywrite

This also allows us to remove the crlf field from the Key struct, since
the only difference it made was converting "\r" to "\r\n" (which is now
done automatically in ttywrite).  In addition, MODE_CRLF is no longer
referenced from x.c.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 config.def.h | 423 +++++++++++++++++++++++++--------------------------
 st.c         |  32 +++-
 x.c          |   6 +-
 3 files changed, 240 insertions(+), 221 deletions(-)

diff --git a/config.def.h b/config.def.h
index 1c181ab..616616a 100644
--- a/config.def.h
+++ b/config.def.h
@@ -229,219 +229,216 @@ static uint forceselmod = ShiftMask;
  * world. Please decide about changes wisely.
  */
 static Key key[] = {
-	/* keysym           mask            string      appkey appcursor crlf */
-	{ XK_KP_Home,       ShiftMask,      "\033[2J",       0,   -1,    0},
-	{ XK_KP_Home,       ShiftMask,      "\033[1;2H",     0,   +1,    0},
-	{ XK_KP_Home,       XK_ANY_MOD,     "\033[H",        0,   -1,    0},
-	{ XK_KP_Home,       XK_ANY_MOD,     "\033[1~",       0,   +1,    0},
-	{ XK_KP_Up,         XK_ANY_MOD,     "\033Ox",       +1,    0,    0},
-	{ XK_KP_Up,         XK_ANY_MOD,     "\033[A",        0,   -1,    0},
-	{ XK_KP_Up,         XK_ANY_MOD,     "\033OA",        0,   +1,    0},
-	{ XK_KP_Down,       XK_ANY_MOD,     "\033Or",       +1,    0,    0},
-	{ XK_KP_Down,       XK_ANY_MOD,     "\033[B",        0,   -1,    0},
-	{ XK_KP_Down,       XK_ANY_MOD,     "\033OB",        0,   +1,    0},
-	{ XK_KP_Left,       XK_ANY_MOD,     "\033Ot",       +1,    0,    0},
-	{ XK_KP_Left,       XK_ANY_MOD,     "\033[D",        0,   -1,    0},
-	{ XK_KP_Left,       XK_ANY_MOD,     "\033OD",        0,   +1,    0},
-	{ XK_KP_Right,      XK_ANY_MOD,     "\033Ov",       +1,    0,    0},
-	{ XK_KP_Right,      XK_ANY_MOD,     "\033[C",        0,   -1,    0},
-	{ XK_KP_Right,      XK_ANY_MOD,     "\033OC",        0,   +1,    0},
-	{ XK_KP_Prior,      ShiftMask,      "\033[5;2~",     0,    0,    0},
-	{ XK_KP_Prior,      XK_ANY_MOD,     "\033[5~",       0,    0,    0},
-	{ XK_KP_Begin,      XK_ANY_MOD,     "\033[E",        0,    0,    0},
-	{ XK_KP_End,        ControlMask,    "\033[J",       -1,    0,    0},
-	{ XK_KP_End,        ControlMask,    "\033[1;5F",    +1,    0,    0},
-	{ XK_KP_End,        ShiftMask,      "\033[K",       -1,    0,    0},
-	{ XK_KP_End,        ShiftMask,      "\033[1;2F",    +1,    0,    0},
-	{ XK_KP_End,        XK_ANY_MOD,     "\033[4~",       0,    0,    0},
-	{ XK_KP_Next,       ShiftMask,      "\033[6;2~",     0,    0,    0},
-	{ XK_KP_Next,       XK_ANY_MOD,     "\033[6~",       0,    0,    0},
-	{ XK_KP_Insert,     ShiftMask,      "\033[2;2~",    +1,    0,    0},
-	{ XK_KP_Insert,     ShiftMask,      "\033[4l",      -1,    0,    0},
-	{ XK_KP_Insert,     ControlMask,    "\033[L",       -1,    0,    0},
-	{ XK_KP_Insert,     ControlMask,    "\033[2;5~",    +1,    0,    0},
-	{ XK_KP_Insert,     XK_ANY_MOD,     "\033[4h",      -1,    0,    0},
-	{ XK_KP_Insert,     XK_ANY_MOD,     "\033[2~",      +1,    0,    0},
-	{ XK_KP_Delete,     ControlMask,    "\033[M",       -1,    0,    0},
-	{ XK_KP_Delete,     ControlMask,    "\033[3;5~",    +1,    0,    0},
-	{ XK_KP_Delete,     ShiftMask,      "\033[2K",      -1,    0,    0},
-	{ XK_KP_Delete,     ShiftMask,      "\033[3;2~",    +1,    0,    0},
-	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[P",       -1,    0,    0},
-	{ XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
-	{ XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +2,    0,    0},
-	{ XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +2,    0,    0},
-	{ XK_KP_Enter,      XK_ANY_MOD,     "\033OM",       +2,    0,    0},
-	{ XK_KP_Enter,      XK_ANY_MOD,     "\r",           -1,    0,   -1},
-	{ XK_KP_Enter,      XK_ANY_MOD,     "\r\n",         -1,    0,   +1},
-	{ XK_KP_Subtract,   XK_ANY_MOD,     "\033Om",       +2,    0,    0},
-	{ XK_KP_Decimal,    XK_ANY_MOD,     "\033On",       +2,    0,    0},
-	{ XK_KP_Divide,     XK_ANY_MOD,     "\033Oo",       +2,    0,    0},
-	{ XK_KP_0,          XK_ANY_MOD,     "\033Op",       +2,    0,    0},
-	{ XK_KP_1,          XK_ANY_MOD,     "\033Oq",       +2,    0,    0},
-	{ XK_KP_2,          XK_ANY_MOD,     "\033Or",       +2,    0,    0},
-	{ XK_KP_3,          XK_ANY_MOD,     "\033Os",       +2,    0,    0},
-	{ XK_KP_4,          XK_ANY_MOD,     "\033Ot",       +2,    0,    0},
-	{ XK_KP_5,          XK_ANY_MOD,     "\033Ou",       +2,    0,    0},
-	{ XK_KP_6,          XK_ANY_MOD,     "\033Ov",       +2,    0,    0},
-	{ XK_KP_7,          XK_ANY_MOD,     "\033Ow",       +2,    0,    0},
-	{ XK_KP_8,          XK_ANY_MOD,     "\033Ox",       +2,    0,    0},
-	{ XK_KP_9,          XK_ANY_MOD,     "\033Oy",       +2,    0,    0},
-	{ XK_Up,            ShiftMask,      "\033[1;2A",     0,    0,    0},
-	{ XK_Up,            Mod1Mask,       "\033[1;3A",     0,    0,    0},
-	{ XK_Up,         ShiftMask|Mod1Mask,"\033[1;4A",     0,    0,    0},
-	{ XK_Up,            ControlMask,    "\033[1;5A",     0,    0,    0},
-	{ XK_Up,      ShiftMask|ControlMask,"\033[1;6A",     0,    0,    0},
-	{ XK_Up,       ControlMask|Mod1Mask,"\033[1;7A",     0,    0,    0},
-	{ XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A",  0,    0,    0},
-	{ XK_Up,            XK_ANY_MOD,     "\033[A",        0,   -1,    0},
-	{ XK_Up,            XK_ANY_MOD,     "\033OA",        0,   +1,    0},
-	{ XK_Down,          ShiftMask,      "\033[1;2B",     0,    0,    0},
-	{ XK_Down,          Mod1Mask,       "\033[1;3B",     0,    0,    0},
-	{ XK_Down,       ShiftMask|Mod1Mask,"\033[1;4B",     0,    0,    0},
-	{ XK_Down,          ControlMask,    "\033[1;5B",     0,    0,    0},
-	{ XK_Down,    ShiftMask|ControlMask,"\033[1;6B",     0,    0,    0},
-	{ XK_Down,     ControlMask|Mod1Mask,"\033[1;7B",     0,    0,    0},
-	{ XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0,    0,    0},
-	{ XK_Down,          XK_ANY_MOD,     "\033[B",        0,   -1,    0},
-	{ XK_Down,          XK_ANY_MOD,     "\033OB",        0,   +1,    0},
-	{ XK_Left,          ShiftMask,      "\033[1;2D",     0,    0,    0},
-	{ XK_Left,          Mod1Mask,       "\033[1;3D",     0,    0,    0},
-	{ XK_Left,       ShiftMask|Mod1Mask,"\033[1;4D",     0,    0,    0},
-	{ XK_Left,          ControlMask,    "\033[1;5D",     0,    0,    0},
-	{ XK_Left,    ShiftMask|ControlMask,"\033[1;6D",     0,    0,    0},
-	{ XK_Left,     ControlMask|Mod1Mask,"\033[1;7D",     0,    0,    0},
-	{ XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0,    0,    0},
-	{ XK_Left,          XK_ANY_MOD,     "\033[D",        0,   -1,    0},
-	{ XK_Left,          XK_ANY_MOD,     "\033OD",        0,   +1,    0},
-	{ XK_Right,         ShiftMask,      "\033[1;2C",     0,    0,    0},
-	{ XK_Right,         Mod1Mask,       "\033[1;3C",     0,    0,    0},
-	{ XK_Right,      ShiftMask|Mod1Mask,"\033[1;4C",     0,    0,    0},
-	{ XK_Right,         ControlMask,    "\033[1;5C",     0,    0,    0},
-	{ XK_Right,   ShiftMask|ControlMask,"\033[1;6C",     0,    0,    0},
-	{ XK_Right,    ControlMask|Mod1Mask,"\033[1;7C",     0,    0,    0},
-	{ XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0,   0,    0},
-	{ XK_Right,         XK_ANY_MOD,     "\033[C",        0,   -1,    0},
-	{ XK_Right,         XK_ANY_MOD,     "\033OC",        0,   +1,    0},
-	{ XK_ISO_Left_Tab,  ShiftMask,      "\033[Z",        0,    0,    0},
-	{ XK_Return,        Mod1Mask,       "\033\r",        0,    0,   -1},
-	{ XK_Return,        Mod1Mask,       "\033\r\n",      0,    0,   +1},
-	{ XK_Return,        XK_ANY_MOD,     "\r",            0,    0,   -1},
-	{ XK_Return,        XK_ANY_MOD,     "\r\n",          0,    0,   +1},
-	{ XK_Insert,        ShiftMask,      "\033[4l",      -1,    0,    0},
-	{ XK_Insert,        ShiftMask,      "\033[2;2~",    +1,    0,    0},
-	{ XK_Insert,        ControlMask,    "\033[L",       -1,    0,    0},
-	{ XK_Insert,        ControlMask,    "\033[2;5~",    +1,    0,    0},
-	{ XK_Insert,        XK_ANY_MOD,     "\033[4h",      -1,    0,    0},
-	{ XK_Insert,        XK_ANY_MOD,     "\033[2~",      +1,    0,    0},
-	{ XK_Delete,        ControlMask,    "\033[M",       -1,    0,    0},
-	{ XK_Delete,        ControlMask,    "\033[3;5~",    +1,    0,    0},
-	{ XK_Delete,        ShiftMask,      "\033[2K",      -1,    0,    0},
-	{ XK_Delete,        ShiftMask,      "\033[3;2~",    +1,    0,    0},
-	{ XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0,    0},
-	{ XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0,    0},
-	{ XK_BackSpace,     XK_NO_MOD,      "\177",          0,    0,    0},
-	{ XK_BackSpace,     Mod1Mask,       "\033\177",      0,    0,    0},
-	{ XK_Home,          ShiftMask,      "\033[2J",       0,   -1,    0},
-	{ XK_Home,          ShiftMask,      "\033[1;2H",     0,   +1,    0},
-	{ XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1,    0},
-	{ XK_Home,          XK_ANY_MOD,     "\033[1~",       0,   +1,    0},
-	{ XK_End,           ControlMask,    "\033[J",       -1,    0,    0},
-	{ XK_End,           ControlMask,    "\033[1;5F",    +1,    0,    0},
-	{ XK_End,           ShiftMask,      "\033[K",       -1,    0,    0},
-	{ XK_End,           ShiftMask,      "\033[1;2F",    +1,    0,    0},
-	{ XK_End,           XK_ANY_MOD,     "\033[4~",       0,    0,    0},
-	{ XK_Prior,         ControlMask,    "\033[5;5~",     0,    0,    0},
-	{ XK_Prior,         ShiftMask,      "\033[5;2~",     0,    0,    0},
-	{ XK_Prior,         XK_ANY_MOD,     "\033[5~",       0,    0,    0},
-	{ XK_Next,          ControlMask,    "\033[6;5~",     0,    0,    0},
-	{ XK_Next,          ShiftMask,      "\033[6;2~",     0,    0,    0},
-	{ XK_Next,          XK_ANY_MOD,     "\033[6~",       0,    0,    0},
-	{ XK_F1,            XK_NO_MOD,      "\033OP" ,       0,    0,    0},
-	{ XK_F1, /* F13 */  ShiftMask,      "\033[1;2P",     0,    0,    0},
-	{ XK_F1, /* F25 */  ControlMask,    "\033[1;5P",     0,    0,    0},
-	{ XK_F1, /* F37 */  Mod4Mask,       "\033[1;6P",     0,    0,    0},
-	{ XK_F1, /* F49 */  Mod1Mask,       "\033[1;3P",     0,    0,    0},
-	{ XK_F1, /* F61 */  Mod3Mask,       "\033[1;4P",     0,    0,    0},
-	{ XK_F2,            XK_NO_MOD,      "\033OQ" ,       0,    0,    0},
-	{ XK_F2, /* F14 */  ShiftMask,      "\033[1;2Q",     0,    0,    0},
-	{ XK_F2, /* F26 */  ControlMask,    "\033[1;5Q",     0,    0,    0},
-	{ XK_F2, /* F38 */  Mod4Mask,       "\033[1;6Q",     0,    0,    0},
-	{ XK_F2, /* F50 */  Mod1Mask,       "\033[1;3Q",     0,    0,    0},
-	{ XK_F2, /* F62 */  Mod3Mask,       "\033[1;4Q",     0,    0,    0},
-	{ XK_F3,            XK_NO_MOD,      "\033OR" ,       0,    0,    0},
-	{ XK_F3, /* F15 */  ShiftMask,      "\033[1;2R",     0,    0,    0},
-	{ XK_F3, /* F27 */  ControlMask,    "\033[1;5R",     0,    0,    0},
-	{ XK_F3, /* F39 */  Mod4Mask,       "\033[1;6R",     0,    0,    0},
-	{ XK_F3, /* F51 */  Mod1Mask,       "\033[1;3R",     0,    0,    0},
-	{ XK_F3, /* F63 */  Mod3Mask,       "\033[1;4R",     0,    0,    0},
-	{ XK_F4,            XK_NO_MOD,      "\033OS" ,       0,    0,    0},
-	{ XK_F4, /* F16 */  ShiftMask,      "\033[1;2S",     0,    0,    0},
-	{ XK_F4, /* F28 */  ControlMask,    "\033[1;5S",     0,    0,    0},
-	{ XK_F4, /* F40 */  Mod4Mask,       "\033[1;6S",     0,    0,    0},
-	{ XK_F4, /* F52 */  Mod1Mask,       "\033[1;3S",     0,    0,    0},
-	{ XK_F5,            XK_NO_MOD,      "\033[15~",      0,    0,    0},
-	{ XK_F5, /* F17 */  ShiftMask,      "\033[15;2~",    0,    0,    0},
-	{ XK_F5, /* F29 */  ControlMask,    "\033[15;5~",    0,    0,    0},
-	{ XK_F5, /* F41 */  Mod4Mask,       "\033[15;6~",    0,    0,    0},
-	{ XK_F5, /* F53 */  Mod1Mask,       "\033[15;3~",    0,    0,    0},
-	{ XK_F6,            XK_NO_MOD,      "\033[17~",      0,    0,    0},
-	{ XK_F6, /* F18 */  ShiftMask,      "\033[17;2~",    0,    0,    0},
-	{ XK_F6, /* F30 */  ControlMask,    "\033[17;5~",    0,    0,    0},
-	{ XK_F6, /* F42 */  Mod4Mask,       "\033[17;6~",    0,    0,    0},
-	{ XK_F6, /* F54 */  Mod1Mask,       "\033[17;3~",    0,    0,    0},
-	{ XK_F7,            XK_NO_MOD,      "\033[18~",      0,    0,    0},
-	{ XK_F7, /* F19 */  ShiftMask,      "\033[18;2~",    0,    0,    0},
-	{ XK_F7, /* F31 */  ControlMask,    "\033[18;5~",    0,    0,    0},
-	{ XK_F7, /* F43 */  Mod4Mask,       "\033[18;6~",    0,    0,    0},
-	{ XK_F7, /* F55 */  Mod1Mask,       "\033[18;3~",    0,    0,    0},
-	{ XK_F8,            XK_NO_MOD,      "\033[19~",      0,    0,    0},
-	{ XK_F8, /* F20 */  ShiftMask,      "\033[19;2~",    0,    0,    0},
-	{ XK_F8, /* F32 */  ControlMask,    "\033[19;5~",    0,    0,    0},
-	{ XK_F8, /* F44 */  Mod4Mask,       "\033[19;6~",    0,    0,    0},
-	{ XK_F8, /* F56 */  Mod1Mask,       "\033[19;3~",    0,    0,    0},
-	{ XK_F9,            XK_NO_MOD,      "\033[20~",      0,    0,    0},
-	{ XK_F9, /* F21 */  ShiftMask,      "\033[20;2~",    0,    0,    0},
-	{ XK_F9, /* F33 */  ControlMask,    "\033[20;5~",    0,    0,    0},
-	{ XK_F9, /* F45 */  Mod4Mask,       "\033[20;6~",    0,    0,    0},
-	{ XK_F9, /* F57 */  Mod1Mask,       "\033[20;3~",    0,    0,    0},
-	{ XK_F10,           XK_NO_MOD,      "\033[21~",      0,    0,    0},
-	{ XK_F10, /* F22 */ ShiftMask,      "\033[21;2~",    0,    0,    0},
-	{ XK_F10, /* F34 */ ControlMask,    "\033[21;5~",    0,    0,    0},
-	{ XK_F10, /* F46 */ Mod4Mask,       "\033[21;6~",    0,    0,    0},
-	{ XK_F10, /* F58 */ Mod1Mask,       "\033[21;3~",    0,    0,    0},
-	{ XK_F11,           XK_NO_MOD,      "\033[23~",      0,    0,    0},
-	{ XK_F11, /* F23 */ ShiftMask,      "\033[23;2~",    0,    0,    0},
-	{ XK_F11, /* F35 */ ControlMask,    "\033[23;5~",    0,    0,    0},
-	{ XK_F11, /* F47 */ Mod4Mask,       "\033[23;6~",    0,    0,    0},
-	{ XK_F11, /* F59 */ Mod1Mask,       "\033[23;3~",    0,    0,    0},
-	{ XK_F12,           XK_NO_MOD,      "\033[24~",      0,    0,    0},
-	{ XK_F12, /* F24 */ ShiftMask,      "\033[24;2~",    0,    0,    0},
-	{ XK_F12, /* F36 */ ControlMask,    "\033[24;5~",    0,    0,    0},
-	{ XK_F12, /* F48 */ Mod4Mask,       "\033[24;6~",    0,    0,    0},
-	{ XK_F12, /* F60 */ Mod1Mask,       "\033[24;3~",    0,    0,    0},
-	{ XK_F13,           XK_NO_MOD,      "\033[1;2P",     0,    0,    0},
-	{ XK_F14,           XK_NO_MOD,      "\033[1;2Q",     0,    0,    0},
-	{ XK_F15,           XK_NO_MOD,      "\033[1;2R",     0,    0,    0},
-	{ XK_F16,           XK_NO_MOD,      "\033[1;2S",     0,    0,    0},
-	{ XK_F17,           XK_NO_MOD,      "\033[15;2~",    0,    0,    0},
-	{ XK_F18,           XK_NO_MOD,      "\033[17;2~",    0,    0,    0},
-	{ XK_F19,           XK_NO_MOD,      "\033[18;2~",    0,    0,    0},
-	{ XK_F20,           XK_NO_MOD,      "\033[19;2~",    0,    0,    0},
-	{ XK_F21,           XK_NO_MOD,      "\033[20;2~",    0,    0,    0},
-	{ XK_F22,           XK_NO_MOD,      "\033[21;2~",    0,    0,    0},
-	{ XK_F23,           XK_NO_MOD,      "\033[23;2~",    0,    0,    0},
-	{ XK_F24,           XK_NO_MOD,      "\033[24;2~",    0,    0,    0},
-	{ XK_F25,           XK_NO_MOD,      "\033[1;5P",     0,    0,    0},
-	{ XK_F26,           XK_NO_MOD,      "\033[1;5Q",     0,    0,    0},
-	{ XK_F27,           XK_NO_MOD,      "\033[1;5R",     0,    0,    0},
-	{ XK_F28,           XK_NO_MOD,      "\033[1;5S",     0,    0,    0},
-	{ XK_F29,           XK_NO_MOD,      "\033[15;5~",    0,    0,    0},
-	{ XK_F30,           XK_NO_MOD,      "\033[17;5~",    0,    0,    0},
-	{ XK_F31,           XK_NO_MOD,      "\033[18;5~",    0,    0,    0},
-	{ XK_F32,           XK_NO_MOD,      "\033[19;5~",    0,    0,    0},
-	{ XK_F33,           XK_NO_MOD,      "\033[20;5~",    0,    0,    0},
-	{ XK_F34,           XK_NO_MOD,      "\033[21;5~",    0,    0,    0},
-	{ XK_F35,           XK_NO_MOD,      "\033[23;5~",    0,    0,    0},
+	/* 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},
 };
 
 /*
diff --git a/st.c b/st.c
index 7d546da..3ebf8c6 100644
--- a/st.c
+++ b/st.c
@@ -108,6 +108,7 @@ typedef struct {
 static void execsh(char **);
 static void stty(char **);
 static void sigchld(int);
+static void ttywriteraw(const char *, size_t);
 
 static void csidump(void);
 static void csihandle(void);
@@ -786,13 +787,38 @@ ttyread(void)
 void
 ttywrite(const char *s, size_t n, int may_echo)
 {
-	fd_set wfd, rfd;
-	ssize_t r;
-	size_t lim = 256;
+	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
diff --git a/x.c b/x.c
index 49a22e4..76fb910 100644
--- a/x.c
+++ b/x.c
@@ -38,10 +38,9 @@ typedef struct {
 	KeySym k;
 	uint mask;
 	char *s;
-	/* three valued logic variables: 0 indifferent, 1 on, -1 off */
+	/* three-valued logic variables: 0 indifferent, 1 on, -1 off */
 	signed char appkey;    /* application keypad */
 	signed char appcursor; /* application cursor */
-	signed char crlf;      /* crlf mode          */
 } Key;
 
 /* X modifiers */
@@ -1680,9 +1679,6 @@ kmap(KeySym k, uint state)
 		if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0)
 			continue;
 
-		if (IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0)
-			continue;
-
 		return kp->s;
 	}
 

From 05c66cb37d9ff278a3e0c45682c4b5e7945deb42 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Fri, 23 Feb 2018 14:16:52 -0600
Subject: [PATCH 0995/1146] Split mode bits between Term and TermWindow

Moves the mode bits used by x.c from Term to TermWindow, absorbing
UI/input-related mode bits (visible/focused/numlock) along the way.

This is gradually reducing external references to Term.  Since
TermWindow is already internal to x.c, we add xsetmode() to allow st to
modify window bits in accordance with escape sequences.

IS_SET() is redefined accordingly (term.mode in st.c, win.mode in x.c).

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c  | 64 +++++++++++++++++++++++++++++------------------------------
 st.h  | 33 +-----------------------------
 win.h | 24 ++++++++++++++++++++++
 x.c   | 50 ++++++++++++++++++++++++++++------------------
 4 files changed, 88 insertions(+), 83 deletions(-)

diff --git a/st.c b/st.c
index 3ebf8c6..01791a5 100644
--- a/st.c
+++ b/st.c
@@ -42,6 +42,7 @@
 #define STR_ARG_SIZ   ESC_ARG_SIZ
 
 /* macros */
+#define IS_SET(flag)		((term.mode & (flag)) != 0)
 #define NUMMAXLEN(x)		((int)(sizeof(x) * 2.56 + 0.5) + 1)
 #define ISCONTROLC0(c)		(BETWEEN(c, 0, 0x1f) || (c) == '\177')
 #define ISCONTROLC1(c)		(BETWEEN(c, 0x80, 0x9f))
@@ -51,6 +52,17 @@
 /* constants */
 #define ISO14755CMD		"dmenu -w \"$WINDOWID\" -p codepoint: </dev/null"
 
+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,
+	MODE_SIXEL       = 1 << 7,
+};
+
 enum cursor_movement {
 	CURSOR_SAVE,
 	CURSOR_LOAD
@@ -977,8 +989,6 @@ tnew(int col, int row)
 {
 	term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
 	tresize(col, row);
-	term.numlock = 1;
-
 	treset();
 }
 
@@ -1414,20 +1424,16 @@ tsetscroll(int t, int b)
 void
 tsetmode(int priv, int set, int *args, int narg)
 {
-	int *lim, mode;
-	int alt;
+	int alt, *lim;
 
 	for (lim = args + narg; args < lim; ++args) {
 		if (priv) {
 			switch (*args) {
 			case 1: /* DECCKM -- Cursor key */
-				MODBIT(term.mode, set, MODE_APPCURSOR);
+				xsetmode(set, MODE_APPCURSOR);
 				break;
 			case 5: /* DECSCNM -- Reverse video */
-				mode = term.mode;
-				MODBIT(term.mode, set, MODE_REVERSE);
-				if (mode != term.mode)
-					redraw();
+				xsetmode(set, MODE_REVERSE);
 				break;
 			case 6: /* DECOM -- Origin */
 				MODBIT(term.c.state, set, CURSOR_ORIGIN);
@@ -1447,36 +1453,36 @@ tsetmode(int priv, int set, int *args, int narg)
 			case 12: /* att610 -- Start blinking cursor (IGNORED) */
 				break;
 			case 25: /* DECTCEM -- Text Cursor Enable Mode */
-				MODBIT(term.mode, !set, MODE_HIDE);
+				xsetmode(!set, MODE_HIDE);
 				break;
 			case 9:    /* X10 mouse compatibility mode */
 				xsetpointermotion(0);
-				MODBIT(term.mode, 0, MODE_MOUSE);
-				MODBIT(term.mode, set, MODE_MOUSEX10);
+				xsetmode(0, MODE_MOUSE);
+				xsetmode(set, MODE_MOUSEX10);
 				break;
 			case 1000: /* 1000: report button press */
 				xsetpointermotion(0);
-				MODBIT(term.mode, 0, MODE_MOUSE);
-				MODBIT(term.mode, set, MODE_MOUSEBTN);
+				xsetmode(0, MODE_MOUSE);
+				xsetmode(set, MODE_MOUSEBTN);
 				break;
 			case 1002: /* 1002: report motion on button press */
 				xsetpointermotion(0);
-				MODBIT(term.mode, 0, MODE_MOUSE);
-				MODBIT(term.mode, set, MODE_MOUSEMOTION);
+				xsetmode(0, MODE_MOUSE);
+				xsetmode(set, MODE_MOUSEMOTION);
 				break;
 			case 1003: /* 1003: enable all mouse motions */
 				xsetpointermotion(set);
-				MODBIT(term.mode, 0, MODE_MOUSE);
-				MODBIT(term.mode, set, MODE_MOUSEMANY);
+				xsetmode(0, MODE_MOUSE);
+				xsetmode(set, MODE_MOUSEMANY);
 				break;
 			case 1004: /* 1004: send focus events to tty */
-				MODBIT(term.mode, set, MODE_FOCUS);
+				xsetmode(set, MODE_FOCUS);
 				break;
 			case 1006: /* 1006: extended reporting mode */
-				MODBIT(term.mode, set, MODE_MOUSESGR);
+				xsetmode(set, MODE_MOUSESGR);
 				break;
 			case 1034:
-				MODBIT(term.mode, set, MODE_8BIT);
+				xsetmode(set, MODE_8BIT);
 				break;
 			case 1049: /* swap screen & set/restore cursor as xterm */
 				if (!allowaltscreen)
@@ -1501,7 +1507,7 @@ tsetmode(int priv, int set, int *args, int narg)
 				tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
 				break;
 			case 2004: /* 2004: bracketed paste mode */
-				MODBIT(term.mode, set, MODE_BRCKTPASTE);
+				xsetmode(set, MODE_BRCKTPASTE);
 				break;
 			/* Not implemented mouse modes. See comments there. */
 			case 1001: /* mouse highlight mode; can hang the
@@ -1522,8 +1528,8 @@ tsetmode(int priv, int set, int *args, int narg)
 			switch (*args) {
 			case 0:  /* Error (IGNORED) */
 				break;
-			case 2:  /* KAM -- keyboard action */
-				MODBIT(term.mode, set, MODE_KBDLOCK);
+			case 2:
+				xsetmode(set, MODE_KBDLOCK);
 				break;
 			case 4:  /* IRM -- Insertion-replacement */
 				MODBIT(term.mode, set, MODE_INSERT);
@@ -2230,10 +2236,10 @@ eschandle(uchar ascii)
 		xloadcols();
 		break;
 	case '=': /* DECPAM -- Application keypad */
-		term.mode |= MODE_APPKEYPAD;
+		xsetmode(1, MODE_APPKEYPAD);
 		break;
 	case '>': /* DECPNM -- Normal keypad */
-		term.mode &= ~MODE_APPKEYPAD;
+		xsetmode(0, MODE_APPKEYPAD);
 		break;
 	case '7': /* DECSC -- Save Cursor */
 		tcursor(CURSOR_SAVE);
@@ -2526,9 +2532,3 @@ redraw(void)
 	tfulldirt();
 	draw();
 }
-
-void
-numlock(const Arg *dummy)
-{
-	term.numlock ^= 1;
-}
diff --git a/st.h b/st.h
index d7738a0..3382d61 100644
--- a/st.h
+++ b/st.h
@@ -13,7 +13,6 @@
 #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 IS_SET(flag)		((term.mode & (flag)) != 0)
 #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)))
@@ -37,34 +36,6 @@ enum glyph_attribute {
 	ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
 };
 
-enum term_mode {
-	MODE_WRAP        = 1 << 0,
-	MODE_INSERT      = 1 << 1,
-	MODE_APPKEYPAD   = 1 << 2,
-	MODE_ALTSCREEN   = 1 << 3,
-	MODE_CRLF        = 1 << 4,
-	MODE_MOUSEBTN    = 1 << 5,
-	MODE_MOUSEMOTION = 1 << 6,
-	MODE_REVERSE     = 1 << 7,
-	MODE_KBDLOCK     = 1 << 8,
-	MODE_HIDE        = 1 << 9,
-	MODE_ECHO        = 1 << 10,
-	MODE_APPCURSOR   = 1 << 11,
-	MODE_MOUSESGR    = 1 << 12,
-	MODE_8BIT        = 1 << 13,
-	MODE_BLINK       = 1 << 14,
-	MODE_FBLINK      = 1 << 15,
-	MODE_FOCUS       = 1 << 16,
-	MODE_MOUSEX10    = 1 << 17,
-	MODE_MOUSEMANY   = 1 << 18,
-	MODE_BRCKTPASTE  = 1 << 19,
-	MODE_PRINT       = 1 << 20,
-	MODE_UTF8        = 1 << 21,
-	MODE_SIXEL       = 1 << 22,
-	MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
-	                  |MODE_MOUSEMANY,
-};
-
 enum selection_mode {
 	SEL_IDLE = 0,
 	SEL_EMPTY = 1,
@@ -120,7 +91,6 @@ typedef struct {
 	char trantbl[4]; /* charset table translation */
 	int charset;  /* current charset */
 	int icharset; /* selected charset for sequence */
-	int numlock; /* lock numbers in keyboard */
 	int *tabs;
 } Term;
 
@@ -130,7 +100,7 @@ typedef struct {
 	int w, h; /* window width and height */
 	int ch; /* char height */
 	int cw; /* char width  */
-	char state; /* focus, redraw, visible */
+	int mode; /* window state/mode flags */
 	int cursor; /* cursor style */
 } TermWindow;
 
@@ -163,7 +133,6 @@ void die(const char *, ...);
 void redraw(void);
 
 void iso14755(const Arg *);
-void numlock(const Arg *);
 void printscreen(const Arg *);
 void printsel(const Arg *);
 void sendbreak(const Arg *);
diff --git a/win.h b/win.h
index 123662e..1e08b16 100644
--- a/win.h
+++ b/win.h
@@ -1,5 +1,28 @@
 /* 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 draw(void);
 void drawregion(int, int, int, int);
 
@@ -10,5 +33,6 @@ void xloadcols(void);
 int xsetcolorname(int, const char *);
 void xsettitle(char *);
 int xsetcursor(int);
+void xsetmode(int, unsigned int);
 void xsetpointermotion(int);
 void xsetsel(char *);
diff --git a/x.c b/x.c
index 76fb910..c5826cf 100644
--- a/x.c
+++ b/x.c
@@ -51,6 +51,7 @@ typedef struct {
 /* 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 *);
@@ -64,6 +65,7 @@ static void zoomreset(const Arg *);
 #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)
@@ -196,11 +198,6 @@ static XWindow xw;
 static XSelection xsel;
 static TermWindow win;
 
-enum window_state {
-	WIN_VISIBLE = 1,
-	WIN_FOCUSED = 2
-};
-
 /* Font Ring Cache */
 enum {
 	FRC_NORMAL,
@@ -263,6 +260,12 @@ selpaste(const Arg *dummy)
 			xw.win, CurrentTime);
 }
 
+void
+numlock(const Arg *dummy)
+{
+	win.mode ^= MODE_NUMLOCK;
+}
+
 void
 zoom(const Arg *arg)
 {
@@ -1090,6 +1093,7 @@ xinit(void)
 	XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
 			PropModeReplace, (uchar *)&thispid, 1);
 
+	win.mode = MODE_NUMLOCK;
 	resettitle();
 	XMapWindow(xw.dpy, xw.win);
 	xhints();
@@ -1319,14 +1323,13 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 		fg = &revfg;
 	}
 
-
 	if (base.mode & ATTR_REVERSE) {
 		temp = fg;
 		fg = bg;
 		bg = temp;
 	}
 
-	if (base.mode & ATTR_BLINK && term.mode & MODE_BLINK)
+	if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK)
 		fg = bg;
 
 	if (base.mode & ATTR_INVISIBLE)
@@ -1440,7 +1443,7 @@ xdrawcursor(void)
 		return;
 
 	/* draw the new one */
-	if (win.state & WIN_FOCUSED) {
+	if (IS_SET(MODE_FOCUSED)) {
 		switch (win.cursor) {
 		case 7: /* st extension: snowman */
 			utf8decode("☃", &g.u, UTF_SIZ);
@@ -1527,7 +1530,7 @@ drawregion(int x1, int y1, int x2, int y2)
 	Glyph base, new;
 	XftGlyphFontSpec *specs;
 
-	if (!(win.state & WIN_VISIBLE))
+	if (!(IS_SET(MODE_VISIBLE)))
 		return;
 
 	for (y = y1; y < y2; y++) {
@@ -1575,13 +1578,13 @@ visibility(XEvent *ev)
 {
 	XVisibilityEvent *e = &ev->xvisibility;
 
-	MODBIT(win.state, e->state != VisibilityFullyObscured, WIN_VISIBLE);
+	MODBIT(win.mode, e->state != VisibilityFullyObscured, MODE_VISIBLE);
 }
 
 void
 unmap(XEvent *ev)
 {
-	win.state &= ~WIN_VISIBLE;
+	win.mode &= ~MODE_VISIBLE;
 }
 
 void
@@ -1591,6 +1594,15 @@ xsetpointermotion(int set)
 	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)
 {
@@ -1614,7 +1626,7 @@ xseturgency(int add)
 void
 xbell(void)
 {
-	if (!(win.state & WIN_FOCUSED))
+	if (!(IS_SET(MODE_FOCUSED)))
 		xseturgency(1);
 	if (bellvolume)
 		XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL);
@@ -1630,13 +1642,13 @@ focus(XEvent *ev)
 
 	if (ev->type == FocusIn) {
 		XSetICFocus(xw.xic);
-		win.state |= WIN_FOCUSED;
+		win.mode |= MODE_FOCUSED;
 		xseturgency(0);
 		if (IS_SET(MODE_FOCUS))
 			ttywrite("\033[I", 3, 0);
 	} else {
 		XUnsetICFocus(xw.xic);
-		win.state &= ~WIN_FOCUSED;
+		win.mode &= ~MODE_FOCUSED;
 		if (IS_SET(MODE_FOCUS))
 			ttywrite("\033[O", 3, 0);
 	}
@@ -1673,7 +1685,7 @@ kmap(KeySym k, uint state)
 
 		if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0)
 			continue;
-		if (term.numlock && kp->appkey == 2)
+		if (IS_SET(MODE_NUMLOCK) && kp->appkey == 2)
 			continue;
 
 		if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0)
@@ -1742,10 +1754,10 @@ cmessage(XEvent *e)
 	 */
 	if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
 		if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
-			win.state |= WIN_FOCUSED;
+			win.mode |= MODE_FOCUSED;
 			xseturgency(0);
 		} else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
-			win.state &= ~WIN_FOCUSED;
+			win.mode &= ~MODE_FOCUSED;
 		}
 	} else if (e->xclient.data.l[0] == xw.wmdeletewin) {
 		/* Send SIGHUP to shell */
@@ -1810,7 +1822,7 @@ run(void)
 			if (blinktimeout) {
 				blinkset = tattrset(ATTR_BLINK);
 				if (!blinkset)
-					MODBIT(term.mode, 0, MODE_BLINK);
+					MODBIT(win.mode, 0, MODE_BLINK);
 			}
 		}
 
@@ -1825,7 +1837,7 @@ run(void)
 		dodraw = 0;
 		if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
 			tsetdirtattr(ATTR_BLINK);
-			term.mode ^= MODE_BLINK;
+			win.mode ^= MODE_BLINK;
 			lastblink = now;
 			dodraw = 1;
 		}

From 88d8293fb4ba150a5f19d58d133b5db93d9dcfa5 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Sat, 24 Feb 2018 14:53:23 -0600
Subject: [PATCH 0996/1146] Move win-agnostic parts of draw/drawregion to st.c

Introduces three functions to encapsulate X-specific behavior:
 * xdrawline: draws a portion of a single line (used by drawregion)
 * xbegindraw: called to prepare for drawing (will be useful for e.g.
   Wayland) and returns true if drawing should happen
 * xfinishdraw: called to finish drawing (used by draw)

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c  | 25 +++++++++++++++++
 st.h  |  1 +
 win.h |  7 ++---
 x.c   | 87 +++++++++++++++++++++++++++--------------------------------
 4 files changed, 69 insertions(+), 51 deletions(-)

diff --git a/st.c b/st.c
index 01791a5..504239e 100644
--- a/st.c
+++ b/st.c
@@ -166,6 +166,8 @@ static int32_t tdefcolor(int *, int *, int);
 static void tdeftran(char);
 static void tstrsequence(uchar);
 
+static void drawregion(int, int, int, int);
+
 static void selscroll(int, int);
 static void selsnap(int *, int *, int);
 
@@ -2526,6 +2528,29 @@ 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)
+{
+	if (!xstartdraw())
+		return;
+	drawregion(0, 0, term.col, term.row);
+	xdrawcursor();
+	xfinishdraw();
+}
+
 void
 redraw(void)
 {
diff --git a/st.h b/st.h
index 3382d61..7026de8 100644
--- a/st.h
+++ b/st.h
@@ -131,6 +131,7 @@ typedef union {
 
 void die(const char *, ...);
 void redraw(void);
+void draw(void);
 
 void iso14755(const Arg *);
 void printscreen(const Arg *);
diff --git a/win.h b/win.h
index 1e08b16..6e662af 100644
--- a/win.h
+++ b/win.h
@@ -23,12 +23,12 @@ enum win_mode {
 	                  |MODE_MOUSEMANY,
 };
 
-void draw(void);
-void drawregion(int, int, int, int);
-
 void xbell(void);
 void xclipcopy(void);
+void xdrawcursor(void);
+void xdrawline(Line, int, int, int);
 void xhints(void);
+void xfinishdraw(void);
 void xloadcols(void);
 int xsetcolorname(int, const char *);
 void xsettitle(char *);
@@ -36,3 +36,4 @@ int xsetcursor(int);
 void xsetmode(int, unsigned int);
 void xsetpointermotion(int);
 void xsetsel(char *);
+int xstartdraw(void);
diff --git a/x.c b/x.c
index c5826cf..96944ee 100644
--- a/x.c
+++ b/x.c
@@ -129,7 +129,6 @@ 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 void xdrawcursor(void);
 static int xgeommasktogravity(int);
 static void xinit(void);
 static void cresize(int, int);
@@ -1512,10 +1511,46 @@ xsettitle(char *p)
 	XFree(prop.value);
 }
 
-void
-draw(void)
+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)
 {
-	drawregion(0, 0, term.col, term.row);
 	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w,
 			win.h, 0, 0);
 	XSetForeground(xw.dpy, dc.gc,
@@ -1523,50 +1558,6 @@ draw(void)
 				defaultfg : defaultbg].pixel);
 }
 
-void
-drawregion(int x1, int y1, int x2, int y2)
-{
-	int i, x, y, ox, numspecs;
-	Glyph base, new;
-	XftGlyphFontSpec *specs;
-
-	if (!(IS_SET(MODE_VISIBLE)))
-		return;
-
-	for (y = y1; y < y2; y++) {
-		if (!term.dirty[y])
-			continue;
-
-		term.dirty[y] = 0;
-
-		specs = xw.specbuf;
-		numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y);
-
-		i = ox = 0;
-		for (x = x1; x < x2 && i < numspecs; x++) {
-			new = term.line[y][x];
-			if (new.mode == ATTR_WDUMMY)
-				continue;
-			if (selected(x, y))
-				new.mode ^= ATTR_REVERSE;
-			if (i > 0 && ATTRCMP(base, new)) {
-				xdrawglyphfontspecs(specs, base, i, ox, y);
-				specs += i;
-				numspecs -= i;
-				i = 0;
-			}
-			if (i == 0) {
-				ox = x;
-				base = new;
-			}
-			i++;
-		}
-		if (i > 0)
-			xdrawglyphfontspecs(specs, base, i, ox, y);
-	}
-	xdrawcursor();
-}
-
 void
 expose(XEvent *ev)
 {

From a5dc1b46976b2252f9d7bb68f126c4b0f351dd1a Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Sat, 24 Feb 2018 14:58:54 -0600
Subject: [PATCH 0997/1146] Pull term references out of xdrawcursor

Gradually reducing x.c dependency on Term object.  Old and new cursor
glyph/position are passed to xdrawcursor.  (There may be an opportunity
to refactor further if we can unify "clear old cursor" and "draw new
cursor" functionality.)

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c  | 15 ++++++++++++++-
 st.h  |  4 +++-
 win.h |  2 +-
 x.c   | 61 +++++++++++++++++++++--------------------------------------
 4 files changed, 40 insertions(+), 42 deletions(-)

diff --git a/st.c b/st.c
index 504239e..4bf6378 100644
--- a/st.c
+++ b/st.c
@@ -2544,10 +2544,23 @@ drawregion(int x1, int y1, int x2, int y2)
 void
 draw(void)
 {
+	int cx = term.c.x;
+
 	if (!xstartdraw())
 		return;
+
+	/* adjust cursor position */
+	LIMIT(term.ocx, 0, term.col-1);
+	LIMIT(term.ocy, 0, term.row-1);
+	if (term.line[term.ocy][term.ocx].mode & ATTR_WDUMMY)
+		term.ocx--;
+	if (term.line[term.c.y][cx].mode & ATTR_WDUMMY)
+		cx--;
+
 	drawregion(0, 0, term.col, term.row);
-	xdrawcursor();
+	xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
+			term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
+	term.ocx = cx, term.ocy = term.c.y;
 	xfinishdraw();
 }
 
diff --git a/st.h b/st.h
index 7026de8..27c48cf 100644
--- a/st.h
+++ b/st.h
@@ -82,8 +82,10 @@ typedef struct {
 	int col;      /* nb col */
 	Line *line;   /* screen */
 	Line *alt;    /* alternate screen */
-	int *dirty;  /* dirtyness of lines */
+	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 */
diff --git a/win.h b/win.h
index 6e662af..7a866fd 100644
--- a/win.h
+++ b/win.h
@@ -25,7 +25,7 @@ enum win_mode {
 
 void xbell(void);
 void xclipcopy(void);
-void xdrawcursor(void);
+void xdrawcursor(int, int, Glyph, int, int, Glyph);
 void xdrawline(Line, int, int, int);
 void xhints(void);
 void xfinishdraw(void);
diff --git a/x.c b/x.c
index 96944ee..d205ca7 100644
--- a/x.c
+++ b/x.c
@@ -1387,41 +1387,26 @@ xdrawglyph(Glyph g, int x, int y)
 }
 
 void
-xdrawcursor(void)
+xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 {
-	static int oldx = 0, oldy = 0;
-	int curx;
-	Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og;
 	Color drawcol;
 
-	LIMIT(oldx, 0, term.col-1);
-	LIMIT(oldy, 0, term.row-1);
-
-	curx = term.c.x;
-
-	/* adjust position if in dummy */
-	if (term.line[oldy][oldx].mode & ATTR_WDUMMY)
-		oldx--;
-	if (term.line[term.c.y][curx].mode & ATTR_WDUMMY)
-		curx--;
-
 	/* remove the old cursor */
-	og = term.line[oldy][oldx];
-	if (selected(oldx, oldy))
+	if (selected(ox, oy))
 		og.mode ^= ATTR_REVERSE;
-	xdrawglyph(og, oldx, oldy);
-
-	g.u = term.line[term.c.y][term.c.x].u;
-	g.mode |= term.line[term.c.y][term.c.x].mode &
-	          (ATTR_BOLD | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_STRUCK);
+	xdrawglyph(og, ox, oy);
 
 	/*
 	 * Select the right color for the right mode.
 	 */
+	g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
+	g.fg = defaultbg;
+	g.bg = defaultcs;
+
 	if (IS_SET(MODE_REVERSE)) {
 		g.mode |= ATTR_REVERSE;
 		g.bg = defaultfg;
-		if (selected(term.c.x, term.c.y)) {
+		if (selected(cx, cy)) {
 			drawcol = dc.col[defaultcs];
 			g.fg = defaultrcs;
 		} else {
@@ -1429,7 +1414,7 @@ xdrawcursor(void)
 			g.fg = defaultcs;
 		}
 	} else {
-		if (selected(term.c.x, term.c.y)) {
+		if (selected(cx, cy)) {
 			drawcol = dc.col[defaultrcs];
 			g.fg = defaultfg;
 			g.bg = defaultrcs;
@@ -1449,44 +1434,42 @@ xdrawcursor(void)
 		case 0: /* Blinking Block */
 		case 1: /* Blinking Block (Default) */
 		case 2: /* Steady Block */
-			g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE;
-			xdrawglyph(g, term.c.x, term.c.y);
+			xdrawglyph(g, cx, cy);
 			break;
 		case 3: /* Blinking Underline */
 		case 4: /* Steady Underline */
 			XftDrawRect(xw.draw, &drawcol,
-					borderpx + curx * win.cw,
-					borderpx + (term.c.y + 1) * win.ch - \
+					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 + curx * win.cw,
-					borderpx + term.c.y * win.ch,
+					borderpx + cx * win.cw,
+					borderpx + cy * win.ch,
 					cursorthickness, win.ch);
 			break;
 		}
 	} else {
 		XftDrawRect(xw.draw, &drawcol,
-				borderpx + curx * win.cw,
-				borderpx + term.c.y * win.ch,
+				borderpx + cx * win.cw,
+				borderpx + cy * win.ch,
 				win.cw - 1, 1);
 		XftDrawRect(xw.draw, &drawcol,
-				borderpx + curx * win.cw,
-				borderpx + term.c.y * win.ch,
+				borderpx + cx * win.cw,
+				borderpx + cy * win.ch,
 				1, win.ch - 1);
 		XftDrawRect(xw.draw, &drawcol,
-				borderpx + (curx + 1) * win.cw - 1,
-				borderpx + term.c.y * win.ch,
+				borderpx + (cx + 1) * win.cw - 1,
+				borderpx + cy * win.ch,
 				1, win.ch - 1);
 		XftDrawRect(xw.draw, &drawcol,
-				borderpx + curx * win.cw,
-				borderpx + (term.c.y + 1) * win.ch - 1,
+				borderpx + cx * win.cw,
+				borderpx + (cy + 1) * win.ch - 1,
 				win.cw, 1);
 	}
-	oldx = curx, oldy = term.c.y;
 }
 
 void

From a3beb626d2dae9d4d0883c7c8cb6ba58b0609105 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Sat, 24 Feb 2018 15:32:48 -0600
Subject: [PATCH 0998/1146] Remove x.c dependency on term

The xinit function only needs to the rows/cols, so pass those in rather
than accessing term directly.  With a bit of arithmetic, we are able to
avoid the need for term.row and term.col in x2col, y2row, and
xdrawglyphfontspecs as well, completing the removal.

Term is now fully internal to st.c.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c | 22 +++++++++++++++++++++-
 st.h | 21 ---------------------
 x.c  | 35 ++++++++++++++++++-----------------
 3 files changed, 39 insertions(+), 39 deletions(-)

diff --git a/st.c b/st.c
index 4bf6378..da832ed 100644
--- a/st.c
+++ b/st.c
@@ -95,6 +95,26 @@ enum escape_state {
 	ESC_DCS        =128,
 };
 
+/* 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;
+} Term;
+
 /* CSI Escape sequence structs */
 /* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
 typedef struct {
@@ -181,11 +201,11 @@ static char *base64dec(const char *);
 static ssize_t xwrite(int, const char *, size_t);
 
 /* Globals */
-Term term;
 int cmdfd;
 pid_t pid;
 int oldbutton   = 3; /* button event on startup: 3 = release */
 
+static Term term;
 static Selection sel;
 static CSIEscape csiescseq;
 static STREscape strescseq;
diff --git a/st.h b/st.h
index 27c48cf..b5bc1b5 100644
--- a/st.h
+++ b/st.h
@@ -76,26 +76,6 @@ typedef struct {
 	char state;
 } TCursor;
 
-/* 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;
-} Term;
-
 /* Purely graphic info */
 typedef struct {
 	int tw, th; /* tty width and height */
@@ -168,7 +148,6 @@ void *xrealloc(void *, size_t);
 char *xstrdup(char *);
 
 /* Globals */
-extern Term term;
 extern int cmdfd;
 extern pid_t pid;
 extern int oldbutton;
diff --git a/x.c b/x.c
index d205ca7..873ff08 100644
--- a/x.c
+++ b/x.c
@@ -130,7 +130,7 @@ static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
 static void xdrawglyph(Glyph, int, int);
 static void xclear(int, int, int, int);
 static int xgeommasktogravity(int);
-static void xinit(void);
+static void xinit(int, int);
 static void cresize(int, int);
 static void xresize(int, int);
 static int xloadfont(Font *, FcPattern *);
@@ -299,18 +299,16 @@ int
 x2col(int x)
 {
 	x -= borderpx;
-	x /= win.cw;
-
-	return LIMIT(x, 0, term.col-1);
+	LIMIT(x, 0, win.tw - 1);
+	return x / win.cw;
 }
 
 int
 y2row(int y)
 {
 	y -= borderpx;
-	y /= win.ch;
-
-	return LIMIT(y, 0, term.row-1);
+	LIMIT(y, 0, win.th - 1);
+	return y / win.ch;
 }
 
 void
@@ -984,7 +982,7 @@ xunloadfonts(void)
 }
 
 void
-xinit(void)
+xinit(int cols, int rows)
 {
 	XGCValues gcvalues;
 	Cursor cursor;
@@ -1009,8 +1007,8 @@ xinit(void)
 	xloadcols();
 
 	/* adjust fixed window geometry */
-	win.w = 2 * borderpx + term.col * win.cw;
-	win.h = 2 * borderpx + term.row * win.ch;
+	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)
@@ -1042,7 +1040,7 @@ xinit(void)
 	XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
 
 	/* font spec buffer */
-	xw.specbuf = xmalloc(term.col * sizeof(GlyphFontSpec));
+	xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec));
 
 	/* Xft rendering context */
 	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
@@ -1337,15 +1335,16 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 	/* Intelligent cleaning up of the borders. */
 	if (x == 0) {
 		xclear(0, (y == 0)? 0 : winy, borderpx,
-			winy + win.ch + ((y >= term.row-1)? win.h : 0));
+			winy + win.ch +
+			((winy + win.ch >= borderpx + win.th)? win.h : 0));
 	}
-	if (x + charlen >= term.col) {
+	if (winx + width >= borderpx + win.tw) {
 		xclear(winx + width, (y == 0)? 0 : winy, win.w,
-			((y >= term.row-1)? win.h : (winy + win.ch)));
+			((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch)));
 	}
 	if (y == 0)
 		xclear(winx, 0, winx + width, borderpx);
-	if (y == term.row-1)
+	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. */
@@ -1930,8 +1929,10 @@ run:
 	}
 	setlocale(LC_CTYPE, "");
 	XSetLocaleModifiers("");
-	tnew(MAX(cols, 1), MAX(rows, 1));
-	xinit();
+	cols = MAX(cols, 1);
+	rows = MAX(rows, 1);
+	tnew(cols, rows);
+	xinit(cols, rows);
 	xsetenv();
 	selinit();
 	run();

From 30683c70ab62fd37b5921cf72077b9aef2cb842e Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Sat, 24 Feb 2018 16:16:12 -0600
Subject: [PATCH 0999/1146] Limit usage of extern to config.h globals

Prefer passing arguments to declaring external global variables.  The
only remaining usage of extern is for config.h variables which are
needed in st.c instead of x.c (where it is now included).

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 config.def.h |  2 +-
 st.c         | 29 +++++++++++++++++------------
 st.h         |  9 ++-------
 x.c          | 16 +++++++++-------
 4 files changed, 29 insertions(+), 27 deletions(-)

diff --git a/config.def.h b/config.def.h
index 616616a..82b1b09 100644
--- a/config.def.h
+++ b/config.def.h
@@ -16,7 +16,7 @@ static int borderpx = 2;
  * 4: value of shell in /etc/passwd
  * 5: value of shell in config.h
  */
-char *shell = "/bin/sh";
+static char *shell = "/bin/sh";
 char *utmp = NULL;
 char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
 
diff --git a/st.c b/st.c
index da832ed..ce32cc0 100644
--- a/st.c
+++ b/st.c
@@ -136,8 +136,7 @@ typedef struct {
 	int narg;              /* nb of args */
 } STREscape;
 
-
-static void execsh(char **);
+static void execsh(char *, char **);
 static void stty(char **);
 static void sigchld(int);
 static void ttywriteraw(const char *, size_t);
@@ -201,15 +200,13 @@ static char *base64dec(const char *);
 static ssize_t xwrite(int, const char *, size_t);
 
 /* Globals */
-int cmdfd;
-pid_t pid;
-int oldbutton   = 3; /* button event on startup: 3 = release */
-
 static Term term;
 static Selection sel;
 static CSIEscape csiescseq;
 static STREscape strescseq;
 static int iofd = 1;
+static int cmdfd;
+static pid_t pid;
 
 static uchar utfbyte[UTF_SIZ + 1] = {0x80,    0, 0xC0, 0xE0, 0xF0};
 static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
@@ -659,7 +656,7 @@ die(const char *errstr, ...)
 }
 
 void
-execsh(char **args)
+execsh(char *cmd, char **args)
 {
 	char *sh, *prog;
 	const struct passwd *pw;
@@ -673,7 +670,7 @@ execsh(char **args)
 	}
 
 	if ((sh = getenv("SHELL")) == NULL)
-		sh = (pw->pw_shell[0]) ? pw->pw_shell : shell;
+		sh = (pw->pw_shell[0]) ? pw->pw_shell : cmd;
 
 	if (args)
 		prog = args[0];
@@ -745,8 +742,8 @@ stty(char **args)
 	    perror("Couldn't call stty");
 }
 
-void
-ttynew(char *line, char *out, char **args)
+int
+ttynew(char *line, char *cmd, char *out, char **args)
 {
 	int m, s;
 
@@ -765,7 +762,7 @@ ttynew(char *line, char *out, char **args)
 			die("open line failed: %s\n", strerror(errno));
 		dup2(cmdfd, 0);
 		stty(args);
-		return;
+		return cmdfd;
 	}
 
 	/* seems to work fine on linux, openbsd and freebsd */
@@ -786,7 +783,7 @@ ttynew(char *line, char *out, char **args)
 			die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
 		close(s);
 		close(m);
-		execsh(args);
+		execsh(cmd, args);
 		break;
 	default:
 		close(s);
@@ -794,6 +791,7 @@ ttynew(char *line, char *out, char **args)
 		signal(SIGCHLD, sigchld);
 		break;
 	}
+	return cmdfd;
 }
 
 size_t
@@ -916,6 +914,13 @@ ttyresize(int tw, int th)
 		fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno));
 }
 
+void
+ttyhangup()
+{
+	/* Send SIGHUP to shell */
+	kill(pid, SIGHUP);
+}
+
 int
 tattrset(int attr)
 {
diff --git a/st.h b/st.h
index b5bc1b5..0a7472b 100644
--- a/st.h
+++ b/st.h
@@ -125,7 +125,8 @@ int tattrset(int);
 void tnew(int, int);
 void tresize(int, int);
 void tsetdirtattr(int);
-void ttynew(char *, char *, char **);
+void ttyhangup(void);
+int ttynew(char *, char *, char *, char **);
 size_t ttyread(void);
 void ttyresize(int, int);
 void ttywrite(const char *, size_t, int);
@@ -147,13 +148,7 @@ void *xmalloc(size_t);
 void *xrealloc(void *, size_t);
 char *xstrdup(char *);
 
-/* Globals */
-extern int cmdfd;
-extern pid_t pid;
-extern int oldbutton;
-
 /* config.h globals */
-extern char *shell;
 extern char *utmp;
 extern char *stty_args;
 extern char *vtiden;
diff --git a/x.c b/x.c
index 873ff08..970d6dd 100644
--- a/x.c
+++ b/x.c
@@ -227,6 +227,8 @@ static char *opt_line  = NULL;
 static char *opt_name  = NULL;
 static char *opt_title = NULL;
 
+static int oldbutton = 3; /* button event on startup: 3 = release */
+
 void
 clipcopy(const Arg *dummy)
 {
@@ -1733,8 +1735,7 @@ cmessage(XEvent *e)
 			win.mode &= ~MODE_FOCUSED;
 		}
 	} else if (e->xclient.data.l[0] == xw.wmdeletewin) {
-		/* Send SIGHUP to shell */
-		kill(pid, SIGHUP);
+		ttyhangup();
 		exit(0);
 	}
 }
@@ -1755,6 +1756,7 @@ run(void)
 	int w = win.w, h = win.h;
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
+	int ttyfd;
 	struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
 	long deltatime;
 
@@ -1774,7 +1776,7 @@ run(void)
 		}
 	} while (ev.type != MapNotify);
 
-	ttynew(opt_line, opt_io, opt_cmd);
+	ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd);
 	cresize(w, h);
 
 	clock_gettime(CLOCK_MONOTONIC, &last);
@@ -1782,15 +1784,15 @@ run(void)
 
 	for (xev = actionfps;;) {
 		FD_ZERO(&rfd);
-		FD_SET(cmdfd, &rfd);
+		FD_SET(ttyfd, &rfd);
 		FD_SET(xfd, &rfd);
 
-		if (pselect(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
+		if (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
 			if (errno == EINTR)
 				continue;
 			die("select failed: %s\n", strerror(errno));
 		}
-		if (FD_ISSET(cmdfd, &rfd)) {
+		if (FD_ISSET(ttyfd, &rfd)) {
 			ttyread();
 			if (blinktimeout) {
 				blinkset = tattrset(ATTR_BLINK);
@@ -1834,7 +1836,7 @@ run(void)
 
 			if (xev && !FD_ISSET(xfd, &rfd))
 				xev--;
-			if (!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
+			if (!FD_ISSET(ttyfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
 				if (blinkset) {
 					if (TIMEDIFF(now, lastblink) \
 							> blinktimeout) {

From e0215d53770a9b6bc6e5d7b9a603ecd34dbd7100 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Sat, 24 Feb 2018 16:32:20 -0600
Subject: [PATCH 1000/1146] Reduce visibility wherever possible

When possible, declare functions/variables static and move struct
definitions out of headers.  In order to allow utf8decode to become
internal, use codepoint for DECSCUSR extension directly.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c  | 31 ++++++++++++++++++++++++++++++-
 st.h  | 40 ----------------------------------------
 win.h |  1 -
 x.c   | 15 +++++++++++++--
 4 files changed, 43 insertions(+), 44 deletions(-)

diff --git a/st.c b/st.c
index ce32cc0..f46aab6 100644
--- a/st.c
+++ b/st.c
@@ -36,6 +36,7 @@
 
 /* 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
@@ -95,6 +96,31 @@ enum escape_state {
 	ESC_DCS        =128,
 };
 
+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 */
@@ -187,15 +213,18 @@ static void tstrsequence(uchar);
 
 static void drawregion(int, int, int, int);
 
+static void selnormalize(void);
 static void selscroll(int, int);
 static void selsnap(int *, int *, int);
 
+static size_t utf8decode(const char *, Rune *, size_t);
 static Rune utf8decodebyte(char, size_t *);
 static char utf8encodebyte(Rune, size_t);
-static char *utf8strchr(char *s, Rune u);
+static char *utf8strchr(char *, Rune);
 static size_t utf8validate(Rune *, size_t);
 
 static char *base64dec(const char *);
+static char base64dec_getc(const char **);
 
 static ssize_t xwrite(int, const char *, size_t);
 
diff --git a/st.h b/st.h
index 0a7472b..1015fc6 100644
--- a/st.h
+++ b/st.h
@@ -1,8 +1,5 @@
 /* See LICENSE for license details. */
 
-/* Arbitrary sizes */
-#define UTF_SIZ       4
-
 /* macros */
 #define MIN(a, b)		((a) < (b) ? (a) : (b))
 #define MAX(a, b)		((a) < (b) ? (b) : (a))
@@ -69,41 +66,6 @@ typedef struct {
 
 typedef Glyph *Line;
 
-typedef struct {
-	Glyph attr; /* current char attributes */
-	int x;
-	int y;
-	char state;
-} TCursor;
-
-/* 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 {
-	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;
-
 typedef union {
 	int i;
 	uint ui;
@@ -137,11 +99,9 @@ void selclear(void);
 void selinit(void);
 void selstart(int, int, int);
 void selextend(int, int, int, int);
-void selnormalize(void);
 int selected(int, int);
 char *getsel(void);
 
-size_t utf8decode(const char *, Rune *, size_t);
 size_t utf8encode(Rune, char *);
 
 void *xmalloc(size_t);
diff --git a/win.h b/win.h
index 7a866fd..31f327d 100644
--- a/win.h
+++ b/win.h
@@ -27,7 +27,6 @@ void xbell(void);
 void xclipcopy(void);
 void xdrawcursor(int, int, Glyph, int, int, Glyph);
 void xdrawline(Line, int, int, int);
-void xhints(void);
 void xfinishdraw(void);
 void xloadcols(void);
 int xsetcolorname(int, const char *);
diff --git a/x.c b/x.c
index 970d6dd..f7b0528 100644
--- a/x.c
+++ b/x.c
@@ -75,6 +75,15 @@ 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;
@@ -133,6 +142,8 @@ static int xgeommasktogravity(int);
 static void xinit(int, int);
 static void cresize(int, int);
 static void xresize(int, int);
+static void xhints(void);
+static int xloadcolor(int, const char *, Color *);
 static int xloadfont(Font *, FcPattern *);
 static void xloadfonts(char *, double);
 static void xunloadfont(Font *);
@@ -1430,8 +1441,8 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 	/* draw the new one */
 	if (IS_SET(MODE_FOCUSED)) {
 		switch (win.cursor) {
-		case 7: /* st extension: snowman */
-			utf8decode("☃", &g.u, UTF_SIZ);
+		case 7: /* st extension: snowman (U+2603) */
+			g.u = 0x2603;
 		case 0: /* Blinking Block */
 		case 1: /* Blinking Block (Default) */
 		case 2: /* Steady Block */

From 403c57ebb5b3745ff93e49b87e526c49dc59a5b9 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Sat, 24 Feb 2018 16:45:42 -0600
Subject: [PATCH 1001/1146] Clean up #includes

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c | 7 -------
 st.h | 3 +++
 x.c  | 3 +--
 3 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index f46aab6..543c615 100644
--- a/st.c
+++ b/st.c
@@ -3,24 +3,17 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
-#include <locale.h>
 #include <pwd.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
-#include <stdint.h>
 #include <sys/ioctl.h>
 #include <sys/select.h>
-#include <sys/stat.h>
-#include <sys/time.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <termios.h>
-#include <time.h>
 #include <unistd.h>
-#include <libgen.h>
 #include <wchar.h>
 
 #include "st.h"
diff --git a/st.h b/st.h
index 1015fc6..dac64d8 100644
--- a/st.h
+++ b/st.h
@@ -1,5 +1,8 @@
 /* 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))
diff --git a/x.c b/x.c
index f7b0528..d0acfee 100644
--- a/x.c
+++ b/x.c
@@ -1,15 +1,14 @@
 /* See LICENSE for license details. */
 #include <errno.h>
+#include <limits.h>
 #include <locale.h>
 #include <signal.h>
-#include <stdint.h>
 #include <sys/select.h>
 #include <time.h>
 #include <unistd.h>
 #include <libgen.h>
 #include <X11/Xatom.h>
 #include <X11/Xlib.h>
-#include <X11/Xutil.h>
 #include <X11/cursorfont.h>
 #include <X11/keysym.h>
 #include <X11/Xft/Xft.h>

From 20e0da7f14cc5f30863e0b8014fa223fbaff1e30 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Sat, 24 Feb 2018 17:09:13 -0600
Subject: [PATCH 1002/1146] General cleanup

Simplifies logic in a couple places and removes a redundant function
call.

Signed-off-by: Devin J. Pohly <djpohly@gmail.com>
---
 st.c |  1 -
 x.c  | 46 +++++++++++++++++++++-------------------------
 2 files changed, 21 insertions(+), 26 deletions(-)

diff --git a/st.c b/st.c
index 543c615..75c3dd1 100644
--- a/st.c
+++ b/st.c
@@ -1693,7 +1693,6 @@ csihandle(void)
 		tputtab(csiescseq.arg[0]);
 		break;
 	case 'J': /* ED -- Clear screen */
-		selclear();
 		switch (csiescseq.arg[0]) {
 		case 0: /* below */
 			tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
diff --git a/x.c b/x.c
index d0acfee..f005687 100644
--- a/x.c
+++ b/x.c
@@ -149,8 +149,8 @@ static void xunloadfont(Font *);
 static void xunloadfonts(void);
 static void xsetenv(void);
 static void xseturgency(int);
-static int x2col(int);
-static int y2row(int);
+static int evcol(XEvent *);
+static int evrow(XEvent *);
 
 static void expose(XEvent *);
 static void visibility(XEvent *);
@@ -308,17 +308,17 @@ zoomreset(const Arg *arg)
 }
 
 int
-x2col(int x)
+evcol(XEvent *e)
 {
-	x -= borderpx;
+	int x = e->xbutton.x - borderpx;
 	LIMIT(x, 0, win.tw - 1);
 	return x / win.cw;
 }
 
 int
-y2row(int y)
+evrow(XEvent *e)
 {
-	y -= borderpx;
+	int y = e->xbutton.y - borderpx;
 	LIMIT(y, 0, win.th - 1);
 	return y / win.ch;
 }
@@ -335,7 +335,7 @@ mousesel(XEvent *e, int done)
 			break;
 		}
 	}
-	selextend(x2col(e->xbutton.x), y2row(e->xbutton.y), seltype, done);
+	selextend(evcol(e), evrow(e), seltype, done);
 	if (done)
 		setsel(getsel(), e->xbutton.time);
 }
@@ -343,9 +343,8 @@ mousesel(XEvent *e, int done)
 void
 mousereport(XEvent *e)
 {
-	int x = x2col(e->xbutton.x), y = y2row(e->xbutton.y),
-	    button = e->xbutton.button, state = e->xbutton.state,
-	    len;
+	int len, x = evcol(e), y = evrow(e),
+	    button = e->xbutton.button, state = e->xbutton.state;
 	char buf[40];
 	static int ox, oy;
 
@@ -440,7 +439,7 @@ bpress(XEvent *e)
 		xsel.tclick2 = xsel.tclick1;
 		xsel.tclick1 = now;
 
-		selstart(x2col(e->xbutton.x), y2row(e->xbutton.y), snap);
+		selstart(evcol(e), evrow(e), snap);
 	}
 }
 
@@ -464,18 +463,16 @@ selnotify(XEvent *e)
 	ulong nitems, ofs, rem;
 	int format;
 	uchar *data, *last, *repl;
-	Atom type, incratom, property;
+	Atom type, incratom, property = None;
 
 	incratom = XInternAtom(xw.dpy, "INCR", 0);
 
 	ofs = 0;
-	if (e->type == SelectionNotify) {
+	if (e->type == SelectionNotify)
 		property = e->xselection.property;
-	} else if(e->type == PropertyNotify) {
+	else if (e->type == PropertyNotify)
 		property = e->xproperty.atom;
-	} else {
-		return;
-	}
+
 	if (property == None)
 		return;
 
@@ -625,7 +622,7 @@ setsel(char *str, Time t)
 
 	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
 	if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
-		selclear_(NULL);
+		selclear();
 }
 
 void
@@ -1407,12 +1404,13 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 		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;
-	g.fg = defaultbg;
-	g.bg = defaultcs;
 
 	if (IS_SET(MODE_REVERSE)) {
 		g.mode |= ATTR_REVERSE;
@@ -1426,17 +1424,15 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 		}
 	} else {
 		if (selected(cx, cy)) {
-			drawcol = dc.col[defaultrcs];
 			g.fg = defaultfg;
 			g.bg = defaultrcs;
 		} else {
-			drawcol = dc.col[defaultcs];
+			g.fg = defaultbg;
+			g.bg = defaultcs;
 		}
+		drawcol = dc.col[g.bg];
 	}
 
-	if (IS_SET(MODE_HIDE))
-		return;
-
 	/* draw the new one */
 	if (IS_SET(MODE_FOCUSED)) {
 		switch (win.cursor) {

From 8b8255ac0e188445f6904ff16272e9e93093cbde Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 9 Mar 2018 15:35:34 +0100
Subject: [PATCH 1003/1146] regression: include termios.h for tcsendbreak etc

---
 st.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index 75c3dd1..65a0cb6 100644
--- a/st.c
+++ b/st.c
@@ -13,6 +13,7 @@
 #include <sys/select.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <termios.h>
 #include <unistd.h>
 #include <wchar.h>
 

From b81888ee7d95d9ecb7b1749630b09a96065a8fea Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 9 Mar 2018 15:36:25 +0100
Subject: [PATCH 1004/1146] xhints: no need to initialize sizeh

---
 x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x.c b/x.c
index f005687..537322b 100644
--- a/x.c
+++ b/x.c
@@ -780,7 +780,7 @@ xhints(void)
 	XClassHint class = {opt_name ? opt_name : termname,
 	                    opt_class ? opt_class : termname};
 	XWMHints wm = {.flags = InputHint, .input = 1};
-	XSizeHints *sizeh = NULL;
+	XSizeHints *sizeh;
 
 	sizeh = XAllocSizeHints();
 

From c5ba9c025b7ebc34979e839453528f6e4a18712d Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 9 Mar 2018 15:36:38 +0100
Subject: [PATCH 1005/1146] use math.h for ceilf

---
 x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x.c b/x.c
index 537322b..d43a529 100644
--- a/x.c
+++ b/x.c
@@ -1,5 +1,6 @@
 /* See LICENSE for license details. */
 #include <errno.h>
+#include <math.h>
 #include <limits.h>
 #include <locale.h>
 #include <signal.h>
@@ -901,7 +902,6 @@ xloadfonts(char *fontstr, double fontsize)
 {
 	FcPattern *pattern;
 	double fontval;
-	float ceilf(float);
 
 	if (fontstr[0] == '-') {
 		pattern = XftXlfdParse(fontstr, False, False);

From 49a4f91fc5caf4b8b64f2b73a6be506fa06917b9 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Wed, 14 Mar 2018 19:50:37 +0100
Subject: [PATCH 1006/1146] bump version to 0.8

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 0aceec4..b2eac10 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.7
+VERSION = 0.8
 
 # Customize below to fit your system
 

From 0f245dfeb9bb4e87a005da2ecdcd7a88ba6e7f32 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Wed, 14 Mar 2018 19:54:50 +0100
Subject: [PATCH 1007/1146] Makefile: add all files to make dist

---
 Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index c678ead..0b3cecd 100644
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,9 @@ clean:
 
 dist: clean
 	mkdir -p st-$(VERSION)
-	cp -R LICENSE Makefile README config.mk config.def.h st.info st.1 arg.h $(SRC) 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)
 

From a712c2dd1815f83a56be33e8055eee29e05dfef7 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Wed, 14 Mar 2018 20:00:35 +0100
Subject: [PATCH 1008/1146] update LICENSE: major contributors

---
 LICENSE | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/LICENSE b/LICENSE
index fa0c63e..84c4d19 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,8 +1,11 @@
 MIT/X Consortium License
 
+© 2014-2018 Hiltjo Posthuma <hiltjo at codemadness dot org>
+© 2018 Devin J. Pohly <djpohly at gmail dot com>
+© 2017-2017 Quentin Rameau <quinq at fifth dot space>
 © 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>
 © 2009 Anselm R Garbe <garbeam at gmail dot com>
-© 2012-2016 Roberto E. Vargas Caballero <k0ga at shike2 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>

From 8ab629031bd958d93deee9203fea32c38fe8ac30 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Wed, 14 Mar 2018 20:06:42 +0100
Subject: [PATCH 1009/1146] LICENSE: fix a few years

---
 LICENSE | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/LICENSE b/LICENSE
index 84c4d19..c356c39 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2,15 +2,15 @@ MIT/X Consortium License
 
 © 2014-2018 Hiltjo Posthuma <hiltjo at codemadness dot org>
 © 2018 Devin J. Pohly <djpohly at gmail dot com>
-© 2017-2017 Quentin Rameau <quinq at fifth dot space>
+© 2014-2017 Quentin Rameau <quinq at fifth dot space>
 © 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>
-© 2009 Anselm R Garbe <garbeam 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 Eric Pruitt <eric.pruitt 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>

From e7ef3c4ce95a21cfcd0988d493f636e1d0115871 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Fri, 16 Mar 2018 15:03:10 +0100
Subject: [PATCH 1010/1146] Fix regression from 69e32a6 when setting title.

---
 x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x.c b/x.c
index d43a529..06e53d3 100644
--- a/x.c
+++ b/x.c
@@ -1492,7 +1492,7 @@ void
 xsettitle(char *p)
 {
 	XTextProperty prop;
-	DEFAULT(p, "st");
+	DEFAULT(p, opt_title);
 
 	Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
 			&prop);

From 0b507bb73138c636fd0ad6f2321624aae1346d58 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Fri, 16 Mar 2018 16:19:18 +0100
Subject: [PATCH 1011/1146] Fix title initialization

---
 x.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/x.c b/x.c
index 06e53d3..d0b26ac 100644
--- a/x.c
+++ b/x.c
@@ -1929,12 +1929,12 @@ main(int argc, char *argv[])
 	} ARGEND;
 
 run:
-	if (argc > 0) {
-		/* eat all remaining arguments */
+	if (argc > 0) /* eat all remaining arguments */
 		opt_cmd = argv;
-		if (!opt_title && !opt_line)
-			opt_title = basename(xstrdup(argv[0]));
-	}
+
+	if (!opt_title)
+		opt_title = (opt_line || !opt_cmd) ? "st" : opt_cmd[0];
+
 	setlocale(LC_CTYPE, "");
 	XSetLocaleModifiers("");
 	cols = MAX(cols, 1);

From 7648697f711d5ae336af142e9cd464d943341b24 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 16 Mar 2018 16:45:58 +0100
Subject: [PATCH 1012/1146] minor code-style: whitespace fixes

---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 65a0cb6..581647b 100644
--- a/st.c
+++ b/st.c
@@ -740,7 +740,6 @@ sigchld(int a)
 	exit(0);
 }
 
-
 void
 stty(char **args)
 {
@@ -762,7 +761,7 @@ stty(char **args)
 	}
 	*q = '\0';
 	if (system(cmd) != 0)
-	    perror("Couldn't call stty");
+		perror("Couldn't call stty");
 }
 
 int

From 5345db3c9be1a22ca19202035b881b951c2f0f9e Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 17 Mar 2018 13:48:10 +0100
Subject: [PATCH 1013/1146] clipcopy: no need to check for free(NULL), set to
 NULL after free

---
 x.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/x.c b/x.c
index d0b26ac..12bc86b 100644
--- a/x.c
+++ b/x.c
@@ -245,8 +245,8 @@ clipcopy(const Arg *dummy)
 {
 	Atom clipboard;
 
-	if (xsel.clipboard != NULL)
-		free(xsel.clipboard);
+	free(xsel.clipboard);
+	xsel.clipboard = NULL;
 
 	if (xsel.primary != NULL) {
 		xsel.clipboard = xstrdup(xsel.primary);

From 6ac8c8aa50d521f82d491ab54eb972660fdf3207 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 17 Mar 2018 13:48:29 +0100
Subject: [PATCH 1014/1146] selextend: clarify: !sel.mode == SEL_IDLE

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 581647b..46c954b 100644
--- a/st.c
+++ b/st.c
@@ -461,7 +461,7 @@ selextend(int col, int row, int type, int done)
 {
 	int oldey, oldex, oldsby, oldsey, oldtype;
 
-	if (!sel.mode)
+	if (sel.mode == SEL_IDLE)
 		return;
 	if (done && sel.mode == SEL_EMPTY) {
 		selclear();

From a5a928bfc1dd049780a45e072cb4ee42de7219bf Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Tue, 20 Mar 2018 21:22:27 +0100
Subject: [PATCH 1015/1146] don't modify argv, use a counter

on some platforms (OpenBSD) this changes the exposed argv in tools using
the kvm_* interface, such as ps and pgrep.
---
 arg.h | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/arg.h b/arg.h
index ba3fb3f..a22e019 100644
--- a/arg.h
+++ b/arg.h
@@ -21,28 +21,30 @@ extern char *argv0;
 					argc--;\
 					break;\
 				}\
-				for (brk_ = 0, argv[0]++, argv_ = argv;\
-						argv[0][0] && !brk_;\
-						argv[0]++) {\
+				int i_;\
+				for (i_ = 1, brk_ = 0, argv_ = argv;\
+						argv[0][i_] && !brk_;\
+						i_++) {\
 					if (argv_ != argv)\
 						break;\
-					argc_ = argv[0][0];\
+					argc_ = argv[0][i_];\
 					switch (argc_)
+
 #define ARGEND			}\
 			}
 
 #define ARGC()		argc_
 
-#define EARGF(x)	((argv[0][1] == '\0' && argv[1] == NULL)?\
+#define EARGF(x)	((argv[0][i_+1] == '\0' && argv[1] == NULL)?\
 				((x), abort(), (char *)0) :\
-				(brk_ = 1, (argv[0][1] != '\0')?\
-					(&argv[0][1]) :\
+				(brk_ = 1, (argv[0][i_+1] != '\0')?\
+					(&argv[0][i_+1]) :\
 					(argc--, argv++, argv[0])))
 
-#define ARGF()		((argv[0][1] == '\0' && argv[1] == NULL)?\
+#define ARGF()		((argv[0][i_+1] == '\0' && argv[1] == NULL)?\
 				(char *)0 :\
-				(brk_ = 1, (argv[0][1] != '\0')?\
-					(&argv[0][1]) :\
+				(brk_ = 1, (argv[0][i_+1] != '\0')?\
+					(&argv[0][i_+1]) :\
 					(argc--, argv++, argv[0])))
 
 #endif

From f4020b2cc4fe45c9e8bfe47fc73deccd867cf9de Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Tue, 20 Mar 2018 21:25:30 +0100
Subject: [PATCH 1016/1146] fix regression by selecting clipboard text

"restore the old behaviour that the primary doesn't get deleted by a simple
left click"

Patch by Daniel Tameling <tamelingdaniel@gmail.com>, thanks!
---
 x.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/x.c b/x.c
index 12bc86b..c343ba2 100644
--- a/x.c
+++ b/x.c
@@ -618,6 +618,9 @@ selrequest(XEvent *e)
 void
 setsel(char *str, Time t)
 {
+	if (!str)
+		return;
+
 	free(xsel.primary);
 	xsel.primary = str;
 

From 6f0f2b7ec3713351de274707672fbadb6cc727a2 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Tue, 20 Mar 2018 21:29:10 +0100
Subject: [PATCH 1017/1146] bump version to 0.8.1

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index b2eac10..039c42c 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.8
+VERSION = 0.8.1
 
 # Customize below to fit your system
 

From 74cff67bd7746c2636ea7bc78a0b8af2f8c44838 Mon Sep 17 00:00:00 2001
From: Daniel Tameling <tamelingdaniel@gmail.com>
Date: Wed, 28 Mar 2018 21:27:58 +0200
Subject: [PATCH 1018/1146] set sel.alt in selstart instead of selextend

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 46c954b..2612c95 100644
--- a/st.c
+++ b/st.c
@@ -446,6 +446,7 @@ 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;
@@ -474,7 +475,6 @@ selextend(int col, int row, int type, int done)
 	oldsey = sel.ne.y;
 	oldtype = sel.type;
 
-	sel.alt = IS_SET(MODE_ALTSCREEN);
 	sel.oe.x = col;
 	sel.oe.y = row;
 	selnormalize();

From bd3f7fd84270025696790512cf3c2dafaf5bc77f Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Thu, 29 Mar 2018 18:18:30 +0200
Subject: [PATCH 1019/1146] st -v: remove years and copyright text

---
 x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x.c b/x.c
index c343ba2..f0195c9 100644
--- a/x.c
+++ b/x.c
@@ -1925,7 +1925,7 @@ main(int argc, char *argv[])
 		opt_embed = EARGF(usage());
 		break;
 	case 'v':
-		die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0);
+		die("%s " VERSION "\n", argv0);
 		break;
 	default:
 		usage();

From 041912a791e8c2f4d5d2415b16210d29d7e701c5 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Thu, 29 Mar 2018 18:30:05 +0200
Subject: [PATCH 1020/1146] error message style and use strerror in a few
 places

---
 st.c | 21 +++++++++++----------
 x.c  | 27 +++++++++++++--------------
 2 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/st.c b/st.c
index 2612c95..0628707 100644
--- a/st.c
+++ b/st.c
@@ -256,10 +256,10 @@ xwrite(int fd, const char *s, size_t len)
 void *
 xmalloc(size_t len)
 {
-	void *p = malloc(len);
+	void *p;
 
-	if (!p)
-		die("Out of memory\n");
+	if (!(p = malloc(len)))
+		die("malloc: %s\n", strerror(errno));
 
 	return p;
 }
@@ -268,7 +268,7 @@ void *
 xrealloc(void *p, size_t len)
 {
 	if ((p = realloc(p, len)) == NULL)
-		die("Out of memory\n");
+		die("realloc: %s\n", strerror(errno));
 
 	return p;
 }
@@ -277,7 +277,7 @@ char *
 xstrdup(char *s)
 {
 	if ((s = strdup(s)) == NULL)
-		die("Out of memory\n");
+		die("strdup: %s\n", strerror(errno));
 
 	return s;
 }
@@ -687,7 +687,7 @@ execsh(char *cmd, char **args)
 	errno = 0;
 	if ((pw = getpwuid(getuid())) == NULL) {
 		if (errno)
-			die("getpwuid:%s\n", strerror(errno));
+			die("getpwuid: %s\n", strerror(errno));
 		else
 			die("who are you?\n");
 	}
@@ -730,7 +730,7 @@ sigchld(int a)
 	pid_t p;
 
 	if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
-		die("Waiting for pid %hd failed: %s\n", pid, strerror(errno));
+		die("waiting for pid %hd failed: %s\n", pid, strerror(errno));
 
 	if (pid != p)
 		return;
@@ -781,7 +781,8 @@ ttynew(char *line, char *cmd, char *out, char **args)
 
 	if (line) {
 		if ((cmdfd = open(line, O_RDWR)) < 0)
-			die("open line failed: %s\n", strerror(errno));
+			die("open line '%s' failed: %s\n",
+			    line, strerror(errno));
 		dup2(cmdfd, 0);
 		stty(args);
 		return cmdfd;
@@ -793,7 +794,7 @@ ttynew(char *line, char *cmd, char *out, char **args)
 
 	switch (pid = fork()) {
 	case -1:
-		die("fork failed\n");
+		die("fork failed: %s\n", strerror(errno));
 		break;
 	case 0:
 		close(iofd);
@@ -826,7 +827,7 @@ ttyread(void)
 
 	/* append read bytes to unprocessed bytes */
 	if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
-		die("Couldn't read from shell: %s\n", strerror(errno));
+		die("couldn't read from shell: %s\n", strerror(errno));
 	buflen += ret;
 
 	written = twrite(buf, buflen, 0);
diff --git a/x.c b/x.c
index f0195c9..c0bd890 100644
--- a/x.c
+++ b/x.c
@@ -742,9 +742,9 @@ xloadcols(void)
 	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]);
+				die("could not allocate color '%s'\n", colorname[i]);
 			else
-				die("Could not allocate color %d\n", i);
+				die("could not allocate color %d\n", i);
 		}
 	loaded = 1;
 }
@@ -869,7 +869,7 @@ xloadfont(Font *f, FcPattern *pattern)
 		if ((XftPatternGetInteger(f->match->pattern, "slant", 0,
 		    &haveattr) != XftResultMatch) || haveattr < wantattr) {
 			f->badslant = 1;
-			fputs("st: font slant does not match\n", stderr);
+			fputs("font slant does not match\n", stderr);
 		}
 	}
 
@@ -878,7 +878,7 @@ xloadfont(Font *f, FcPattern *pattern)
 		if ((XftPatternGetInteger(f->match->pattern, "weight", 0,
 		    &haveattr) != XftResultMatch) || haveattr != wantattr) {
 			f->badweight = 1;
-			fputs("st: font weight does not match\n", stderr);
+			fputs("font weight does not match\n", stderr);
 		}
 	}
 
@@ -906,14 +906,13 @@ xloadfonts(char *fontstr, double fontsize)
 	FcPattern *pattern;
 	double fontval;
 
-	if (fontstr[0] == '-') {
+	if (fontstr[0] == '-')
 		pattern = XftXlfdParse(fontstr, False, False);
-	} else {
+	else
 		pattern = FcNameParse((FcChar8 *)fontstr);
-	}
 
 	if (!pattern)
-		die("st: can't open font %s\n", fontstr);
+		die("can't open font %s\n", fontstr);
 
 	if (fontsize > 1) {
 		FcPatternDel(pattern, FC_PIXEL_SIZE);
@@ -939,7 +938,7 @@ xloadfonts(char *fontstr, double fontsize)
 	}
 
 	if (xloadfont(&dc.font, pattern))
-		die("st: can't open font %s\n", fontstr);
+		die("can't open font %s\n", fontstr);
 
 	if (usedfontsize < 0) {
 		FcPatternGetDouble(dc.font.match->pattern,
@@ -956,17 +955,17 @@ xloadfonts(char *fontstr, double fontsize)
 	FcPatternDel(pattern, FC_SLANT);
 	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
 	if (xloadfont(&dc.ifont, pattern))
-		die("st: can't open font %s\n", fontstr);
+		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("st: can't open font %s\n", fontstr);
+		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("st: can't open font %s\n", fontstr);
+		die("can't open font %s\n", fontstr);
 
 	FcPatternDestroy(pattern);
 }
@@ -1003,13 +1002,13 @@ xinit(int cols, int rows)
 	XColor xmousefg, xmousebg;
 
 	if (!(xw.dpy = XOpenDisplay(NULL)))
-		die("Can't open display\n");
+		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");
+		die("could not init fontconfig.\n");
 
 	usedfont = (opt_font == NULL)? font : opt_font;
 	xloadfonts(usedfont, 0);

From 30ce2cc002585409b36c630512c6ca4db8f88f15 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 25 May 2018 11:59:28 +0200
Subject: [PATCH 1021/1146] Pledge on OpenBSD

---
 config.mk | 6 ++++++
 st.c      | 8 ++++++++
 2 files changed, 14 insertions(+)

diff --git a/config.mk b/config.mk
index 039c42c..c7355f1 100644
--- a/config.mk
+++ b/config.mk
@@ -23,6 +23,12 @@ CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
 STCFLAGS = $(INCS) $(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`
+
 # compiler and linker
 # CC = c99
 
diff --git a/st.c b/st.c
index 0628707..b9750f2 100644
--- a/st.c
+++ b/st.c
@@ -28,6 +28,10 @@
  #include <libutil.h>
 #endif
 
+#ifndef __OpenBSD__
+#define pledge(a,b) 0
+#endif
+
 /* Arbitrary sizes */
 #define UTF_INVALID   0xFFFD
 #define UTF_SIZ       4
@@ -806,9 +810,13 @@ ttynew(char *line, char *cmd, char *out, char **args)
 			die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
 		close(s);
 		close(m);
+		if (pledge("stdio getpw proc exec", NULL) == -1)
+			die("pledge\n");
 		execsh(cmd, args);
 		break;
 	default:
+		if (pledge("stdio rpath tty proc", NULL) == -1)
+			die("pledge\n");
 		close(s);
 		cmdfd = m;
 		signal(SIGCHLD, sigchld);

From 235a783e039986fca3ccefec08ea45804dab196f Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 25 May 2018 13:04:09 +0200
Subject: [PATCH 1022/1146] code-style for pledge(2)

feedback from Klemens, thanks
---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index b9750f2..76bb3ea 100644
--- a/st.c
+++ b/st.c
@@ -28,10 +28,6 @@
  #include <libutil.h>
 #endif
 
-#ifndef __OpenBSD__
-#define pledge(a,b) 0
-#endif
-
 /* Arbitrary sizes */
 #define UTF_INVALID   0xFFFD
 #define UTF_SIZ       4
@@ -810,13 +806,17 @@ ttynew(char *line, char *cmd, char *out, char **args)
 			die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
 		close(s);
 		close(m);
+#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);

From dc3b5babf1f8639a0d65cd347fc7879ac0461012 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 2 Jun 2018 17:11:14 +0200
Subject: [PATCH 1023/1146] config.mk: remove extra newline before EOF

---
 config.mk | 1 -
 1 file changed, 1 deletion(-)

diff --git a/config.mk b/config.mk
index c7355f1..e676105 100644
--- a/config.mk
+++ b/config.mk
@@ -31,4 +31,3 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
 
 # compiler and linker
 # CC = c99
-

From 29f341da7cf32888f45005e08de202d9a372d972 Mon Sep 17 00:00:00 2001
From: Jules Maselbas <jules.maselbas@grenoble-inp.org>
Date: Wed, 27 Jun 2018 17:08:30 +0200
Subject: [PATCH 1024/1146] Fix crash on resize

Prevent to realloc xw.specbuc with a negative number of col.
Add proper hints for the minimal size, for one character.
---
 x.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/x.c b/x.c
index c0bd890..00cb6b1 100644
--- a/x.c
+++ b/x.c
@@ -672,6 +672,8 @@ cresize(int width, int 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);
@@ -681,8 +683,8 @@ cresize(int width, int height)
 void
 xresize(int col, int row)
 {
-	win.tw = MAX(1, col * win.cw);
-	win.th = MAX(1, row * win.ch);
+	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,
@@ -788,15 +790,17 @@ xhints(void)
 
 	sizeh = XAllocSizeHints();
 
-	sizeh->flags = PSize | PResizeInc | PBaseSize;
+	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 | PMinSize;
+		sizeh->flags |= PMaxSize;
 		sizeh->min_width = sizeh->max_width = win.w;
 		sizeh->min_height = sizeh->max_height = win.h;
 	}

From 1911c9274d9b03f3d7999c6ce26e2d5169642d26 Mon Sep 17 00:00:00 2001
From: Jules Maselbas <jules.maselbas@grenoble-inp.org>
Date: Sat, 14 Jul 2018 11:16:36 +0200
Subject: [PATCH 1025/1146] Simplify cursor color handling

---
 x.c | 30 ++++++++++++------------------
 1 file changed, 12 insertions(+), 18 deletions(-)

diff --git a/x.c b/x.c
index 00cb6b1..ffd005f 100644
--- a/x.c
+++ b/x.c
@@ -1418,25 +1418,19 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 	 */
 	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;
-		}
+	if (selected(cx, cy)) {
+		g.bg = defaultrcs;
+		g.fg = defaultfg;
 	} else {
-		if (selected(cx, cy)) {
-			g.fg = defaultfg;
-			g.bg = defaultrcs;
-		} else {
-			g.fg = defaultbg;
-			g.bg = defaultcs;
-		}
-		drawcol = dc.col[g.bg];
+		g.bg = defaultcs;
+		g.fg = defaultbg;
+	}
+	drawcol = dc.col[g.bg];
+
+	if (IS_SET(MODE_REVERSE)) {
+		drawcol.color.red = ~drawcol.color.red;
+		drawcol.color.green = ~drawcol.color.green;
+		drawcol.color.blue = ~drawcol.color.blue;
 	}
 
 	/* draw the new one */

From b51bcd5553af3db394014efbd78acf7828fa48ff Mon Sep 17 00:00:00 2001
From: Jules Maselbas <jules.maselbas@grenoble-inp.org>
Date: Sat, 14 Jul 2018 11:16:37 +0200
Subject: [PATCH 1026/1146] Make cursor follow text color

---
 config.def.h |  2 --
 x.c          | 12 +++++++-----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/config.def.h b/config.def.h
index 82b1b09..ca6b0db 100644
--- a/config.def.h
+++ b/config.def.h
@@ -118,8 +118,6 @@ static const char *colorname[] = {
  */
 unsigned int defaultfg = 7;
 unsigned int defaultbg = 0;
-static unsigned int defaultcs = 256;
-static unsigned int defaultrcs = 257;
 
 /*
  * Default shape of cursor
diff --git a/x.c b/x.c
index ffd005f..b51821d 100644
--- a/x.c
+++ b/x.c
@@ -1419,13 +1419,15 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 	g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
 
 	if (selected(cx, cy)) {
-		g.bg = defaultrcs;
-		g.fg = defaultfg;
+		drawcol = dc.col[g.bg];
 	} else {
-		g.bg = defaultcs;
-		g.fg = defaultbg;
+		g.mode |= ATTR_REVERSE;
+
+		if (g.mode & ATTR_BOLD && BETWEEN(g.fg, 0, 7))
+			drawcol = dc.col[g.fg + 8];
+		else
+			drawcol = dc.col[g.fg];
 	}
-	drawcol = dc.col[g.bg];
 
 	if (IS_SET(MODE_REVERSE)) {
 		drawcol.color.red = ~drawcol.color.red;

From 5535c1f04c665c05faff2a65d5558246b7748d49 Mon Sep 17 00:00:00 2001
From: Jules Maselbas <jules.maselbas@grenoble-inp.org>
Date: Sun, 15 Jul 2018 13:53:37 +0200
Subject: [PATCH 1027/1146] Fix crash when cursor color is truecolor

Reported-by: Ivan Tham <pickfire@riseup.net>
---
 x.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/x.c b/x.c
index b51821d..4155a70 100644
--- a/x.c
+++ b/x.c
@@ -1404,6 +1404,7 @@ void
 xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 {
 	Color drawcol;
+	uint32_t cc;
 
 	/* remove the old cursor */
 	if (selected(ox, oy))
@@ -1419,14 +1420,22 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 	g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
 
 	if (selected(cx, cy)) {
-		drawcol = dc.col[g.bg];
+		cc = g.bg;
 	} else {
 		g.mode |= ATTR_REVERSE;
-
 		if (g.mode & ATTR_BOLD && BETWEEN(g.fg, 0, 7))
-			drawcol = dc.col[g.fg + 8];
+			cc = g.fg + 8;
 		else
-			drawcol = dc.col[g.fg];
+			cc = g.fg;
+	}
+
+	if (IS_TRUECOL(cc)) {
+		drawcol.color.alpha = 0xffff;
+		drawcol.color.red = TRUERED(cc);
+		drawcol.color.green = TRUEGREEN(cc);
+		drawcol.color.blue = TRUEBLUE(cc);
+	} else {
+		drawcol = dc.col[cc];
 	}
 
 	if (IS_SET(MODE_REVERSE)) {

From 732be223ee7ba5486713c63f944699fd6285af96 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Tue, 17 Jul 2018 20:01:54 +0200
Subject: [PATCH 1028/1146] Revert "Fix crash when cursor color is truecolor"

This reverts commit 5535c1f04c665c05faff2a65d5558246b7748d49.
---
 x.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/x.c b/x.c
index 4155a70..b51821d 100644
--- a/x.c
+++ b/x.c
@@ -1404,7 +1404,6 @@ void
 xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 {
 	Color drawcol;
-	uint32_t cc;
 
 	/* remove the old cursor */
 	if (selected(ox, oy))
@@ -1420,22 +1419,14 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 	g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
 
 	if (selected(cx, cy)) {
-		cc = g.bg;
+		drawcol = dc.col[g.bg];
 	} else {
 		g.mode |= ATTR_REVERSE;
-		if (g.mode & ATTR_BOLD && BETWEEN(g.fg, 0, 7))
-			cc = g.fg + 8;
-		else
-			cc = g.fg;
-	}
 
-	if (IS_TRUECOL(cc)) {
-		drawcol.color.alpha = 0xffff;
-		drawcol.color.red = TRUERED(cc);
-		drawcol.color.green = TRUEGREEN(cc);
-		drawcol.color.blue = TRUEBLUE(cc);
-	} else {
-		drawcol = dc.col[cc];
+		if (g.mode & ATTR_BOLD && BETWEEN(g.fg, 0, 7))
+			drawcol = dc.col[g.fg + 8];
+		else
+			drawcol = dc.col[g.fg];
 	}
 
 	if (IS_SET(MODE_REVERSE)) {

From 8ed7a4b3b755407a7724a586ef224051bc306f4f Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Tue, 17 Jul 2018 20:01:57 +0200
Subject: [PATCH 1029/1146] Revert "Make cursor follow text color"

This reverts commit b51bcd5553af3db394014efbd78acf7828fa48ff.
---
 config.def.h |  2 ++
 x.c          | 12 +++++-------
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/config.def.h b/config.def.h
index ca6b0db..82b1b09 100644
--- a/config.def.h
+++ b/config.def.h
@@ -118,6 +118,8 @@ static const char *colorname[] = {
  */
 unsigned int defaultfg = 7;
 unsigned int defaultbg = 0;
+static unsigned int defaultcs = 256;
+static unsigned int defaultrcs = 257;
 
 /*
  * Default shape of cursor
diff --git a/x.c b/x.c
index b51821d..ffd005f 100644
--- a/x.c
+++ b/x.c
@@ -1419,15 +1419,13 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 	g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
 
 	if (selected(cx, cy)) {
-		drawcol = dc.col[g.bg];
+		g.bg = defaultrcs;
+		g.fg = defaultfg;
 	} else {
-		g.mode |= ATTR_REVERSE;
-
-		if (g.mode & ATTR_BOLD && BETWEEN(g.fg, 0, 7))
-			drawcol = dc.col[g.fg + 8];
-		else
-			drawcol = dc.col[g.fg];
+		g.bg = defaultcs;
+		g.fg = defaultbg;
 	}
+	drawcol = dc.col[g.bg];
 
 	if (IS_SET(MODE_REVERSE)) {
 		drawcol.color.red = ~drawcol.color.red;

From 4f4bccd1627c845330235721f593d2e93418723d Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Tue, 17 Jul 2018 20:01:58 +0200
Subject: [PATCH 1030/1146] Revert "Simplify cursor color handling"

This reverts commit 1911c9274d9b03f3d7999c6ce26e2d5169642d26.
---
 x.c | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/x.c b/x.c
index ffd005f..00cb6b1 100644
--- a/x.c
+++ b/x.c
@@ -1418,19 +1418,25 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 	 */
 	g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
 
-	if (selected(cx, cy)) {
-		g.bg = defaultrcs;
-		g.fg = defaultfg;
-	} else {
-		g.bg = defaultcs;
-		g.fg = defaultbg;
-	}
-	drawcol = dc.col[g.bg];
-
 	if (IS_SET(MODE_REVERSE)) {
-		drawcol.color.red = ~drawcol.color.red;
-		drawcol.color.green = ~drawcol.color.green;
-		drawcol.color.blue = ~drawcol.color.blue;
+		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 */

From 67d0cb65d0794e2d91e72e5fa1e3612172e5812e Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Tue, 11 Sep 2018 13:11:28 +0200
Subject: [PATCH 1031/1146] Remove the ISO 14755 feature

And move it to the patches section.
Keeping it would force to add an exec pledge on OpenBSD, and some
people think it's bloated, so bye!
---
 config.def.h |  1 -
 st.1         |  4 ----
 st.c         | 26 --------------------------
 st.h         |  1 -
 4 files changed, 32 deletions(-)

diff --git a/config.def.h b/config.def.h
index 82b1b09..823e79f 100644
--- a/config.def.h
+++ b/config.def.h
@@ -177,7 +177,6 @@ static Shortcut shortcuts[] = {
 	{ TERMMOD,              XK_V,           clippaste,      {.i =  0} },
 	{ TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
 	{ TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
-	{ TERMMOD,              XK_I,           iso14755,       {.i =  0} },
 };
 
 /*
diff --git a/st.1 b/st.1
index 81bceff..e8d6059 100644
--- a/st.1
+++ b/st.1
@@ -159,10 +159,6 @@ Copy the selected text to the clipboard selection.
 .TP
 .B Ctrl-Shift-v
 Paste from the clipboard selection.
-.TP
-.B Ctrl-Shift-i
-Launch dmenu to enter a unicode codepoint and send the corresponding glyph
-to st.
 .SH CUSTOMIZATION
 .B st
 can be customized by creating a custom config.h and (re)compiling the source
diff --git a/st.c b/st.c
index 76bb3ea..574dbee 100644
--- a/st.c
+++ b/st.c
@@ -38,15 +38,11 @@
 
 /* macros */
 #define IS_SET(flag)		((term.mode & (flag)) != 0)
-#define NUMMAXLEN(x)		((int)(sizeof(x) * 2.56 + 0.5) + 1)
 #define ISCONTROLC0(c)		(BETWEEN(c, 0, 0x1f) || (c) == '\177')
 #define ISCONTROLC1(c)		(BETWEEN(c, 0x80, 0x9f))
 #define ISCONTROL(c)		(ISCONTROLC0(c) || ISCONTROLC1(c))
 #define ISDELIM(u)		(utf8strchr(worddelimiters, u) != NULL)
 
-/* constants */
-#define ISO14755CMD		"dmenu -w \"$WINDOWID\" -p codepoint: </dev/null"
-
 enum term_mode {
 	MODE_WRAP        = 1 << 0,
 	MODE_INSERT      = 1 << 1,
@@ -1981,28 +1977,6 @@ tprinter(char *s, size_t len)
 	}
 }
 
-void
-iso14755(const Arg *arg)
-{
-	FILE *p;
-	char *us, *e, codepoint[9], uc[UTF_SIZ];
-	unsigned long utf32;
-
-	if (!(p = popen(ISO14755CMD, "r")))
-		return;
-
-	us = fgets(codepoint, sizeof(codepoint), p);
-	pclose(p);
-
-	if (!us || *us == '\0' || *us == '-' || strlen(us) > 7)
-		return;
-	if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX ||
-	    (*e != '\n' && *e != '\0'))
-		return;
-
-	ttywrite(uc, utf8encode(utf32, uc), 1);
-}
-
 void
 toggleprinter(const Arg *arg)
 {
diff --git a/st.h b/st.h
index dac64d8..38c61c4 100644
--- a/st.h
+++ b/st.h
@@ -80,7 +80,6 @@ void die(const char *, ...);
 void redraw(void);
 void draw(void);
 
-void iso14755(const Arg *);
 void printscreen(const Arg *);
 void printsel(const Arg *);
 void sendbreak(const Arg *);

From 30ec9a3dc354ab1a561c9edd808046bdf5dfd392 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Tue, 11 Sep 2018 19:06:35 +0200
Subject: [PATCH 1032/1146] small code-style fix

---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 574dbee..46cf2da 100644
--- a/st.c
+++ b/st.c
@@ -1452,7 +1452,8 @@ tsetattr(int *attr, int l)
 			} else {
 				fprintf(stderr,
 					"erresc(default): gfx attr %d unknown\n",
-					attr[i]), csidump();
+					attr[i]);
+				csidump();
 			}
 			break;
 		}

From b4d68d4daa2716c0064605a2a92082a7287ee54a Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun, 4 Nov 2018 14:30:56 +0100
Subject: [PATCH 1033/1146] st: small typofix in comment

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 46cf2da..a51d19c 100644
--- a/st.c
+++ b/st.c
@@ -2262,7 +2262,7 @@ eschandle(uchar ascii)
 	case 'Z': /* DECID -- Identify Terminal */
 		ttywrite(vtiden, strlen(vtiden), 0);
 		break;
-	case 'c': /* RIS -- Reset to inital state */
+	case 'c': /* RIS -- Reset to initial state */
 		treset();
 		resettitle();
 		xloadcols();

From d7bf023b2f2d41cb6983bb3ce2c6d1bf049150b3 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun, 4 Nov 2018 14:35:07 +0100
Subject: [PATCH 1034/1146] fix memory leak in xloadcols()

reported by Avi Halachmi (:avih)" <avihpit@yahoo.com>

patch slightly changed by me.
---
 x.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/x.c b/x.c
index 00cb6b1..0422421 100644
--- a/x.c
+++ b/x.c
@@ -733,12 +733,12 @@ xloadcols(void)
 	static int loaded;
 	Color *cp;
 
-	dc.collen = MAX(LEN(colorname), 256);
-	dc.col = xmalloc(dc.collen * sizeof(Color));
-
 	if (loaded) {
 		for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp)
 			XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
+	} else {
+		dc.collen = MAX(LEN(colorname), 256);
+		dc.col = xmalloc(dc.collen * sizeof(Color));
 	}
 
 	for (i = 0; i < dc.collen; i++)

From 096b125db7ec254002a049ef3a5c1204bd7f0ad9 Mon Sep 17 00:00:00 2001
From: Lauri Tirkkonen <lotheac@iki.fi>
Date: Tue, 11 Dec 2018 11:43:03 +0200
Subject: [PATCH 1035/1146] output child WEXITSTATUS/WTERMSIG on abnormal
 termination

---
 st.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index a51d19c..b8e6077 100644
--- a/st.c
+++ b/st.c
@@ -731,8 +731,10 @@ sigchld(int a)
 	if (pid != p)
 		return;
 
-	if (!WIFEXITED(stat) || WEXITSTATUS(stat))
-		die("child finished with error '%d'\n", stat);
+	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);
 }
 

From 7e19e116764d2651721cb9062ccaac31b0c771f2 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 4 Jan 2019 12:33:01 +0100
Subject: [PATCH 1036/1146] Makefile: fix dependencies on config.h

patch by Younes Khoudli (changed slightly). Thanks
---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 0b3cecd..470ac86 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,7 @@ config.h:
 	$(CC) $(STCFLAGS) -c $<
 
 st.o: config.h st.h win.h
-x.o: arg.h st.h win.h
+x.o: arg.h config.h st.h win.h
 
 $(OBJ): config.h config.mk
 

From e23acb9188b7bc7a7cfc418ac45671003abcc341 Mon Sep 17 00:00:00 2001
From: Paride Legovini <pl@ninthfloor.org>
Date: Fri, 4 Jan 2019 09:48:37 +0100
Subject: [PATCH 1037/1146] Set the path of pkg-config in a variable instead of
 hardcoding it

In this way the path of pkg-config can be overridden from the command
line. This is useful for example when cross-compiling.
---
 config.mk | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/config.mk b/config.mk
index e676105..64a1da9 100644
--- a/config.mk
+++ b/config.mk
@@ -10,13 +10,15 @@ 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`
+       `$(PKG_CONFIG) --cflags fontconfig` \
+       `$(PKG_CONFIG) --cflags freetype2`
 LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
-       `pkg-config --libs fontconfig` \
-       `pkg-config --libs freetype2`
+       `$(PKG_CONFIG) --libs fontconfig` \
+       `$(PKG_CONFIG) --libs freetype2`
 
 # flags
 CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600

From 16d98738e74f189b3a00c23390ab5a9a22b056a1 Mon Sep 17 00:00:00 2001
From: Paride Legovini <pl@ninthfloor.org>
Date: Thu, 10 Jan 2019 13:36:09 +0100
Subject: [PATCH 1038/1146] Let the user specify CPPFLAGS

This complements the work done in d4928ed, allowing the user to specify
the preprocessor flags with the CPPFLAGS environment variable. This is
useful for example to specify preprocessor macros with -D.

CFLAGS could be used instead, but CPPFLAGS is more correct and is expected
to be honored in some cases. For example, the helper scripts to build
Debian packages make use of CPPFLAGS, but the variable is currently
being ignored unless manually appended to CFLAGS.
---
 config.mk | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config.mk b/config.mk
index 64a1da9..5059632 100644
--- a/config.mk
+++ b/config.mk
@@ -21,8 +21,8 @@ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
        `$(PKG_CONFIG) --libs freetype2`
 
 # flags
-CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
-STCFLAGS = $(INCS) $(CPPFLAGS) $(CFLAGS)
+STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
 STLDFLAGS = $(LIBS) $(LDFLAGS)
 
 # OpenBSD:

From 3be4cf11d79ca87ff1fbbb57801913ec6f822429 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Thu, 10 Jan 2019 18:16:17 +0100
Subject: [PATCH 1039/1146] config: add Shift+Insert as selpaste() again

This was changed before in:
commit 20f713548de451b67db3306cf8cf7b2f38fee05c on Wed Jan 25 19:17:38 2017
---
 config.def.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/config.def.h b/config.def.h
index 823e79f..0e01717 100644
--- a/config.def.h
+++ b/config.def.h
@@ -176,6 +176,7 @@ static Shortcut shortcuts[] = {
 	{ 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} },
 };
 

From 75f92eb3489275bfcad901e5ca424134eda6e2f4 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 9 Feb 2019 12:48:39 +0100
Subject: [PATCH 1040/1146] bump version to 0.8.2

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 5059632..0cbb002 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.8.1
+VERSION = 0.8.2
 
 # Customize below to fit your system
 

From e85b6b64660214121164ea97fb098eaa4935f7db Mon Sep 17 00:00:00 2001
From: Ivan Tham <pickfire@riseup.net>
Date: Tue, 12 Feb 2019 18:41:41 +0100
Subject: [PATCH 1041/1146] better Input Method Editor (IME) support

Features:

- Allow input methods swap with hotkey (E.g. left ctrl + left shift).
- Over-the-spot pre-editing style, pre-edit data placed over insertion point.
- Restart IME without segmentation fault.

TODO:

- Automatically pickup IME if st started before IME
---
 st.c  |  1 +
 win.h |  1 +
 x.c   | 69 ++++++++++++++++++++++++++++++++++++++++++++---------------
 3 files changed, 54 insertions(+), 17 deletions(-)

diff --git a/st.c b/st.c
index b8e6077..cf8687e 100644
--- a/st.c
+++ b/st.c
@@ -2594,6 +2594,7 @@ draw(void)
 			term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
 	term.ocx = cx, term.ocy = term.c.y;
 	xfinishdraw();
+	xximspot(term.ocx, term.ocy);
 }
 
 void
diff --git a/win.h b/win.h
index 31f327d..a6ef1b9 100644
--- a/win.h
+++ b/win.h
@@ -36,3 +36,4 @@ void xsetmode(int, unsigned int);
 void xsetpointermotion(int);
 void xsetsel(char *);
 int xstartdraw(void);
+void xximspot(int, int);
diff --git a/x.c b/x.c
index 0422421..865dacc 100644
--- a/x.c
+++ b/x.c
@@ -139,6 +139,9 @@ static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
 static void xdrawglyph(Glyph, int, int);
 static void xclear(int, int, int, int);
 static int xgeommasktogravity(int);
+static void ximopen(Display *);
+static void ximinstantiate(Display *, XPointer, XPointer);
+static void ximdestroy(XIM, XPointer, XPointer);
 static void xinit(int, int);
 static void cresize(int, int);
 static void xresize(int, int);
@@ -996,6 +999,43 @@ xunloadfonts(void)
 	xunloadfont(&dc.ibfont);
 }
 
+void
+ximopen(Display *dpy)
+{
+	XIMCallback destroy = { .client_data = NULL, .callback = ximdestroy };
+
+	if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+		XSetLocaleModifiers("@im=local");
+		if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+			XSetLocaleModifiers("@im=");
+			if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL)
+				die("XOpenIM failed. Could not open input device.\n");
+		}
+	}
+	if (XSetIMValues(xw.xim, XNDestroyCallback, &destroy, NULL) != NULL)
+		die("XSetIMValues failed. Could not set input method value.\n");
+	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
+				XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL);
+	if (xw.xic == NULL)
+		die("XCreateIC failed. Could not obtain input method.\n");
+}
+
+void
+ximinstantiate(Display *dpy, XPointer client, XPointer call)
+{
+	ximopen(dpy);
+	XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
+					ximinstantiate, NULL);
+}
+
+void
+ximdestroy(XIM xim, XPointer client, XPointer call)
+{
+	xw.xim = NULL;
+	XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
+					ximinstantiate, NULL);
+}
+
 void
 xinit(int cols, int rows)
 {
@@ -1033,7 +1073,7 @@ xinit(int cols, int rows)
 	xw.attrs.background_pixel = dc.col[defaultbg].pixel;
 	xw.attrs.border_pixel = dc.col[defaultbg].pixel;
 	xw.attrs.bit_gravity = NorthWestGravity;
-	xw.attrs.event_mask = FocusChangeMask | KeyPressMask
+	xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask
 		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
 		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
 	xw.attrs.colormap = xw.cmap;
@@ -1061,22 +1101,7 @@ xinit(int cols, int rows)
 	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
 
 	/* input methods */
-	if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
-		XSetLocaleModifiers("@im=local");
-		if ((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
-			XSetLocaleModifiers("@im=");
-			if ((xw.xim = XOpenIM(xw.dpy,
-					NULL, NULL, NULL)) == NULL) {
-				die("XOpenIM failed. Could not open input"
-					" device.\n");
-			}
-		}
-	}
-	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
-					   | XIMStatusNothing, XNClientWindow, xw.win,
-					   XNFocusWindow, xw.win, NULL);
-	if (xw.xic == NULL)
-		die("XCreateIC failed. Could not obtain input method.\n");
+	ximopen(xw.dpy);
 
 	/* white cursor, black outline */
 	cursor = XCreateFontCursor(xw.dpy, mouseshape);
@@ -1554,6 +1579,16 @@ xfinishdraw(void)
 				defaultfg : defaultbg].pixel);
 }
 
+void
+xximspot(int x, int y)
+{
+	XPoint spot = { borderpx + x * win.cw, borderpx + (y + 1) * win.ch };
+	XVaNestedList attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
+
+	XSetICValues(xw.xic, XNPreeditAttributes, attr, NULL);
+	XFree(attr);
+}
+
 void
 expose(XEvent *ev)
 {

From a8cb8e94547d7e31441d2444e8a196415e3e4c1f Mon Sep 17 00:00:00 2001
From: magras <dr.magras@gmail.com>
Date: Thu, 28 Feb 2019 04:56:01 +0300
Subject: [PATCH 1042/1146] fix use after free in font caching algorithm

Current font caching algorithm contains a use after free error. A font
removed from `frc` might be still listed in `wx.specbuf`. It will lead
to a crash inside `XftDrawGlyphFontSpec()`.

Steps to reproduce:
$ st -f 'Misc Tamsyn:scalable=false'
$ curl https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt

Of course, result depends on fonts installed on a system and fontconfig.
In my case, I'm getting consistent segfaults with different fonts.

I replaced a fixed array with a simple unbounded buffer with a constant
growth rate. Cache starts with a capacity of 0, gets increments by 16,
and never shrinks. On my machine after `cat UTF-8-demo.txt` buffer
reaches a capacity of 192. During casual use capacity stays at 0.
---
 x.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/x.c b/x.c
index 865dacc..2cd76d0 100644
--- a/x.c
+++ b/x.c
@@ -226,8 +226,9 @@ typedef struct {
 } Fontcache;
 
 /* Fontcache is an array now. A new font will be appended to the array. */
-static Fontcache frc[16];
+static Fontcache *frc = NULL;
 static int frclen = 0;
+static int frccap = 0;
 static char *usedfont = NULL;
 static double usedfontsize = 0;
 static double defaultfontsize = 0;
@@ -1244,12 +1245,14 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
 					fcpattern, &fcres);
 
 			/*
-			 * Overwrite or create the new cache entry.
+			 * Allocate memory for the new cache entry.
 			 */
-			if (frclen >= LEN(frc)) {
-				frclen = LEN(frc) - 1;
-				XftFontClose(xw.dpy, frc[frclen].font);
-				frc[frclen].unicodep = 0;
+			if (frclen >= frccap) {
+				frccap += 16;
+				if (!frc)
+					frc = xmalloc(frccap * sizeof(Fontcache));
+				else
+					frc = xrealloc(frc, frccap * sizeof(Fontcache));
 			}
 
 			frc[frclen].font = XftFontOpenPattern(xw.dpy,

From 4e0135afeca43f5affe13d7269cb98e7ac526074 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun, 3 Mar 2019 11:23:54 +0100
Subject: [PATCH 1043/1146] style: remove double empty newlines

---
 st.c | 1 -
 x.c  | 2 --
 2 files changed, 3 deletions(-)

diff --git a/st.c b/st.c
index cf8687e..379dd10 100644
--- a/st.c
+++ b/st.c
@@ -2335,7 +2335,6 @@ tputc(Rune u)
 			goto check_control_code;
 		}
 
-
 		if (IS_SET(MODE_SIXEL)) {
 			/* TODO: implement sixel mode */
 			return;
diff --git a/x.c b/x.c
index 2cd76d0..aa86b31 100644
--- a/x.c
+++ b/x.c
@@ -763,7 +763,6 @@ xsetcolorname(int x, const char *name)
 	if (!BETWEEN(x, 0, dc.collen))
 		return 1;
 
-
 	if (!xloadcolor(x, name, &ncolor))
 		return 1;
 
@@ -1769,7 +1768,6 @@ kpress(XEvent *ev)
 	ttywrite(buf, len, 1);
 }
 
-
 void
 cmessage(XEvent *e)
 {

From ed68fe7dce2b21b4e0e595b99d47790e76812cb7 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun, 3 Mar 2019 11:29:43 +0100
Subject: [PATCH 1044/1146] simplify (greedy) font caching allocating a bit

POSIX says:
"If ptr is a null pointer, realloc() shall be equivalent to malloc() for the
 specified size."
---
 x.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/x.c b/x.c
index aa86b31..5828a3b 100644
--- a/x.c
+++ b/x.c
@@ -1243,15 +1243,10 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
 			fontpattern = FcFontSetMatch(0, fcsets, 1,
 					fcpattern, &fcres);
 
-			/*
-			 * Allocate memory for the new cache entry.
-			 */
+			/* Allocate memory for the new cache entry. */
 			if (frclen >= frccap) {
 				frccap += 16;
-				if (!frc)
-					frc = xmalloc(frccap * sizeof(Fontcache));
-				else
-					frc = xrealloc(frc, frccap * sizeof(Fontcache));
+				frc = xrealloc(frc, frccap * sizeof(Fontcache));
 			}
 
 			frc[frclen].font = XftFontOpenPattern(xw.dpy,

From 75b4ba4b4be70a3ae429b1719d18b021839216d5 Mon Sep 17 00:00:00 2001
From: Lauri Tirkkonen <lotheac@iki.fi>
Date: Wed, 13 Mar 2019 17:08:50 +0200
Subject: [PATCH 1045/1146] be silent about explicitly unhandled mouse modes

---
 st.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index 379dd10..d35f89d 100644
--- a/st.c
+++ b/st.c
@@ -1575,6 +1575,7 @@ tsetmode(int priv, int set, int *args, int narg)
 			case 1015: /* urxvt mangled mouse mode; incompatible
 				      and can be mistaken for other control
 				      codes. */
+				break;
 			default:
 				fprintf(stderr,
 					"erresc: unknown private set/reset mode %d\n",

From d5efd256aa3840476579a27293ef1fb92a4b51e7 Mon Sep 17 00:00:00 2001
From: Lauri Tirkkonen <lotheac@iki.fi>
Date: Wed, 13 Mar 2019 19:40:52 +0200
Subject: [PATCH 1046/1146] replace utf8strchr with wcschr

---
 config.def.h |  4 ++--
 st.c         | 20 +-------------------
 st.h         |  2 +-
 3 files changed, 4 insertions(+), 22 deletions(-)

diff --git a/config.def.h b/config.def.h
index 0e01717..482901e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -30,9 +30,9 @@ static float chscale = 1.0;
 /*
  * word delimiter string
  *
- * More advanced example: " `'\"()[]{}"
+ * More advanced example: L" `'\"()[]{}"
  */
-char *worddelimiters = " ";
+wchar_t *worddelimiters = L" ";
 
 /* selection timeouts (in milliseconds) */
 static unsigned int doubleclicktimeout = 300;
diff --git a/st.c b/st.c
index d35f89d..812f30c 100644
--- a/st.c
+++ b/st.c
@@ -41,7 +41,7 @@
 #define ISCONTROLC0(c)		(BETWEEN(c, 0, 0x1f) || (c) == '\177')
 #define ISCONTROLC1(c)		(BETWEEN(c, 0x80, 0x9f))
 #define ISCONTROL(c)		(ISCONTROLC0(c) || ISCONTROLC1(c))
-#define ISDELIM(u)		(utf8strchr(worddelimiters, u) != NULL)
+#define ISDELIM(u)		(u != 0 && wcschr(worddelimiters, u) != NULL)
 
 enum term_mode {
 	MODE_WRAP        = 1 << 0,
@@ -210,7 +210,6 @@ static void selsnap(int *, int *, int);
 static size_t utf8decode(const char *, Rune *, size_t);
 static Rune utf8decodebyte(char, size_t *);
 static char utf8encodebyte(Rune, size_t);
-static char *utf8strchr(char *, Rune);
 static size_t utf8validate(Rune *, size_t);
 
 static char *base64dec(const char *);
@@ -337,23 +336,6 @@ utf8encodebyte(Rune u, size_t i)
 	return utfbyte[i] | (u & ~utfmask[i]);
 }
 
-char *
-utf8strchr(char *s, Rune u)
-{
-	Rune r;
-	size_t i, j, len;
-
-	len = strlen(s);
-	for (i = 0, j = 0; i < len; i += j) {
-		if (!(j = utf8decode(&s[i], &r, len - i)))
-			break;
-		if (r == u)
-			return &(s[i]);
-	}
-
-	return NULL;
-}
-
 size_t
 utf8validate(Rune *u, size_t i)
 {
diff --git a/st.h b/st.h
index 38c61c4..4da3051 100644
--- a/st.h
+++ b/st.h
@@ -114,7 +114,7 @@ char *xstrdup(char *);
 extern char *utmp;
 extern char *stty_args;
 extern char *vtiden;
-extern char *worddelimiters;
+extern wchar_t *worddelimiters;
 extern int allowaltscreen;
 extern char *termname;
 extern unsigned int tabspaces;

From add0211522737b79dad990ccd65c8af63b5cc1dd Mon Sep 17 00:00:00 2001
From: Lauri Tirkkonen <lotheac@iki.fi>
Date: Wed, 13 Mar 2019 17:15:04 +0200
Subject: [PATCH 1047/1146] use iswspace()/iswpunct() to find word delimiters

this inverts the configuration logic: you no longer provide a list of
delimiters -- all space and punctuation characters are considered
delimiters, unless listed in extrawordchars.
---
 config.def.h | 7 ++++---
 st.c         | 3 ++-
 st.h         | 2 +-
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/config.def.h b/config.def.h
index 482901e..9ce45a7 100644
--- a/config.def.h
+++ b/config.def.h
@@ -28,11 +28,12 @@ static float cwscale = 1.0;
 static float chscale = 1.0;
 
 /*
- * word delimiter string
+ * all space and punctuation characters are considered word delimiters, unless
+ * listed here.
  *
- * More advanced example: L" `'\"()[]{}"
+ * More advanced example: L"#$%&+,-./:=?_~"
  */
-wchar_t *worddelimiters = L" ";
+wchar_t *extrawordchars = L"./:";
 
 /* selection timeouts (in milliseconds) */
 static unsigned int doubleclicktimeout = 300;
diff --git a/st.c b/st.c
index 812f30c..c383b43 100644
--- a/st.c
+++ b/st.c
@@ -16,6 +16,7 @@
 #include <termios.h>
 #include <unistd.h>
 #include <wchar.h>
+#include <wctype.h>
 
 #include "st.h"
 #include "win.h"
@@ -41,7 +42,7 @@
 #define ISCONTROLC0(c)		(BETWEEN(c, 0, 0x1f) || (c) == '\177')
 #define ISCONTROLC1(c)		(BETWEEN(c, 0x80, 0x9f))
 #define ISCONTROL(c)		(ISCONTROLC0(c) || ISCONTROLC1(c))
-#define ISDELIM(u)		(u != 0 && wcschr(worddelimiters, u) != NULL)
+#define ISDELIM(u)		((iswspace(u) || iswpunct(u)) && wcschr(extrawordchars, u) == NULL)
 
 enum term_mode {
 	MODE_WRAP        = 1 << 0,
diff --git a/st.h b/st.h
index 4da3051..a3b19de 100644
--- a/st.h
+++ b/st.h
@@ -114,7 +114,7 @@ char *xstrdup(char *);
 extern char *utmp;
 extern char *stty_args;
 extern char *vtiden;
-extern wchar_t *worddelimiters;
+extern wchar_t *extrawordchars;
 extern int allowaltscreen;
 extern char *termname;
 extern unsigned int tabspaces;

From 927621f6da015f51710c03279b00c6cc38057e32 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 15 Mar 2019 12:31:54 +0100
Subject: [PATCH 1048/1146] config.def.h: tweak extra worddelimiters

This changes the selection more like xterm.
To test try: "find /" and select a path.
---
 config.def.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 9ce45a7..ac5e8ce 100644
--- a/config.def.h
+++ b/config.def.h
@@ -33,7 +33,7 @@ static float chscale = 1.0;
  *
  * More advanced example: L"#$%&+,-./:=?_~"
  */
-wchar_t *extrawordchars = L"./:";
+wchar_t *extrawordchars = L"";
 
 /* selection timeouts (in milliseconds) */
 static unsigned int doubleclicktimeout = 300;

From 9acec468fbeaa9f90578352b610431ca9b2d4ee4 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 15 Mar 2019 14:42:50 +0100
Subject: [PATCH 1049/1146] minor code-style, initialize var at the top of
 function

---
 st.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/st.c b/st.c
index c383b43..f342e5c 100644
--- a/st.c
+++ b/st.c
@@ -1830,7 +1830,7 @@ csireset(void)
 void
 strhandle(void)
 {
-	char *p = NULL;
+	char *p = NULL, *dec;
 	int j, narg, par;
 
 	term.esc &= ~(ESC_STR_END|ESC_STR);
@@ -1848,8 +1848,6 @@ strhandle(void)
 			return;
 		case 52:
 			if (narg > 2) {
-				char *dec;
-
 				dec = base64dec(strescseq.args[2]);
 				if (dec) {
 					xsetsel(dec);

From b650256044f867851725f712fdac58d4ff294808 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 15 Mar 2019 14:44:28 +0100
Subject: [PATCH 1050/1146] dont print color warning on color reset OSC 104
 without parameter

also print explicitly "(null)" when printf "%s" p=NULL.

noticed when exiting mutt: printf '\x1b]104\x07'
---
 st.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index f342e5c..48d65ca 100644
--- a/st.c
+++ b/st.c
@@ -1865,7 +1865,10 @@ strhandle(void)
 		case 104: /* color reset, here p = NULL */
 			j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
 			if (xsetcolorname(j, p)) {
-				fprintf(stderr, "erresc: invalid color %s\n", p);
+				if (par == 104 && narg <= 1)
+					return; /* color reset without parameter */
+				fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
+				        j, p ? p : "(null)");
 			} else {
 				/*
 				 * TODO if defaultbg color is changed, borders

From 21367a040f056f6a207fafa066bd1cb2d9cae586 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 15 Mar 2019 20:40:16 +0100
Subject: [PATCH 1051/1146] revert part of commit
 add0211522737b79dad990ccd65c8af63b5cc1dd

"use iswspace()/iswpunct() to find word delimiters

    this inverts the configuration logic: you no longer provide a list of
    delimiters -- all space and punctuation characters are considered
    delimiters, unless listed in extrawordchars."

Feedback from IRC and personal preference.
---
 config.def.h | 7 +++----
 st.c         | 3 +--
 st.h         | 2 +-
 3 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/config.def.h b/config.def.h
index ac5e8ce..482901e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -28,12 +28,11 @@ static float cwscale = 1.0;
 static float chscale = 1.0;
 
 /*
- * all space and punctuation characters are considered word delimiters, unless
- * listed here.
+ * word delimiter string
  *
- * More advanced example: L"#$%&+,-./:=?_~"
+ * More advanced example: L" `'\"()[]{}"
  */
-wchar_t *extrawordchars = L"";
+wchar_t *worddelimiters = L" ";
 
 /* selection timeouts (in milliseconds) */
 static unsigned int doubleclicktimeout = 300;
diff --git a/st.c b/st.c
index 48d65ca..8e6ccb5 100644
--- a/st.c
+++ b/st.c
@@ -16,7 +16,6 @@
 #include <termios.h>
 #include <unistd.h>
 #include <wchar.h>
-#include <wctype.h>
 
 #include "st.h"
 #include "win.h"
@@ -42,7 +41,7 @@
 #define ISCONTROLC0(c)		(BETWEEN(c, 0, 0x1f) || (c) == '\177')
 #define ISCONTROLC1(c)		(BETWEEN(c, 0x80, 0x9f))
 #define ISCONTROL(c)		(ISCONTROLC0(c) || ISCONTROLC1(c))
-#define ISDELIM(u)		((iswspace(u) || iswpunct(u)) && wcschr(extrawordchars, u) == NULL)
+#define ISDELIM(u)		(u && wcschr(worddelimiters, u))
 
 enum term_mode {
 	MODE_WRAP        = 1 << 0,
diff --git a/st.h b/st.h
index a3b19de..4da3051 100644
--- a/st.h
+++ b/st.h
@@ -114,7 +114,7 @@ char *xstrdup(char *);
 extern char *utmp;
 extern char *stty_args;
 extern char *vtiden;
-extern wchar_t *extrawordchars;
+extern wchar_t *worddelimiters;
 extern int allowaltscreen;
 extern char *termname;
 extern unsigned int tabspaces;

From f1546cf9c1f9fc52d26dbbcf73210901e83c7ecf Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
Date: Wed, 10 Apr 2019 01:54:43 +0300
Subject: [PATCH 1052/1146] selection: fix view to match actual selection on
 first cell

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 8e6ccb5..ede7ae6 100644
--- a/st.c
+++ b/st.c
@@ -458,7 +458,7 @@ selextend(int col, int row, int type, int done)
 	selnormalize();
 	sel.type = type;
 
-	if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type)
+	if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY)
 		tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
 
 	sel.mode = done ? SEL_IDLE : SEL_READY;

From caa1d8fbea2b92bca24652af0fee874bdbbbb3e5 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 17 May 2019 13:00:10 +0200
Subject: [PATCH 1053/1146] FAQ: add entry about color emoji Xft bug

This has been asked many times on IRC and the mailinglist. Make it easier to
find information about this particular Xft issue by adding it to the FAQ.
---
 FAQ | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/FAQ b/FAQ
index 921c493..ecf7af8 100644
--- a/FAQ
+++ b/FAQ
@@ -165,3 +165,30 @@ Apply [1].
 
 [1] http://st.suckless.org/patches/delkey
 
+## 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.

From 2b8333f553c14c15398e810353e192eb05938580 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Mon, 26 Aug 2019 17:58:47 +0200
Subject: [PATCH 1054/1146] config.def.h: remove crlf value section

this is not used anymore.

patch sent as an ed script using RFC2549 by k0ga.
---
 config.def.h | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index 482901e..6ebea98 100644
--- a/config.def.h
+++ b/config.def.h
@@ -195,10 +195,6 @@ static Shortcut shortcuts[] = {
  * * 0: no value
  * * > 0: cursor application mode enabled
  * * < 0: cursor application mode disabled
- * crlf value
- * * 0: no value
- * * > 0: crlf mode is enabled
- * * < 0: crlf mode is disabled
  *
  * Be careful with the order of the definitions because st searches in
  * this table sequentially, so any XK_ANY_MOD must be in the last

From ba7f4d69af62d20e13fea78a408095e017410651 Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
Date: Thu, 10 Oct 2019 23:02:26 +0300
Subject: [PATCH 1055/1146] mouse shortcuts: allow same functions as kb
 shortcuts

Previously mouse shortcuts supported only ttywrite.

This required adding an "Arg" function ttysend - which does what the
original mouse shortcuts did.
---
 config.def.h |  6 +++---
 st.h         |  1 +
 x.c          | 20 ++++++++++++++------
 3 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/config.def.h b/config.def.h
index 6ebea98..36ff6ce 100644
--- a/config.def.h
+++ b/config.def.h
@@ -155,9 +155,9 @@ static unsigned int defaultattr = 11;
  * Beware that overloading Button1 will disable the selection.
  */
 static MouseShortcut mshortcuts[] = {
-	/* button               mask            string */
-	{ Button4,              XK_ANY_MOD,     "\031" },
-	{ Button5,              XK_ANY_MOD,     "\005" },
+	/* mask                 button   function        argument */
+	{ XK_ANY_MOD,           Button4, ttysend,        {.s = "\031"} },
+	{ XK_ANY_MOD,           Button5, ttysend,        {.s = "\005"} },
 };
 
 /* Internal keyboard shortcuts. */
diff --git a/st.h b/st.h
index 4da3051..a1928ca 100644
--- a/st.h
+++ b/st.h
@@ -74,6 +74,7 @@ typedef union {
 	uint ui;
 	float f;
 	const void *v;
+	const char *s;
 } Arg;
 
 void die(const char *, ...);
diff --git a/x.c b/x.c
index 5828a3b..2a05a81 100644
--- a/x.c
+++ b/x.c
@@ -29,9 +29,10 @@ typedef struct {
 } Shortcut;
 
 typedef struct {
-	uint b;
-	uint mask;
-	char *s;
+	uint mod;
+	uint button;
+	void (*func)(const Arg *);
+	const Arg arg;
 } MouseShortcut;
 
 typedef struct {
@@ -56,6 +57,7 @@ static void selpaste(const Arg *);
 static void zoom(const Arg *);
 static void zoomabs(const Arg *);
 static void zoomreset(const Arg *);
+static void ttysend(const Arg *);
 
 /* config.h for applying patches and the configuration. */
 #include "config.h"
@@ -312,6 +314,12 @@ zoomreset(const Arg *arg)
 	}
 }
 
+void
+ttysend(const Arg *arg)
+{
+	ttywrite(arg->s, strlen(arg->s), 1);
+}
+
 int
 evcol(XEvent *e)
 {
@@ -421,9 +429,9 @@ bpress(XEvent *e)
 	}
 
 	for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
-		if (e->xbutton.button == ms->b
-				&& match(ms->mask, e->xbutton.state)) {
-			ttywrite(ms->s, strlen(ms->s), 1);
+		if (e->xbutton.button == ms->button
+				&& match(ms->mod, e->xbutton.state)) {
+			ms->func(&(ms->arg));
 			return;
 		}
 	}

From b6d280de6df30167ce9cf30fadefc362e77729e7 Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
Date: Thu, 10 Oct 2019 23:42:30 +0300
Subject: [PATCH 1056/1146] mouse shortcuts: allow override for all shortcuts

Allow forceselmod to override all mouse shortcuts rather than only
selection, and rename it to forcemousemod as it's now more appropriate.

This will affect mouse shortcuts which use mask other than XK_ANY_MOD.

This does not affect the default behavior because the default mouse
shortcuts (wheel) use XK_ANY_MOD, where forceselmod already activated
the override also before this change.

Previously, if a mouse shortcut was configured with a specific mod and
forceselmod was held, then the shortcut did not execute unless the
configured mod included forceselmod.
---
 config.def.h | 14 +++++++-------
 x.c          | 12 ++++++------
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/config.def.h b/config.def.h
index 36ff6ce..a0a0d2d 100644
--- a/config.def.h
+++ b/config.def.h
@@ -150,6 +150,13 @@ static unsigned int mousebg = 0;
  */
 static unsigned int defaultattr = 11;
 
+/*
+ * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
+ * Note that if you want to use ShiftMask with selmasks, set this to an other
+ * modifier, set to 0 to not use it.
+ */
+static uint forcemousemod = ShiftMask;
+
 /*
  * Internal mouse shortcuts.
  * Beware that overloading Button1 will disable the selection.
@@ -213,13 +220,6 @@ static KeySym mappedkeys[] = { -1 };
  */
 static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
 
-/*
- * Override mouse-select while mask is active (when MODE_MOUSE is set).
- * Note that if you want to use ShiftMask with selmasks, set this to an other
- * modifier, set to 0 to not use it.
- */
-static uint forceselmod = ShiftMask;
-
 /*
  * This is the huge key array which defines all compatibility to the Linux
  * world. Please decide about changes wisely.
diff --git a/x.c b/x.c
index 2a05a81..c967caf 100644
--- a/x.c
+++ b/x.c
@@ -340,7 +340,7 @@ void
 mousesel(XEvent *e, int done)
 {
 	int type, seltype = SEL_REGULAR;
-	uint state = e->xbutton.state & ~(Button1Mask | forceselmod);
+	uint state = e->xbutton.state & ~(Button1Mask | forcemousemod);
 
 	for (type = 1; type < LEN(selmasks); ++type) {
 		if (match(selmasks[type], state)) {
@@ -423,14 +423,14 @@ bpress(XEvent *e)
 	MouseShortcut *ms;
 	int snap;
 
-	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
 		mousereport(e);
 		return;
 	}
 
 	for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
-		if (e->xbutton.button == ms->button
-				&& match(ms->mod, e->xbutton.state)) {
+		if (e->xbutton.button == ms->button &&
+		    match(ms->mod, e->xbutton.state & ~forcemousemod)) {
 			ms->func(&(ms->arg));
 			return;
 		}
@@ -650,7 +650,7 @@ xsetsel(char *str)
 void
 brelease(XEvent *e)
 {
-	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
 		mousereport(e);
 		return;
 	}
@@ -664,7 +664,7 @@ brelease(XEvent *e)
 void
 bmotion(XEvent *e)
 {
-	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
 		mousereport(e);
 		return;
 	}

From d2b75db8d7519a20af8bf09e9c205507f9ff828c Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
Date: Fri, 11 Oct 2019 02:26:10 +0300
Subject: [PATCH 1057/1146] mouse shortcuts: don't hardcode selpaste

Because selpaste is activated on release, a release flag was added to
mouse shortcuts which controls whether activation is on press/release,
and selpaste binding to button2 was moved to config.h .

button1 remains the only hardcoded mouse button - for selection + copy.
---
 config.def.h |  3 ++-
 x.c          | 35 ++++++++++++++++++++++++-----------
 2 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/config.def.h b/config.def.h
index a0a0d2d..546edda 100644
--- a/config.def.h
+++ b/config.def.h
@@ -162,7 +162,8 @@ static uint forcemousemod = ShiftMask;
  * Beware that overloading Button1 will disable the selection.
  */
 static MouseShortcut mshortcuts[] = {
-	/* mask                 button   function        argument */
+	/* mask                 button   function        argument       release */
+	{ XK_ANY_MOD,           Button2, selpaste,       {.i = 0},      1 },
 	{ XK_ANY_MOD,           Button4, ttysend,        {.s = "\031"} },
 	{ XK_ANY_MOD,           Button5, ttysend,        {.s = "\005"} },
 };
diff --git a/x.c b/x.c
index c967caf..8f570c2 100644
--- a/x.c
+++ b/x.c
@@ -33,6 +33,7 @@ typedef struct {
 	uint button;
 	void (*func)(const Arg *);
 	const Arg arg;
+	uint  release;
 } MouseShortcut;
 
 typedef struct {
@@ -165,6 +166,7 @@ static void kpress(XEvent *);
 static void cmessage(XEvent *);
 static void resize(XEvent *);
 static void focus(XEvent *);
+static int mouseaction(XEvent *, uint);
 static void brelease(XEvent *);
 static void bpress(XEvent *);
 static void bmotion(XEvent *);
@@ -416,11 +418,27 @@ mousereport(XEvent *e)
 	ttywrite(buf, len, 0);
 }
 
+int
+mouseaction(XEvent *e, uint release)
+{
+	MouseShortcut *ms;
+
+	for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
+		if (ms->release == release &&
+		    ms->button == e->xbutton.button &&
+		    match(ms->mod, e->xbutton.state & ~forcemousemod)) {
+			ms->func(&(ms->arg));
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
 void
 bpress(XEvent *e)
 {
 	struct timespec now;
-	MouseShortcut *ms;
 	int snap;
 
 	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
@@ -428,13 +446,8 @@ bpress(XEvent *e)
 		return;
 	}
 
-	for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
-		if (e->xbutton.button == ms->button &&
-		    match(ms->mod, e->xbutton.state & ~forcemousemod)) {
-			ms->func(&(ms->arg));
-			return;
-		}
-	}
+	if (mouseaction(e, 0))
+		return;
 
 	if (e->xbutton.button == Button1) {
 		/*
@@ -655,9 +668,9 @@ brelease(XEvent *e)
 		return;
 	}
 
-	if (e->xbutton.button == Button2)
-		selpaste(NULL);
-	else if (e->xbutton.button == Button1)
+	if (mouseaction(e, 1))
+		return;
+	if (e->xbutton.button == Button1)
 		mousesel(e, 1);
 }
 

From a2c479c4c8d035c11a91e4b954a9f161bf4c7150 Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
Date: Thu, 24 Oct 2019 15:42:07 +0300
Subject: [PATCH 1058/1146] mouse shortcuts: allow using forcemousemod (e.g.
 shift)

The recent mouse shurtcuts commits allow customization, but ignore
forcemousemod mask (default: shift) as a modifier, for no good reason
other than following the behavior of the KB shortcuts.

Allow using forcemousemod too, which now can be used to invoke
different shortcuts, though the automatic effect of forcemousemod will
be lost for buttons which use mask with forcemousemod.

E.g. the default is:

static uint forcemousemod = ShiftMask;
...
{ XK_ANY_MOD,           Button4, ttysend,        {.s = "\031"} },
...

where ttysend will be invoked for button4 with any mod when not in mouse
mode, and with shift when in mouse mode.

Now it's possible to do this:
{ ShiftMask,            Button4, ttysend,        {.s = "foo"} },
{ XK_ANY_MOD,           Button4, ttysend,        {.s = "\031"} },

Which will invoke ttysend("foo") while shift is held and ttysend("\031")
otherwise. Shift still overrides mouse mode, but will now send "foo".

Previously with this setup the second binding was always invoked
because the forceousemod mask was always removed from the event.

Buttons which don't use forcemousemod behave the same as before.

This is useful e.g. for the scrollback mouse patch, which wants to
configure shift+wheel for scrollback, while keeping the normal behavior
without shift.
---
 x.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/x.c b/x.c
index 8f570c2..6406925 100644
--- a/x.c
+++ b/x.c
@@ -426,7 +426,8 @@ mouseaction(XEvent *e, uint release)
 	for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
 		if (ms->release == release &&
 		    ms->button == e->xbutton.button &&
-		    match(ms->mod, e->xbutton.state & ~forcemousemod)) {
+		    (match(ms->mod, e->xbutton.state) ||  /* exact or forced */
+		     match(ms->mod, e->xbutton.state & ~forcemousemod))) {
 			ms->func(&(ms->arg));
 			return 1;
 		}

From 1f09f0b0bbba29ceed9b4e6d558b6ad5b0843cfe Mon Sep 17 00:00:00 2001
From: Ingo Lohmar <ingo.lohmar@posteo.net>
Date: Fri, 31 May 2019 22:25:35 +0200
Subject: [PATCH 1059/1146] apply hints before initial mapping (ICCCM)

For WM_CLASS this is mentioned in the ICCCM docs
https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.2.5
(third sentence).

When changing the WM_CLASS from the command line, this is necessary for
window managers to pick it up before applying class-based rules.
---
 x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x.c b/x.c
index 6406925..bc3ad5a 100644
--- a/x.c
+++ b/x.c
@@ -1154,8 +1154,8 @@ xinit(int cols, int rows)
 
 	win.mode = MODE_NUMLOCK;
 	resettitle();
-	XMapWindow(xw.dpy, xw.win);
 	xhints();
+	XMapWindow(xw.dpy, xw.win);
 	XSync(xw.dpy, False);
 
 	clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1);

From 83866428de031300eab03fbb116bcf7d2b1d4f60 Mon Sep 17 00:00:00 2001
From: "Sebastian J. Bronner" <waschtl@sbronner.com>
Date: Tue, 5 Nov 2019 18:16:39 +0100
Subject: [PATCH 1060/1146] Fix tmux terminfo extensions Se and Ss

The tmux terminfo extensions Ss and Se are currently specified as
booleans in `st.info`. They should be strings. See
https://github.com/tmux/tmux/blob/eeedb43ae847a0a692ceea965f7556e84bca4fd0/tty-term.c
lines 254 and 265.

I have used the values from
https://invisible-island.net/ncurses/terminfo.src.html#toc-_S_I_M_P_L_E_T_E_R_M
for this patch.
---
 st.info | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.info b/st.info
index 52fc617..78ffd30 100644
--- a/st.info
+++ b/st.info
@@ -189,10 +189,10 @@ st| simpleterm,
 	rmxx=\E[29m,
 	smxx=\E[9m,
 # tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
-	Se,
-	Ss,
 	Tc,
 	Ms=\E]52;%p1%s;%p2%s\007,
+	Se=\E[2 q,
+	Ss=\E[%p1%d q,
 
 st-256color| simpleterm with 256 colors,
 	use=st,

From ea4d933ed9d8ce16699c84892a29e070c70b2eb9 Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
Date: Wed, 16 Oct 2019 11:17:23 +0300
Subject: [PATCH 1061/1146] base64dec: don't read out of bounds

Previously, base64dec checked terminating input '\0' every 4 calls to
base64dec_getc, where the latter progressed one or more chars on each
call, and could read past '\0' in the way it was used.

The input to base64dec currently comes only from OSC 52 escape seq
(copy to clipboard), and reading past '\0' or even past the buffer
boundary was easy to trigger.

Also, even if we could trust external input to be valid base64, there
are different base64 standards, and not all of them require padding
to 4 bytes blocks (using trailing '=' chars).

It didn't affect short OSC 52 strings because the buffer is initialized
to 0's, so typically it did stop within the buffer, but if the string
was trimmed to fit (the buffer is 512 bytes) then it did also read past
the end of the buffer, and the decoded suffix ended up arbitrary.

This patch makes base64dec_getc not progress past '\0', and instead
produce fake trailing padding of '='.

Additionally, at base64dec, if padding is detected at the first or
second byte of a quartet, then we identify it as invalid and abort
(a valid quartet has at least two leading non-padding bytes).
---
 st.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index ede7ae6..a8f8232 100644
--- a/st.c
+++ b/st.c
@@ -366,7 +366,7 @@ char
 base64dec_getc(const char **src)
 {
 	while (**src && !isprint(**src)) (*src)++;
-	return *((*src)++);
+	return **src ? *((*src)++) : '=';  /* emulate padding if string ends */
 }
 
 char *
@@ -384,6 +384,10 @@ base64dec(const char *src)
 		int c = base64_digits[(unsigned char) base64dec_getc(&src)];
 		int d = base64_digits[(unsigned char) base64dec_getc(&src)];
 
+		/* invalid input. 'a' can be -1, e.g. if src is "\n" (c-str) */
+		if (a == -1 || b == -1)
+			break;
+
 		*dst++ = (a << 2) | ((b & 0x30) >> 4);
 		if (c == -1)
 			break;

From 7ceb3d1f72eabfa678e5cfae176c57630ad98c43 Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
Date: Wed, 16 Oct 2019 12:19:49 +0300
Subject: [PATCH 1062/1146] STREscape: don't trim prematurely

STRescape holds strings in escape sequences such as OSC and DCS, and
its buffer is 512 bytes.

If the input is too big then trailing chars are ignored, but the test
was off-by-1 such that it took 510 chars instead of 511 (before a
terminating NULL is added).

Now the full size can be utilized.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index a8f8232..50226d1 100644
--- a/st.c
+++ b/st.c
@@ -2330,7 +2330,7 @@ tputc(Rune u)
 		if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q')
 			term.mode |= MODE_SIXEL;
 
-		if (strescseq.len+len >= sizeof(strescseq.buf)-1) {
+		if (strescseq.len+len >= sizeof(strescseq.buf)) {
 			/*
 			 * Here is a bug in terminals. If the user never sends
 			 * some code to stop the str or esc command, then st

From 289c52b7aa9b0e826bbea6f956755b3199b3ccac Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Wed, 16 Oct 2019 12:38:43 +0300
Subject: [PATCH 1063/1146] CSIEscape, STREscape: use size_t for buffer length

---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 50226d1..0c1acd4 100644
--- a/st.c
+++ b/st.c
@@ -135,7 +135,7 @@ typedef struct {
 /* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
 typedef struct {
 	char buf[ESC_BUF_SIZ]; /* raw string */
-	int len;               /* raw string length */
+	size_t len;            /* raw string length */
 	char priv;
 	int arg[ESC_ARG_SIZ];
 	int narg;              /* nb of args */
@@ -147,7 +147,7 @@ typedef struct {
 typedef struct {
 	char type;             /* ESC type ... */
 	char buf[STR_BUF_SIZ]; /* raw string */
-	int len;               /* raw string length */
+	size_t len;            /* raw string length */
 	char *args[STR_ARG_SIZ];
 	int narg;              /* nb of args */
 } STREscape;
@@ -1803,7 +1803,7 @@ csihandle(void)
 void
 csidump(void)
 {
-	int i;
+	size_t i;
 	uint c;
 
 	fprintf(stderr, "ESC[");
@@ -1921,7 +1921,7 @@ strparse(void)
 void
 strdump(void)
 {
-	int i;
+	size_t i;
 	uint c;
 
 	fprintf(stderr, "ESC%c", strescseq.type);

From 2e54a21b5ae249a6bcedab9db611ea86037a018b Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
Date: Wed, 16 Oct 2019 12:55:53 +0300
Subject: [PATCH 1064/1146] OSC 52 - copy to clipboard: don't limit to 382
 bytes

Strings which an application sends to the terminal in OSC, DCS, etc
are typically small (title, colors, etc) but one exception is OSC 52
which copies text to the clipboard, and is used for instance by tmux.

Previously st cropped these strings at 512 bytes, which for OSC 52
limited the copied text to 382 bytes (remaining buffer space before
base64). This made it less useful than it can be.

Now it's a dynamic growing buffer. It remains allocated after use,
resets to 512 when a new string starts, or leaked on exit.

Resetting/deallocating the buffer right after use (at strhandle) is
possible with some more code, however, it doesn't always end up used,
and to cover those cases too will require even more code, so resetting
only on new string is good enough for now.
---
 st.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 0c1acd4..3e48410 100644
--- a/st.c
+++ b/st.c
@@ -146,7 +146,8 @@ typedef struct {
 /* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
 typedef struct {
 	char type;             /* ESC type ... */
-	char buf[STR_BUF_SIZ]; /* raw string */
+	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 */
@@ -1948,7 +1949,10 @@ strdump(void)
 void
 strreset(void)
 {
-	memset(&strescseq, 0, sizeof(strescseq));
+	strescseq = (STREscape){
+		.buf = xrealloc(strescseq.buf, STR_BUF_SIZ),
+		.siz = STR_BUF_SIZ,
+	};
 }
 
 void
@@ -2330,7 +2334,7 @@ tputc(Rune u)
 		if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q')
 			term.mode |= MODE_SIXEL;
 
-		if (strescseq.len+len >= sizeof(strescseq.buf)) {
+		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
@@ -2344,7 +2348,10 @@ tputc(Rune u)
 			 * term.esc = 0;
 			 * strhandle();
 			 */
-			return;
+			if (strescseq.siz > (SIZE_MAX - UTF_SIZ) / 2)
+				return;
+			strescseq.siz *= 2;
+			strescseq.buf = xrealloc(strescseq.buf, strescseq.siz);
 		}
 
 		memmove(&strescseq.buf[strescseq.len], c, len);

From 384830110bddcebed00b6530a5336f07ad7c405f Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun, 17 Nov 2019 20:04:52 +0100
Subject: [PATCH 1065/1146] update FAQ

- add common question about the w3m image drawing hack.
- remove some bad advise about $TERM.
- change some links to https.
---
 FAQ | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/FAQ b/FAQ
index ecf7af8..78c769a 100644
--- a/FAQ
+++ b/FAQ
@@ -1,6 +1,6 @@
 ## Why does st not handle utmp entries?
 
-Use the excellent tool of [utmp](http://git.suckless.org/utmp/) for this task.
+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!
 
@@ -15,13 +15,6 @@ you can manually run `tic -sx st.info`.
 * Some programs don’t complain about the lacking st description and default to
   another terminal. In that case see the question about terminfo.
 
-## I get some weird glitches/visual bug on _random program_!
-
-Try launching it with a different TERM: $ TERM=xterm myapp. toe(1) will give
-you a list of available terminals, but you’ll most likely switch between xterm,
-st or st-256color. The default value for TERM can be changed in config.h
-(TNAME).
-
 ## How do I scroll back up?
 
 Using a terminal multiplexer.
@@ -104,7 +97,7 @@ St is emulating the Linux way of handling backspace being delete and delete bein
 backspace.
 
 This is an issue that was discussed in suckless mailing list
-<http://lists.suckless.org/dev/1404/20697.html>. Here is why some old grumpy
+<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
@@ -163,7 +156,15 @@ terminal users wants its backspace to be how he feels it:
 
 Apply [1].
 
-[1] http://st.suckless.org/patches/delkey
+[1] https://st.suckless.org/patches/delkey
+
+## Why do images not work in st (in programs such as w3m)?
+
+This is a terrible hack that overdraws an image on top of the terminal emulator
+window. It also relies on a very specific way the terminal draws it's contents.
+
+A more proper (but limited way) would be using sixels. Which st doesn't
+support.
 
 ## BadLength X error in Xft when trying to render emoji
 

From 895e5b50a8cc835c19a45e1e328eb4dc78f5fd0c Mon Sep 17 00:00:00 2001
From: Ivan Tham <pickfire@riseup.net>
Date: Sat, 18 Jan 2020 15:52:25 +0800
Subject: [PATCH 1066/1146] Increase XmbLookupString buffer
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Current buffer is too short to input medium to long sentences from IME.
Input with longer text will show the wrong input, taking 64 instead of
32 bytes should be enough for most of the cases. Broken cases before,

Chinese (taken from song 也可以)
可不可以轻轻的松开自己

Japanese (taken from bootleggers rom quote)
あなたは家のように感じる
---
 x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x.c b/x.c
index bc3ad5a..e000894 100644
--- a/x.c
+++ b/x.c
@@ -1743,7 +1743,7 @@ kpress(XEvent *ev)
 {
 	XKeyEvent *e = &ev->xkey;
 	KeySym ksym;
-	char buf[32], *customkey;
+	char buf[64], *customkey;
 	int len;
 	Rune c;
 	Status status;

From 99de33395126fc9708f442d155e737b9182f6ef4 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Sun, 2 Feb 2020 15:37:29 +0100
Subject: [PATCH 1067/1146] x: move IME variables into XWindow ime embedded
 struct

---
 x.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/x.c b/x.c
index e000894..60eeee1 100644
--- a/x.c
+++ b/x.c
@@ -94,8 +94,10 @@ typedef struct {
 	Drawable buf;
 	GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
 	Atom xembed, wmdeletewin, netwmname, netwmpid;
-	XIM xim;
-	XIC xic;
+	struct {
+		XIM xim;
+		XIC xic;
+	} ime;
 	Draw draw;
 	Visual *vis;
 	XSetWindowAttributes attrs;
@@ -1026,18 +1028,18 @@ ximopen(Display *dpy)
 {
 	XIMCallback destroy = { .client_data = NULL, .callback = ximdestroy };
 
-	if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+	if ((xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
 		XSetLocaleModifiers("@im=local");
-		if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+		if ((xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
 			XSetLocaleModifiers("@im=");
-			if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL)
+			if ((xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL)
 				die("XOpenIM failed. Could not open input device.\n");
 		}
 	}
-	if (XSetIMValues(xw.xim, XNDestroyCallback, &destroy, NULL) != NULL)
+	if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &destroy, NULL) != NULL)
 		die("XSetIMValues failed. Could not set input method value.\n");
-	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
-				XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL);
+	xw.xic = XCreateIC(xw.ime.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
+	                   XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL);
 	if (xw.xic == NULL)
 		die("XCreateIC failed. Could not obtain input method.\n");
 }
@@ -1053,7 +1055,7 @@ ximinstantiate(Display *dpy, XPointer client, XPointer call)
 void
 ximdestroy(XIM xim, XPointer client, XPointer call)
 {
-	xw.xim = NULL;
+	xw.ime.xim = NULL;
 	XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
 					ximinstantiate, NULL);
 }
@@ -1682,13 +1684,13 @@ focus(XEvent *ev)
 		return;
 
 	if (ev->type == FocusIn) {
-		XSetICFocus(xw.xic);
+		XSetICFocus(xw.ime.xic);
 		win.mode |= MODE_FOCUSED;
 		xseturgency(0);
 		if (IS_SET(MODE_FOCUS))
 			ttywrite("\033[I", 3, 0);
 	} else {
-		XUnsetICFocus(xw.xic);
+		XUnsetICFocus(xw.ime.xic);
 		win.mode &= ~MODE_FOCUSED;
 		if (IS_SET(MODE_FOCUS))
 			ttywrite("\033[O", 3, 0);
@@ -1752,7 +1754,7 @@ kpress(XEvent *ev)
 	if (IS_SET(MODE_KBDLOCK))
 		return;
 
-	len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
+	len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
 	/* 1. shortcuts */
 	for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
 		if (ksym == bp->keysym && match(bp->mod, e->state)) {

From 2cb539142b97bd2a5c1a322fd7c063c6afb67c9b Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Sun, 2 Feb 2020 15:38:08 +0100
Subject: [PATCH 1068/1146] x: do not instantiate a new nested list on each
 cursor move

---
 x.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/x.c b/x.c
index 60eeee1..5af6e4d 100644
--- a/x.c
+++ b/x.c
@@ -97,6 +97,8 @@ typedef struct {
 	struct {
 		XIM xim;
 		XIC xic;
+		XPoint spot;
+		XVaNestedList spotlist;
 	} ime;
 	Draw draw;
 	Visual *vis;
@@ -1042,6 +1044,9 @@ ximopen(Display *dpy)
 	                   XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL);
 	if (xw.xic == NULL)
 		die("XCreateIC failed. Could not obtain input method.\n");
+
+	xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot,
+	                                      NULL);
 }
 
 void
@@ -1058,6 +1063,7 @@ ximdestroy(XIM xim, XPointer client, XPointer call)
 	xw.ime.xim = NULL;
 	XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
 					ximinstantiate, NULL);
+	XFree(xw.ime.spotlist);
 }
 
 void
@@ -1603,11 +1609,13 @@ xfinishdraw(void)
 void
 xximspot(int x, int y)
 {
-	XPoint spot = { borderpx + x * win.cw, borderpx + (y + 1) * win.ch };
-	XVaNestedList attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
+	if (xw.ime.xic == NULL)
+		return;
 
-	XSetICValues(xw.xic, XNPreeditAttributes, attr, NULL);
-	XFree(attr);
+	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

From cd785755f2e3e3305c7d2556a04423a40bce060a Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Sun, 2 Feb 2020 17:38:36 +0100
Subject: [PATCH 1069/1146] x: check we still have an XIC context before
 accessing it

---
 x.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/x.c b/x.c
index 5af6e4d..b488617 100644
--- a/x.c
+++ b/x.c
@@ -1061,6 +1061,7 @@ void
 ximdestroy(XIM xim, XPointer client, XPointer call)
 {
 	xw.ime.xim = NULL;
+	xw.ime.xic = NULL;
 	XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
 					ximinstantiate, NULL);
 	XFree(xw.ime.spotlist);
@@ -1692,13 +1693,15 @@ focus(XEvent *ev)
 		return;
 
 	if (ev->type == FocusIn) {
-		XSetICFocus(xw.ime.xic);
+		if (xw.ime.xic)
+			XSetICFocus(xw.ime.xic);
 		win.mode |= MODE_FOCUSED;
 		xseturgency(0);
 		if (IS_SET(MODE_FOCUS))
 			ttywrite("\033[I", 3, 0);
 	} else {
-		XUnsetICFocus(xw.ime.xic);
+		if (xw.ime.xic)
+			XUnsetICFocus(xw.ime.xic);
 		win.mode &= ~MODE_FOCUSED;
 		if (IS_SET(MODE_FOCUS))
 			ttywrite("\033[O", 3, 0);

From 26cdfebf31f024e331429e482b1ee342708888e3 Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Sun, 2 Feb 2020 21:47:19 +0100
Subject: [PATCH 1070/1146] x: fix XIM handling

Do not try to set specific IM method, let the user specify it with
XMODIFIERS.

If the requested method is not available or opening fails, fallback to
the default input handler and register a handler on the new IM server
availability signal.

Do the same when the input server is closed and (re)started.
---
 x.c | 68 +++++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 44 insertions(+), 24 deletions(-)

diff --git a/x.c b/x.c
index b488617..1f62129 100644
--- a/x.c
+++ b/x.c
@@ -146,9 +146,10 @@ static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
 static void xdrawglyph(Glyph, int, int);
 static void xclear(int, int, int, int);
 static int xgeommasktogravity(int);
-static void ximopen(Display *);
+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);
@@ -1025,48 +1026,61 @@ xunloadfonts(void)
 	xunloadfont(&dc.ibfont);
 }
 
-void
+int
 ximopen(Display *dpy)
 {
-	XIMCallback destroy = { .client_data = NULL, .callback = ximdestroy };
+	XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy };
+	XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy };
 
-	if ((xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
-		XSetLocaleModifiers("@im=local");
-		if ((xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
-			XSetLocaleModifiers("@im=");
-			if ((xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL)
-				die("XOpenIM failed. Could not open input device.\n");
-		}
-	}
-	if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &destroy, NULL) != NULL)
-		die("XSetIMValues failed. Could not set input method value.\n");
-	xw.xic = XCreateIC(xw.ime.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
-	                   XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL);
-	if (xw.xic == NULL)
-		die("XCreateIC failed. Could not obtain input method.\n");
+	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,
+		                       XNFocusWindow, 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)
 {
-	ximopen(dpy);
-	XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
-					ximinstantiate, NULL);
+	if (ximopen(dpy))
+		XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
+		                                 ximinstantiate, NULL);
 }
 
 void
 ximdestroy(XIM xim, XPointer client, XPointer call)
 {
 	xw.ime.xim = NULL;
-	xw.ime.xic = NULL;
 	XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
-					ximinstantiate, 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)
 {
@@ -1132,7 +1146,10 @@ xinit(int cols, int rows)
 	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
 
 	/* input methods */
-	ximopen(xw.dpy);
+	if (!ximopen(xw.dpy)) {
+		XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
+	                                       ximinstantiate, NULL);
+	}
 
 	/* white cursor, black outline */
 	cursor = XCreateFontCursor(xw.dpy, mouseshape);
@@ -1765,7 +1782,10 @@ kpress(XEvent *ev)
 	if (IS_SET(MODE_KBDLOCK))
 		return;
 
-	len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
+	if (xw.ime.xic)
+		len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
+	else
+		len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
 	/* 1. shortcuts */
 	for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
 		if (ksym == bp->keysym && match(bp->mod, e->state)) {

From 51e19ea11dd42eefed1ca136ee3f6be975f618b1 Mon Sep 17 00:00:00 2001
From: Ivan Tham <pickfire@riseup.net>
Date: Tue, 18 Feb 2020 23:28:47 +0800
Subject: [PATCH 1071/1146] Remove explicit XNFocusWindow

XCreateIC ICValues default XNFocusWindow to XNClientWindow if not
specified, it can be omitted since it is the same.

From the documentation
https://www.x.org/releases/current/doc/libX11/libX11/libX11.html

> Focus Window
>
> The XNFocusWindow argument specifies the focus window. The primary
> purpose of the XNFocusWindow is to identify the window that will receive
> the key event when input is composed.
>
> When this XIC value is left unspecified, the input method will use the
> client window as the default focus window.
---
 x.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/x.c b/x.c
index 1f62129..48a6676 100644
--- a/x.c
+++ b/x.c
@@ -1047,7 +1047,6 @@ ximopen(Display *dpy)
 		xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle,
 		                       XIMPreeditNothing | XIMStatusNothing,
 		                       XNClientWindow, xw.win,
-		                       XNFocusWindow, xw.win,
 		                       XNDestroyCallback, &icdestroy,
 		                       NULL);
 	}

From 28ad28839985e965c9ca06a9a202523414c84ac4 Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
Date: Thu, 2 Apr 2020 11:43:22 +0300
Subject: [PATCH 1072/1146] mouseshortcuts: fix custom modifier on release

This line didn't work at mshortcuts at config.h:

  /*  mask       button   function  arg       release */
    { ShiftMask, Button2, selpaste, {.i = 0}, 1 },

and now it does work.

The issue was that XButtonEvent.state is "the logical state ... just prior
to the event", which means that on release the state has the Button2Mask
bit set because button2 was down just before it was released.

The issue didn't manifest with the default shift + middle-click on release
(to override mouse mode) because its specified modifier is XK_ANY_MOD, at
which case match(...) ignores any specific bits and simply returns true.

The issue also doesn't manifest on press, because prior to the event
Button<N> was not down and its mask bit is not set.

Fix by filtering out the mask of the button which we're currently matching.

We could have said "well, that's how button events behave, you should
use ShiftMask|Button2Mask for release", but this both not obvious to
figure out, and specifically here always filtering does not prevent
configuring any useful modifiers combination. So it's a win-win.
---
 x.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/x.c b/x.c
index 48a6676..4cf6b21 100644
--- a/x.c
+++ b/x.c
@@ -171,6 +171,7 @@ 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 *);
@@ -423,16 +424,30 @@ mousereport(XEvent *e)
 	ttywrite(buf, len, 0);
 }
 
+uint
+buttonmask(uint button)
+{
+	return button == Button1 ? Button1Mask
+	     : button == Button2 ? Button2Mask
+	     : button == Button3 ? Button3Mask
+	     : button == Button4 ? Button4Mask
+	     : button == Button5 ? Button5Mask
+	     : 0;
+}
+
 int
 mouseaction(XEvent *e, uint release)
 {
 	MouseShortcut *ms;
 
+	/* ignore 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, e->xbutton.state) ||  /* exact or forced */
-		     match(ms->mod, e->xbutton.state & ~forcemousemod))) {
+		    (match(ms->mod, state) ||  /* exact or forced */
+		     match(ms->mod, state & ~forcemousemod))) {
 			ms->func(&(ms->arg));
 			return 1;
 		}

From 5703aa0390484dd7da4bd9c388c85708d8fcd339 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 10 Apr 2020 12:12:43 +0200
Subject: [PATCH 1073/1146] make argv0 not static, fixes a warning with tcc

Reported by Aajonus, thanks!
---
 x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x.c b/x.c
index 4cf6b21..e5f1737 100644
--- a/x.c
+++ b/x.c
@@ -15,7 +15,7 @@
 #include <X11/Xft/Xft.h>
 #include <X11/XKBlib.h>
 
-static char *argv0;
+char *argv0;
 #include "arg.h"
 #include "st.h"
 #include "win.h"

From 21e0d6e8b8d20903494386e7e6f43201b3761154 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 10 Apr 2020 22:06:32 +0200
Subject: [PATCH 1074/1146] Add support for scroll(1)

Scroll is a program that stores all the lines of its child and be used in st as
a way of implementing scrollback.

This solution is much better than implementing the scrollback in st itself
because having a different program allows to use it in any other program
without doing modifications to those programs.
---
 config.def.h |  3 ++-
 st.1         |  3 ++-
 st.c         | 16 ++++++++++------
 st.h         |  1 +
 4 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/config.def.h b/config.def.h
index 546edda..dfcbda9 100644
--- a/config.def.h
+++ b/config.def.h
@@ -11,13 +11,14 @@ static int borderpx = 2;
 /*
  * What program is execed by st depends of these precedence rules:
  * 1: program passed with -e
- * 2: utmp option
+ * 2: scroll and/or utmp
  * 3: SHELL environment variable
  * 4: value of shell in /etc/passwd
  * 5: value of shell in config.h
  */
 static char *shell = "/bin/sh";
 char *utmp = NULL;
+char *scroll = NULL;
 char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
 
 /* identification sequence returned in DA and DECID */
diff --git a/st.1 b/st.1
index e8d6059..39120b4 100644
--- a/st.1
+++ b/st.1
@@ -170,7 +170,8 @@ See the LICENSE file for the terms of redistribution.
 .SH SEE ALSO
 .BR tabbed (1),
 .BR utmp (1),
-.BR stty (1)
+.BR stty (1),
+.BR scroll (1)
 .SH BUGS
 See the TODO file in the distribution.
 
diff --git a/st.c b/st.c
index 3e48410..5f2352a 100644
--- a/st.c
+++ b/st.c
@@ -664,7 +664,7 @@ die(const char *errstr, ...)
 void
 execsh(char *cmd, char **args)
 {
-	char *sh, *prog;
+	char *sh, *prog, *arg;
 	const struct passwd *pw;
 
 	errno = 0;
@@ -678,13 +678,17 @@ execsh(char *cmd, char **args)
 	if ((sh = getenv("SHELL")) == NULL)
 		sh = (pw->pw_shell[0]) ? pw->pw_shell : cmd;
 
-	if (args)
+	if (args) {
 		prog = args[0];
-	else if (utmp)
-		prog = utmp;
-	else
+		arg = NULL;
+	} else if (scroll || utmp) {
+		prog = scroll ? scroll : utmp;
+		arg = scroll ? utmp : NULL;
+	} else {
 		prog = sh;
-	DEFAULT(args, ((char *[]) {prog, NULL}));
+		arg = NULL;
+	}
+	DEFAULT(args, ((char *[]) {prog, arg, NULL}));
 
 	unsetenv("COLUMNS");
 	unsetenv("LINES");
diff --git a/st.h b/st.h
index a1928ca..d978458 100644
--- a/st.h
+++ b/st.h
@@ -113,6 +113,7 @@ char *xstrdup(char *);
 
 /* config.h globals */
 extern char *utmp;
+extern char *scroll;
 extern char *stty_args;
 extern char *vtiden;
 extern wchar_t *worddelimiters;

From e52319cc7d153e4f59b38c4fb4c0556e118d4775 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 10 Apr 2020 22:25:46 +0200
Subject: [PATCH 1075/1146] ttyread: test for EOF while reading tty

When a read operation returns 0 then it means that we arrived to the end of the
file, and new reads will return 0 unless you do some other operation such as
lseek(). This case happens with USB-232 adapters when they are unplugged.
---
 st.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/st.c b/st.c
index 5f2352a..81973ee 100644
--- a/st.c
+++ b/st.c
@@ -823,17 +823,24 @@ ttyread(void)
 	int ret;
 
 	/* append read bytes to unprocessed bytes */
-	if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
+	ret = read(cmdfd, buf+buflen, LEN(buf)-buflen);
+
+	switch (ret) {
+	case 0:
+		fputs("Found EOF in input\n", stderr);
+		exit(0);
+	case -1:
 		die("couldn't read from shell: %s\n", strerror(errno));
-	buflen += ret;
+	default:
+		buflen += ret;
+		written = twrite(buf, buflen, 0);
+		buflen -= written;
+		/* keep any uncomplete utf8 char for the next call */
+		if (buflen > 0)
+			memmove(buf, buf + written, buflen);
+		return ret;
 
-	written = twrite(buf, buflen, 0);
-	buflen -= written;
-	/* keep any uncomplete utf8 char for the next call */
-	if (buflen > 0)
-		memmove(buf, buf + written, buflen);
-
-	return ret;
+	}
 }
 
 void

From fbae700a3f32db76106b0ff6f49a73ecf0c2b4fe Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 10 Apr 2020 22:26:12 +0200
Subject: [PATCH 1076/1146] Fix style issue

---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 81973ee..2ecf8f3 100644
--- a/st.c
+++ b/st.c
@@ -366,7 +366,8 @@ static const char base64_digits[] = {
 char
 base64dec_getc(const char **src)
 {
-	while (**src && !isprint(**src)) (*src)++;
+	while (**src && !isprint(**src))
+		(*src)++;
 	return **src ? *((*src)++) : '=';  /* emulate padding if string ends */
 }
 

From 019449a7e64a881be8cc5d715fe9de32726ba190 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Fri, 10 Apr 2020 22:50:23 +0200
Subject: [PATCH 1077/1146] Add terminfo entries for backspace mode

St used to use backspace as BS until the commit 230d0c8, but due
to general lack of knowledge of lusers, we moved to the most common
configuration in linux to avoid answering the same question 3 times
per month. With the most common configuration we have a backspace
that returns a DEL, and we have a Delete key that doesn't return a
DEL character neither a BS.

When dealing with devices connected using a serial line (or even
with Plan9) it is more common Backspace as BS and Delete as DEL. For
this reason, st is not always the best tool when you talk with a
serial device.

This patch adds new terminfo entries for Backspace as BS and Delete
as DEL. A patch for confg.h is also added, to make easier switch
between both configurations.
---
 st.info | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/st.info b/st.info
index 78ffd30..1df490b 100644
--- a/st.info
+++ b/st.info
@@ -220,3 +220,13 @@ st-meta-256color| simpleterm with meta key and 256 colors,
 	smm=\E[?1034h,
 	rs2=\E[4l\E>\E[?1034h,
 	is2=\E[4l\E>\E[?1034h,
+
+st-bs| simpleterm with backspace as backspace,
+	use=st,
+	kbs=\010,
+	kdch1=\177,
+
+st-bs-256color| simpleterm with backspace as backspace and 256colors,
+	use=st-256color,
+	kbs=\010,
+	kdch1=\177,

From 0b73612c0dc51dbec1717e5da94bc94559c37246 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 11 Apr 2020 11:52:58 +0200
Subject: [PATCH 1078/1146] Update FAQ with the last modifications

---
 FAQ | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/FAQ b/FAQ
index 78c769a..85534a4 100644
--- a/FAQ
+++ b/FAQ
@@ -17,10 +17,16 @@ you can manually run `tic -sx st.info`.
 
 ## How do I scroll back up?
 
-Using a terminal multiplexer.
+* 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/).
 
-* `st -e tmux` using C-b [
-* `st -e screen` using C-a ESC
+## I would like to have utmp and/or scroll functionality by default
+
+You can add the absolute patch of both programs in your config.h
+file. You only have to modify the value of utmp and scroll variables.
 
 ## Why doesn't the Del key work in some programs?
 

From c1145268f6b6c6f03a8bec1c09d356d6a4eba77e Mon Sep 17 00:00:00 2001
From: Quentin Rameau <quinq@fifth.space>
Date: Sat, 11 Apr 2020 12:09:20 +0200
Subject: [PATCH 1079/1146] Launch scroll program with the default shell

---
 st.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 2ecf8f3..59db144 100644
--- a/st.c
+++ b/st.c
@@ -682,9 +682,12 @@ execsh(char *cmd, char **args)
 	if (args) {
 		prog = args[0];
 		arg = NULL;
-	} else if (scroll || utmp) {
-		prog = scroll ? scroll : utmp;
-		arg = scroll ? utmp : NULL;
+	} else if (scroll) {
+		prog = scroll;
+		arg = utmp ? utmp : sh;
+	} else if (utmp) {
+		prog = utmp;
+		arg = NULL;
 	} else {
 		prog = sh;
 		arg = NULL;

From e997303502ddd5c26cfc41af0ff5356bffc04359 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 11 Apr 2020 13:29:48 +0200
Subject: [PATCH 1080/1146] Fix small typos

---
 st.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 59db144..a545724 100644
--- a/st.c
+++ b/st.c
@@ -823,15 +823,14 @@ ttyread(void)
 {
 	static char buf[BUFSIZ];
 	static int buflen = 0;
-	int written;
-	int ret;
+	int ret, written;
 
 	/* append read bytes to unprocessed bytes */
 	ret = read(cmdfd, buf+buflen, LEN(buf)-buflen);
 
 	switch (ret) {
 	case 0:
-		fputs("Found EOF in input\n", stderr);
+		fputs("found EOF in input\n", stderr);
 		exit(0);
 	case -1:
 		die("couldn't read from shell: %s\n", strerror(errno));
@@ -839,7 +838,7 @@ ttyread(void)
 		buflen += ret;
 		written = twrite(buf, buflen, 0);
 		buflen -= written;
-		/* keep any uncomplete utf8 char for the next call */
+		/* keep any incomplete UTF-8 byte sequence for the next call */
 		if (buflen > 0)
 			memmove(buf, buf + written, buflen);
 		return ret;

From d66bd405c0d0f29beff89683a04a10297e962cb9 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 11 Apr 2020 13:56:31 +0200
Subject: [PATCH 1081/1146] config.def.h: add a comment for the scroll variable

---
 config.def.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/config.def.h b/config.def.h
index dfcbda9..0895a1f 100644
--- a/config.def.h
+++ b/config.def.h
@@ -18,6 +18,7 @@ static int borderpx = 2;
  */
 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";
 

From 771bc401f76b329f78a285ca65355d4b43415172 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <k0ga@shike2.com>
Date: Sat, 11 Apr 2020 14:46:17 +0200
Subject: [PATCH 1082/1146] Add st-mono terminfo entry

This entry is intended for monocolor display and it is very
helpful for color haters.
---
 st.info | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/st.info b/st.info
index 1df490b..e2abc98 100644
--- a/st.info
+++ b/st.info
@@ -1,4 +1,4 @@
-st| simpleterm,
+st-mono| simpleterm monocolor,
 	acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
 	am,
 	bce,
@@ -10,7 +10,7 @@ st| simpleterm,
 	civis=\E[?25l,
 	clear=\E[H\E[2J,
 	cnorm=\E[?12l\E[?25h,
-	colors#8,
+	colors#2,
 	cols#80,
 	cr=^M,
 	csr=\E[%i%p1%d;%p2%dr,
@@ -168,13 +168,8 @@ st| simpleterm,
 	rs1=\Ec,
 	rs2=\E[4l\E>\E[?1034l,
 	sc=\E7,
-	setab=\E[4%p1%dm,
-	setaf=\E[3%p1%dm,
-	setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
-	setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
-	sgr0=\E[0m,
-	sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
 	sitm=\E[3m,
+	sgr0=\E[0m,
 	smacs=\E(0,
 	smcup=\E[?1049h,
 	smir=\E[4h,
@@ -194,6 +189,15 @@ st| simpleterm,
 	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,

From 33a9a456644ceb235ea6ce61282f3bdce7a8b547 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 11 Apr 2020 15:45:06 +0200
Subject: [PATCH 1083/1146] just remove the EOF message

---
 st.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.c b/st.c
index a545724..9e568c6 100644
--- a/st.c
+++ b/st.c
@@ -830,7 +830,6 @@ ttyread(void)
 
 	switch (ret) {
 	case 0:
-		fputs("found EOF in input\n", stderr);
 		exit(0);
 	case -1:
 		die("couldn't read from shell: %s\n", strerror(errno));

From 72e3f6c7c05b4d5b56388508bb20a863aec279f5 Mon Sep 17 00:00:00 2001
From: Ivan Tham <pickfire@riseup.net>
Date: Sun, 19 Apr 2020 19:38:39 +0200
Subject: [PATCH 1084/1146] Update XIM cursor position only if changed

Updating XIM cursor position is expensive, so only update it when cursor
position changed.
---
 st.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 9e568c6..0ce6ac2 100644
--- a/st.c
+++ b/st.c
@@ -2571,6 +2571,7 @@ void
 drawregion(int x1, int y1, int x2, int y2)
 {
 	int y;
+
 	for (y = y1; y < y2; y++) {
 		if (!term.dirty[y])
 			continue;
@@ -2583,7 +2584,7 @@ drawregion(int x1, int y1, int x2, int y2)
 void
 draw(void)
 {
-	int cx = term.c.x;
+	int cx = term.c.x, ocx = term.ocx, ocy = term.ocy;
 
 	if (!xstartdraw())
 		return;
@@ -2599,9 +2600,11 @@ draw(void)
 	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;
+	term.ocx = cx;
+	term.ocy = term.c.y;
 	xfinishdraw();
-	xximspot(term.ocx, term.ocy);
+	if (ocx != term.ocx || ocy != term.ocy)
+		xximspot(term.ocx, term.ocy);
 }
 
 void

From 43a395ae91f7d67ce694e65edeaa7bbc720dd027 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Mon, 27 Apr 2020 13:56:25 +0200
Subject: [PATCH 1085/1146] bump version to 0.8.3

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 0cbb002..beafc35 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.8.2
+VERSION = 0.8.3
 
 # Customize below to fit your system
 

From d6ea0a1a61853dd892029a7126e7fdb70c371878 Mon Sep 17 00:00:00 2001
From: Jan Klemkow <j.klemkow@wemelug.de>
Date: Thu, 30 Apr 2020 00:10:02 +0200
Subject: [PATCH 1086/1146] replace exit(3) by _exit(2) in signal handler
 sigchld()

exit(3) is not async-signal-safe but, _exit(2) is.
This change prevents st to crash and dump core.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 0ce6ac2..2bf133f 100644
--- a/st.c
+++ b/st.c
@@ -730,7 +730,7 @@ sigchld(int a)
 		die("child exited with status %d\n", WEXITSTATUS(stat));
 	else if (WIFSIGNALED(stat))
 		die("child terminated due to signal %d\n", WTERMSIG(stat));
-	exit(0);
+	_exit(0);
 }
 
 void

From 1d590910652519268152eae6b97cf30ace4e90c0 Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
Date: Tue, 26 Feb 2019 22:37:49 +0200
Subject: [PATCH 1087/1146] auto-sync: draw on idle to avoid flicker/tearing

st could easily tear/flicker with animation or other unattended
output. This commit eliminates most of the tear/flicker.

Before this commit, the display timing had two "modes":

- Interactively, st was waiting fixed `1000/xfps` ms after forwarding
  the kb/mouse event to the application and before drawing.

- Unattended, and specifically with animations, the draw frequency was
  throttled to `actionfps`. Animation at a higher rate would throttle
  and likely tear, and at lower rates it was tearing big frames
  (specifically, when one `read` didn't get a full "frame").

The interactive behavior was decent, but it was impossible to get good
unattended-draw behavior even with carefully chosen configuration.

This commit changes the behavior such that it draws on idle instead of
using fixed latency/frequency. This means that it tries to draw only
when it's very likely that the application has completed its output
(or after some duration without idle), so it mostly succeeds to avoid
tear, flicker, and partial drawing.

The config values minlatency/maxlatency replace xfps/actionfps and
define the range which the algorithm is allowed to wait from the
initial draw-trigger until the actual draw. The range enables the
flexibility to choose when to draw - when least likely to flicker.

It also unifies the interactive and unattended behavior and config
values, which makes the code simpler as well - without sacrificing
latency during interactive use, because typically interactively idle
arrives very quickly, so the wait is typically minlatency.

While it only slighly improves interactive behavior, for animations
and other unattended-drawing it improves greatly, as it effectively
adapts to any [animation] output rate without tearing, throttling,
redundant drawing, or unnecessary delays (sounds impossible, but it
works).
---
 config.def.h |  11 +++--
 x.c          | 120 ++++++++++++++++++++++++---------------------------
 2 files changed, 65 insertions(+), 66 deletions(-)

diff --git a/config.def.h b/config.def.h
index 0895a1f..fdbacfd 100644
--- a/config.def.h
+++ b/config.def.h
@@ -43,9 +43,14 @@ static unsigned int tripleclicktimeout = 600;
 /* alt screens */
 int allowaltscreen = 1;
 
-/* frames per second st should at maximum draw to the screen */
-static unsigned int xfps = 120;
-static unsigned int actionfps = 30;
+/*
+ * 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
diff --git a/x.c b/x.c
index e5f1737..cbbd11f 100644
--- a/x.c
+++ b/x.c
@@ -1867,10 +1867,9 @@ run(void)
 	XEvent ev;
 	int w = win.w, h = win.h;
 	fd_set rfd;
-	int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
-	int ttyfd;
-	struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
-	long deltatime;
+	int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing;
+	struct timespec seltv, *tv, now, lastblink, trigger;
+	double timeout;
 
 	/* Waiting for window mapping */
 	do {
@@ -1891,82 +1890,77 @@ run(void)
 	ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd);
 	cresize(w, h);
 
-	clock_gettime(CLOCK_MONOTONIC, &last);
-	lastblink = last;
-
-	for (xev = actionfps;;) {
+	for (timeout = -1, drawing = 0, lastblink = (struct timespec){0};;) {
 		FD_ZERO(&rfd);
 		FD_SET(ttyfd, &rfd);
 		FD_SET(xfd, &rfd);
 
+		if (XPending(xw.dpy))
+			timeout = 0;  /* existing events might not set xfd */
+
+		seltv.tv_sec = timeout / 1E3;
+		seltv.tv_nsec = 1E6 * (timeout - 1E3 * seltv.tv_sec);
+		tv = timeout >= 0 ? &seltv : NULL;
+
 		if (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
 			if (errno == EINTR)
 				continue;
 			die("select failed: %s\n", strerror(errno));
 		}
-		if (FD_ISSET(ttyfd, &rfd)) {
-			ttyread();
-			if (blinktimeout) {
-				blinkset = tattrset(ATTR_BLINK);
-				if (!blinkset)
-					MODBIT(win.mode, 0, MODE_BLINK);
-			}
-		}
-
-		if (FD_ISSET(xfd, &rfd))
-			xev = actionfps;
-
 		clock_gettime(CLOCK_MONOTONIC, &now);
-		drawtimeout.tv_sec = 0;
-		drawtimeout.tv_nsec =  (1000 * 1E6)/ xfps;
-		tv = &drawtimeout;
 
-		dodraw = 0;
-		if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
-			tsetdirtattr(ATTR_BLINK);
-			win.mode ^= MODE_BLINK;
-			lastblink = now;
-			dodraw = 1;
-		}
-		deltatime = TIMEDIFF(now, last);
-		if (deltatime > 1000 / (xev ? xfps : actionfps)) {
-			dodraw = 1;
-			last = now;
+		if (FD_ISSET(ttyfd, &rfd))
+			ttyread();
+
+		xev = 0;
+		while (XPending(xw.dpy)) {
+			xev = 1;
+			XNextEvent(xw.dpy, &ev);
+			if (XFilterEvent(&ev, None))
+				continue;
+			if (handler[ev.type])
+				(handler[ev.type])(&ev);
 		}
 
-		if (dodraw) {
-			while (XPending(xw.dpy)) {
-				XNextEvent(xw.dpy, &ev);
-				if (XFilterEvent(&ev, None))
-					continue;
-				if (handler[ev.type])
-					(handler[ev.type])(&ev);
+		/*
+		 * To reduce flicker and tearing, when new content or event
+		 * triggers drawing, we first wait a bit to ensure we got
+		 * everything, and if nothing new arrives - we draw.
+		 * We start with trying to wait minlatency ms. If more content
+		 * arrives sooner, we retry with shorter and shorter preiods,
+		 * and eventually draw even without idle after maxlatency ms.
+		 * Typically this results in low latency while interacting,
+		 * maximum latency intervals during `cat huge.txt`, and perfect
+		 * sync with periodic updates from animations/key-repeats/etc.
+		 */
+		if (FD_ISSET(ttyfd, &rfd) || xev) {
+			if (!drawing) {
+				trigger = now;
+				drawing = 1;
 			}
+			timeout = (maxlatency - TIMEDIFF(now, trigger)) \
+			          / maxlatency * minlatency;
+			if (timeout > 0)
+				continue;  /* we have time, try to find idle */
+		}
 
-			draw();
-			XFlush(xw.dpy);
-
-			if (xev && !FD_ISSET(xfd, &rfd))
-				xev--;
-			if (!FD_ISSET(ttyfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
-				if (blinkset) {
-					if (TIMEDIFF(now, lastblink) \
-							> blinktimeout) {
-						drawtimeout.tv_nsec = 1000;
-					} else {
-						drawtimeout.tv_nsec = (1E6 * \
-							(blinktimeout - \
-							TIMEDIFF(now,
-								lastblink)));
-					}
-					drawtimeout.tv_sec = \
-					    drawtimeout.tv_nsec / 1E9;
-					drawtimeout.tv_nsec %= (long)1E9;
-				} else {
-					tv = NULL;
-				}
+		/* idle detected or maxlatency exhausted -> draw */
+		timeout = -1;
+		if (blinktimeout && tattrset(ATTR_BLINK)) {
+			timeout = blinktimeout - TIMEDIFF(now, lastblink);
+			if (timeout <= 0) {
+				if (-timeout > blinktimeout) /* start visible */
+					win.mode |= MODE_BLINK;
+				win.mode ^= MODE_BLINK;
+				tsetdirtattr(ATTR_BLINK);
+				lastblink = now;
+				timeout = blinktimeout;
 			}
 		}
+
+		draw();
+		XFlush(xw.dpy);
+		drawing = 0;
 	}
 }
 

From 87545c612e8ab6e7cd1ef38e2355d0cb86df79f2 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 9 May 2020 13:55:34 +0200
Subject: [PATCH 1088/1146] tiny code-style and typo-fix in comment

---
 st.c | 6 +++---
 x.c  | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 2bf133f..c161497 100644
--- a/st.c
+++ b/st.c
@@ -38,7 +38,7 @@
 
 /* macros */
 #define IS_SET(flag)		((term.mode & (flag)) != 0)
-#define ISCONTROLC0(c)		(BETWEEN(c, 0, 0x1f) || (c) == '\177')
+#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))
@@ -2023,7 +2023,7 @@ tdumpline(int n)
 	bp = &term.line[n][0];
 	end = &bp[MIN(tlinelen(n), term.col) - 1];
 	if (bp != end || bp->u != ' ') {
-		for ( ;bp <= end; ++bp)
+		for ( ; bp <= end; ++bp)
 			tprinter(buf, utf8encode(bp->u, buf));
 	}
 	tprinter("\n", 1);
@@ -2307,7 +2307,7 @@ tputc(Rune u)
 	Glyph *gp;
 
 	control = ISCONTROL(u);
-	if (!IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
+	if (!IS_SET(MODE_UTF8 | MODE_SIXEL)) {
 		c[0] = u;
 		width = len = 1;
 	} else {
diff --git a/x.c b/x.c
index cbbd11f..7bfc36f 100644
--- a/x.c
+++ b/x.c
@@ -1927,7 +1927,7 @@ run(void)
 		 * 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 preiods,
+		 * 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

From 8211e36d281990a39db1853bcd454ac59e53d521 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 9 May 2020 13:56:28 +0200
Subject: [PATCH 1089/1146] fix for incorrect (partial) written sequences when
 libc wcwidth() == -1

Fix an issue with incorrect (partial) written sequences when libc wcwidth() ==
-1. The sequence is updated to on wcwidth(u) == -1:

	c = "\357\277\275"

but len isn't.

A way to reproduce in practise:

* st -o dump.txt
* In the terminal: printf '\xcd\xb8'
- This is codepoint 888, on OpenBSD it reports wcwidth() == -1.
- Quit the terminal.
- Look in dump.txt (partial written sequence of "UTF_INVALID").

This was introduced in:

"	commit 11625c7166b7e4dad414606227acec2de1c36464
	Author: czarkoff@gmail.com <czarkoff@gmail.com>
	Date:   Tue Oct 28 12:55:28 2014 +0100

	    Replace character with U+FFFD if wcwidth() is -1

	    Helpful when new Unicode codepoints are not recognized by libc."

Change:

Remove setting the sequence. If this happens to break something, another
solution could be setting len = 3 for the sequence.
---
 st.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/st.c b/st.c
index c161497..5d4054f 100644
--- a/st.c
+++ b/st.c
@@ -2312,10 +2312,8 @@ tputc(Rune u)
 		width = len = 1;
 	} else {
 		len = utf8encode(u, c);
-		if (!control && (width = wcwidth(u)) == -1) {
-			memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
+		if (!control && (width = wcwidth(u)) == -1)
 			width = 1;
-		}
 	}
 
 	if (IS_SET(MODE_PRINT))

From cde480c6939e62771ba3b60ef4eb848031aee9f9 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 9 May 2020 14:03:14 +0200
Subject: [PATCH 1090/1146] optimize column width calculation and utf-8 encode
 for ASCII

In particular on OpenBSD and on glibc wcwidth() is quite expensive.
On musl there is little difference.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 5d4054f..1414f98 100644
--- a/st.c
+++ b/st.c
@@ -2307,7 +2307,7 @@ tputc(Rune u)
 	Glyph *gp;
 
 	control = ISCONTROL(u);
-	if (!IS_SET(MODE_UTF8 | MODE_SIXEL)) {
+	if (u < 127 || !IS_SET(MODE_UTF8 | MODE_SIXEL)) {
 		c[0] = u;
 		width = len = 1;
 	} else {

From 914fb825df3bde7abdd7947e54f8bf4d2b55e34e Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 9 May 2020 14:43:31 +0200
Subject: [PATCH 1091/1146] code-style: add fallthrough comment

Patch by Steve Ward, thanks.
---
 st.c | 1 +
 x.c  | 1 +
 2 files changed, 2 insertions(+)

diff --git a/st.c b/st.c
index 1414f98..a8de17d 100644
--- a/st.c
+++ b/st.c
@@ -2153,6 +2153,7 @@ tcontrolcode(uchar ascii)
 		return;
 	case '\032': /* SUB */
 		tsetchar('?', &term.c.attr, term.c.x, term.c.y);
+		/* FALLTHROUGH */
 	case '\030': /* CAN */
 		csireset();
 		break;
diff --git a/x.c b/x.c
index 7bfc36f..1dc44d6 100644
--- a/x.c
+++ b/x.c
@@ -1528,6 +1528,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 		switch (win.cursor) {
 		case 7: /* st extension: snowman (U+2603) */
 			g.u = 0x2603;
+			/* FALLTHROUGH */
 		case 0: /* Blinking Block */
 		case 1: /* Blinking Block (Default) */
 		case 2: /* Steady Block */

From 8304d4f0599b1be2226c28c553547070658d4af3 Mon Sep 17 00:00:00 2001
From: Jakub Leszczak <szatan@gecc.xyz>
Date: Wed, 6 May 2020 13:35:06 +0200
Subject: [PATCH 1092/1146] Fix selection: selclear in tputc

---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index a8de17d..8c42a9c 100644
--- a/st.c
+++ b/st.c
@@ -2412,7 +2412,7 @@ check_control_code:
 		 */
 		return;
 	}
-	if (sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
+	if (selected(term.c.x, term.c.y))
 		selclear();
 
 	gp = &term.line[term.c.y][term.c.x];

From 9c30066e73f0105c3fccb7582c8172d5117857b3 Mon Sep 17 00:00:00 2001
From: Jakub Leszczak <szatan@gecc.xyz>
Date: Wed, 6 May 2020 13:35:53 +0200
Subject: [PATCH 1093/1146] Fix selection: ignore ATTR_WRAP when rectangular
 selection in getsel

---
 st.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 8c42a9c..7c15d5f 100644
--- a/st.c
+++ b/st.c
@@ -634,7 +634,8 @@ getsel(void)
 		 * st.
 		 * FIXME: Fix the computer world.
 		 */
-		if ((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP))
+		if ((y < sel.ne.y || lastx >= linelen) &&
+		    (!(last->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR))
 			*ptr++ = '\n';
 	}
 	*ptr = 0;

From 045a0fab4f80b57f4a982ae6bc5f33fe21d66111 Mon Sep 17 00:00:00 2001
From: Jakub Leszczak <szatan@gecc.xyz>
Date: Wed, 6 May 2020 13:36:59 +0200
Subject: [PATCH 1094/1146] Fix selection: selscroll

---
 st.c | 26 ++++++++------------------
 1 file changed, 8 insertions(+), 18 deletions(-)

diff --git a/st.c b/st.c
index 7c15d5f..0d35613 100644
--- a/st.c
+++ b/st.c
@@ -1106,27 +1106,17 @@ selscroll(int orig, int n)
 	if (sel.ob.x == -1)
 		return;
 
-	if (BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig, term.bot)) {
-		if ((sel.ob.y += n) > term.bot || (sel.oe.y += n) < term.top) {
+	if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) {
+		selclear();
+	} else if (BETWEEN(sel.nb.y, orig, term.bot)) {
+		sel.ob.y += n;
+		sel.oe.y += n;
+		if (sel.ob.y < term.top || sel.ob.y > term.bot ||
+		    sel.oe.y < term.top || sel.oe.y > term.bot) {
 			selclear();
-			return;
-		}
-		if (sel.type == SEL_RECTANGULAR) {
-			if (sel.ob.y < term.top)
-				sel.ob.y = term.top;
-			if (sel.oe.y > term.bot)
-				sel.oe.y = term.bot;
 		} else {
-			if (sel.ob.y < term.top) {
-				sel.ob.y = term.top;
-				sel.ob.x = 0;
-			}
-			if (sel.oe.y > term.bot) {
-				sel.oe.y = term.bot;
-				sel.oe.x = term.col;
-			}
+			selnormalize();
 		}
-		selnormalize();
 	}
 }
 

From bda9c9ffa645ee5e4b2507474ebfa1c5efb889b2 Mon Sep 17 00:00:00 2001
From: k0ga <k0ga@shike2.com>
Date: Sat, 16 May 2020 09:48:18 +0000
Subject: [PATCH 1095/1146] Make shift+wheel behaves as shift+Prev/Next

St uses a very good hack where mouse wheel genereates ^Y and ^E,
that are the same keys that less and vi uses for backward and
fordward scrolling. Scroll, as many terminal emulators, use
shift+Prev/Next for scrolling, but it is also using ^E and ^Y
for scroling, characters that are reserved in the POSIX shell
in emacs mode for end of line and yanking, making scroll unsable
in st.

This patch adds a new hack, making shift+wheel returning the
same sequences than shift+Prev/Next, meaning that scroll or
any other similar program will not be able to differentiate
between them.
---
 config.def.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/config.def.h b/config.def.h
index fdbacfd..293e00c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -171,7 +171,9 @@ static uint forcemousemod = ShiftMask;
 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"} },
 };
 

From f8afebdfa0cc9a57b22c39c47e9b585f69453eb7 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas" <k0ga@shike2.com>
Date: Sat, 16 May 2020 10:42:51 +0000
Subject: [PATCH 1096/1146] Add rin terminfo capability

Tianlin Qu discovered that st is missing rin (scroll back #1 lines).
---
 st.info | 1 +
 1 file changed, 1 insertion(+)

diff --git a/st.info b/st.info
index e2abc98..d0694e2 100644
--- a/st.info
+++ b/st.info
@@ -158,6 +158,7 @@ st-mono| simpleterm monocolor,
 	rc=\E8,
 	rev=\E[7m,
 	ri=\EM,
+	rin=\E[%p1%dT,
 	ritm=\E[23m,
 	rmacs=\E(B,
 	rmcup=\E[?1049l,

From e8392b282c2eaa28725241a9612804fb55113da4 Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
Date: Thu, 14 May 2020 18:18:07 +0300
Subject: [PATCH 1097/1146] support REP (repeat) escape sequence

The sequence \e[Nb prints the last printed char N (more) times if it's
printable, and it's ignored after newline or other control chars.

This is Ecma-048/ANSI-X3.6 sequence and not DEC VT. It's supported by
xterm, and ncurses uses it when possible, e.g. when TERM is xterm* (and
with this commit also st*).

xterm supports only codepoints<=255, possibly due to internal limits.
We support any value/codepoint which was placed in a cell.

To test:
- tput rep 65 4 -> prints 'AAAA'
- printf "\342\225\246\033[4b" -> prints U+2566 1+4 times.
---
 st.c    | 10 ++++++++++
 st.info |  1 +
 2 files changed, 11 insertions(+)

diff --git a/st.c b/st.c
index 0d35613..54af098 100644
--- a/st.c
+++ b/st.c
@@ -129,6 +129,7 @@ typedef struct {
 	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 */
@@ -1648,6 +1649,12 @@ csihandle(void)
 		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);
@@ -2373,6 +2380,8 @@ check_control_code:
 		/*
 		 * control codes are not shown ever
 		 */
+		if (!term.esc)
+			term.lastc = 0;
 		return;
 	} else if (term.esc & ESC_START) {
 		if (term.esc & ESC_CSI) {
@@ -2422,6 +2431,7 @@ check_control_code:
 	}
 
 	tsetchar(u, &term.c.attr, term.c.x, term.c.y);
+	term.lastc = u;
 
 	if (width == 2) {
 		gp->mode |= ATTR_WIDE;
diff --git a/st.info b/st.info
index d0694e2..e5393db 100644
--- a/st.info
+++ b/st.info
@@ -184,6 +184,7 @@ st-mono| simpleterm monocolor,
 # XTerm extensions
 	rmxx=\E[29m,
 	smxx=\E[9m,
+	rep=%p1%c\E[%p2%{1}%-%db,
 # tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
 	Tc,
 	Ms=\E]52;%p1%s;%p2%s\007,

From 475a0a36cb4fda1da30f014da65988e99b222876 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 16 May 2020 18:06:42 +0200
Subject: [PATCH 1098/1146] Revert "support REP (repeat) escape sequence"

This reverts commit e8392b282c2eaa28725241a9612804fb55113da4.

There is currently a bug in older ncurses versions (like on OpenBSD) where a
fix for a bug with REP is not backported yet. Most likely in tty/tty_update.c:

Noticed while using lynx (which uses ncurses/curses).
To reproduce using lynx: echo "Z0000000" | lynx -stdin

or using the program:

int
main(void)
{
	WINDOW *win;
	win = initscr();

	printw("Z0000000");

	refresh();

	sleep(5);

	return 0;
}

This prints "ZZZZZZZ" (incorrectly).
---
 st.c    | 10 ----------
 st.info |  1 -
 2 files changed, 11 deletions(-)

diff --git a/st.c b/st.c
index 54af098..0d35613 100644
--- a/st.c
+++ b/st.c
@@ -129,7 +129,6 @@ typedef struct {
 	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 */
@@ -1649,12 +1648,6 @@ csihandle(void)
 		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);
@@ -2380,8 +2373,6 @@ check_control_code:
 		/*
 		 * control codes are not shown ever
 		 */
-		if (!term.esc)
-			term.lastc = 0;
 		return;
 	} else if (term.esc & ESC_START) {
 		if (term.esc & ESC_CSI) {
@@ -2431,7 +2422,6 @@ check_control_code:
 	}
 
 	tsetchar(u, &term.c.attr, term.c.x, term.c.y);
-	term.lastc = u;
 
 	if (width == 2) {
 		gp->mode |= ATTR_WIDE;
diff --git a/st.info b/st.info
index e5393db..d0694e2 100644
--- a/st.info
+++ b/st.info
@@ -184,7 +184,6 @@ st-mono| simpleterm monocolor,
 # XTerm extensions
 	rmxx=\E[29m,
 	smxx=\E[9m,
-	rep=%p1%c\E[%p2%{1}%-%db,
 # tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
 	Tc,
 	Ms=\E]52;%p1%s;%p2%s\007,

From dec6b530a4fddf405c1822b2cac6e2036d3c8b75 Mon Sep 17 00:00:00 2001
From: Steve Ward <planet36@gmail.com>
Date: Wed, 20 May 2020 22:24:55 -0400
Subject: [PATCH 1099/1146] Call xsetcursor to set win.cursor in main

In xsetcursor, remove "DEFAULT(cursor, 1)" because 0 is a valid value.
Increase max allowed value of cursor from 6 to 7 (st extension).
---
 x.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/x.c b/x.c
index 1dc44d6..210f184 100644
--- a/x.c
+++ b/x.c
@@ -1526,8 +1526,8 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
 	/* draw the new one */
 	if (IS_SET(MODE_FOCUSED)) {
 		switch (win.cursor) {
-		case 7: /* st extension: snowman (U+2603) */
-			g.u = 0x2603;
+		case 7: /* st extension */
+			g.u = 0x2603; /* snowman (U+2603) */
 			/* FALLTHROUGH */
 		case 0: /* Blinking Block */
 		case 1: /* Blinking Block (Default) */
@@ -1690,8 +1690,7 @@ xsetmode(int set, unsigned int flags)
 int
 xsetcursor(int cursor)
 {
-	DEFAULT(cursor, 1);
-	if (!BETWEEN(cursor, 0, 6))
+	if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */
 		return 1;
 	win.cursor = cursor;
 	return 0;
@@ -1983,7 +1982,7 @@ main(int argc, char *argv[])
 {
 	xw.l = xw.t = 0;
 	xw.isfixed = False;
-	win.cursor = cursorshape;
+	xsetcursor(cursorshape);
 
 	ARGBEGIN {
 	case 'a':

From 94b8ec002101a5e8f52a342e53431eea71aa0631 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 30 May 2020 21:34:57 +0200
Subject: [PATCH 1100/1146] Partially add back in "support REP (repeat) escape
 sequence"

Add the functionality back in for xterm compatibility, but do not expose the
capability in st.info (yet).

Some notes:

It was reverted because it caused some issues with ncurses in some
configurations, namely when using BSD padding (--enable-bsdpad, BSD_TPUTS) in
ncurses it caused issues with repeating digits.

A fix has been upstreamed in ncurses since snapshot 20200523. The fix is also
backported to OpenBSD -current.
---
 st.c    | 10 ++++++++++
 st.info |  2 ++
 2 files changed, 12 insertions(+)

diff --git a/st.c b/st.c
index 0d35613..54af098 100644
--- a/st.c
+++ b/st.c
@@ -129,6 +129,7 @@ typedef struct {
 	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 */
@@ -1648,6 +1649,12 @@ csihandle(void)
 		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);
@@ -2373,6 +2380,8 @@ check_control_code:
 		/*
 		 * control codes are not shown ever
 		 */
+		if (!term.esc)
+			term.lastc = 0;
 		return;
 	} else if (term.esc & ESC_START) {
 		if (term.esc & ESC_CSI) {
@@ -2422,6 +2431,7 @@ check_control_code:
 	}
 
 	tsetchar(u, &term.c.attr, term.c.x, term.c.y);
+	term.lastc = u;
 
 	if (width == 2) {
 		gp->mode |= ATTR_WIDE;
diff --git a/st.info b/st.info
index d0694e2..8201ad6 100644
--- a/st.info
+++ b/st.info
@@ -184,6 +184,8 @@ st-mono| simpleterm monocolor,
 # 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,

From e6e2c6199f102f1459b53717050eee27832f4f87 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 30 May 2020 21:39:49 +0200
Subject: [PATCH 1101/1146] tiny style fix

---
 st.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 54af098..2d901ab 100644
--- a/st.c
+++ b/st.c
@@ -843,7 +843,6 @@ ttyread(void)
 		if (buflen > 0)
 			memmove(buf, buf + written, buflen);
 		return ret;
-
 	}
 }
 
@@ -1778,7 +1777,7 @@ csihandle(void)
 		break;
 	case 'n': /* DSR – Device Status Report (cursor position) */
 		if (csiescseq.arg[0] == 6) {
-			len = snprintf(buf, sizeof(buf),"\033[%i;%iR",
+			len = snprintf(buf, sizeof(buf), "\033[%i;%iR",
 					term.c.y+1, term.c.x+1);
 			ttywrite(buf, len, 0);
 		}

From 0f8b40652bca0670f1f0bda069bbc55f8b5e364d Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 30 May 2020 21:50:54 +0200
Subject: [PATCH 1102/1146] FAQ: add some details about the w3m img hack

... and an example patch to switch from double-buffering to a single buffer.
---
 FAQ | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 54 insertions(+), 5 deletions(-)

diff --git a/FAQ b/FAQ
index 85534a4..fb40264 100644
--- a/FAQ
+++ b/FAQ
@@ -2,12 +2,14 @@
 
 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
@@ -15,6 +17,7 @@ you can manually run `tic -sx st.info`.
 * 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.
@@ -23,11 +26,13 @@ you can manually run `tic -sx st.info`.
 * Using the excellent tool of [scroll](https://git.suckless.org/scroll/).
 * Using the scrollback [patch](https://st.suckless.org/patches/scrollback/).
 
+
 ## I would like to have utmp and/or scroll functionality by default
 
 You can add the absolute patch of both programs in your config.h
 file. You only have to modify the value of utmp and scroll variables.
 
+
 ## Why doesn't the Del key work in some programs?
 
 Taken from the terminfo manpage:
@@ -83,12 +88,14 @@ If you are using zsh, then read the zsh FAQ
 
 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
@@ -97,6 +104,7 @@ If you want to compile st for OpenBSD you have to remove -lrt from config.mk, an
 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
@@ -158,19 +166,60 @@ terminal users wants its backspace to be how he feels it:
 	[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 (in programs such as w3m)?
 
-This is a terrible hack that overdraws an image on top of the terminal emulator
-window. It also relies on a very specific way the terminal draws it's contents.
+## 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
+@@ -561,10 +561,6 @@ xresize(int col, int row)
+ 	win.tw = MAX(1, col * win.cw);
+ 	win.th = MAX(1, row * win.ch);
+ 
+-	XFreePixmap(xw.dpy, xw.buf);
+-	xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
+-			DefaultDepth(xw.dpy, xw.scr));
+-	XftDrawChange(xw.draw, xw.buf);
+ 	xclear(0, 0, win.w, win.h);
+ }
+ 
+@@ -921,8 +917,7 @@ xinit(void)
+ 	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);
+ 
+@@ -1386,8 +1381,6 @@ void
+ draw(void)
+ {
+ 	drawregion(0, 0, term.col, term.row);
+-	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);
 
-A more proper (but limited way) would be using sixels. Which st doesn't
-support.
 
 ## BadLength X error in Xft when trying to render emoji
 

From a2a704492b9f4d2408d180f7aeeacf4c789a1d67 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 30 May 2020 21:56:18 +0200
Subject: [PATCH 1103/1146] config.def.h: add an option allowwindowops, by
 default off (secure)

Similar to the xterm AllowWindowOps option, this is an option to allow or
disallow certain (non-interactive) operations that can be insecure or
exploited.

NOTE: xsettitle() is not guarded by this because st does not support printing
the window title. Else this could be exploitable (arbitrary code execution).
Similar problems have been found in the past in other terminal emulators.

The sequence for base64-encoded clipboard copy is now guarded because it allows
a sequence written to the terminal to manipulate the clipboard of the running
user non-interactively, for example:

printf '\x1b]52;0;ZWNobyBoaQ0=\a'
---
 config.def.h | 4 ++++
 st.c         | 2 +-
 st.h         | 1 +
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 293e00c..6f05dce 100644
--- a/config.def.h
+++ b/config.def.h
@@ -43,6 +43,10 @@ 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
diff --git a/st.c b/st.c
index 2d901ab..ef8abd5 100644
--- a/st.c
+++ b/st.c
@@ -1861,7 +1861,7 @@ strhandle(void)
 				xsettitle(strescseq.args[1]);
 			return;
 		case 52:
-			if (narg > 2) {
+			if (narg > 2 && allowwindowops) {
 				dec = base64dec(strescseq.args[2]);
 				if (dec) {
 					xsetsel(dec);
diff --git a/st.h b/st.h
index d978458..3d351b6 100644
--- a/st.h
+++ b/st.h
@@ -118,6 +118,7 @@ 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;

From 9ba7ecf7b15ec2986c6142036706aa353b249ef9 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Mon, 1 Jun 2020 14:09:46 +0200
Subject: [PATCH 1104/1146] FAQ: fix single-buffer patch

rebase against master
---
 FAQ | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/FAQ b/FAQ
index fb40264..0f9609d 100644
--- a/FAQ
+++ b/FAQ
@@ -189,18 +189,18 @@ buffer.
 diff --git a/x.c b/x.c
 --- a/x.c
 +++ b/x.c
-@@ -561,10 +561,6 @@ xresize(int col, int row)
- 	win.tw = MAX(1, col * win.cw);
- 	win.th = MAX(1, row * win.ch);
+@@ -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);
- }
  
-@@ -921,8 +917,7 @@ xinit(void)
+ 	/* 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);
@@ -210,10 +210,10 @@ diff --git a/x.c b/x.c
  	XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
  	XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
  
-@@ -1386,8 +1381,6 @@ void
- draw(void)
+@@ -1632,8 +1627,6 @@ xdrawline(Line line, int x1, int y1, int x2)
+ void
+ xfinishdraw(void)
  {
- 	drawregion(0, 0, term.col, term.row);
 -	XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w,
 -			win.h, 0, 0);
  	XSetForeground(xw.dpy, dc.gc,

From 818ec746f4caae453d09368b101c3e841cf39870 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Wed, 17 Jun 2020 21:35:39 +0200
Subject: [PATCH 1105/1146] fix unicode glitch in DCS strings, patch by Tim
 Allen
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Reported on the mailinglist:

"
I discovered recently that if an application running inside st tries to
send a DCS string, subsequent Unicode characters get messed up. For
example, consider the following test-case:

    printf '\303\277\033P\033\\\303\277'

...where:

  - \303\277 is the UTF-8 encoding of U+00FF LATIN SMALL LETTER Y WITH
    DIAERESIS (ÿ).
  - \033P is ESC P, the token that begins a DCS string.
  - \033\\ is ESC \, a token that ends a DCS string.
  - \303\277 is the same ÿ character again.

If I run the above command in a VTE-based terminal, or xterm, or
QTerminal, or pterm (PuTTY), I get the output:

    ÿÿ

...which is to say, the empty DCS string is ignored. However, if I run
that command inside st (as of commit 9ba7ecf), I get:

    ÿÿ

...where those last two characters are \303\277 interpreted as ISO8859-1
characters, instead of UTF-8.

I spent some time tracing through the state machines in st.c, and so far
as I can tell, this is how it works currently:

  - ESC P sets the "ESC_DCS" and "ESC_STR" flags, indicating that
    incoming bytes should be collected into the strescseq buffer, rather
    than being interpreted.
  - ESC \ sets the "ESC_STR_END" flag (when ESC is received), and then
    calls strhandle() (when \ is received) to interpret the collected
    bytes.
  - If the collected bytes begin with 'P' (i.e. if this was a DCS
    string) strhandle() sets the "ESC_DCS" flag again, confusing the
    state machine.

If my understanding is correct, fixing the problem should be as easy as
removing the line that sets ESC_DCS from strhandle():

diff --git a/st.c b/st.c
index ef8abd5..b5b805a 100644
--- a/st.c
+++ b/st.c
@@ -1897,7 +1897,6 @@ strhandle(void)
		xsettitle(strescseq.args[0]);
		return;
	case 'P': /* DCS -- Device Control String */
-		term.mode |= ESC_DCS;
	case '_': /* APC -- Application Program Command */
	case '^': /* PM -- Privacy Message */
		return;

I've tried the above patch and it fixes my problem, but I don't know if
it introduces any others.
"
---
 st.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.c b/st.c
index ef8abd5..b5b805a 100644
--- a/st.c
+++ b/st.c
@@ -1897,7 +1897,6 @@ strhandle(void)
 		xsettitle(strescseq.args[0]);
 		return;
 	case 'P': /* DCS -- Device Control String */
-		term.mode |= ESC_DCS;
 	case '_': /* APC -- Application Program Command */
 	case '^': /* PM -- Privacy Message */
 		return;

From f74a9df6e1fc88eebe6d673d888b61fd83cf6fc4 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Wed, 17 Jun 2020 22:05:48 +0200
Subject: [PATCH 1106/1146] remove sixel stub code

Remove stub code that was used for an experiment of adding sixel code to st
from the commit f7398434.
---
 st.c | 26 +++++---------------------
 1 file changed, 5 insertions(+), 21 deletions(-)

diff --git a/st.c b/st.c
index b5b805a..76b7e0d 100644
--- a/st.c
+++ b/st.c
@@ -51,7 +51,6 @@ enum term_mode {
 	MODE_ECHO        = 1 << 4,
 	MODE_PRINT       = 1 << 5,
 	MODE_UTF8        = 1 << 6,
-	MODE_SIXEL       = 1 << 7,
 };
 
 enum cursor_movement {
@@ -78,12 +77,11 @@ enum charset {
 enum escape_state {
 	ESC_START      = 1,
 	ESC_CSI        = 2,
-	ESC_STR        = 4,  /* OSC, PM, APC */
+	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,
-	ESC_DCS        =128,
 };
 
 typedef struct {
@@ -2090,12 +2088,9 @@ tdectest(char c)
 void
 tstrsequence(uchar c)
 {
-	strreset();
-
 	switch (c) {
 	case 0x90:   /* DCS -- Device Control String */
 		c = 'P';
-		term.esc |= ESC_DCS;
 		break;
 	case 0x9f:   /* APC -- Application Program Command */
 		c = '_';
@@ -2107,6 +2102,7 @@ tstrsequence(uchar c)
 		c = ']';
 		break;
 	}
+	strreset();
 	strescseq.type = c;
 	term.esc |= ESC_STR;
 }
@@ -2304,7 +2300,7 @@ tputc(Rune u)
 	Glyph *gp;
 
 	control = ISCONTROL(u);
-	if (u < 127 || !IS_SET(MODE_UTF8 | MODE_SIXEL)) {
+	if (u < 127 || !IS_SET(MODE_UTF8)) {
 		c[0] = u;
 		width = len = 1;
 	} else {
@@ -2325,23 +2321,11 @@ tputc(Rune u)
 	if (term.esc & ESC_STR) {
 		if (u == '\a' || u == 030 || u == 032 || u == 033 ||
 		   ISCONTROLC1(u)) {
-			term.esc &= ~(ESC_START|ESC_STR|ESC_DCS);
-			if (IS_SET(MODE_SIXEL)) {
-				/* TODO: render sixel */;
-				term.mode &= ~MODE_SIXEL;
-				return;
-			}
+			term.esc &= ~(ESC_START|ESC_STR);
 			term.esc |= ESC_STR_END;
 			goto check_control_code;
 		}
 
-		if (IS_SET(MODE_SIXEL)) {
-			/* TODO: implement sixel mode */
-			return;
-		}
-		if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q')
-			term.mode |= MODE_SIXEL;
-
 		if (strescseq.len+len >= strescseq.siz) {
 			/*
 			 * Here is a bug in terminals. If the user never sends
@@ -2453,7 +2437,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
 	int n;
 
 	for (n = 0; n < buflen; n += charsize) {
-		if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
+		if (IS_SET(MODE_UTF8)) {
 			/* process a complete utf8 char */
 			charsize = utf8decode(buf + n, &u, buflen - n);
 			if (charsize == 0)

From 81067c65ea4dd80e8eb34755a4f50a4a8c7df06b Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Wed, 17 Jun 2020 23:44:34 +0200
Subject: [PATCH 1107/1146] LICENSE: bump years

---
 LICENSE | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LICENSE b/LICENSE
index c356c39..d80eb47 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 MIT/X Consortium License
 
-© 2014-2018 Hiltjo Posthuma <hiltjo at codemadness dot org>
+© 2014-2020 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>

From b27a383a3acc7decf00e6e889fca265430b5d329 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Wed, 17 Jun 2020 23:47:00 +0200
Subject: [PATCH 1108/1146] config.mk: use PKG_CONFIG in commented OpenBSD
 section

---
 config.mk | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config.mk b/config.mk
index beafc35..7b1c3db 100644
--- a/config.mk
+++ b/config.mk
@@ -28,8 +28,8 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
 # OpenBSD:
 #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
 #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
-#       `pkg-config --libs fontconfig` \
-#       `pkg-config --libs freetype2`
+#       `$(PKG_CONFIG) --libs fontconfig` \
+#       `$(PKG_CONFIG) --libs freetype2`
 
 # compiler and linker
 # CC = c99

From fa253f077f19b3220c7655b81bd91e52f4367803 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 19 Jun 2020 11:27:17 +0200
Subject: [PATCH 1109/1146] bump version to 0.8.4

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 7b1c3db..c070a4a 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.8.3
+VERSION = 0.8.4
 
 # Customize below to fit your system
 

From 28b4c822c5c0acec300fdf15c6e3ede9f5e2335d Mon Sep 17 00:00:00 2001
From: John Collis <john.collis@alliedtelesis.co.nz>
Date: Sun, 6 Sep 2020 17:53:41 +1200
Subject: [PATCH 1110/1146] ST: Add WM_ICON_NAME property support

Also added _NET_WM_ICON_NAME.
---
 st.c  |  9 +++++++++
 win.h |  1 +
 x.c   | 16 +++++++++++++++-
 3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 76b7e0d..ae7fa63 100644
--- a/st.c
+++ b/st.c
@@ -1844,6 +1844,7 @@ strhandle(void)
 {
 	char *p = NULL, *dec;
 	int j, narg, par;
+	static int winname = 0;
 
 	term.esc &= ~(ESC_STR_END|ESC_STR);
 	strparse();
@@ -1853,7 +1854,15 @@ strhandle(void)
 	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]);
diff --git a/win.h b/win.h
index a6ef1b9..e6e4369 100644
--- a/win.h
+++ b/win.h
@@ -30,6 +30,7 @@ void xdrawline(Line, int, int, int);
 void xfinishdraw(void);
 void xloadcols(void);
 int xsetcolorname(int, const char *);
+void xseticontitle(char *);
 void xsettitle(char *);
 int xsetcursor(int);
 void xsetmode(int, unsigned int);
diff --git a/x.c b/x.c
index 210f184..120e495 100644
--- a/x.c
+++ b/x.c
@@ -93,7 +93,7 @@ typedef struct {
 	Window win;
 	Drawable buf;
 	GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
-	Atom xembed, wmdeletewin, netwmname, netwmpid;
+	Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid;
 	struct {
 		XIM xim;
 		XIC xic;
@@ -1186,6 +1186,7 @@ xinit(int cols, int rows)
 	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);
@@ -1579,6 +1580,19 @@ xsetenv(void)
 	setenv("WINDOWID", buf, 1);
 }
 
+void
+xseticontitle(char *p)
+{
+	XTextProperty prop;
+	DEFAULT(p, opt_title);
+
+	Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
+			&prop);
+	XSetWMIconName(xw.dpy, xw.win, &prop);
+	XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname);
+	XFree(prop.value);
+}
+
 void
 xsettitle(char *p)
 {

From 4ef0cbd8b9371f37f7d02ef37b5378b879e6b8bf Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun, 18 Oct 2020 11:18:03 +0200
Subject: [PATCH 1111/1146] remove unused variable from previous patch

---
 st.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/st.c b/st.c
index ae7fa63..abbbe4b 100644
--- a/st.c
+++ b/st.c
@@ -1844,7 +1844,6 @@ strhandle(void)
 {
 	char *p = NULL, *dec;
 	int j, narg, par;
-	static int winname = 0;
 
 	term.esc &= ~(ESC_STR_END|ESC_STR);
 	strparse();

From 9e68fdbcdb06dfa3d23fe3a7a7f7b59e40e1ea2f Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 19 Mar 2021 11:54:36 +0100
Subject: [PATCH 1112/1146] fix: correctly encode mouse buttons >= 8 in X10 and
 SGR mode

These are typically mapped in X11 to the side-buttons (backward/forwards) on
the mouse. A comparison of the button numbers in SGR mode (first field):

st old:
0 1 2 64 65 66 67 68 69 70

st new (it is the same as xterm now):
0 1 2 64 65 66 67 128 129 130

A script to test and reproduce it, first argument is "h" (on) or "l" (off):

	#!/bin/sh
	printf '\x1b[?1000%s\x1b[?1006%s' "$1" "$1"

	for n in 1 2 3 4 5 6 7 8 9 10; do
		printf 'button %d\n' "$n"
		xdotool click "$n"
		printf '\n\n'
	done
---
 x.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/x.c b/x.c
index 120e495..8bf998e 100644
--- a/x.c
+++ b/x.c
@@ -387,7 +387,9 @@ mousereport(XEvent *e)
 			button = 3;
 		} else {
 			button -= Button1;
-			if (button >= 3)
+			if (button >= 7)
+				button += 128 - 7;
+			else if (button >= 3)
 				button += 64 - 3;
 		}
 		if (e->xbutton.type == ButtonPress) {

From 4536f46cfff50c66a115755def0155d8e246b02f Mon Sep 17 00:00:00 2001
From: "Markus F.X.J. Oberhumer" <markus@oberhumer.com>
Date: Sun, 28 Mar 2021 21:16:59 +0200
Subject: [PATCH 1113/1146] Mild const-correctness improvements.

Only touch a few things, the main focus is to
improve code readability.
---
 st.c | 44 +++++++++++++++++++++++---------------------
 st.h |  4 ++--
 x.c  |  6 +++---
 3 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/st.c b/st.c
index abbbe4b..ebdf360 100644
--- a/st.c
+++ b/st.c
@@ -186,18 +186,18 @@ static void tputc(Rune);
 static void treset(void);
 static void tscrollup(int, int);
 static void tscrolldown(int, int);
-static void tsetattr(int *, int);
-static void tsetchar(Rune, Glyph *, int, int);
+static void 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, int *, int);
+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(int *, int *, int);
+static int32_t tdefcolor(const int *, int *, int);
 static void tdeftran(char);
 static void tstrsequence(uchar);
 
@@ -226,10 +226,10 @@ static int iofd = 1;
 static int cmdfd;
 static pid_t pid;
 
-static uchar utfbyte[UTF_SIZ + 1] = {0x80,    0, 0xC0, 0xE0, 0xF0};
-static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
-static Rune utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  0x10000};
-static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
+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)
@@ -269,12 +269,14 @@ xrealloc(void *p, size_t len)
 }
 
 char *
-xstrdup(char *s)
+xstrdup(const char *s)
 {
-	if ((s = strdup(s)) == NULL)
+	char *p;
+
+	if ((p = strdup(s)) == NULL)
 		die("strdup: %s\n", strerror(errno));
 
-	return s;
+	return p;
 }
 
 size_t
@@ -518,7 +520,7 @@ selsnap(int *x, int *y, int direction)
 {
 	int newx, newy, xt, yt;
 	int delim, prevdelim;
-	Glyph *gp, *prevgp;
+	const Glyph *gp, *prevgp;
 
 	switch (sel.snap) {
 	case SNAP_WORD:
@@ -591,7 +593,7 @@ getsel(void)
 {
 	char *str, *ptr;
 	int y, bufsize, lastx, linelen;
-	Glyph *gp, *last;
+	const Glyph *gp, *last;
 
 	if (sel.ob.x == -1)
 		return NULL;
@@ -758,7 +760,7 @@ stty(char **args)
 }
 
 int
-ttynew(char *line, char *cmd, char *out, char **args)
+ttynew(const char *line, char *cmd, const char *out, char **args)
 {
 	int m, s;
 
@@ -1186,9 +1188,9 @@ tmoveto(int x, int y)
 }
 
 void
-tsetchar(Rune u, Glyph *attr, int x, int y)
+tsetchar(Rune u, const Glyph *attr, int x, int y)
 {
-	static char *vt100_0[62] = { /* 0x41 - 0x7e */
+	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 */
@@ -1300,7 +1302,7 @@ tdeleteline(int n)
 }
 
 int32_t
-tdefcolor(int *attr, int *npar, int l)
+tdefcolor(const int *attr, int *npar, int l)
 {
 	int32_t idx = -1;
 	uint r, g, b;
@@ -1350,7 +1352,7 @@ tdefcolor(int *attr, int *npar, int l)
 }
 
 void
-tsetattr(int *attr, int l)
+tsetattr(const int *attr, int l)
 {
 	int i;
 	int32_t idx;
@@ -1468,9 +1470,9 @@ tsetscroll(int t, int b)
 }
 
 void
-tsetmode(int priv, int set, int *args, int narg)
+tsetmode(int priv, int set, const int *args, int narg)
 {
-	int alt, *lim;
+	int alt; const int *lim;
 
 	for (lim = args + narg; args < lim; ++args) {
 		if (priv) {
@@ -2020,7 +2022,7 @@ void
 tdumpline(int n)
 {
 	char buf[UTF_SIZ];
-	Glyph *bp, *end;
+	const Glyph *bp, *end;
 
 	bp = &term.line[n][0];
 	end = &bp[MIN(tlinelen(n), term.col) - 1];
diff --git a/st.h b/st.h
index 3d351b6..fa2eddf 100644
--- a/st.h
+++ b/st.h
@@ -91,7 +91,7 @@ void tnew(int, int);
 void tresize(int, int);
 void tsetdirtattr(int);
 void ttyhangup(void);
-int ttynew(char *, char *, char *, char **);
+int ttynew(const char *, char *, const char *, char **);
 size_t ttyread(void);
 void ttyresize(int, int);
 void ttywrite(const char *, size_t, int);
@@ -109,7 +109,7 @@ size_t utf8encode(Rune, char *);
 
 void *xmalloc(size_t);
 void *xrealloc(void *, size_t);
-char *xstrdup(char *);
+char *xstrdup(const char *);
 
 /* config.h globals */
 extern char *utmp;
diff --git a/x.c b/x.c
index 8bf998e..7186040 100644
--- a/x.c
+++ b/x.c
@@ -156,7 +156,7 @@ static void xresize(int, int);
 static void xhints(void);
 static int xloadcolor(int, const char *, Color *);
 static int xloadfont(Font *, FcPattern *);
-static void xloadfonts(char *, double);
+static void xloadfonts(const char *, double);
 static void xunloadfont(Font *);
 static void xunloadfonts(void);
 static void xsetenv(void);
@@ -952,7 +952,7 @@ xloadfont(Font *f, FcPattern *pattern)
 }
 
 void
-xloadfonts(char *fontstr, double fontsize)
+xloadfonts(const char *fontstr, double fontsize)
 {
 	FcPattern *pattern;
 	double fontval;
@@ -960,7 +960,7 @@ xloadfonts(char *fontstr, double fontsize)
 	if (fontstr[0] == '-')
 		pattern = XftXlfdParse(fontstr, False, False);
 	else
-		pattern = FcNameParse((FcChar8 *)fontstr);
+		pattern = FcNameParse((const FcChar8 *)fontstr);
 
 	if (!pattern)
 		die("can't open font %s\n", fontstr);

From 2ec571a30c0c3b1a17f6b3631c80d573582f59a1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petar=20Kapri=C5=A1?= <petarkapris@firemail.cc>
Date: Sun, 18 Jul 2021 00:14:00 +0200
Subject: [PATCH 1114/1146] Add 14th bit to XK_SWITCH_MOD bitmask

The bits of uint signal in an XKeyEvent which concern the key group (keyboard
layout) are bits 13 and 14, as documented here:
https://www.x.org/releases/X11R7.7/doc/libX11/XKB/xkblib.html#Groups_and_Shift_Levels
In the older version, only bit 13 was marked as part of XK_SWITCH_MOD, this
causes issues for users who have more than two keymaps. the 14th bit is not
in ignoremod, key sequences are not caught by match(), if they switch to a third
or fourth keyboard.
---
 x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x.c b/x.c
index 7186040..248d505 100644
--- a/x.c
+++ b/x.c
@@ -48,7 +48,7 @@ typedef struct {
 /* X modifiers */
 #define XK_ANY_MOD    UINT_MAX
 #define XK_NO_MOD     0
-#define XK_SWITCH_MOD (1<<13)
+#define XK_SWITCH_MOD (1<<13|1<<14)
 
 /* function definitions used in config.h */
 static void clipcopy(const Arg *);

From 1d3142da968da7f6f61f1c1708f39ca233eda150 Mon Sep 17 00:00:00 2001
From: Koichi Murase <myoga.murase@gmail.com>
Date: Tue, 24 Aug 2021 06:25:05 +0900
Subject: [PATCH 1115/1146] fix a problem that the standard streams are
 unexpectedly closed

In the current implementation, the slave PTY (assigned to the variable
`s') is always closed after duplicating it to file descriptors of
standard streams (0, 1, and 2).  However, when the allocated slave PTY
`s' is already one of 0, 1, or 2, this causes unexpected closing of a
standard stream.  The same problem occurs when the file descriptor of
the master PTY (the variable `m') is one of 0, 1, or 2.

In this patch, the original master PTY (m) is closed before it would
be overwritten by duplicated slave PTYs.  The original slave PTY (s)
is closed only when it is not one of the stanrad streams.
---
 st.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index ebdf360..a9338e1 100644
--- a/st.c
+++ b/st.c
@@ -793,14 +793,15 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
 		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));
-		close(s);
-		close(m);
+		if (s > 2)
+			close(s);
 #ifdef __OpenBSD__
 		if (pledge("stdio getpw proc exec", NULL) == -1)
 			die("pledge\n");

From 2f6e597ed871cff91c627850d03152cae5f45779 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Tue, 24 Aug 2021 13:44:35 +0200
Subject: [PATCH 1116/1146] fix possible rare crash when
 Xutf8TextPropertyToTextList fails

from the XmbTextListToTextProperty(3) man page:

"If insufficient memory is available for the new value string, the functions
return XNoMemory.  If the current locale is not supported, the functions return
XLocaleNotSupported.  In both of these error cases, the functions do not set
text_prop_return."

Reported by Steffen Nurpmeso <steffen@sdaoden.eu>, thanks!
---
 x.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/x.c b/x.c
index 248d505..89786b8 100644
--- a/x.c
+++ b/x.c
@@ -1588,8 +1588,9 @@ xseticontitle(char *p)
 	XTextProperty prop;
 	DEFAULT(p, opt_title);
 
-	Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
-			&prop);
+	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);
@@ -1601,8 +1602,9 @@ xsettitle(char *p)
 	XTextProperty prop;
 	DEFAULT(p, opt_title);
 
-	Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
-			&prop);
+	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);

From 8e310303903792c010d03c046ba75f8b18f7d3a7 Mon Sep 17 00:00:00 2001
From: Raheman Vaiya <r.vaiya@gmail.com>
Date: Sun, 26 Dec 2021 18:57:04 +0100
Subject: [PATCH 1117/1146] Add support for OSC color sequences

---
 config.def.h |  8 ++++--
 st.c         | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 st.h         |  3 ++
 x.c          | 13 +++++++++
 4 files changed, 100 insertions(+), 4 deletions(-)

diff --git a/config.def.h b/config.def.h
index 6f05dce..91ab8ca 100644
--- a/config.def.h
+++ b/config.def.h
@@ -120,6 +120,8 @@ static const char *colorname[] = {
 	/* more colors can be added after 255 to use with DefaultXX */
 	"#cccccc",
 	"#555555",
+	"gray90", /* default foreground colour */
+	"black", /* default background colour */
 };
 
 
@@ -127,9 +129,9 @@ static const char *colorname[] = {
  * Default colors (colorname index)
  * foreground, background, cursor, reverse cursor
  */
-unsigned int defaultfg = 7;
-unsigned int defaultbg = 0;
-static unsigned int defaultcs = 256;
+unsigned int defaultfg = 258;
+unsigned int defaultbg = 259;
+unsigned int defaultcs = 256;
 static unsigned int defaultrcs = 257;
 
 /*
diff --git a/st.c b/st.c
index a9338e1..781dbf2 100644
--- a/st.c
+++ b/st.c
@@ -1842,6 +1842,42 @@ csireset(void)
 	memset(&csiescseq, 0, sizeof(csiescseq));
 }
 
+void
+osc4_color_response(int num)
+{
+	int n;
+	char buf[32];
+	unsigned char r, g, b;
+
+	if (xgetcolor(num, &r, &g, &b)) {
+		fprintf(stderr, "erresc: failed to fetch osc4 color %d\n", num);
+		return;
+	}
+
+	n = snprintf(buf, sizeof buf, "\033]4;%d;rgb:%02x%02x/%02x%02x/%02x%02x\007",
+		     num, r, r, g, g, b, b);
+
+	ttywrite(buf, n, 1);
+}
+
+void
+osc_color_response(int index, int num)
+{
+	int n;
+	char buf[32];
+	unsigned char r, g, b;
+
+	if (xgetcolor(index, &r, &g, &b)) {
+		fprintf(stderr, "erresc: failed to fetch osc color %d\n", index);
+		return;
+	}
+
+	n = snprintf(buf, sizeof buf, "\033]%d;rgb:%02x%02x/%02x%02x/%02x%02x\007",
+		     num, r, r, g, g, b, b);
+
+	ttywrite(buf, n, 1);
+}
+
 void
 strhandle(void)
 {
@@ -1880,6 +1916,45 @@ strhandle(void)
 				}
 			}
 			return;
+		case 10:
+			if (narg < 2)
+				break;
+
+			p = strescseq.args[1];
+
+			if (!strcmp(p, "?"))
+				osc_color_response(defaultfg, 10);
+			else if (xsetcolorname(defaultfg, p))
+				fprintf(stderr, "erresc: invalid foreground color: %s\n", p);
+			else
+				redraw();
+			break;
+		case 11:
+			if (narg < 2)
+				break;
+
+			p = strescseq.args[1];
+
+			if (!strcmp(p, "?"))
+				osc_color_response(defaultbg, 11);
+			else if (xsetcolorname(defaultbg, p))
+				fprintf(stderr, "erresc: invalid background color: %s\n", p);
+			else
+				redraw();
+			break;
+		case 12:
+			if (narg < 2)
+				break;
+
+			p = strescseq.args[1];
+
+			if (!strcmp(p, "?"))
+				osc_color_response(defaultcs, 12);
+			else if (xsetcolorname(defaultcs, p))
+				fprintf(stderr, "erresc: invalid cursor color: %s\n", p);
+			else
+				redraw();
+			break;
 		case 4: /* color set */
 			if (narg < 3)
 				break;
@@ -1887,7 +1962,10 @@ strhandle(void)
 			/* FALLTHROUGH */
 		case 104: /* color reset, here p = NULL */
 			j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
-			if (xsetcolorname(j, p)) {
+
+			if (!strcmp(p, "?"))
+				osc4_color_response(j);
+			else if (xsetcolorname(j, p)) {
 				if (par == 104 && narg <= 1)
 					return; /* color reset without parameter */
 				fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
diff --git a/st.h b/st.h
index fa2eddf..519b9bd 100644
--- a/st.h
+++ b/st.h
@@ -111,6 +111,8 @@ void *xmalloc(size_t);
 void *xrealloc(void *, size_t);
 char *xstrdup(const char *);
 
+int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b);
+
 /* config.h globals */
 extern char *utmp;
 extern char *scroll;
@@ -123,3 +125,4 @@ extern char *termname;
 extern unsigned int tabspaces;
 extern unsigned int defaultfg;
 extern unsigned int defaultbg;
+extern unsigned int defaultcs;
diff --git a/x.c b/x.c
index 89786b8..8a16faa 100644
--- a/x.c
+++ b/x.c
@@ -799,6 +799,19 @@ xloadcols(void)
 	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)
 {

From 273db5ceaf392e68c2faf8f7dec14ea2e25e980d Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun, 26 Dec 2021 19:00:41 +0100
Subject: [PATCH 1118/1146] follow-up fix for OSC color sequences, return

Otherwise the message "erresc: unknown str" is printed.
---
 st.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/st.c b/st.c
index 781dbf2..6783c2b 100644
--- a/st.c
+++ b/st.c
@@ -1928,7 +1928,7 @@ strhandle(void)
 				fprintf(stderr, "erresc: invalid foreground color: %s\n", p);
 			else
 				redraw();
-			break;
+			return;
 		case 11:
 			if (narg < 2)
 				break;
@@ -1941,7 +1941,7 @@ strhandle(void)
 				fprintf(stderr, "erresc: invalid background color: %s\n", p);
 			else
 				redraw();
-			break;
+			return;
 		case 12:
 			if (narg < 2)
 				break;
@@ -1954,7 +1954,7 @@ strhandle(void)
 				fprintf(stderr, "erresc: invalid cursor color: %s\n", p);
 			else
 				redraw();
-			break;
+			return;
 		case 4: /* color set */
 			if (narg < 3)
 				break;

From a0467c802d4f86ed162486e3453dd61181423902 Mon Sep 17 00:00:00 2001
From: Jochen Sprickerhof <git@jochen.sprickerhof.de>
Date: Mon, 27 Dec 2021 11:41:42 +0100
Subject: [PATCH 1119/1146] Fix null pointer access in strhandle

According to the spec the argument is optional for 104, so p can be
NULL as can be tested with printf '\x1b]104\x07'. This is a regression
of 8e31030.
---
 st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 6783c2b..de2dd0e 100644
--- a/st.c
+++ b/st.c
@@ -1960,10 +1960,10 @@ strhandle(void)
 				break;
 			p = strescseq.args[2];
 			/* FALLTHROUGH */
-		case 104: /* color reset, here p = NULL */
+		case 104: /* color reset */
 			j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
 
-			if (!strcmp(p, "?"))
+			if (p && !strcmp(p, "?"))
 				osc4_color_response(j);
 			else if (xsetcolorname(j, p)) {
 				if (par == 104 && narg <= 1)

From 65f1dc428315ae9d7f362e10c668557c1379e7af Mon Sep 17 00:00:00 2001
From: jamin <acdimalev@gmail.com>
Date: Wed, 29 Dec 2021 09:07:17 -0800
Subject: [PATCH 1120/1146] Fix overtyping wide characters.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Overtyping the first half of a wide character with the
second half of a wide character results in display garbage.
This is because the trailing dummy is not cleaned up.

i.e.  ATTR_WIDE, ATTR_WDUMMY, ATTR_WDUMMY

Here is a short script for demonstrating the behavior:

	#!/bin/sh
	alias printf=/usr/bin/printf
	printf こんにちは!; sleep 2
	printf '\x1b[5D'; sleep 2
	printf へ; sleep 2
	printf ' '; sleep 2
	echo
---
 st.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/st.c b/st.c
index de2dd0e..51049ba 100644
--- a/st.c
+++ b/st.c
@@ -2507,6 +2507,10 @@ check_control_code:
 	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;
 		}

From 7e1c68f25d9f08687a94eeef8d7f8ffd0d14b911 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun, 2 Jan 2022 12:15:45 +0100
Subject: [PATCH 1121/1146] FAQ: fix a typo, patch -> path

---
 FAQ | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/FAQ b/FAQ
index 0f9609d..969b195 100644
--- a/FAQ
+++ b/FAQ
@@ -29,8 +29,8 @@ you can manually run `tic -sx st.info`.
 
 ## I would like to have utmp and/or scroll functionality by default
 
-You can add the absolute patch of both programs in your config.h
-file. You only have to modify the value of utmp and scroll variables.
+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?

From 7fb0c0cc681f36be2ad12091ef93a41671f32738 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 7 Jan 2022 12:39:57 +0100
Subject: [PATCH 1122/1146] bump version to 0.8.5

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index c070a4a..4c4c5d5 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.8.4
+VERSION = 0.8.5
 
 # Customize below to fit your system
 

From ea7cd7b62fdfa6a1fbd882d1565d557577f2cf32 Mon Sep 17 00:00:00 2001
From: robert <robertrussell.72001@gmail.com>
Date: Sat, 8 Jan 2022 11:40:34 -0800
Subject: [PATCH 1123/1146] Fix mousereport

This patch replaces the previous one I sent.

The following changes are made in this patch:
 - Fix tracking of pressed buttons. Previously, pressing two buttons and
   then releasing one would make st think no buttons are pressed, which
   in particular broke MODE_MOUSEMOTION.
 - Always send the lowest-numbered pressed button on motion events; when
   no button is pressed for a motion event in MODE_MOUSEMANY, then send
   a release. This matches the behaviour of xterm. (Previously, st sent
   the most recently pressed button in the motion report.)
 - Remove UB (?) access to potentially inactive struct member
   e->xbutton.button of XEvent union.
 - Fix (unlikely) possibility of overflow for large button numbers.

The one discrepancy I found between st and xterm is that xterm sometimes
encodes buttons with large numbers (>5) strangely. E.g., xterm reports
presses of buttons 8 and 9 as releases, whereas st properly (?) encodes
them as presses.
---
 x.c | 86 ++++++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 51 insertions(+), 35 deletions(-)

diff --git a/x.c b/x.c
index 8a16faa..5f4ea73 100644
--- a/x.c
+++ b/x.c
@@ -252,7 +252,7 @@ static char *opt_line  = NULL;
 static char *opt_name  = NULL;
 static char *opt_title = NULL;
 
-static int oldbutton = 3; /* button event on startup: 3 = release */
+static uint buttons; /* bit field of pressed buttons */
 
 void
 clipcopy(const Arg *dummy)
@@ -364,61 +364,68 @@ mousesel(XEvent *e, int done)
 void
 mousereport(XEvent *e)
 {
-	int len, x = evcol(e), y = evrow(e),
-	    button = e->xbutton.button, state = e->xbutton.state;
+	int len, btn, code;
+	int x = evcol(e), y = evrow(e);
+	int state = e->xbutton.state;
 	char buf[40];
 	static int ox, oy;
 
-	/* from urxvt */
-	if (e->xbutton.type == MotionNotify) {
+	if (e->type == MotionNotify) {
 		if (x == ox && y == oy)
 			return;
 		if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
 			return;
-		/* MOUSE_MOTION: no reporting if no button is pressed */
-		if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
+		/* MODE_MOUSEMOTION: no reporting if no button is pressed */
+		if (IS_SET(MODE_MOUSEMOTION) && buttons == 0)
 			return;
-
-		button = oldbutton + 32;
-		ox = x;
-		oy = y;
+		/* 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 {
-		if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
-			button = 3;
-		} else {
-			button -= Button1;
-			if (button >= 7)
-				button += 128 - 7;
-			else if (button >= 3)
-				button += 64 - 3;
-		}
-		if (e->xbutton.type == ButtonPress) {
-			oldbutton = button;
-			ox = x;
-			oy = y;
-		} else if (e->xbutton.type == ButtonRelease) {
-			oldbutton = 3;
+		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;
-			if (button == 64 || button == 65)
+			/* 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)) {
-		button += ((state & ShiftMask  ) ? 4  : 0)
-			+ ((state & Mod4Mask   ) ? 8  : 0)
-			+ ((state & ControlMask) ? 16 : 0);
+		code += ((state & ShiftMask  ) ?  4 : 0)
+		      + ((state & Mod4Mask   ) ?  8 : 0)
+		      + ((state & ControlMask) ? 16 : 0);
 	}
 
 	if (IS_SET(MODE_MOUSESGR)) {
 		len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
-				button, x+1, y+1,
-				e->xbutton.type == ButtonRelease ? 'm' : 'M');
+				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+button, 32+x+1, 32+y+1);
+				32+code, 32+x+1, 32+y+1);
 	} else {
 		return;
 	}
@@ -461,9 +468,13 @@ mouseaction(XEvent *e, uint release)
 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;
@@ -472,7 +483,7 @@ bpress(XEvent *e)
 	if (mouseaction(e, 0))
 		return;
 
-	if (e->xbutton.button == Button1) {
+	if (btn == Button1) {
 		/*
 		 * If the user clicks below predefined timeouts specific
 		 * snapping behaviour is exposed.
@@ -686,6 +697,11 @@ xsetsel(char *str)
 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;
@@ -693,7 +709,7 @@ brelease(XEvent *e)
 
 	if (mouseaction(e, 1))
 		return;
-	if (e->xbutton.button == Button1)
+	if (btn == Button1)
 		mousesel(e, 1);
 }
 

From b1d97fec47b0d6633addb848131388ec40154ebc Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Mon, 10 Jan 2022 17:11:17 +0100
Subject: [PATCH 1124/1146] LICENSE: bump year

---
 LICENSE | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LICENSE b/LICENSE
index d80eb47..3cbf420 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 MIT/X Consortium License
 
-© 2014-2020 Hiltjo Posthuma <hiltjo at codemadness dot org>
+© 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>

From 2c5edf28ec851907305d73c6218ce75d39f1767f Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Wed, 12 Jan 2022 09:44:27 +0100
Subject: [PATCH 1125/1146] X10/SGR mouse: use alt as meta key instead of
 super/windows key

---
 x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x.c b/x.c
index 5f4ea73..cd96575 100644
--- a/x.c
+++ b/x.c
@@ -415,7 +415,7 @@ mousereport(XEvent *e)
 
 	if (!IS_SET(MODE_MOUSEX10)) {
 		code += ((state & ShiftMask  ) ?  4 : 0)
-		      + ((state & Mod4Mask   ) ?  8 : 0)
+		      + ((state & Mod1Mask   ) ?  8 : 0) /* meta key: alt */
 		      + ((state & ControlMask) ? 16 : 0);
 	}
 

From e823e2308f2a99023032a3966ebb7036a31d305f Mon Sep 17 00:00:00 2001
From: Santtu Lakkala <inz@inz.fi>
Date: Thu, 17 Feb 2022 16:00:47 +0200
Subject: [PATCH 1126/1146] Delay redrawals on palette changes

Build on auto-sync and only mark window dirty on palette changes and let
the event handler do the actual draw.
---
 st.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index 51049ba..c71fa06 100644
--- a/st.c
+++ b/st.c
@@ -1927,7 +1927,7 @@ strhandle(void)
 			else if (xsetcolorname(defaultfg, p))
 				fprintf(stderr, "erresc: invalid foreground color: %s\n", p);
 			else
-				redraw();
+				tfulldirt();
 			return;
 		case 11:
 			if (narg < 2)
@@ -1940,7 +1940,7 @@ strhandle(void)
 			else if (xsetcolorname(defaultbg, p))
 				fprintf(stderr, "erresc: invalid background color: %s\n", p);
 			else
-				redraw();
+				tfulldirt();
 			return;
 		case 12:
 			if (narg < 2)
@@ -1953,7 +1953,7 @@ strhandle(void)
 			else if (xsetcolorname(defaultcs, p))
 				fprintf(stderr, "erresc: invalid cursor color: %s\n", p);
 			else
-				redraw();
+				tfulldirt();
 			return;
 		case 4: /* color set */
 			if (narg < 3)
@@ -1975,7 +1975,7 @@ strhandle(void)
 				 * TODO if defaultbg color is changed, borders
 				 * are dirty
 				 */
-				redraw();
+				tfulldirt();
 			}
 			return;
 		}

From 2aefa348baf4b702fdce98eb105bcba175d8283f Mon Sep 17 00:00:00 2001
From: Zacchary Dempsey-Plante <zacc@ztdp.ca>
Date: Sun, 13 Mar 2022 10:44:08 +0100
Subject: [PATCH 1127/1146] make underlines and strikethroughs respect
 `chscale`

---
 x.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/x.c b/x.c
index cd96575..2a3bd38 100644
--- a/x.c
+++ b/x.c
@@ -1493,12 +1493,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 
 	/* Render underline and strikethrough. */
 	if (base.mode & ATTR_UNDERLINE) {
-		XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
+		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 / 3,
+		XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3,
 				width, 1);
 	}
 

From af3bb68add1c40d19d0dee382009e21b0870a38f Mon Sep 17 00:00:00 2001
From: NRK <nrk@disroot.org>
Date: Fri, 18 Mar 2022 16:20:54 +0600
Subject: [PATCH 1128/1146] avoid potential UB when using isprint()

all the ctype.h functions' argument must be representable as an unsigned
char or as EOF, otherwise the behavior is undefined.
---
 st.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/st.c b/st.c
index c71fa06..1307fdf 100644
--- a/st.c
+++ b/st.c
@@ -367,7 +367,7 @@ static const char base64_digits[] = {
 char
 base64dec_getc(const char **src)
 {
-	while (**src && !isprint(**src))
+	while (**src && !isprint((unsigned char)**src))
 		(*src)++;
 	return **src ? *((*src)++) : '=';  /* emulate padding if string ends */
 }

From ef0551932fb162f907b40185d2f48c3b497708ee Mon Sep 17 00:00:00 2001
From: NRK <nrk@disroot.org>
Date: Fri, 18 Mar 2022 17:03:34 +0600
Subject: [PATCH 1129/1146] base64_digits: reduce scope, implicit zero, +1 size

the array is not accessed outside of base64dec() so it makes sense to
limit it's scope to the related function. the static-storage duration of
the array is kept intact.

this also removes unnecessary explicit zeroing from the start and end of
the array. anything that wasn't explicitly zero-ed will now be
implicitly zero-ed instead.

the validity of the new array can be easily confirmed via running this
trivial loop:

	for (int i = 0; i < 255; ++i)
		assert(base64_digits[i] == base64_digits_old[i]);

lastly, as pointed out by Roberto, the array needs to have 256 elements
in order to able access it as any unsigned char as an index; the
previous array had 255.

however, this array will only be accessed at indexes which are
isprint() || '=' (see `base64dec_getc()`), so reducing the size of the
array to the highest printable ascii char (127 AFAIK) + 1 might also be
a valid strategy.
---
 st.c | 22 +++++++---------------
 1 file changed, 7 insertions(+), 15 deletions(-)

diff --git a/st.c b/st.c
index 1307fdf..f43cfd3 100644
--- a/st.c
+++ b/st.c
@@ -349,21 +349,6 @@ utf8validate(Rune *u, size_t i)
 	return i;
 }
 
-static const char base64_digits[] = {
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0,
-	63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, -1, 0, 0, 0, 0, 1,
-	2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
-	22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34,
-	35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
 char
 base64dec_getc(const char **src)
 {
@@ -377,6 +362,13 @@ 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);

From 8629d9a1da72cc18568a8f146307b0e939b77ebf Mon Sep 17 00:00:00 2001
From: NRK <nrk@disroot.org>
Date: Fri, 7 Jan 2022 23:21:04 +0600
Subject: [PATCH 1130/1146] code-golfing: cleanup osc color related code

* adds missing function prototype
* move xgetcolor() prototype to win.h (that's where all the other x.c
  func prototype seems to be declared at)
* check for snprintf error/truncation
* reduces code duplication for osc 10/11/12
* unify osc_color_response() and osc4_color_response() into a single function

the latter two was suggested by Quentin Rameau in his patch review on
the hackers list.
---
 st.c  | 88 +++++++++++++++++++++--------------------------------------
 st.h  |  2 --
 win.h |  1 +
 3 files changed, 32 insertions(+), 59 deletions(-)

diff --git a/st.c b/st.c
index f43cfd3..6ba467d 100644
--- a/st.c
+++ b/st.c
@@ -161,6 +161,7 @@ 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);
@@ -1835,39 +1836,28 @@ csireset(void)
 }
 
 void
-osc4_color_response(int num)
+osc_color_response(int num, int index, int is_osc4)
 {
 	int n;
 	char buf[32];
 	unsigned char r, g, b;
 
-	if (xgetcolor(num, &r, &g, &b)) {
-		fprintf(stderr, "erresc: failed to fetch osc4 color %d\n", num);
+	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]4;%d;rgb:%02x%02x/%02x%02x/%02x%02x\007",
-		     num, r, r, g, g, b, b);
-
-	ttywrite(buf, n, 1);
-}
-
-void
-osc_color_response(int index, int num)
-{
-	int n;
-	char buf[32];
-	unsigned char r, g, b;
-
-	if (xgetcolor(index, &r, &g, &b)) {
-		fprintf(stderr, "erresc: failed to fetch osc color %d\n", 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);
 	}
-
-	n = snprintf(buf, sizeof buf, "\033]%d;rgb:%02x%02x/%02x%02x/%02x%02x\007",
-		     num, r, r, g, g, b, b);
-
-	ttywrite(buf, n, 1);
 }
 
 void
@@ -1875,6 +1865,11 @@ 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();
@@ -1909,43 +1904,22 @@ strhandle(void)
 			}
 			return;
 		case 10:
-			if (narg < 2)
-				break;
-
-			p = strescseq.args[1];
-
-			if (!strcmp(p, "?"))
-				osc_color_response(defaultfg, 10);
-			else if (xsetcolorname(defaultfg, p))
-				fprintf(stderr, "erresc: invalid foreground color: %s\n", p);
-			else
-				tfulldirt();
-			return;
 		case 11:
-			if (narg < 2)
-				break;
-
-			p = strescseq.args[1];
-
-			if (!strcmp(p, "?"))
-				osc_color_response(defaultbg, 11);
-			else if (xsetcolorname(defaultbg, p))
-				fprintf(stderr, "erresc: invalid background color: %s\n", p);
-			else
-				tfulldirt();
-			return;
 		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(defaultcs, 12);
-			else if (xsetcolorname(defaultcs, p))
-				fprintf(stderr, "erresc: invalid cursor color: %s\n", p);
-			else
+			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)
@@ -1955,9 +1929,9 @@ strhandle(void)
 		case 104: /* color reset */
 			j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
 
-			if (p && !strcmp(p, "?"))
-				osc4_color_response(j);
-			else if (xsetcolorname(j, p)) {
+			if (p && !strcmp(p, "?")) {
+				osc_color_response(j, 0, 1);
+			} else if (xsetcolorname(j, p)) {
 				if (par == 104 && narg <= 1)
 					return; /* color reset without parameter */
 				fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
diff --git a/st.h b/st.h
index 519b9bd..fd3b0d8 100644
--- a/st.h
+++ b/st.h
@@ -111,8 +111,6 @@ void *xmalloc(size_t);
 void *xrealloc(void *, size_t);
 char *xstrdup(const char *);
 
-int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b);
-
 /* config.h globals */
 extern char *utmp;
 extern char *scroll;
diff --git a/win.h b/win.h
index e6e4369..6de960d 100644
--- a/win.h
+++ b/win.h
@@ -30,6 +30,7 @@ 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);

From baa9357e96d2478baa52a3301e70ac80a229b726 Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun, 1 May 2022 18:38:40 +0200
Subject: [PATCH 1131/1146] Makefile: add manual path for OpenBSD

---
 config.mk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/config.mk b/config.mk
index 4c4c5d5..ddf278a 100644
--- a/config.mk
+++ b/config.mk
@@ -30,6 +30,7 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
 #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
 #       `$(PKG_CONFIG) --libs fontconfig` \
 #       `$(PKG_CONFIG) --libs freetype2`
+#MANPREFIX = ${PREFIX}/man
 
 # compiler and linker
 # CC = c99

From aac8698a4388ee9f5a6c3950b83162ef9d1c5197 Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Tue, 17 May 2022 21:33:17 -0500
Subject: [PATCH 1132/1146] add scrollback 0.8.5 patch

---
 config.def.h |   2 +
 st.c         | 125 ++++++++++++++++++++++++++++++++++++++++-----------
 st.h         |   2 +
 3 files changed, 102 insertions(+), 27 deletions(-)

diff --git a/config.def.h b/config.def.h
index 91ab8ca..e3b469b 100644
--- a/config.def.h
+++ b/config.def.h
@@ -201,6 +201,8 @@ static Shortcut shortcuts[] = {
 	{ TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
 	{ ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
 	{ TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
+	{ ShiftMask,            XK_Page_Up,     kscrollup,      {.i = -1} },
+	{ ShiftMask,            XK_Page_Down,   kscrolldown,    {.i = -1} },
 };
 
 /*
diff --git a/st.c b/st.c
index 6ba467d..91e7077 100644
--- a/st.c
+++ b/st.c
@@ -35,6 +35,7 @@
 #define ESC_ARG_SIZ   16
 #define STR_BUF_SIZ   ESC_BUF_SIZ
 #define STR_ARG_SIZ   ESC_ARG_SIZ
+#define HISTSIZE      2000
 
 /* macros */
 #define IS_SET(flag)		((term.mode & (flag)) != 0)
@@ -42,6 +43,9 @@
 #define ISCONTROLC1(c)		(BETWEEN(c, 0x80, 0x9f))
 #define ISCONTROL(c)		(ISCONTROLC0(c) || ISCONTROLC1(c))
 #define ISDELIM(u)		(u && wcschr(worddelimiters, u))
+#define TLINE(y)		((y) < term.scr ? term.hist[((y) + term.histi - \
+				term.scr + HISTSIZE + 1) % HISTSIZE] : \
+				term.line[(y) - term.scr])
 
 enum term_mode {
 	MODE_WRAP        = 1 << 0,
@@ -115,6 +119,9 @@ typedef struct {
 	int col;      /* nb col */
 	Line *line;   /* screen */
 	Line *alt;    /* alternate screen */
+	Line hist[HISTSIZE]; /* history buffer */
+	int histi;    /* history index */
+	int scr;      /* scroll back */
 	int *dirty;   /* dirtyness of lines */
 	TCursor c;    /* cursor */
 	int ocx;      /* old cursor col */
@@ -185,8 +192,8 @@ 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 tscrollup(int, int, int);
+static void tscrolldown(int, int, int);
 static void tsetattr(const int *, int);
 static void tsetchar(Rune, const Glyph *, int, int);
 static void tsetdirt(int, int);
@@ -409,10 +416,10 @@ tlinelen(int y)
 {
 	int i = term.col;
 
-	if (term.line[y][i - 1].mode & ATTR_WRAP)
+	if (TLINE(y)[i - 1].mode & ATTR_WRAP)
 		return i;
 
-	while (i > 0 && term.line[y][i - 1].u == ' ')
+	while (i > 0 && TLINE(y)[i - 1].u == ' ')
 		--i;
 
 	return i;
@@ -521,7 +528,7 @@ selsnap(int *x, int *y, int direction)
 		 * Snap around if the word wraps around at the end or
 		 * beginning of a line.
 		 */
-		prevgp = &term.line[*y][*x];
+		prevgp = &TLINE(*y)[*x];
 		prevdelim = ISDELIM(prevgp->u);
 		for (;;) {
 			newx = *x + direction;
@@ -536,14 +543,14 @@ selsnap(int *x, int *y, int direction)
 					yt = *y, xt = *x;
 				else
 					yt = newy, xt = newx;
-				if (!(term.line[yt][xt].mode & ATTR_WRAP))
+				if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
 					break;
 			}
 
 			if (newx >= tlinelen(newy))
 				break;
 
-			gp = &term.line[newy][newx];
+			gp = &TLINE(newy)[newx];
 			delim = ISDELIM(gp->u);
 			if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
 					|| (delim && gp->u != prevgp->u)))
@@ -564,14 +571,14 @@ selsnap(int *x, int *y, int direction)
 		*x = (direction < 0) ? 0 : term.col - 1;
 		if (direction < 0) {
 			for (; *y > 0; *y += direction) {
-				if (!(term.line[*y-1][term.col-1].mode
+				if (!(TLINE(*y-1)[term.col-1].mode
 						& ATTR_WRAP)) {
 					break;
 				}
 			}
 		} else if (direction > 0) {
 			for (; *y < term.row-1; *y += direction) {
-				if (!(term.line[*y][term.col-1].mode
+				if (!(TLINE(*y)[term.col-1].mode
 						& ATTR_WRAP)) {
 					break;
 				}
@@ -602,13 +609,13 @@ getsel(void)
 		}
 
 		if (sel.type == SEL_RECTANGULAR) {
-			gp = &term.line[y][sel.nb.x];
+			gp = &TLINE(y)[sel.nb.x];
 			lastx = sel.ne.x;
 		} else {
-			gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0];
+			gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0];
 			lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
 		}
-		last = &term.line[y][MIN(lastx, linelen-1)];
+		last = &TLINE(y)[MIN(lastx, linelen-1)];
 		while (last >= gp && last->u == ' ')
 			--last;
 
@@ -844,6 +851,9 @@ void
 ttywrite(const char *s, size_t n, int may_echo)
 {
 	const char *next;
+	Arg arg = (Arg) { .i = term.scr };
+
+	kscrolldown(&arg);
 
 	if (may_echo && IS_SET(MODE_ECHO))
 		twrite(s, n, 1);
@@ -1055,12 +1065,52 @@ tswapscreen(void)
 }
 
 void
-tscrolldown(int orig, int n)
+kscrolldown(const Arg* a)
+{
+	int n = a->i;
+
+	if (n < 0)
+		n = term.row + n;
+
+	if (n > term.scr)
+		n = term.scr;
+
+	if (term.scr > 0) {
+		term.scr -= n;
+		selscroll(0, -n);
+		tfulldirt();
+	}
+}
+
+void
+kscrollup(const Arg* a)
+{
+	int n = a->i;
+
+	if (n < 0)
+		n = term.row + n;
+
+	if (term.scr <= HISTSIZE-n) {
+		term.scr += n;
+		selscroll(0, n);
+		tfulldirt();
+	}
+}
+
+void
+tscrolldown(int orig, int n, int copyhist)
 {
 	int i;
 	Line temp;
 
 	LIMIT(n, 0, term.bot-orig+1);
+	if (copyhist) {
+		term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
+		temp = term.hist[term.histi];
+		term.hist[term.histi] = term.line[term.bot];
+		term.line[term.bot] = temp;
+	}
+
 
 	tsetdirt(orig, term.bot-n);
 	tclearregion(0, term.bot-n+1, term.col-1, term.bot);
@@ -1071,17 +1121,28 @@ tscrolldown(int orig, int n)
 		term.line[i-n] = temp;
 	}
 
-	selscroll(orig, n);
+	if (term.scr == 0)
+		selscroll(orig, n);
 }
 
 void
-tscrollup(int orig, int n)
+tscrollup(int orig, int n, int copyhist)
 {
 	int i;
 	Line temp;
 
 	LIMIT(n, 0, term.bot-orig+1);
 
+	if (copyhist) {
+		term.histi = (term.histi + 1) % HISTSIZE;
+		temp = term.hist[term.histi];
+		term.hist[term.histi] = term.line[orig];
+		term.line[orig] = temp;
+	}
+
+	if (term.scr > 0 && term.scr < HISTSIZE)
+		term.scr = MIN(term.scr + n, HISTSIZE-1);
+
 	tclearregion(0, orig, term.col-1, orig+n-1);
 	tsetdirt(orig+n, term.bot);
 
@@ -1091,7 +1152,8 @@ tscrollup(int orig, int n)
 		term.line[i+n] = temp;
 	}
 
-	selscroll(orig, -n);
+	if (term.scr == 0)
+		selscroll(orig, -n);
 }
 
 void
@@ -1120,7 +1182,7 @@ tnewline(int first_col)
 	int y = term.c.y;
 
 	if (y == term.bot) {
-		tscrollup(term.top, 1);
+		tscrollup(term.top, 1, 1);
 	} else {
 		y++;
 	}
@@ -1285,14 +1347,14 @@ void
 tinsertblankline(int n)
 {
 	if (BETWEEN(term.c.y, term.top, term.bot))
-		tscrolldown(term.c.y, n);
+		tscrolldown(term.c.y, n, 0);
 }
 
 void
 tdeleteline(int n)
 {
 	if (BETWEEN(term.c.y, term.top, term.bot))
-		tscrollup(term.c.y, n);
+		tscrollup(term.c.y, n, 0);
 }
 
 int32_t
@@ -1729,11 +1791,11 @@ csihandle(void)
 		break;
 	case 'S': /* SU -- Scroll <n> line up */
 		DEFAULT(csiescseq.arg[0], 1);
-		tscrollup(term.top, csiescseq.arg[0]);
+		tscrollup(term.top, csiescseq.arg[0], 0);
 		break;
 	case 'T': /* SD -- Scroll <n> line down */
 		DEFAULT(csiescseq.arg[0], 1);
-		tscrolldown(term.top, csiescseq.arg[0]);
+		tscrolldown(term.top, csiescseq.arg[0], 0);
 		break;
 	case 'L': /* IL -- Insert <n> blank lines */
 		DEFAULT(csiescseq.arg[0], 1);
@@ -2296,7 +2358,7 @@ eschandle(uchar ascii)
 		return 0;
 	case 'D': /* IND -- Linefeed */
 		if (term.c.y == term.bot) {
-			tscrollup(term.top, 1);
+			tscrollup(term.top, 1, 1);
 		} else {
 			tmoveto(term.c.x, term.c.y+1);
 		}
@@ -2309,7 +2371,7 @@ eschandle(uchar ascii)
 		break;
 	case 'M': /* RI -- Reverse index */
 		if (term.c.y == term.top) {
-			tscrolldown(term.top, 1);
+			tscrolldown(term.top, 1, 1);
 		} else {
 			tmoveto(term.c.x, term.c.y-1);
 		}
@@ -2523,7 +2585,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
 void
 tresize(int col, int row)
 {
-	int i;
+	int i, j;
 	int minrow = MIN(row, term.row);
 	int mincol = MIN(col, term.col);
 	int *bp;
@@ -2560,6 +2622,14 @@ tresize(int col, int row)
 	term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
 	term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
 
+	for (i = 0; i < HISTSIZE; i++) {
+		term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph));
+		for (j = mincol; j < col; j++) {
+			term.hist[i][j] = term.c.attr;
+			term.hist[i][j].u = ' ';
+		}
+	}
+
 	/* resize each row to new width, zero-pad if needed */
 	for (i = 0; i < minrow; i++) {
 		term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
@@ -2618,7 +2688,7 @@ drawregion(int x1, int y1, int x2, int y2)
 			continue;
 
 		term.dirty[y] = 0;
-		xdrawline(term.line[y], x1, y, x2);
+		xdrawline(TLINE(y), x1, y, x2);
 	}
 }
 
@@ -2639,8 +2709,9 @@ draw(void)
 		cx--;
 
 	drawregion(0, 0, term.col, term.row);
-	xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
-			term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
+	if (term.scr == 0)
+		xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
+				term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
 	term.ocx = cx;
 	term.ocy = term.c.y;
 	xfinishdraw();
diff --git a/st.h b/st.h
index fd3b0d8..818a6f8 100644
--- a/st.h
+++ b/st.h
@@ -81,6 +81,8 @@ void die(const char *, ...);
 void redraw(void);
 void draw(void);
 
+void kscrolldown(const Arg *);
+void kscrollup(const Arg *);
 void printscreen(const Arg *);
 void printsel(const Arg *);
 void sendbreak(const Arg *);

From f380807190336e6e1eb7b1dd7685657a8680a392 Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Tue, 17 May 2022 21:44:46 -0500
Subject: [PATCH 1133/1146] some configuration changes

---
 config.h | 467 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 467 insertions(+)
 create mode 100644 config.h

diff --git a/config.h b/config.h
new file mode 100644
index 0000000..4eae287
--- /dev/null
+++ b/config.h
@@ -0,0 +1,467 @@
+/* See LICENSE file for copyright and license details. */
+
+/*
+ * appearance
+ *
+ * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
+ */
+static char *font = "Fantasque Sans Mono:pixelsize=14: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 */
+	"#161510",
+	"#a32810",
+	"#727a18",
+	"#a37720",
+	"#3d6266",
+	"#7a4955",
+	"#557a55",
+	"#8e8463",
+
+	/* 8 bright colors */
+	"#4c4635",
+	"#cc3214",
+	"#8e991e",
+	"#cc9528",
+	"#4c7b7f",
+	"#995b6b",
+	"#6b996b",
+	"#ccbc8e",
+
+	[255] = 0,
+
+	/* more colors can be added after 255 to use with DefaultXX */
+	"#cccccc",
+	"#555555",
+};
+
+
+/*
+ * Default colors (colorname index)
+ * foreground, background, cursor, reverse cursor
+ */
+unsigned int defaultfg = 7;
+unsigned int defaultbg = 0;
+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} },
+	{ MODKEY,               XK_h,           zoom,           {.f = +1} },
+	{ MODKEY,               XK_l,           zoom,           {.f = -1} },
+	{ MODKEY,               XK_C,           clipcopy,       {.i =  0} },
+	{ MODKEY,               XK_V,           clippaste,      {.i =  0} },
+	{ MODKEY,               XK_k,           kscrollup,      {.i = -1} },
+	{ MODKEY,               XK_j,           kscrolldown,    {.i = -1} },
+};
+
+/*
+ * 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{|}~";

From 1bbc19928684e5685e344f5f5380a808852443b9 Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Tue, 17 May 2022 21:53:15 -0500
Subject: [PATCH 1134/1146] add externalpipe patch

---
 st.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 st.h |  1 +
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 91e7077..210cd03 100644
--- a/st.c
+++ b/st.c
@@ -725,8 +725,14 @@ sigchld(int a)
 	if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
 		die("waiting for pid %hd failed: %s\n", pid, strerror(errno));
 
-	if (pid != p)
+	if (pid != p) {
+		if (p == 0 && wait(&stat) < 0)
+			die("wait: %s\n", strerror(errno));
+
+		/* reinstall sigchld handler */
+		signal(SIGCHLD, sigchld);
 		return;
+	}
 
 	if (WIFEXITED(stat) && WEXITSTATUS(stat))
 		die("child exited with status %d\n", WEXITSTATUS(stat));
@@ -2043,6 +2049,59 @@ strparse(void)
 	}
 }
 
+void
+externalpipe(const Arg *arg)
+{
+	int to[2];
+	char buf[UTF_SIZ];
+	void (*oldsigpipe)(int);
+	Glyph *bp, *end;
+	int lastpos, n, newline;
+
+	if (pipe(to) == -1)
+		return;
+
+	switch (fork()) {
+	case -1:
+		close(to[0]);
+		close(to[1]);
+		return;
+	case 0:
+		dup2(to[0], STDIN_FILENO);
+		close(to[0]);
+		close(to[1]);
+		execvp(((char **)arg->v)[0], (char **)arg->v);
+		fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]);
+		perror("failed");
+		exit(0);
+	}
+
+	close(to[0]);
+	/* ignore sigpipe for now, in case child exists early */
+	oldsigpipe = signal(SIGPIPE, SIG_IGN);
+	newline = 0;
+	for (n = 0; n < term.row; n++) {
+		bp = term.line[n];
+		lastpos = MIN(tlinelen(n) + 1, term.col) - 1;
+		if (lastpos < 0)
+			break;
+		end = &bp[lastpos + 1];
+		for (; bp < end; ++bp)
+			if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0)
+				break;
+		if ((newline = term.line[n][lastpos].mode & ATTR_WRAP))
+			continue;
+		if (xwrite(to[1], "\n", 1) < 0)
+			break;
+		newline = 0;
+	}
+	if (newline)
+		(void)xwrite(to[1], "\n", 1);
+	close(to[1]);
+	/* restore */
+	signal(SIGPIPE, oldsigpipe);
+}
+
 void
 strdump(void)
 {
diff --git a/st.h b/st.h
index 818a6f8..ee3bee2 100644
--- a/st.h
+++ b/st.h
@@ -81,6 +81,7 @@ void die(const char *, ...);
 void redraw(void);
 void draw(void);
 
+void externalpipe(const Arg *);
 void kscrolldown(const Arg *);
 void kscrollup(const Arg *);
 void printscreen(const Arg *);

From 72d0d47817e2aa770305c69bb28fcc0ead06a49e Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Tue, 17 May 2022 21:54:14 -0500
Subject: [PATCH 1135/1146] colors at launch patch

---
 x.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/x.c b/x.c
index 2a3bd38..afa06be 100644
--- a/x.c
+++ b/x.c
@@ -2027,6 +2027,8 @@ usage(void)
 int
 main(int argc, char *argv[])
 {
+    int i;
+    char *colval;
 	xw.l = xw.t = 0;
 	xw.isfixed = False;
 	xsetcursor(cursorshape);
@@ -2071,6 +2073,11 @@ main(int argc, char *argv[])
 	case 'v':
 		die("%s " VERSION "\n", argv0);
 		break;
+    case 'C':
+        colval = strtok(EARGF(usage()), "@");
+        i = atoi(strtok(NULL, "@"));
+		colorname[i] = colval;
+		break;
 	default:
 		usage();
 	} ARGEND;

From 3b0804dde2e2963da680e299e84e0797295cb200 Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Mon, 13 Jun 2022 14:06:36 -0500
Subject: [PATCH 1136/1146] misc st patches and other things

---
 config.h |  6 ++----
 st.c     | 36 ++++++++++++++++++++++++++++++++----
 st.info  |  4 ++--
 win.h    |  4 +++-
 x.c      | 41 ++++++++++++++++++++++++++++++++++++++---
 5 files changed, 77 insertions(+), 14 deletions(-)

diff --git a/config.h b/config.h
index 4eae287..331607b 100644
--- a/config.h
+++ b/config.h
@@ -1,8 +1,6 @@
 /* See LICENSE file for copyright and license details. */
 
 /*
- * appearance
- *
  * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
  */
 static char *font = "Fantasque Sans Mono:pixelsize=14:antialias=true:autohint=true";
@@ -190,8 +188,8 @@ static Shortcut shortcuts[] = {
 	{ XK_ANY_MOD,           XK_Break,       sendbreak,      {.i =  0} },
 	{ MODKEY,               XK_h,           zoom,           {.f = +1} },
 	{ MODKEY,               XK_l,           zoom,           {.f = -1} },
-	{ MODKEY,               XK_C,           clipcopy,       {.i =  0} },
-	{ MODKEY,               XK_V,           clippaste,      {.i =  0} },
+	{ MODKEY,               XK_c,           clipcopy,       {.i =  0} },
+	{ MODKEY,               XK_v,           clippaste,      {.i =  0} },
 	{ MODKEY,               XK_k,           kscrollup,      {.i = -1} },
 	{ MODKEY,               XK_j,           kscrolldown,    {.i = -1} },
 };
diff --git a/st.c b/st.c
index 210cd03..ebfd5e0 100644
--- a/st.c
+++ b/st.c
@@ -1870,6 +1870,33 @@ csihandle(void)
 			goto unknown;
 		}
 		break;
+	case 't': /* title stack operations */
+		switch (csiescseq.arg[0]) {
+		case 22: /* pust current title on stack */
+			switch (csiescseq.arg[1]) {
+			case 0:
+			case 1:
+			case 2:
+				xpushtitle();
+				break;
+			default:
+				goto unknown;
+			}
+			break;
+		case 23: /* pop last title from stack */
+			switch (csiescseq.arg[1]) {
+			case 0:
+			case 1:
+			case 2:
+				xsettitle(NULL, 1);
+				break;
+			default:
+				goto unknown;
+			}
+			break;
+		default:
+			goto unknown;
+		}
 	}
 }
 
@@ -1948,7 +1975,7 @@ strhandle(void)
 		switch (par) {
 		case 0:
 			if (narg > 1) {
-				xsettitle(strescseq.args[1]);
+				xsettitle(strescseq.args[1], 0);
 				xseticontitle(strescseq.args[1]);
 			}
 			return;
@@ -1958,7 +1985,7 @@ strhandle(void)
 			return;
 		case 2:
 			if (narg > 1)
-				xsettitle(strescseq.args[1]);
+				xsettitle(strescseq.args[1], 0);
 			return;
 		case 52:
 			if (narg > 2 && allowwindowops) {
@@ -2015,7 +2042,7 @@ strhandle(void)
 		}
 		break;
 	case 'k': /* old title set compatibility */
-		xsettitle(strescseq.args[0]);
+		xsettitle(strescseq.args[0], 0);
 		return;
 	case 'P': /* DCS -- Device Control String */
 	case '_': /* APC -- Application Program Command */
@@ -2440,6 +2467,7 @@ eschandle(uchar ascii)
 		break;
 	case 'c': /* RIS -- Reset to initial state */
 		treset();
+		xfreetitlestack();
 		resettitle();
 		xloadcols();
 		break;
@@ -2734,7 +2762,7 @@ tresize(int col, int row)
 void
 resettitle(void)
 {
-	xsettitle(NULL);
+	xsettitle(NULL, 0);
 }
 
 void
diff --git a/st.info b/st.info
index 8201ad6..aeef606 100644
--- a/st.info
+++ b/st.info
@@ -161,7 +161,7 @@ st-mono| simpleterm monocolor,
 	rin=\E[%p1%dT,
 	ritm=\E[23m,
 	rmacs=\E(B,
-	rmcup=\E[?1049l,
+	rmcup=\E[?1049l\E[23;0;0t,
 	rmir=\E[4l,
 	rmkx=\E[?1l\E>,
 	rmso=\E[27m,
@@ -172,7 +172,7 @@ st-mono| simpleterm monocolor,
 	sitm=\E[3m,
 	sgr0=\E[0m,
 	smacs=\E(0,
-	smcup=\E[?1049h,
+	smcup=\E[?1049h\E[22;0;0t,
 	smir=\E[4h,
 	smkx=\E[?1h\E=,
 	smso=\E[7m,
diff --git a/win.h b/win.h
index 6de960d..2a40aa0 100644
--- a/win.h
+++ b/win.h
@@ -32,7 +32,9 @@ void xloadcols(void);
 int xsetcolorname(int, const char *);
 int xgetcolor(int, unsigned char *, unsigned char *, unsigned char *);
 void xseticontitle(char *);
-void xsettitle(char *);
+void xfreetitlestack(void);
+void xsettitle(char *, int);
+void xpushtitle(void);
 int xsetcursor(int);
 void xsetmode(int, unsigned int);
 void xsetpointermotion(int);
diff --git a/x.c b/x.c
index afa06be..21b5d77 100644
--- a/x.c
+++ b/x.c
@@ -63,6 +63,9 @@ static void ttysend(const Arg *);
 /* config.h for applying patches and the configuration. */
 #include "config.h"
 
+/* size of title stack */
+#define TITLESTACKSIZE 8
+
 /* XEMBED messages */
 #define XEMBED_FOCUS_IN  4
 #define XEMBED_FOCUS_OUT 5
@@ -220,6 +223,8 @@ static DC dc;
 static XWindow xw;
 static XSelection xsel;
 static TermWindow win;
+static int tstki; /* title stack index */
+static char *titlestack[TITLESTACKSIZE]; /* title stack */
 
 /* Font Ring Cache */
 enum {
@@ -1626,10 +1631,30 @@ xseticontitle(char *p)
 }
 
 void
-xsettitle(char *p)
+xfreetitlestack(void)
 {
-	XTextProperty prop;
-	DEFAULT(p, opt_title);
+	for (int i = 0; i < LEN(titlestack); i++) {
+		free(titlestack[i]);
+		titlestack[i] = NULL;
+	}
+}
+
+void
+xsettitle(char *p, int pop)
+{
+ 	XTextProperty prop;
+ 
+	free(titlestack[tstki]);
+	if (pop) {
+		titlestack[tstki] = NULL;
+		tstki = (tstki - 1 + TITLESTACKSIZE) % TITLESTACKSIZE;
+		p = titlestack[tstki] ? titlestack[tstki] : opt_title;
+	} else if (p) {
+		titlestack[tstki] = xstrdup(p);
+	} else {
+		titlestack[tstki] = NULL;
+		p = opt_title;
+	}
 
 	if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
 	                                &prop) != Success)
@@ -1639,6 +1664,16 @@ xsettitle(char *p)
 	XFree(prop.value);
 }
 
+void
+xpushtitle(void)
+{
+	int tstkin = (tstki + 1) % TITLESTACKSIZE;
+
+	free(titlestack[tstkin]);
+	titlestack[tstkin] = titlestack[tstki] ? xstrdup(titlestack[tstki]) : NULL;
+	tstki = tstkin;
+}
+
 int
 xstartdraw(void)
 {

From 71551993eee955e9084ac029107e9b59225944d2 Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Thu, 10 Nov 2022 13:40:39 +0000
Subject: [PATCH 1137/1146] add -p flag to st

---
 st.1 |  7 +++++--
 x.c  | 13 +++++++++++--
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/st.1 b/st.1
index 39120b4..1a81012 100644
--- a/st.1
+++ b/st.1
@@ -3,7 +3,7 @@
 st \- simple terminal
 .SH SYNOPSIS
 .B st
-.RB [ \-aiv ]
+.RB [ \-aivp ]
 .RB [ \-c
 .IR class ]
 .RB [ \-f
@@ -27,7 +27,7 @@ st \- simple terminal
 .RI [ arguments ...]]
 .PP
 .B st
-.RB [ \-aiv ]
+.RB [ \-aivp ]
 .RB [ \-c
 .IR class ]
 .RB [ \-f
@@ -81,6 +81,9 @@ writes all the I/O to
 This feature is useful when recording st sessions. A value of "-" means
 standard output.
 .TP
+.BI \-p
+enters pixel-perfect mode, where -g requests specific pixels instead of characters
+.TP
 .BI \-T " title"
 defines the window title (default 'st').
 .TP
diff --git a/x.c b/x.c
index 21b5d77..f097307 100644
--- a/x.c
+++ b/x.c
@@ -256,6 +256,7 @@ static char *opt_io    = NULL;
 static char *opt_line  = NULL;
 static char *opt_name  = NULL;
 static char *opt_title = NULL;
+static int  opt_pixel  =    0;
 
 static uint buttons; /* bit field of pressed buttons */
 
@@ -1157,8 +1158,13 @@ xinit(int cols, int rows)
 	xloadcols();
 
 	/* adjust fixed window geometry */
-	win.w = 2 * borderpx + cols * win.cw;
-	win.h = 2 * borderpx + rows * win.ch;
+	if(!opt_pixel) {
+		win.w = 2 * borderpx + cols * win.cw;
+		win.h = 2 * borderpx + rows * win.ch;
+	} else {
+		win.w = cols;
+		win.h = rows;
+	}
 	if (xw.gm & XNegative)
 		xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
 	if (xw.gm & YNegative)
@@ -2092,6 +2098,9 @@ main(int argc, char *argv[])
 	case 'o':
 		opt_io = EARGF(usage());
 		break;
+	case 'p':
+		opt_pixel = 1;
+		break;
 	case 'l':
 		opt_line = EARGF(usage());
 		break;

From 3b5f0f2ecc5c53941ac85a853f0127e9e4e639a5 Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Thu, 10 Nov 2022 13:41:42 +0000
Subject: [PATCH 1138/1146] make a proper .gitignore add following files to
 gitignore:   st   st.o   tags   x.o

---
 .gitignore | 4 ++++
 1 file changed, 4 insertions(+)
 create mode 100644 .gitignore

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2065291
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+st
+st.o
+tags
+x.o

From 9766ec500a4c8d9341b67f981bf92f7fd2a7f82c Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Thu, 10 Nov 2022 13:43:06 +0000
Subject: [PATCH 1139/1146] allow selection to disppaear when selected
 elsewhere

---
 x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x.c b/x.c
index f097307..0ecb5fe 100644
--- a/x.c
+++ b/x.c
@@ -208,7 +208,7 @@ static void (*handler[LASTEvent])(XEvent *) = {
  * Uncomment if you want the selection to disappear when you select something
  * different in another window.
  */
-/*	[SelectionClear] = selclear_, */
+	[SelectionClear] = selclear_,
 	[SelectionNotify] = selnotify,
 /*
  * PropertyNotify is only turned on when there is some INCR transfer happening

From 06dd2f8566e3783265cde92e0ed51d55009d8b37 Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Thu, 22 Dec 2022 15:30:55 -0600
Subject: [PATCH 1140/1146] change installation path

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index ddf278a..1df13cb 100644
--- a/config.mk
+++ b/config.mk
@@ -4,7 +4,7 @@ VERSION = 0.8.5
 # Customize below to fit your system
 
 # paths
-PREFIX = /usr/local
+PREFIX = $(HOME)/.local
 MANPREFIX = $(PREFIX)/share/man
 
 X11INC = /usr/X11R6/include

From eebb40fc4968524cc8ef4c3d5323241fdb257446 Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Sat, 4 Feb 2023 15:27:01 -0600
Subject: [PATCH 1141/1146] exit with code of subprocess

---
 st.c | 13 ++++++++++++-
 st.h |  1 +
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index ebfd5e0..bebfa9d 100644
--- a/st.c
+++ b/st.c
@@ -664,6 +664,17 @@ die(const char *errstr, ...)
 	exit(1);
 }
 
+void
+die_err(int err, const char *errstr, ...)
+{
+	va_list ap;
+
+	va_start(ap, errstr);
+	vfprintf(stderr, errstr, ap);
+	va_end(ap);
+	exit(err);
+}
+
 void
 execsh(char *cmd, char **args)
 {
@@ -735,7 +746,7 @@ sigchld(int a)
 	}
 
 	if (WIFEXITED(stat) && WEXITSTATUS(stat))
-		die("child exited with status %d\n", WEXITSTATUS(stat));
+		die_err(WEXITSTATUS(stat), "child exited with status %d\n", WEXITSTATUS(stat));
 	else if (WIFSIGNALED(stat))
 		die("child terminated due to signal %d\n", WTERMSIG(stat));
 	_exit(0);
diff --git a/st.h b/st.h
index ee3bee2..46d1f5d 100644
--- a/st.h
+++ b/st.h
@@ -78,6 +78,7 @@ typedef union {
 } Arg;
 
 void die(const char *, ...);
+void die_error(int err, const char *, ...);
 void redraw(void);
 void draw(void);
 

From 562d6ff6a9198460c1434664ba65edb709067ab4 Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Sun, 2 Apr 2023 12:49:14 -0500
Subject: [PATCH 1142/1146] reverse the zoom controls

---
 config.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config.h b/config.h
index 331607b..029d977 100644
--- a/config.h
+++ b/config.h
@@ -186,8 +186,8 @@ static MouseShortcut mshortcuts[] = {
 static Shortcut shortcuts[] = {
 	/* mask                 keysym          function        argument */
 	{ XK_ANY_MOD,           XK_Break,       sendbreak,      {.i =  0} },
-	{ MODKEY,               XK_h,           zoom,           {.f = +1} },
-	{ MODKEY,               XK_l,           zoom,           {.f = -1} },
+	{ MODKEY,               XK_h,           zoom,           {.f = -1} },
+	{ MODKEY,               XK_l,           zoom,           {.f = +1} },
 	{ MODKEY,               XK_c,           clipcopy,       {.i =  0} },
 	{ MODKEY,               XK_v,           clippaste,      {.i =  0} },
 	{ MODKEY,               XK_k,           kscrollup,      {.i = -1} },

From 6094c5f5dd44fb1890ad080082f54c55b0ec0b98 Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Thu, 14 Mar 2024 07:45:25 -0500
Subject: [PATCH 1143/1146] split color configuration into seperate file

---
 colors.h | 28 ++++++++++++++++++++++++++++
 config.h | 30 +-----------------------------
 2 files changed, 29 insertions(+), 29 deletions(-)
 create mode 100644 colors.h

diff --git a/colors.h b/colors.h
new file mode 100644
index 0000000..25d05b7
--- /dev/null
+++ b/colors.h
@@ -0,0 +1,28 @@
+/* Terminal colors (16 first used in escape sequence) */
+static const char *colorname[] = {
+	/* 8 normal colors */
+	"#161510",
+	"#a32810",
+	"#727a18",
+	"#a37720",
+	"#3d6266",
+	"#7a4955",
+	"#557a55",
+	"#8e8463",
+
+	/* 8 bright colors */
+	"#4c4635",
+	"#cc3214",
+	"#8e991e",
+	"#cc9528",
+	"#4c7b7f",
+	"#995b6b",
+	"#6b996b",
+	"#ccbc8e",
+
+	[255] = 0,
+
+	/* more colors can be added after 255 to use with DefaultXX */
+	"#cccccc",
+	"#555555",
+};
diff --git a/config.h b/config.h
index 029d977..b14cde7 100644
--- a/config.h
+++ b/config.h
@@ -91,35 +91,7 @@ char *termname = "st-256color";
  */
 unsigned int tabspaces = 8;
 
-/* Terminal colors (16 first used in escape sequence) */
-static const char *colorname[] = {
-	/* 8 normal colors */
-	"#161510",
-	"#a32810",
-	"#727a18",
-	"#a37720",
-	"#3d6266",
-	"#7a4955",
-	"#557a55",
-	"#8e8463",
-
-	/* 8 bright colors */
-	"#4c4635",
-	"#cc3214",
-	"#8e991e",
-	"#cc9528",
-	"#4c7b7f",
-	"#995b6b",
-	"#6b996b",
-	"#ccbc8e",
-
-	[255] = 0,
-
-	/* more colors can be added after 255 to use with DefaultXX */
-	"#cccccc",
-	"#555555",
-};
-
+#include <colors.h>
 
 /*
  * Default colors (colorname index)

From bad198ee025c030c4e7b6d4fdf7e11ea1ca89a4e Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Sun, 24 Mar 2024 20:39:08 -0500
Subject: [PATCH 1144/1146] integrate st merge into repo

---
 builds/st.nix      |  5 +----
 builds/st/config.h |  2 +-
 flake.lock         | 51 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/builds/st.nix b/builds/st.nix
index 0121835..fa428cf 100644
--- a/builds/st.nix
+++ b/builds/st.nix
@@ -14,10 +14,7 @@ stdenv.mkDerivation rec {
   pname = "st";
   version = "1.02";
 
-  src = fetchgit {
-    url = "https://git.beepboop.systems/rndusr/st";
-    sha256 = "sha256-zdID1SUnTO/zl90EG8TguBNYYCnrnqFnSLz32kQZbng=";
-  };
+  src = ./st;
 
   nativeBuildInputs = [ pkg-config fontconfig freetype ncurses ];
   buildInputs = [ libX11 libXft ] ++ extraLibs;
diff --git a/builds/st/config.h b/builds/st/config.h
index b14cde7..b1f9552 100644
--- a/builds/st/config.h
+++ b/builds/st/config.h
@@ -91,7 +91,7 @@ char *termname = "st-256color";
  */
 unsigned int tabspaces = 8;
 
-#include <colors.h>
+#include "colors.h"
 
 /*
  * Default colors (colorname index)
diff --git a/flake.lock b/flake.lock
index 02f83f7..dbcef2d 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1,5 +1,21 @@
 {
   "nodes": {
+    "base16-schemes": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1696158499,
+        "narHash": "sha256-5yIHgDTPjoX/3oDEfLSQ0eJZdFL1SaCfb9d6M0RmOTM=",
+        "owner": "tinted-theming",
+        "repo": "base16-schemes",
+        "rev": "a9112eaae86d9dd8ee6bb9445b664fba2f94037a",
+        "type": "github"
+      },
+      "original": {
+        "owner": "tinted-theming",
+        "repo": "base16-schemes",
+        "type": "github"
+      }
+    },
     "blobs": {
       "flake": false,
       "locked": {
@@ -112,6 +128,25 @@
         "type": "github"
       }
     },
+    "nix-colors": {
+      "inputs": {
+        "base16-schemes": "base16-schemes",
+        "nixpkgs-lib": "nixpkgs-lib"
+      },
+      "locked": {
+        "lastModified": 1707825078,
+        "narHash": "sha256-hTfge2J2W+42SZ7VHXkf4kjU+qzFqPeC9k66jAUBMHk=",
+        "owner": "misterio77",
+        "repo": "nix-colors",
+        "rev": "b01f024090d2c4fc3152cd0cf12027a7b8453ba1",
+        "type": "github"
+      },
+      "original": {
+        "owner": "misterio77",
+        "repo": "nix-colors",
+        "type": "github"
+      }
+    },
     "nix-formatter-pack": {
       "inputs": {
         "nixpkgs": [
@@ -224,6 +259,21 @@
         "type": "github"
       }
     },
+    "nixpkgs-lib": {
+      "locked": {
+        "lastModified": 1697935651,
+        "narHash": "sha256-qOfWjQ2JQSQL15KLh6D7xQhx0qgZlYZTYlcEiRuAMMw=",
+        "owner": "nix-community",
+        "repo": "nixpkgs.lib",
+        "rev": "e1e11fdbb01113d85c7f41cada9d2847660e3902",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "repo": "nixpkgs.lib",
+        "type": "github"
+      }
+    },
     "nixpkgs_2": {
       "locked": {
         "lastModified": 1705856552,
@@ -308,6 +358,7 @@
         "firefox-addons": "firefox-addons",
         "home-manager": "home-manager",
         "home-manager-phone": "home-manager-phone",
+        "nix-colors": "nix-colors",
         "nix-on-droid": "nix-on-droid",
         "nixpkgs": "nixpkgs",
         "phone-nixpkgs": "phone-nixpkgs",

From 0d6ba3e72af0fad7bf9995f195aa75acb54ef587 Mon Sep 17 00:00:00 2001
From: randomuser <randomuser@tilde.club>
Date: Sun, 24 Mar 2024 20:42:24 -0500
Subject: [PATCH 1145/1146] change README to reflect licensing change

---
 README.md | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 823ab2d..249ee1b 100644
--- a/README.md
+++ b/README.md
@@ -33,4 +33,7 @@ things to do
 license
 -------
 
-all materials, except `./home/wallpapers/pape.jpg`, is licensed under the GPLv3. the licensing status of `pape.jpg` is unknown.
+all materials, except for:
+	a) `./home/wallpapers/pape.jpg`, which is of unknown licenses, and
+	b) ./builds/st, which is licensed under MIT, persuant to ./builds/st/LICENSE,
+is licensed under the GPLv3.

From 206980aa9815ba81250bef36eac626aa4d651e61 Mon Sep 17 00:00:00 2001
From: rndusr <ryan@beepboop.systems>
Date: Fri, 29 Mar 2024 15:54:34 -0500
Subject: [PATCH 1146/1146] remove roundcube

---
 boxes/netbox/default.nix | 38 +++++++++++++++++++-----------
 flake.lock               | 51 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 14 deletions(-)

diff --git a/boxes/netbox/default.nix b/boxes/netbox/default.nix
index 8bdee39..0cafbc4 100644
--- a/boxes/netbox/default.nix
+++ b/boxes/netbox/default.nix
@@ -187,12 +187,22 @@
     forceSSL = true;
     enableACME = true;
     root = "/var/www/beepboop.systems";
+    locations."/" = {
+      extraConfig = ''
+        if ($request_uri ~ ^/(.*)\.html(\?|$)) {
+          return 302 /$1;
+        }
+        try_files $uri $uri.html $uri/ =404;
+      '';
+    };
   };
 
   services.nginx.virtualHosts."git.beepboop.systems" = {
     forceSSL = true;
     enableACME = true;
-    locations."/".proxyPass = "http://localhost:3001";
+    locations."/" = {
+      proxyPass = "http://localhost:3001";
+    };
   };
 
   services.nginx.virtualHosts."bit.beepboop.systems" = {
@@ -245,19 +255,19 @@
     email = "nickforanick@protonmail.com";
   };
 
-  services.roundcube = {
-    enable = true;
-    # this is the url of the vhost, not necessarily the same as the fqdn of
-    # the mailserver
-    hostName = "cube.beepboop.systems";
-    extraConfig = ''
-      # starttls needed for authentication, so the fqdn required to match
-      # the certificate
-      $config['smtp_server'] = "tls://${config.mailserver.fqdn}";
-      $config['smtp_user'] = "%u";
-      $config['smtp_pass'] = "%p";
-    '';
-  };
+#  services.roundcube = {
+#    enable = true;
+#    # this is the url of the vhost, not necessarily the same as the fqdn of
+#    # the mailserver
+#    hostName = "cube.beepboop.systems";
+#    extraConfig = ''
+#      # starttls needed for authentication, so the fqdn required to match
+#      # the certificate
+#      $config['smtp_server'] = "tls://${config.mailserver.fqdn}";
+#      $config['smtp_user'] = "%u";
+#      $config['smtp_pass'] = "%p";
+#    '';
+#  };
 
   services.nginx.virtualHosts."roundcube.beepboop.systems" = {
     forceSSL = true;
diff --git a/flake.lock b/flake.lock
index 02f83f7..dbcef2d 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1,5 +1,21 @@
 {
   "nodes": {
+    "base16-schemes": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1696158499,
+        "narHash": "sha256-5yIHgDTPjoX/3oDEfLSQ0eJZdFL1SaCfb9d6M0RmOTM=",
+        "owner": "tinted-theming",
+        "repo": "base16-schemes",
+        "rev": "a9112eaae86d9dd8ee6bb9445b664fba2f94037a",
+        "type": "github"
+      },
+      "original": {
+        "owner": "tinted-theming",
+        "repo": "base16-schemes",
+        "type": "github"
+      }
+    },
     "blobs": {
       "flake": false,
       "locked": {
@@ -112,6 +128,25 @@
         "type": "github"
       }
     },
+    "nix-colors": {
+      "inputs": {
+        "base16-schemes": "base16-schemes",
+        "nixpkgs-lib": "nixpkgs-lib"
+      },
+      "locked": {
+        "lastModified": 1707825078,
+        "narHash": "sha256-hTfge2J2W+42SZ7VHXkf4kjU+qzFqPeC9k66jAUBMHk=",
+        "owner": "misterio77",
+        "repo": "nix-colors",
+        "rev": "b01f024090d2c4fc3152cd0cf12027a7b8453ba1",
+        "type": "github"
+      },
+      "original": {
+        "owner": "misterio77",
+        "repo": "nix-colors",
+        "type": "github"
+      }
+    },
     "nix-formatter-pack": {
       "inputs": {
         "nixpkgs": [
@@ -224,6 +259,21 @@
         "type": "github"
       }
     },
+    "nixpkgs-lib": {
+      "locked": {
+        "lastModified": 1697935651,
+        "narHash": "sha256-qOfWjQ2JQSQL15KLh6D7xQhx0qgZlYZTYlcEiRuAMMw=",
+        "owner": "nix-community",
+        "repo": "nixpkgs.lib",
+        "rev": "e1e11fdbb01113d85c7f41cada9d2847660e3902",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "repo": "nixpkgs.lib",
+        "type": "github"
+      }
+    },
     "nixpkgs_2": {
       "locked": {
         "lastModified": 1705856552,
@@ -308,6 +358,7 @@
         "firefox-addons": "firefox-addons",
         "home-manager": "home-manager",
         "home-manager-phone": "home-manager-phone",
+        "nix-colors": "nix-colors",
         "nix-on-droid": "nix-on-droid",
         "nixpkgs": "nixpkgs",
         "phone-nixpkgs": "phone-nixpkgs",