commit e705380171b86c93719d3ea8b2db7c23fa106c54
Author: Sean Estabrooks <seanlkml@sympatico.ca>
Date:   Sun Mar 13 18:12:05 2011 -0700

    Handle per-screen changes to the cursor colour.
    
    You can set different cursor colours per screen or
    application.  For example, in the Vim editor the
    cursor colour can change when you're in insert mode.
    
    If your terminal type has "xterm" in its name when
    Tmux starts up, everything should work transparently
    with no more configuration (unless your terminal
    doesn't handle these extended control codes).
    
    However, your applications may require some setup to
    send proper escape codes. For example, the sequence
    "\033]12;red\007" to set the cursor colour red, and
    "\033]112\007" to restore the default cursor colour.
    
    Tmux accepts these xterm cursor-colour sequences and
    passes them through to the underlying terminal when
    it's an xterm. Unless you do further configuration,
    these codes are silently ignored for all other
    terminal types.
    
    To accommodate other terminals, you may define two
    Tmux specific terminfo variables. They must both
    be defined:
    
       tmuxscc: set_cursor_colour
    	 - the desired colour is extracted from the
    	   application and passed as a parameter
    
       tmuxecc: end_cursor_colour
    	 - return the cursor to the default colour
    
    Your applications must send standard xterm-like
    escape sequences, and tmux will translate them
    to the codes given in the variables above.
    
    The xterm sequences contain the requested colour
    which is extracted and passed as a parameter to
    tmuxscc. Use "%p1%s" to embed it in the escape
    sequence for your terminal.  For example:
    
     tmuxscc=\E[%p1%sJ -> \E[redJ, \E[blueJ, etc
    
    You can add tmuxecc/tmuxscc via an option in your
    tmux.conf file to avoid altering the actual terminfo
    database. For example, for a terminal type "console"
    that recognizes standard xterm codes, you could:
    
     set-option -g terminal-overrides
      "console:tmuxscc=\\E]12;%p1%s\\007:tmuxecc=\\E]112\\007"

diff --git a/input.c b/input.c
index 6e36c77..b2d5eeb 100644
--- a/input.c
+++ b/input.c
@@ -1445,17 +1445,36 @@ input_enter_osc(struct input_ctx *ictx)
 void
 input_exit_osc(struct input_ctx *ictx)
 {
-	if (ictx->flags & INPUT_DISCARD)
-		return;
-	log_debug("%s: \"%s\"", __func__, ictx->input_buf);
+	int option = 0;
+	u_char *p = ictx->input_buf;
 
-	if (ictx->input_len < 2 || ictx->input_buf[1] != ';')
+	if (ictx->flags & INPUT_DISCARD)
 		return;
-	if (ictx->input_buf[0] != '0' && ictx->input_buf[0] != '2')
+	if (ictx->input_len < 1 || *p < '0' || *p > '9')
 		return;
 
-	screen_set_title(ictx->ctx.s, ictx->input_buf + 2);
-	server_status_window(ictx->wp->window);
+	log_debug("%s: \"%s\"", __func__, p);
+
+	while (*p >= '0' && *p <= '9')
+		option = option * 10 + *p++ - '0';
+
+	if (*p == ';')
+		++p;
+
+	switch (option) {
+	case 0:
+	case 2:
+		screen_set_title(ictx->ctx.s, p);
+		server_status_window(ictx->wp->window);
+		break;
+	case 12:
+	case 112:
+		screen_set_cursor_colour(ictx->ctx.s, p);
+		break;
+	default:
+		log_debug("%s: unknown '%u'", __func__, option);
+		break;
+	}
 }
 
 /* APC string started. */
diff --git a/screen.c b/screen.c
index a3261c0..d3aa957 100644
--- a/screen.c
+++ b/screen.c
@@ -41,6 +41,7 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
 	else
 		s->title = xstrdup("");
 
+	s->ccolour = xstrdup("");
 	s->tabs = NULL;
 
 	screen_reinit(s);
@@ -72,6 +73,7 @@ screen_free(struct screen *s)
 	if (s->tabs != NULL)
 		xfree(s->tabs);
 	xfree(s->title);
+	xfree(s->ccolour);
 	grid_destroy(s->grid);
 }
 
@@ -90,6 +92,14 @@ screen_reset_tabs(struct screen *s)
 		bit_set(s->tabs, i);
 }
 
+/* Set screen cursor colour. */
+void
+screen_set_cursor_colour(struct screen *s, const char *colour_string)
+{
+	xfree(s->ccolour);
+	s->ccolour = xstrdup(colour_string);
+}
+
 /* Set screen title. */
 void
 screen_set_title(struct screen *s, const char *title)
diff --git a/server-client.c b/server-client.c
index d38e312..9a192d4 100644
--- a/server-client.c
+++ b/server-client.c
@@ -472,7 +472,7 @@ server_client_reset_state(struct client *c)
 		mode &= ~MODE_MOUSE_UTF8;
 
 	/* Set the terminal mode and reset attributes. */
-	tty_update_mode(&c->tty, mode);
+	tty_update_mode(&c->tty, mode, s->ccolour);
 	tty_reset(&c->tty);
 }
 
diff --git a/tmux.h b/tmux.h
index 49e2d97..065b1ea 100644
--- a/tmux.h
+++ b/tmux.h
@@ -321,8 +321,10 @@ enum tty_code_code {
 	TTYC_SMUL,	/* enter_underline_mode, us */
 	TTYC_VPA,	/* row_address, cv */
 	TTYC_XENL,	/* eat_newline_glitch, xn */
+	TTYC_TMUX_SCC,	/* start colour cursor, tmuxscc */
+	TTYC_TMUX_ECC,	/* end colour coursor, tmuxecc */
 };
-#define NTTYCODE (TTYC_XENL + 1)
+#define NTTYCODE (TTYC_TMUX_ECC + 1)
 
 /* Termcap types. */
 enum tty_code_type {
@@ -700,6 +702,7 @@ struct screen {
 
 	u_int		 cx;		/* cursor x */
 	u_int		 cy;		/* cursor y */
+	char		*ccolour;	/* cursor colour string */
 
 	u_int		 rupper;	/* scroll region top */
 	u_int		 rlower;	/* scroll region bottom */
@@ -991,6 +994,7 @@ struct tty {
 
 	u_int		 cx;
 	u_int		 cy;
+	char *		 ccolour;
 
 	int		 mode;
 
@@ -1391,6 +1395,7 @@ void	tty_cursor(struct tty *, u_int, u_int);
 void	tty_putcode(struct tty *, enum tty_code_code);
 void	tty_putcode1(struct tty *, enum tty_code_code, int);
 void	tty_putcode2(struct tty *, enum tty_code_code, int, int);
+void	tty_putcode_uchar1(struct tty *, enum tty_code_code, const u_char *);
 void	tty_puts(struct tty *, const char *);
 void	tty_putc(struct tty *, u_char);
 void	tty_pututf8(struct tty *, const struct grid_utf8 *);
@@ -1399,7 +1404,8 @@ int	tty_resize(struct tty *);
 void	tty_start_tty(struct tty *);
 void	tty_stop_tty(struct tty *);
 void	tty_set_title(struct tty *, const char *);
-void	tty_update_mode(struct tty *, int);
+void	tty_update_mode(struct tty *, int, const char *);
+void	tty_force_cursor_colour(struct tty *, const char *);
 void	tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int);
 int	tty_open(struct tty *, const char *, char **);
 void	tty_close(struct tty *);
@@ -1433,6 +1439,8 @@ const char	*tty_term_string(struct tty_term *, enum tty_code_code);
 const char	*tty_term_string1(struct tty_term *, enum tty_code_code, int);
 const char	*tty_term_string2(
 		     struct tty_term *, enum tty_code_code, int, int);
+const char	*tty_term_uchar1(
+		     struct tty_term *, enum tty_code_code, const u_char *);
 int		 tty_term_number(struct tty_term *, enum tty_code_code);
 int		 tty_term_flag(struct tty_term *, enum tty_code_code);
 
@@ -1811,6 +1819,7 @@ void	 screen_init(struct screen *, u_int, u_int, u_int);
 void	 screen_reinit(struct screen *);
 void	 screen_free(struct screen *);
 void	 screen_reset_tabs(struct screen *);
+void	 screen_set_cursor_colour(struct screen *, const char *);
 void	 screen_set_title(struct screen *, const char *);
 void	 screen_resize(struct screen *, u_int, u_int);
 void	 screen_set_selection(struct screen *,
diff --git a/tty-term.c b/tty-term.c
index 473a434..ba63e5f 100644
--- a/tty-term.c
+++ b/tty-term.c
@@ -183,6 +183,8 @@ const struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
 	{ TTYC_SMUL, TTYCODE_STRING, "smul" },
 	{ TTYC_VPA, TTYCODE_STRING, "vpa" },
 	{ TTYC_XENL, TTYCODE_FLAG, "xenl" },
+	{ TTYC_TMUX_SCC, TTYCODE_STRING, "tmuxscc" },
+	{ TTYC_TMUX_ECC, TTYCODE_STRING, "tmuxecc" },
 };
 
 char *
@@ -376,6 +378,18 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
 			break;
 		}
 	}
+
+	if (   !tty_term_has(term, TTYC_TMUX_SCC)
+	    || !tty_term_has(term, TTYC_TMUX_ECC)) {
+		if (strstr(term->name, "xterm") != NULL) {
+			code = &term->codes[TTYC_TMUX_ECC];
+			code->value.string = xstrdup("\033]112\007");
+			code->type = TTYCODE_STRING;
+			code = &term->codes[TTYC_TMUX_SCC];
+			code->value.string = xstrdup("\033]12;%p1%s\007");
+			code->type = TTYCODE_STRING;
+		}
+	}
 	tty_term_override(term, overrides);
 
 	/* Delete curses data. */
@@ -481,6 +495,12 @@ tty_term_string2(struct tty_term *term, enum tty_code_code code, int a, int b)
 	return (tparm((char *) tty_term_string(term, code), a, b, 0, 0, 0, 0, 0, 0, 0));
 }
 
