mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	Support for extended underline styles on terminals which offer them,
enabled by adding the Smulx capability with terminal-overrides (add something like ',vte*:Smulx=\E[4\:%p1%dm'). GitHub issue 1492.
This commit is contained in:
		
							
								
								
									
										56
									
								
								attributes.c
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								attributes.c
									
									
									
									
									
								
							@@ -25,13 +25,13 @@
 | 
			
		||||
const char *
 | 
			
		||||
attributes_tostring(int attr)
 | 
			
		||||
{
 | 
			
		||||
	static char	buf[128];
 | 
			
		||||
	static char	buf[512];
 | 
			
		||||
	size_t		len;
 | 
			
		||||
 | 
			
		||||
	if (attr == 0)
 | 
			
		||||
		return ("none");
 | 
			
		||||
 | 
			
		||||
	len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s",
 | 
			
		||||
	len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s",
 | 
			
		||||
	    (attr & GRID_ATTR_BRIGHT) ? "bright," : "",
 | 
			
		||||
	    (attr & GRID_ATTR_DIM) ? "dim," : "",
 | 
			
		||||
	    (attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "",
 | 
			
		||||
@@ -39,7 +39,11 @@ attributes_tostring(int attr)
 | 
			
		||||
	    (attr & GRID_ATTR_REVERSE) ? "reverse," : "",
 | 
			
		||||
	    (attr & GRID_ATTR_HIDDEN) ? "hidden," : "",
 | 
			
		||||
	    (attr & GRID_ATTR_ITALICS) ? "italics," : "",
 | 
			
		||||
	    (attr & GRID_ATTR_STRIKETHROUGH) ? "strikethrough," : "");
 | 
			
		||||
	    (attr & GRID_ATTR_STRIKETHROUGH) ? "strikethrough," : "",
 | 
			
		||||
	    (attr & GRID_ATTR_UNDERSCORE_2) ? "double-underscore," : "",
 | 
			
		||||
	    (attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "",
 | 
			
		||||
	    (attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "",
 | 
			
		||||
	    (attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "");
 | 
			
		||||
	if (len > 0)
 | 
			
		||||
		buf[len - 1] = '\0';
 | 
			
		||||
 | 
			
		||||
@@ -52,6 +56,25 @@ attributes_fromstring(const char *str)
 | 
			
		||||
	const char	delimiters[] = " ,|";
 | 
			
		||||
	int		attr;
 | 
			
		||||
	size_t		end;
 | 
			
		||||
	u_int		i;
 | 
			
		||||
	struct {
 | 
			
		||||
		const char*	name;
 | 
			
		||||
		int		attr;
 | 
			
		||||
	} table[] = {
 | 
			
		||||
		{ "bright", GRID_ATTR_BRIGHT },
 | 
			
		||||
		{ "bold", GRID_ATTR_BRIGHT },
 | 
			
		||||
		{ "dim", GRID_ATTR_DIM },
 | 
			
		||||
		{ "underscore", GRID_ATTR_UNDERSCORE },
 | 
			
		||||
		{ "blink", GRID_ATTR_BLINK },
 | 
			
		||||
		{ "reverse", GRID_ATTR_REVERSE },
 | 
			
		||||
		{ "hidden", GRID_ATTR_HIDDEN },
 | 
			
		||||
		{ "italics", GRID_ATTR_ITALICS },
 | 
			
		||||
		{ "strikethrough", GRID_ATTR_STRIKETHROUGH },
 | 
			
		||||
		{ "double-underscore", GRID_ATTR_UNDERSCORE_2 },
 | 
			
		||||
		{ "curly-underscore", GRID_ATTR_UNDERSCORE_3 },
 | 
			
		||||
		{ "dotted-underscore", GRID_ATTR_UNDERSCORE_4 },
 | 
			
		||||
		{ "dashed-underscore", GRID_ATTR_UNDERSCORE_5 }
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	if (*str == '\0' || strcspn(str, delimiters) == 0)
 | 
			
		||||
		return (-1);
 | 
			
		||||
@@ -64,24 +87,15 @@ attributes_fromstring(const char *str)
 | 
			
		||||
	attr = 0;
 | 
			
		||||
	do {
 | 
			
		||||
		end = strcspn(str, delimiters);
 | 
			
		||||
		if ((end == 6 && strncasecmp(str, "bright", end) == 0) ||
 | 
			
		||||
		    (end == 4 && strncasecmp(str, "bold", end) == 0))
 | 
			
		||||
			attr |= GRID_ATTR_BRIGHT;
 | 
			
		||||
		else if (end == 3 && strncasecmp(str, "dim", end) == 0)
 | 
			
		||||
			attr |= GRID_ATTR_DIM;
 | 
			
		||||
		else if (end == 10 && strncasecmp(str, "underscore", end) == 0)
 | 
			
		||||
			attr |= GRID_ATTR_UNDERSCORE;
 | 
			
		||||
		else if (end == 5 && strncasecmp(str, "blink", end) == 0)
 | 
			
		||||
			attr |= GRID_ATTR_BLINK;
 | 
			
		||||
		else if (end == 7 && strncasecmp(str, "reverse", end) == 0)
 | 
			
		||||
			attr |= GRID_ATTR_REVERSE;
 | 
			
		||||
		else if (end == 6 && strncasecmp(str, "hidden", end) == 0)
 | 
			
		||||
			attr |= GRID_ATTR_HIDDEN;
 | 
			
		||||
		else if (end == 7 && strncasecmp(str, "italics", end) == 0)
 | 
			
		||||
			attr |= GRID_ATTR_ITALICS;
 | 
			
		||||
		else if (end == 13 && strncasecmp(str, "strikethrough", end) == 0)
 | 
			
		||||
			attr |= GRID_ATTR_STRIKETHROUGH;
 | 
			
		||||
		else
 | 
			
		||||
		for (i = 0; i < nitems(table); i++) {
 | 
			
		||||
			if (end != strlen(table[i].name))
 | 
			
		||||
				continue;
 | 
			
		||||
			if (strncasecmp(str, table[i].name, end) == 0) {
 | 
			
		||||
				attr |= table[i].attr;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (i == nitems(table))
 | 
			
		||||
			return (-1);
 | 
			
		||||
		str += end + strspn(str + end, delimiters);
 | 
			
		||||
	} while (*str != '\0');
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								grid.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								grid.c
									
									
									
									
									
								
							@@ -764,7 +764,11 @@ grid_string_cells_code(const struct grid_cell *lastgc,
 | 
			
		||||
		{ GRID_ATTR_BLINK, 5 },
 | 
			
		||||
		{ GRID_ATTR_REVERSE, 7 },
 | 
			
		||||
		{ GRID_ATTR_HIDDEN, 8 },
 | 
			
		||||
		{ GRID_ATTR_STRIKETHROUGH, 9 }
 | 
			
		||||
		{ GRID_ATTR_STRIKETHROUGH, 9 },
 | 
			
		||||
		{ GRID_ATTR_UNDERSCORE_2, 42 },
 | 
			
		||||
		{ GRID_ATTR_UNDERSCORE_3, 43 },
 | 
			
		||||
		{ GRID_ATTR_UNDERSCORE_4, 44 },
 | 
			
		||||
		{ GRID_ATTR_UNDERSCORE_5, 45 },
 | 
			
		||||
	};
 | 
			
		||||
	n = 0;
 | 
			
		||||
 | 
			
		||||
@@ -790,11 +794,15 @@ grid_string_cells_code(const struct grid_cell *lastgc,
 | 
			
		||||
		else
 | 
			
		||||
			strlcat(buf, "\033[", len);
 | 
			
		||||
		for (i = 0; i < n; i++) {
 | 
			
		||||
			if (i + 1 < n)
 | 
			
		||||
				xsnprintf(tmp, sizeof tmp, "%d;", s[i]);
 | 
			
		||||
			else
 | 
			
		||||
			if (s[i] < 10)
 | 
			
		||||
				xsnprintf(tmp, sizeof tmp, "%d", s[i]);
 | 
			
		||||
			else {
 | 
			
		||||
				xsnprintf(tmp, sizeof tmp, "%d:%d", s[i] / 10,
 | 
			
		||||
				    s[i] % 10);
 | 
			
		||||
			}
 | 
			
		||||
			strlcat(buf, tmp, len);
 | 
			
		||||
			if (i + 1 < n)
 | 
			
		||||
				strlcat(buf, ";", len);
 | 
			
		||||
		}
 | 
			
		||||
		strlcat(buf, "m", len);
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								input.c
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								input.c
									
									
									
									
									
								
							@@ -1835,10 +1835,11 @@ input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
 | 
			
		||||
static void
 | 
			
		||||
input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
 | 
			
		||||
{
 | 
			
		||||
	char		*s = ictx->param_list[i].str, *copy, *ptr, *out;
 | 
			
		||||
	int		 p[8];
 | 
			
		||||
	u_int		 n;
 | 
			
		||||
	const char	*errstr;
 | 
			
		||||
	struct grid_cell	*gc = &ictx->cell.cell;
 | 
			
		||||
	char			*s = ictx->param_list[i].str, *copy, *ptr, *out;
 | 
			
		||||
	int			 p[8];
 | 
			
		||||
	u_int			 n;
 | 
			
		||||
	const char		*errstr;
 | 
			
		||||
 | 
			
		||||
	for (n = 0; n < nitems(p); n++)
 | 
			
		||||
		p[n] = -1;
 | 
			
		||||
@@ -1857,7 +1858,39 @@ input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
 | 
			
		||||
	}
 | 
			
		||||
	free(copy);
 | 
			
		||||
 | 
			
		||||
	if (n == 0 || (p[0] != 38 && p[0] != 48))
 | 
			
		||||
	if (n == 0)
 | 
			
		||||
		return;
 | 
			
		||||
	if (p[0] == 4) {
 | 
			
		||||
		if (n != 2)
 | 
			
		||||
			return;
 | 
			
		||||
		switch (p[1]) {
 | 
			
		||||
		case 0:
 | 
			
		||||
			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
 | 
			
		||||
			break;
 | 
			
		||||
		case 1:
 | 
			
		||||
			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
 | 
			
		||||
			gc->attr |= GRID_ATTR_UNDERSCORE;
 | 
			
		||||
			break;
 | 
			
		||||
		case 2:
 | 
			
		||||
			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
 | 
			
		||||
			gc->attr |= GRID_ATTR_UNDERSCORE_2;
 | 
			
		||||
			break;
 | 
			
		||||
		case 3:
 | 
			
		||||
			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
 | 
			
		||||
			gc->attr |= GRID_ATTR_UNDERSCORE_3;
 | 
			
		||||
			break;
 | 
			
		||||
		case 4:
 | 
			
		||||
			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
 | 
			
		||||
			gc->attr |= GRID_ATTR_UNDERSCORE_4;
 | 
			
		||||
			break;
 | 
			
		||||
		case 5:
 | 
			
		||||
			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
 | 
			
		||||
			gc->attr |= GRID_ATTR_UNDERSCORE_5;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if (p[0] != 38 && p[0] != 48)
 | 
			
		||||
		return;
 | 
			
		||||
	if (p[1] == -1)
 | 
			
		||||
		i = 2;
 | 
			
		||||
@@ -1927,6 +1960,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
 | 
			
		||||
			gc->attr |= GRID_ATTR_ITALICS;
 | 
			
		||||
			break;
 | 
			
		||||
		case 4:
 | 
			
		||||
			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
 | 
			
		||||
			gc->attr |= GRID_ATTR_UNDERSCORE;
 | 
			
		||||
			break;
 | 
			
		||||
		case 5:
 | 
			
		||||
@@ -1948,7 +1982,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
 | 
			
		||||
			gc->attr &= ~GRID_ATTR_ITALICS;
 | 
			
		||||
			break;
 | 
			
		||||
		case 24:
 | 
			
		||||
			gc->attr &= ~GRID_ATTR_UNDERSCORE;
 | 
			
		||||
			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
 | 
			
		||||
			break;
 | 
			
		||||
		case 25:
 | 
			
		||||
			gc->attr &= ~GRID_ATTR_BLINK;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								tmux.1
									
									
									
									
									
								
							@@ -2769,8 +2769,12 @@ or a comma-delimited list of one or more of:
 | 
			
		||||
.Ic reverse ,
 | 
			
		||||
.Ic hidden ,
 | 
			
		||||
.Ic italics ,
 | 
			
		||||
.Ic strikethrough ,
 | 
			
		||||
.Ic double-underscore
 | 
			
		||||
.Ic curly-underscore
 | 
			
		||||
.Ic dotted-underscore
 | 
			
		||||
or
 | 
			
		||||
.Ic strikethrough
 | 
			
		||||
.Ic dashed-underscore
 | 
			
		||||
to turn an attribute on, or an attribute prefixed with
 | 
			
		||||
.Ql no
 | 
			
		||||
to turn one off.
 | 
			
		||||
@@ -4419,6 +4423,11 @@ to change the cursor colour from inside
 | 
			
		||||
.Bd -literal -offset indent
 | 
			
		||||
$ printf '\e033]12;red\e033\e\e'
 | 
			
		||||
.Ed
 | 
			
		||||
.It Em \&Smulx
 | 
			
		||||
Set a styled underline.
 | 
			
		||||
The single parameter is one of: 0 for no underline, 1 for normal
 | 
			
		||||
underline, 2 for double underline, 3 for curly underline, 4 for dotted
 | 
			
		||||
underline and 5 for dashed underline.
 | 
			
		||||
.It Em \&Ss , Se
 | 
			
		||||
Set or reset the cursor style.
 | 
			
		||||
If set, a sequence such as this may be used
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								tmux.h
									
									
									
									
									
								
							@@ -421,6 +421,7 @@ enum tty_code_code {
 | 
			
		||||
	TTYC_SMCUP,
 | 
			
		||||
	TTYC_SMKX,
 | 
			
		||||
	TTYC_SMSO,
 | 
			
		||||
	TTYC_SMULX,
 | 
			
		||||
	TTYC_SMUL,
 | 
			
		||||
	TTYC_SMXX,
 | 
			
		||||
	TTYC_SS,
 | 
			
		||||
@@ -546,6 +547,18 @@ enum utf8_state {
 | 
			
		||||
#define GRID_ATTR_ITALICS 0x40
 | 
			
		||||
#define GRID_ATTR_CHARSET 0x80	/* alternative character set */
 | 
			
		||||
#define GRID_ATTR_STRIKETHROUGH 0x100
 | 
			
		||||
#define GRID_ATTR_UNDERSCORE_2 0x200
 | 
			
		||||
#define GRID_ATTR_UNDERSCORE_3 0x400
 | 
			
		||||
#define GRID_ATTR_UNDERSCORE_4 0x800
 | 
			
		||||
#define GRID_ATTR_UNDERSCORE_5 0x1000
 | 
			
		||||
 | 
			
		||||
/* All underscore attributes. */
 | 
			
		||||
#define GRID_ATTR_ALL_UNDERSCORE \
 | 
			
		||||
	(GRID_ATTR_UNDERSCORE|	 \
 | 
			
		||||
	 GRID_ATTR_UNDERSCORE_2| \
 | 
			
		||||
	 GRID_ATTR_UNDERSCORE_3| \
 | 
			
		||||
	 GRID_ATTR_UNDERSCORE_4| \
 | 
			
		||||
	 GRID_ATTR_UNDERSCORE_5)
 | 
			
		||||
 | 
			
		||||
/* Grid flags. */
 | 
			
		||||
#define GRID_FLAG_FG256 0x1
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								tty-term.c
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								tty-term.c
									
									
									
									
									
								
							@@ -253,6 +253,7 @@ static const struct tty_term_code_entry tty_term_codes[] = {
 | 
			
		||||
	[TTYC_SMCUP] = { TTYCODE_STRING, "smcup" },
 | 
			
		||||
	[TTYC_SMKX] = { TTYCODE_STRING, "smkx" },
 | 
			
		||||
	[TTYC_SMSO] = { TTYCODE_STRING, "smso" },
 | 
			
		||||
	[TTYC_SMULX] = { TTYCODE_STRING, "Smulx" },
 | 
			
		||||
	[TTYC_SMUL] = { TTYCODE_STRING, "smul" },
 | 
			
		||||
	[TTYC_SMXX] =  { TTYCODE_STRING, "smxx" },
 | 
			
		||||
	[TTYC_SS] = { TTYCODE_STRING, "Ss" },
 | 
			
		||||
@@ -299,25 +300,53 @@ tty_term_strip(const char *s)
 | 
			
		||||
	return (xstrdup(buf));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
tty_term_override_next(const char *s, size_t *offset)
 | 
			
		||||
{
 | 
			
		||||
	static char	value[BUFSIZ];
 | 
			
		||||
	size_t		n = 0, at = *offset;
 | 
			
		||||
 | 
			
		||||
	if (s[at] == '\0')
 | 
			
		||||
		return (NULL);
 | 
			
		||||
 | 
			
		||||
	while (s[at] != '\0') {
 | 
			
		||||
		if (s[at] == ':') {
 | 
			
		||||
			if (s[at + 1] == ':') {
 | 
			
		||||
				value[n++] = ':';
 | 
			
		||||
				at += 2;
 | 
			
		||||
			} else
 | 
			
		||||
				break;
 | 
			
		||||
		} else {
 | 
			
		||||
			value[n++] = s[at];
 | 
			
		||||
			at++;
 | 
			
		||||
		}
 | 
			
		||||
		if (n == (sizeof value) - 1)
 | 
			
		||||
			return (NULL);
 | 
			
		||||
	}
 | 
			
		||||
	if (s[at] != '\0')
 | 
			
		||||
		*offset = at + 1;
 | 
			
		||||
	else
 | 
			
		||||
		*offset = at;
 | 
			
		||||
	value[n] = '\0';
 | 
			
		||||
	return (value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
tty_term_override(struct tty_term *term, const char *override)
 | 
			
		||||
{
 | 
			
		||||
	const struct tty_term_code_entry	*ent;
 | 
			
		||||
	struct tty_code				*code;
 | 
			
		||||
	char					*next, *s, *copy, *cp, *value;
 | 
			
		||||
	size_t                                   offset = 0;
 | 
			
		||||
	char					*cp, *value, *s;
 | 
			
		||||
	const char				*errstr;
 | 
			
		||||
	u_int					 i;
 | 
			
		||||
	int					 n, remove;
 | 
			
		||||
 | 
			
		||||
	copy = next = xstrdup(override);
 | 
			
		||||
 | 
			
		||||
	s = strsep(&next, ":");
 | 
			
		||||
	if (s == NULL || next == NULL || fnmatch(s, term->name, 0) != 0) {
 | 
			
		||||
		free(copy);
 | 
			
		||||
	s = tty_term_override_next(override, &offset);
 | 
			
		||||
	if (s == NULL || fnmatch(s, term->name, 0) != 0)
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while ((s = strsep(&next, ":")) != NULL) {
 | 
			
		||||
	while ((s = tty_term_override_next(override, &offset)) != NULL) {
 | 
			
		||||
		if (*s == '\0')
 | 
			
		||||
			continue;
 | 
			
		||||
		value = NULL;
 | 
			
		||||
@@ -338,6 +367,8 @@ tty_term_override(struct tty_term *term, const char *override)
 | 
			
		||||
 | 
			
		||||
		if (remove)
 | 
			
		||||
			log_debug("%s override: %s@", term->name, s);
 | 
			
		||||
		else if (*value == '\0')
 | 
			
		||||
			log_debug("%s override: %s", term->name, s);
 | 
			
		||||
		else
 | 
			
		||||
			log_debug("%s override: %s=%s", term->name, s, value);
 | 
			
		||||
 | 
			
		||||
@@ -376,7 +407,6 @@ tty_term_override(struct tty_term *term, const char *override)
 | 
			
		||||
 | 
			
		||||
		free(value);
 | 
			
		||||
	}
 | 
			
		||||
	free(s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct tty_term *
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								tty.c
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								tty.c
									
									
									
									
									
								
							@@ -1832,8 +1832,19 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc,
 | 
			
		||||
		tty_putcode(tty, TTYC_DIM);
 | 
			
		||||
	if (changed & GRID_ATTR_ITALICS)
 | 
			
		||||
		tty_set_italics(tty);
 | 
			
		||||
	if (changed & GRID_ATTR_UNDERSCORE)
 | 
			
		||||
		tty_putcode(tty, TTYC_SMUL);
 | 
			
		||||
	if (changed & GRID_ATTR_ALL_UNDERSCORE) {
 | 
			
		||||
		if ((changed & GRID_ATTR_UNDERSCORE) ||
 | 
			
		||||
		    !tty_term_has(tty->term, TTYC_SMULX))
 | 
			
		||||
			tty_putcode(tty, TTYC_SMUL);
 | 
			
		||||
		else if (changed & GRID_ATTR_UNDERSCORE_2)
 | 
			
		||||
			tty_putcode1(tty, TTYC_SMULX, 2);
 | 
			
		||||
		else if (changed & GRID_ATTR_UNDERSCORE_3)
 | 
			
		||||
			tty_putcode1(tty, TTYC_SMULX, 3);
 | 
			
		||||
		else if (changed & GRID_ATTR_UNDERSCORE_4)
 | 
			
		||||
			tty_putcode1(tty, TTYC_SMULX, 4);
 | 
			
		||||
		else if (changed & GRID_ATTR_UNDERSCORE_5)
 | 
			
		||||
			tty_putcode1(tty, TTYC_SMULX, 5);
 | 
			
		||||
	}
 | 
			
		||||
	if (changed & GRID_ATTR_BLINK)
 | 
			
		||||
		tty_putcode(tty, TTYC_BLINK);
 | 
			
		||||
	if (changed & GRID_ATTR_REVERSE) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user