commit b74276fa3e77467491fb2d7473837f0b4b5f87d3
Author: Sean <seanlkml@sympatico.ca>
Date:   Sun Mar 13 13:47:05 2011 -0700

    Handle xterm OSC cursor-color escape sequences
    
    For example the sequence "\033]12;red\007" should set the cursor
    color for the current window to red.

diff --git a/input.c b/input.c
index 6e36c77..1b0ef45 100644
--- a/input.c
+++ b/input.c
@@ -208,6 +208,7 @@ const struct input_transition input_state_dcs_intermediate_table[];
 const struct input_transition input_state_dcs_handler_table[];
 const struct input_transition input_state_dcs_escape_table[];
 const struct input_transition input_state_dcs_ignore_table[];
+const struct input_transition input_state_osc_parameter_table[];
 const struct input_transition input_state_osc_string_table[];
 const struct input_transition input_state_apc_string_table[];
 const struct input_transition input_state_rename_string_table[];
@@ -307,10 +308,17 @@ const struct input_state input_state_dcs_ignore = {
 	input_state_dcs_ignore_table
 };
 
+/* osc_parameter state definition. */
+const struct input_state input_state_osc_parameter = {
+	"osc_parameter",
+	input_enter_osc, NULL,
+	input_state_osc_parameter_table
+};
+
 /* osc_string state definition. */
 const struct input_state input_state_osc_string = {
 	"osc_string",
-	input_enter_osc, input_exit_osc,
+	NULL, input_exit_osc,
 	input_state_osc_string_table
 };
 
@@ -390,7 +398,7 @@ const struct input_transition input_state_esc_enter_table[] = {
 	{ 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
 	{ 0x5b, 0x5b, NULL,		  &input_state_csi_enter },
 	{ 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
-	{ 0x5d, 0x5d, NULL,		  &input_state_osc_string },
+	{ 0x5d, 0x5d, NULL,		  &input_state_osc_parameter },
 	{ 0x5e, 0x5e, NULL,		  &input_state_consume_st },
 	{ 0x5f, 0x5f, NULL,		  &input_state_apc_string },
 	{ 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
@@ -565,6 +573,22 @@ const struct input_transition input_state_dcs_ignore_table[] = {
 	{ -1, -1, NULL, NULL }
 };
 
+
+/* osc_parameter state table. */
+const struct input_transition input_state_osc_parameter_table[] = {
+	INPUT_STATE_ANYWHERE,
+
+	{ 0x00, 0x17, NULL,	    &input_state_ground },
+	{ 0x19, 0x19, NULL,	    &input_state_ground },
+	{ 0x1c, 0x1f, NULL,	    &input_state_ground },
+	{ 0x30, 0x39, input_parameter, NULL},
+	{ 0x3b, 0x3a, NULL,	    &input_state_ground },
+	{ 0x3b, 0x3b, NULL,	    &input_state_osc_string },
+	{ 0x3c, 0xff, NULL,	    &input_state_ground },
+
+	{ -1, -1, NULL, NULL }
+};
+
 /* osc_string state table. */
 const struct input_transition input_state_osc_string_table[] = {
 	INPUT_STATE_ANYWHERE,
@@ -1447,15 +1471,26 @@ input_exit_osc(struct input_ctx *ictx)
 {
 	if (ictx->flags & INPUT_DISCARD)
 		return;
-	log_debug("%s: \"%s\"", __func__, ictx->input_buf);
+	log_warnx("%s: \"%s\" \"%s\"", __func__, ictx->param_buf, ictx->input_buf);
 
-	if (ictx->input_len < 2 || ictx->input_buf[1] != ';')
+	if (input_split(ictx) != 0)
 		return;
-	if (ictx->input_buf[0] != '0' && ictx->input_buf[0] != '2')
+	if (ictx->param_list_len != 1)
 		return;
 
-	screen_set_title(ictx->ctx.s, ictx->input_buf + 2);
-	server_status_window(ictx->wp->window);
+	switch (ictx->param_list[0]) {
+	case 0:
+	case 2:
+		screen_set_title(ictx->ctx.s, ictx->input_buf);
+		server_status_window(ictx->wp->window);
+		break;
+	case 12:
+		screen_set_cursor_color(ictx->ctx.s, ictx->input_buf);
+		break;
+	default:
+		log_debug("%s: unknown '%u'", __func__, ictx->param_list[0]);
+		break;
+	}
 }
 
 /* APC string started. */
diff --git a/screen.c b/screen.c
index a3261c0..b323fde 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->ccolor = 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->ccolor);
 	grid_destroy(s->grid);
 }
 
@@ -90,6 +92,14 @@ screen_reset_tabs(struct screen *s)
 		bit_set(s->tabs, i);
 }
 
+/* Set screen cursor color. */
+void
+screen_set_cursor_color(struct screen *s, const char *color_string)
+{
+	xfree(s->ccolor);
+	s->ccolor = xstrdup(color_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..ea8e906 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->ccolor);
 	tty_reset(&c->tty);
 }
 
diff --git a/tmux.h b/tmux.h
index 49e2d97..92c41d6 100644
--- a/tmux.h
+++ b/tmux.h
@@ -700,6 +700,7 @@ struct screen {
 
 	u_int		 cx;		/* cursor x */
 	u_int		 cy;		/* cursor y */
+	char		*ccolor;	/* cursor colour string */
 
 	u_int		 rupper;	/* scroll region top */
 	u_int		 rlower;	/* scroll region bottom */
@@ -991,6 +992,7 @@ struct tty {
 
 	u_int		 cx;
 	u_int		 cy;
+	char *		 ccolor;
 
 	int		 mode;
 
@@ -1399,7 +1401,7 @@ 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_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 *);
@@ -1811,6 +1813,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_color(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.c b/tty.c
index 8f0103a..e95ec2a 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->ccolor = xstrdup("");
 
 	tty->flags = 0;
 	tty->term_flags = 0;
@@ -277,6 +278,7 @@ tty_free(struct tty *tty)
 {
 	tty_close(tty);
 
+	xfree(tty->ccolor);
 	if (tty->path != NULL)
 		xfree(tty->path);
 	if (tty->termname != NULL)
@@ -380,7 +382,7 @@ tty_set_title(struct tty *tty, const char *title)
 }
 
 void
-tty_update_mode(struct tty *tty, int mode)
+tty_update_mode(struct tty *tty, int mode, const char *ccolor)
 {
 	int	changed;
 
@@ -394,6 +396,13 @@ tty_update_mode(struct tty *tty, int mode)
 		else
 			tty_putcode(tty, TTYC_CIVIS);
 	}
+	if (strcmp(ccolor, tty->ccolor)) {
+		tty_puts(tty, "\033]12;");
+		tty_puts(tty, ccolor);
+		tty_puts(tty, "\007");
+		xfree(tty->ccolor);
+		tty->ccolor = xstrdup(ccolor);
+	}
 	if (changed & ALL_MOUSE_MODES) {
 		if (mode & ALL_MOUSE_MODES) {
 			if (mode & MODE_MOUSE_UTF8)
@@ -477,7 +486,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->ccolor);
 
 	sx = screen_size_x(s);
 	if (sx > s->grid->linedata[s->grid->hsize + py].cellsize)
@@ -517,7 +526,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->ccolor);
 		return;
 	}
 	tty_reset(tty);
@@ -529,7 +538,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->ccolor);
 }
 
 void