+const char *
+tty_term_uchar1(struct tty_term *term, enum tty_code_code code, const u_char *a)
+{
+	return (tparm((char *) tty_term_string(term, code), a, 0, 0, 0, 0, 0, 0, 0, 0));
+}
+
 int
 tty_term_number(struct tty_term *term, enum tty_code_code code)
 {
diff --git a/tty.c b/tty.c
index 8f0103a..c77b991 100644
--- a/tty.c
+++ b/tty.c
@@ -66,6 +66,7 @@ tty_init(struct tty *tty, int fd, char *term)
 	if ((path = ttyname(fd)) == NULL)
 		fatalx("ttyname failed");
 	tty->path = xstrdup(path);
+	tty->ccolour = xstrdup("");
 
 	tty->flags = 0;
 	tty->term_flags = 0;
@@ -207,6 +208,8 @@ tty_start_tty(struct tty *tty)
 	tty->mode = MODE_CURSOR;
 
 	tty->flags |= TTY_STARTED;
+
+	tty_force_cursor_colour(tty, "");
 }
 
 void
@@ -236,6 +239,7 @@ tty_stop_tty(struct tty *tty)
 	tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0));
 	tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX));
 	tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR));
+	tty_raw(tty, tty_term_string(tty->term, TTYC_TMUX_ECC));
 
 	tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM));
 	if (tty_term_has(tty->term, TTYC_KMOUS))
