From 16bdd970dcc68e50f26c512b3ead628b9b899c88 Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Tue, 20 Jan 2015 08:18:04 +0000
Subject: [PATCH] Support blinking cursor mode, both the xterm CSI ?12 h/l and
 (the backwards) screen CSI 34 h/l. From Guanpeng Xu.

---
 input.c    | 12 ++++++++++++
 tmux.h     |  3 ++-
 tty-term.c |  1 +
 tty.c      | 12 ++++++++----
 4 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/input.c b/input.c
index fcc91180..de11f629 100644
--- a/input.c
+++ b/input.c
@@ -1342,6 +1342,9 @@ input_csi_dispatch_rm(struct input_ctx *ictx)
 		case 4:		/* IRM */
 			screen_write_mode_clear(&ictx->ctx, MODE_INSERT);
 			break;
+		case 34:
+			screen_write_mode_set(&ictx->ctx, MODE_BLINKING);
+			break;
 		default:
 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
 			break;
@@ -1368,6 +1371,9 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
 		case 7:		/* DECAWM */
 			screen_write_mode_clear(&ictx->ctx, MODE_WRAP);
 			break;
+		case 12:
+			screen_write_mode_clear(&ictx->ctx, MODE_BLINKING);
+			break;
 		case 25:	/* TCEM */
 			screen_write_mode_clear(&ictx->ctx, MODE_CURSOR);
 			break;
@@ -1413,6 +1419,9 @@ input_csi_dispatch_sm(struct input_ctx *ictx)
 		case 4:		/* IRM */
 			screen_write_mode_set(&ictx->ctx, MODE_INSERT);
 			break;
+		case 34:
+			screen_write_mode_clear(&ictx->ctx, MODE_BLINKING);
+			break;
 		default:
 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
 			break;
@@ -1439,6 +1448,9 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
 		case 7:		/* DECAWM */
 			screen_write_mode_set(&ictx->ctx, MODE_WRAP);
 			break;
+		case 12:
+			screen_write_mode_set(&ictx->ctx, MODE_BLINKING);
+			break;
 		case 25:	/* TCEM */
 			screen_write_mode_set(&ictx->ctx, MODE_CURSOR);
 			break;
diff --git a/tmux.h b/tmux.h
index aff664c0..c73b59ca 100644
--- a/tmux.h
+++ b/tmux.h
@@ -175,6 +175,7 @@ enum tty_code_code {
 	TTYC_CUP,	/* cursor_address, cm */
 	TTYC_CUU,	/* parm_up_cursor, UP */
 	TTYC_CUU1,	/* cursor_up, up */
+	TTYC_CVVIS,	/* cursor_visible, vs */
 	TTYC_DCH,	/* parm_dch, DC */
 	TTYC_DCH1,	/* delete_character, dc */
 	TTYC_DIM,	/* enter_dim_mode, mh */
@@ -600,7 +601,7 @@ struct mode_key_table {
 #define MODE_WRAP 0x10		/* whether lines wrap */
 #define MODE_MOUSE_STANDARD 0x20
 #define MODE_MOUSE_BUTTON 0x40
-/* 0x80 unused */
+#define MODE_BLINKING 0x80
 #define MODE_MOUSE_UTF8 0x100
 #define MODE_MOUSE_SGR 0x200
 #define MODE_BRACKETPASTE 0x400
diff --git a/tty-term.c b/tty-term.c
index f866a2d8..c8a6ba8b 100644
--- a/tty-term.c
+++ b/tty-term.c
@@ -54,6 +54,7 @@ const struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
 	{ TTYC_CUP, TTYCODE_STRING, "cup" },
 	{ TTYC_CUU, TTYCODE_STRING, "cuu" },
 	{ TTYC_CUU1, TTYCODE_STRING, "cuu1" },
+	{ TTYC_CVVIS, TTYCODE_STRING, "cvvis" },
 	{ TTYC_DCH, TTYCODE_STRING, "dch" },
 	{ TTYC_DCH1, TTYCODE_STRING, "dch1" },
 	{ TTYC_DIM, TTYCODE_STRING, "dim" },
diff --git a/tty.c b/tty.c
index 9f57c365..2ff2fccc 100644
--- a/tty.c
+++ b/tty.c
@@ -482,10 +482,14 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
 		mode &= ~MODE_CURSOR;
 
 	changed = mode ^ tty->mode;
-	if (changed & MODE_CURSOR) {
-		if (mode & MODE_CURSOR)
-			tty_putcode(tty, TTYC_CNORM);
-		else
+	if (changed & (MODE_CURSOR|MODE_BLINKING)) {
+		if (mode & MODE_CURSOR) {
+			if (mode & MODE_BLINKING &&
+			    tty_term_has(tty->term, TTYC_CVVIS))
+				tty_putcode(tty, TTYC_CVVIS);
+			else
+				tty_putcode(tty, TTYC_CNORM);
+		} else
 			tty_putcode(tty, TTYC_CIVIS);
 	}
 	if (tty->cstyle != s->cstyle) {