X-Git-Url: https://git.xinqibao.xyz/st.git/blobdiff_plain/6b315558f8095b91988d5b305ed06e082da48889..1fc4afd1e6609732178369c7f17c917204aad4cc:/st.c

diff --git a/st.c b/st.c
index c50a202..3aa8539 100644
--- a/st.c
+++ b/st.c
@@ -76,8 +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 CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x))
+#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))
@@ -90,16 +89,19 @@ char *argv0;
 #define VT102ID "\033[?6c"
 
 enum glyph_attribute {
-	ATTR_NULL      = 0,
-	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_NULL      = 0,
+	ATTR_BOLD      = 1,
+	ATTR_FAINT     = 2,
+	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,
 };
 
 enum cursor_movement {
@@ -180,8 +182,7 @@ typedef unsigned long ulong;
 typedef unsigned short ushort;
 
 typedef XftDraw *Draw;
-typedef XftColor Colour;
-typedef Colormap Colourmap;
+typedef XftColor Color;
 
 typedef struct {
 	char c[UTF_SIZ]; /* character code */
@@ -242,7 +243,7 @@ typedef struct {
 /* Purely graphic info */
 typedef struct {
 	Display *dpy;
-	Colourmap cmap;
+	Colormap cmap;
 	Window win;
 	Drawable buf;
 	Atom xembed, wmdeletewin, netwmname, netwmpid;
@@ -296,8 +297,8 @@ typedef struct {
 	char *clip;
 	Atom xtarget;
 	bool alt;
-	struct timeval tclick1;
-	struct timeval tclick2;
+	struct timespec tclick1;
+	struct timespec tclick2;
 } Selection;
 
 typedef union {
@@ -341,7 +342,7 @@ typedef struct {
 
 /* Drawing Context */
 typedef struct {
-	Colour col[LEN(colorname) < 256 ? 256 : LEN(colorname)];
+	Color col[MAX(LEN(colorname), 256)];
 	Font font, bfont, ifont, ibfont;
 	GC gc;
 } DC;
@@ -393,10 +394,9 @@ 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 tselcs(void);
 static void tdeftran(char);
 static inline bool match(uint, uint);
 static void ttynew(void);
@@ -443,7 +443,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);
@@ -659,9 +659,20 @@ 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) {
-	if(sel.ob.y == sel.oe.y) {
+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 {
@@ -670,6 +681,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
@@ -685,7 +705,8 @@ selected(int x, int y) {
 
 void
 selsnap(int mode, int *x, int *y, int direction) {
-	int i;
+	int newx, newy, xt, yt;
+	Glyph *gp;
 
 	switch(mode) {
 	case SNAP_WORD:
@@ -694,36 +715,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 (newx >= tlinelen(newy))
+				break;
 
-			if(strchr(worddelimiters,
-					term.line[*y][*x+direction].c[0])) {
+			gp = &term.line[newy][newx];
+			if (!(gp->mode & ATTR_WDUMMY) && strchr(worddelimiters, gp->c[0]))
 				break;
-			}
 
-			*x += direction;
+			*x = newx;
+			*y = newy;
 		}
 		break;
 	case SNAP_LINE:
@@ -749,25 +765,13 @@ 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;
 	}
 }
 
 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);
 
@@ -782,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) {
@@ -831,6 +835,8 @@ mousereport(XEvent *e) {
 			/* MODE_MOUSEX10: no button release reporting */
 			if(IS_SET(MODE_MOUSEX10))
 				return;
+			if (button == 64 || button == 65)
+				return;
 		}
 	}
 
@@ -857,10 +863,10 @@ mousereport(XEvent *e) {
 
 void
 bpress(XEvent *e) {
-	struct timeval now;
+	struct timespec now;
 	Mousekey *mk;
 
-	if(IS_SET(MODE_MOUSE)) {
+	if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);
 		return;
 	}
@@ -874,7 +880,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);
@@ -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
@@ -914,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)
@@ -951,7 +957,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';
 
 		/*
@@ -959,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';
 		}
 	}
@@ -1092,7 +1095,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;
 	}
@@ -1115,7 +1118,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;
 	}
@@ -1451,7 +1454,7 @@ selscroll(int orig, int n) {
 				sel.oe.x = term.col;
 			}
 		}
-		selsort();
+		selnormalize();
 	}
 }
 
@@ -1535,7 +1538,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];
 		}
@@ -1631,7 +1634,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 +1651,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 +1666,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]);
@@ -1682,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;
@@ -1698,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;
@@ -1715,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;
@@ -1839,7 +1870,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)
@@ -1853,7 +1884,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;
@@ -2148,10 +2179,10 @@ 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)) {
+			if(xsetcolorname(j, p)) {
 				fprintf(stderr, "erresc: invalid color %s\n", p);
 			} else {
 				/*
@@ -2315,50 +2346,37 @@ techo(char *buf, int 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}
-	};
+	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];
+	} else {
+		term.trantbl[term.icharset] = vcs[p - cs];
+	}
 }
 
 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] = "?";
 
 	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 */
@@ -2374,15 +2392,13 @@ 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;
-		tselcs();
-		break;
+		return;
 	case '\017': /* SI */
 		term.charset = 1;
-		tselcs();
-		break;
+		return;
 	case '\032': /* SUB */
 		tsetchar(question, &term.c.attr, term.c.x, term.c.y);
 	case '\030': /* CAN */
@@ -2393,6 +2409,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 */
@@ -2408,11 +2425,10 @@ tcontrolcode(uchar ascii) {
 	case 0x9e:   /* TODO: PM */
 	case 0x9f:   /* TODO: APC */
 		break;
-	default:
-		return 0;
 	}
+	/* only CAN, SUB, \a and C1 chars interrupt a sequence */
 	term.esc &= ~(ESC_STR_END|ESC_STR);
-	return 1;
+	return;
 }
 
 void
@@ -2461,7 +2477,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);
@@ -2491,8 +2507,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;
@@ -2506,7 +2525,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 {
@@ -2590,11 +2608,6 @@ tputc(char *c, int len) {
 		 */
 		return;
 	}
-	/*
-	 * Display control codes only if we are in graphic mode
-	 */
-	if(control && !(term.c.attr.mode & ATTR_GFX))
-		return;
 	if(sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
 		selclear(NULL);
 
@@ -2731,17 +2744,17 @@ sixd_to_16bit(int x) {
 
 void
 xloadcols(void) {
-	int i, r, g, b;
+	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 colors [0-15] colors 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;
@@ -2750,27 +2763,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++;
-			}
-		}
+	/* 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);
 	}
 
-	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 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;
 }
@@ -2778,33 +2784,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
@@ -2905,6 +2923,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);
@@ -2950,8 +2969,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);
@@ -3006,6 +3025,7 @@ xzoom(const Arg *arg) {
 	xloadfonts(usedfont, usedfontsize + arg->i);
 	cresize(0, 0);
 	redraw(0);
+	xhints();
 }
 
 void
@@ -3120,7 +3140,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;
@@ -3165,24 +3185,20 @@ 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 colors [0-7]
+		 * to bright system colors [8-15]
 		 */
-		font = &dc.bfont;
-		frcflags = FRC_BOLD;
+		if(BETWEEN(base.fg, 0, 7))
+			fg = &dc.col[base.fg + 8];
+
+		if(base.mode & ATTR_ITALIC) {
+			font = &dc.ibfont;
+			frcflags = FRC_ITALICBOLD;
+		} else {
+			font = &dc.bfont;
+			frcflags = FRC_BOLD;
+		}
 	}
 
 	if(IS_SET(MODE_REVERSE)) {
@@ -3220,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,
@@ -3262,28 +3281,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)
@@ -3370,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);
 }
@@ -3455,6 +3473,7 @@ void
 redraw(int timeout) {
 	struct timespec tv = {0, timeout * 1000};
 
+	tfulldirt();
 	draw();
 
 	if(timeout > 0) {
@@ -3730,7 +3749,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) {
@@ -3746,17 +3766,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));
@@ -3773,9 +3791,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) * 1E6;
 		tv = &drawtimeout;
 
 		dodraw = 0;
@@ -3810,9 +3828,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 = (1E6 * \
 							(blinktimeout - \
 							TIMEDIFF(now,
 								lastblink)));