@@ -277,6 +281,7 @@ tty_free(struct tty *tty)
 {
 	tty_close(tty);
 
+	xfree(tty->ccolour);
 	if (tty->path != NULL)
 		xfree(tty->path);
 	if (tty->termname != NULL)
@@ -312,6 +317,13 @@ tty_putcode2(struct tty *tty, enum tty_code_code code, int a, int b)
 }
 
 void
+tty_putcode_uchar1(struct tty *tty, enum tty_code_code code, const u_char *a)
+{
+	if (a)
+		tty_puts(tty, tty_term_uchar1(tty->term, code, a));
+}
+
+void
 tty_puts(struct tty *tty, const char *s)
 {
 	if (*s == '\0')
@@ -380,10 +392,23 @@ tty_set_title(struct tty *tty, const char *title)
 }
 
 void
-tty_update_mode(struct tty *tty, int mode)
+tty_force_cursor_colour(struct tty *tty, const char *ccolour)
+{
+	if (*ccolour == 0)
+		tty_putcode(tty, TTYC_TMUX_ECC);
+	else	tty_putcode_uchar1(tty, TTYC_TMUX_SCC, ccolour);
+	xfree(tty->ccolour);
+	tty->ccolour = xstrdup(ccolour);
+}
+
+void
+tty_update_mode(struct tty *tty, int mode, const char *ccolour)
 {
 	int	changed;
 
+	if (strcmp(ccolour, tty->ccolour))
+		tty_force_cursor_colour(tty, ccolour);
+
 	if (tty->flags & TTY_NOCURSOR)
 		mode &= ~MODE_CURSOR;
 
@@ -477,7 +502,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy)
 	const struct grid_utf8	*gu;
 	u_int			 i, sx;
 
-	tty_update_mode(tty, tty->mode & ~MODE_CURSOR);
+	tty_update_mode(tty, tty->mode & ~MODE_CURSOR, s->ccolour);
 
 	sx = screen_size_x(s);
 	if (sx > s->grid->linedata[s->grid->hsize + py].cellsize)
@@ -517,7 +542,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy)
 	}
 
 	if (sx >= tty->sx) {
-		tty_update_mode(tty, tty->mode);
+		tty_update_mode(tty, tty->mode, s->ccolour);
 		return;
 	}
 	tty_reset(tty);
@@ -529,7 +554,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy)
 		for (i = sx; i < screen_size_x(s); i++)
 			tty_putc(tty, ' ');
 	}
-	tty_update_mode(tty, tty->mode);
+	tty_update_mode(tty, tty->mode, s->ccolour);
 }
 
 void
