X-Git-Url: https://git.xinqibao.xyz/st.git/blobdiff_plain/41f70a1cff9c5653bebea996728fa76e2507eca3..0e48a1995eee1c2babc58523ef0be296e4b1c3e8:/st.c?ds=inline

diff --git a/st.c b/st.c
index 486735d..f2b3095 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>
@@ -62,26 +63,29 @@ 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 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 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 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)
 
 
 enum glyph_attribute {
@@ -272,7 +276,7 @@ typedef struct {
 	uint b;
 	uint mask;
 	char *s;
-} Mousekey;
+} MouseShortcut;
 
 typedef struct {
 	KeySym k;
@@ -331,6 +335,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"
@@ -411,7 +416,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);
@@ -435,7 +440,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);
@@ -519,14 +523,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;
@@ -559,14 +564,16 @@ ssize_t
 xwrite(int fd, const char *s, size_t len)
 {
 	size_t aux = len;
+	ssize_t r;
 
 	while (len > 0) {
-		ssize_t r = write(fd, s, len);
+		r = write(fd, s, len);
 		if (r < 0)
 			return r;
 		len -= r;
 		s += r;
 	}
+
 	return aux;
 }
 
@@ -620,6 +627,7 @@ utf8decode(char *c, Rune *u, size_t clen)
 		return 0;
 	*u = udecoded;
 	utf8validate(u, len);
+
 	return len;
 }
 
@@ -629,6 +637,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;
 }
 
@@ -640,11 +649,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;
 }
 
@@ -667,6 +678,7 @@ utf8strchr(char *s, Rune u)
 		if (r == u)
 			return &(s[i]);
 	}
+
 	return NULL;
 }
 
@@ -677,15 +689,17 @@ utf8validate(Rune *u, size_t i)
 		*u = UTF_INVALID;
 	for (i = 1; *u > utfmax[i]; ++i)
 		;
+
 	return 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;
@@ -931,17 +945,17 @@ void
 bpress(XEvent *e)
 {
 	struct timespec now;
-	Mousekey *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;
 		}
 	}
@@ -992,7 +1006,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];
@@ -1120,10 +1137,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 */
@@ -1320,9 +1337,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];
@@ -1416,8 +1432,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;
 	}
@@ -1450,7 +1465,7 @@ ttynew(void)
 	}
 }
 
-void
+size_t
 ttyread(void)
 {
 	static char buf[BUFSIZ];
@@ -1475,14 +1490,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.
@@ -1492,37 +1509,32 @@ 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, &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.
 			 */
-			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 < lim)? n : lim)) < 0)
+				goto write_error;
 			if (r < n) {
 				/*
 				 * We weren't able to write out everything.
 				 * This means the buffer is getting full
 				 * again. Empty it.
 				 */
-				ttyread();
+				if (n < lim)
+					lim = ttyread();
 				n -= r;
 				s += r;
 			} else {
@@ -1530,7 +1542,13 @@ ttywrite(const char *s, size_t n)
 				break;
 			}
 		}
+		if (FD_ISSET(cmdfd, &rfd))
+			lim = ttyread();
 	}
+	return;
+
+write_error:
+	die("write error on tty: %s\n", strerror(errno));
 }
 
 void
@@ -2419,15 +2437,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;
 	}
@@ -2568,6 +2586,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)
 {
@@ -2764,18 +2789,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);
@@ -2784,9 +2828,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;
 	}
@@ -2886,15 +2930,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
@@ -3125,6 +3169,7 @@ xloadcolor(int i, const char *name, Color *ncolor)
 		} else
 			name = colorname[i];
 	}
+
 	return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
 }
 
@@ -3164,18 +3209,8 @@ xsetcolorname(int x, const char *name)
 
 	XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
 	dc.col[x] = ncolor;
-	return 0;
-}
 
-void
-xtermclear(int col1, int row1, int col2, int row2)
-{
-	XftDrawRect(xw.draw,
-			&dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
-			borderpx + col1 * xw.cw,
-			borderpx + row1 * xw.ch,
-			(col2-col1+1) * xw.cw,
-			(row2-row1+1) * xw.ch);
+	return 0;
 }
 
 /*
@@ -3192,7 +3227,8 @@ xclear(int x1, int y1, int x2, int y2)
 void
 xhints(void)
 {
-	XClassHint class = {opt_class ? opt_class : termname, termname};
+	XClassHint class = {opt_name ? opt_name : termname,
+	                    opt_class ? opt_class : termname};
 	XWMHints wm = {.flags = InputHint, .input = 1};
 	XSizeHints *sizeh = NULL;
 
@@ -3233,6 +3269,7 @@ xgeommasktogravity(int mask)
 	case YNegative:
 		return SouthWestGravity;
 	}
+
 	return SouthEastGravity;
 }
 
@@ -3241,6 +3278,7 @@ xloadfont(Font *f, FcPattern *pattern)
 {
 	FcPattern *match;
 	FcResult result;
+	XGlyphInfo extents;
 
 	match = FcFontMatch(NULL, pattern, &result);
 	if (!match)
@@ -3251,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);
 
@@ -3260,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;
 }
@@ -3377,6 +3419,7 @@ xzoomabs(const Arg *arg)
 	xunloadfonts();
 	xloadfonts(usedfont, arg->f);
 	cresize(0, 0);
+	ttyresize();
 	redraw();
 	xhints();
 }
@@ -3399,6 +3442,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");
@@ -3422,7 +3466,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;
@@ -3471,11 +3515,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);
@@ -3616,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++;
 	}
@@ -3763,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);
 }
@@ -3772,7 +3828,9 @@ 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;
 
 	LIMIT(oldx, 0, term.col-1);
 	LIMIT(oldy, 0, term.row-1);
@@ -3785,10 +3843,36 @@ xdrawcursor(void)
 	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;
 
-	/* remove the old cursor */
-	xdrawglyph(term.line[oldy][oldx], oldx, oldy);
+	/*
+	 * 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;
@@ -3796,47 +3880,44 @@ 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;
-					}
-
-				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;
+		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, &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);
@@ -3886,7 +3967,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))
@@ -3896,7 +3977,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;
@@ -4122,7 +4202,6 @@ cresize(int width, int height)
 
 	tresize(col, row);
 	xresize(col, row);
-	ttyresize();
 }
 
 void
@@ -4132,6 +4211,7 @@ resize(XEvent *e)
 		return;
 
 	cresize(e->xconfigure.width, e->xconfigure.height);
+	ttyresize();
 }
 
 void
@@ -4148,9 +4228,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;
@@ -4160,8 +4240,9 @@ run(void)
 		}
 	} while (ev.type != MapNotify);
 
-	ttynew();
 	cresize(w, h);
+	ttynew();
+	ttyresize();
 
 	clock_gettime(CLOCK_MONOTONIC, &last);
 	lastblink = last;
@@ -4245,12 +4326,14 @@ run(void)
 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"
-	"       st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
-	"          [-i] [-t title] [-w windowid] [-l line] [stty_args ...]\n",
-	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
@@ -4260,7 +4343,7 @@ main(int argc, char *argv[])
 
 	xw.l = xw.t = 0;
 	xw.isfixed = False;
-	xw.cursor = 0;
+	xw.cursor = cursorshape;
 
 	ARGBEGIN {
 	case 'a':
@@ -4289,13 +4372,19 @@ 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());
 		break;
 	case 'w':
 		opt_embed = EARGF(usage());
 		break;
 	case 'v':
+		die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0);
+		break;
 	default:
 		usage();
 	} ARGEND;
@@ -4316,3 +4405,4 @@ run:
 
 	return 0;
 }
+