From f1828921dfed4b7f2ba38b8c4a370b42965c404c Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Sun, 23 Feb 2014 00:53:06 +0000
Subject: [PATCH 01/23] Change terminal-overrides to a server option (now that
 we have them), it doesn't make much sense as a session option.

---
 cmd-attach-session.c |  2 +-
 cmd-new-session.c    |  2 +-
 options-table.c      | 16 +++++-----
 server-client.c      |  8 ++---
 tmux.1               | 72 ++++++++++++++++++++++----------------------
 tmux.h               |  6 ++--
 tty-term.c           |  7 +++--
 tty.c                |  4 +--
 8 files changed, 58 insertions(+), 59 deletions(-)

diff --git a/cmd-attach-session.c b/cmd-attach-session.c
index 6fb83d20..94f01e4c 100644
--- a/cmd-attach-session.c
+++ b/cmd-attach-session.c
@@ -132,7 +132,7 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag,
 		server_redraw_client(cmdq->client);
 		s->curw->flags &= ~WINLINK_ALERTFLAGS;
 	} else {
-		if (server_client_open(cmdq->client, s, &cause) != 0) {
+		if (server_client_open(cmdq->client, &cause) != 0) {
 			cmdq_error(cmdq, "open terminal failed: %s", cause);
 			free(cause);
 			return (CMD_RETURN_ERROR);
diff --git a/cmd-new-session.c b/cmd-new-session.c
index bf843cad..db8416e0 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -145,7 +145,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
 
 	/* Open the terminal if necessary. */
 	if (!detached && !already_attached) {
-		if (server_client_open(c, NULL, &cause) != 0) {
+		if (server_client_open(c, &cause) != 0) {
 			cmdq_error(cmdq, "open terminal failed: %s", cause);
 			free(cause);
 			goto error;
diff --git a/options-table.c b/options-table.c
index ec1d3680..ea848259 100644
--- a/options-table.c
+++ b/options-table.c
@@ -91,6 +91,14 @@ const struct options_table_entry server_options_table[] = {
 	  .default_num = 1
 	},
 
+	{ .name = "terminal-overrides",
+	  .type = OPTIONS_TABLE_STRING,
+	  .default_str = "*256col*:colors=256"
+	                 ",xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007"
+	                 ":Cs=\\E]12;%p1%s\\007:Cr=\\E]112\\007"
+			 ":Ss=\\E[%p1%d q:Se=\\E[2 q,screen*:XT"
+	},
+
 	{ .name = NULL }
 };
 
@@ -466,14 +474,6 @@ const struct options_table_entry session_options_table[] = {
 	  .default_num = 0 /* overridden in main() */
 	},
 
-	{ .name = "terminal-overrides",
-	  .type = OPTIONS_TABLE_STRING,
-	  .default_str = "*256col*:colors=256"
-	                 ",xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007"
-	                 ":Cs=\\E]12;%p1%s\\007:Cr=\\E]112\\007"
-			 ":Ss=\\E[%p1%d q:Se=\\E[2 q,screen*:XT"
-	},
-
 	{ .name = "update-environment",
 	  .type = OPTIONS_TABLE_STRING,
 	  .default_str = "DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID "
diff --git a/server-client.c b/server-client.c
index ed8159f5..35df7531 100644
--- a/server-client.c
+++ b/server-client.c
@@ -114,11 +114,8 @@ server_client_create(int fd)
 
 /* Open client terminal if needed. */
 int
-server_client_open(struct client *c, struct session *s, char **cause)
+server_client_open(struct client *c, char **cause)
 {
-	struct options	*oo = s != NULL ? &s->options : &global_s_options;
-	char		*overrides;
-
 	if (c->flags & CLIENT_CONTROL)
 		return (0);
 
@@ -127,8 +124,7 @@ server_client_open(struct client *c, struct session *s, char **cause)
 		return (-1);
 	}
 
-	overrides = options_get_string(oo, "terminal-overrides");
-	if (tty_open(&c->tty, overrides, cause) != 0)
+	if (tty_open(&c->tty, cause) != 0)
 		return (-1);
 
 	return (0);
diff --git a/tmux.1 b/tmux.1
index c0f04094..ba4c8537 100644
--- a/tmux.1
+++ b/tmux.1
@@ -2161,6 +2161,42 @@ disallowedWindowOps: 20,21,SetXprop
 Or changing this property from the
 .Xr xterm 1
 interactive menu when required.
+.It Ic terminal-overrides Ar string
+Contains a list of entries which override terminal descriptions read using
+.Xr terminfo 5 .
+.Ar string
+is a comma-separated list of items each a colon-separated string made up of a
+terminal type pattern (matched using
+.Xr fnmatch 3 )
+and a set of
+.Em name=value
+entries.
+.Pp
+For example, to set the
+.Ql clear
+.Xr terminfo 5
+entry to
+.Ql \ee[H\ee[2J
+for all terminal types and the
+.Ql dch1
+entry to
+.Ql \ee[P
+for the
+.Ql rxvt
+terminal type, the option could be set to the string:
+.Bd -literal -offset indent
+"*:clear=\ee[H\ee[2J,rxvt:dch1=\ee[P"
+.Ed
+.Pp
+The terminal entry value is passed through
+.Xr strunvis 3
+before interpretation.
+The default value forcibly corrects the
+.Ql colors
+entry for terminals which support 256 colours:
+.Bd -literal -offset indent
+"*256col*:colors=256,xterm*:XT"
+.Ed
 .El
 .Pp
 Available session options are:
@@ -2605,42 +2641,6 @@ and
 .Ic status-right
 strings as UTF-8; notably, this is important for wide characters.
 This option defaults to off.
-.It Ic terminal-overrides Ar string
-Contains a list of entries which override terminal descriptions read using
-.Xr terminfo 5 .
-.Ar string
-is a comma-separated list of items each a colon-separated string made up of a
-terminal type pattern (matched using
-.Xr fnmatch 3 )
-and a set of
-.Em name=value
-entries.
-.Pp
-For example, to set the
-.Ql clear
-.Xr terminfo 5
-entry to
-.Ql \ee[H\ee[2J
-for all terminal types and the
-.Ql dch1
-entry to
-.Ql \ee[P
-for the
-.Ql rxvt
-terminal type, the option could be set to the string:
-.Bd -literal -offset indent
-"*:clear=\ee[H\ee[2J,rxvt:dch1=\ee[P"
-.Ed
-.Pp
-The terminal entry value is passed through
-.Xr strunvis 3
-before interpretation.
-The default value forcibly corrects the
-.Ql colors
-entry for terminals which support 256 colours:
-.Bd -literal -offset indent
-"*256col*:colors=256,xterm*:XT"
-.Ed
 .It Ic update-environment Ar variables
 Set a space-separated string containing a list of environment variables to be
 copied into the session environment when a new session is created or an
diff --git a/tmux.h b/tmux.h
index c6919622..5801b35e 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1650,7 +1650,7 @@ void	tty_set_title(struct tty *, const char *);
 void	tty_update_mode(struct tty *, int, struct screen *);
 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 **);
+int	tty_open(struct tty *, char **);
 void	tty_close(struct tty *);
 void	tty_free(struct tty *);
 void	tty_write(
@@ -1679,7 +1679,7 @@ void	tty_bell(struct tty *);
 /* tty-term.c */
 extern struct tty_terms tty_terms;
 extern const struct tty_term_code_entry tty_term_codes[NTTYCODE];
-struct tty_term *tty_term_find(char *, int, const char *, char **);
+struct tty_term *tty_term_find(char *, int, char **);
 void		 tty_term_free(struct tty_term *);
 int		 tty_term_has(struct tty_term *, enum tty_code_code);
 const char	*tty_term_string(struct tty_term *, enum tty_code_code);
@@ -1893,7 +1893,7 @@ void	 server_add_accept(int);
 /* server-client.c */
 void	 server_client_handle_key(struct client *, int);
 void	 server_client_create(int);
-int      server_client_open(struct client *, struct session *, char **);
+int      server_client_open(struct client *, char **);
 void	 server_client_lost(struct client *);
 void	 server_client_callback(int, short, void *);
 void	 server_client_status_timer(void);
diff --git a/tty-term.c b/tty-term.c
index 8644a845..a66aad83 100644
--- a/tty-term.c
+++ b/tty-term.c
@@ -305,7 +305,7 @@ tty_term_override(struct tty_term *term, const char *overrides)
 }
 
 struct tty_term *
-tty_term_find(char *name, int fd, const char *overrides, char **cause)
+tty_term_find(char *name, int fd, char **cause)
 {
 	struct tty_term				*term;
 	const struct tty_term_code_entry	*ent;
@@ -383,7 +383,10 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
 			break;
 		}
 	}
-	tty_term_override(term, overrides);
+
+	/* Apply terminal overrides. */
+	s = options_get_string(&global_options, "terminal-overrides");
+	tty_term_override(term, s);
 
 	/* Delete curses data. */
 	del_curterm(cur_term);
diff --git a/tty.c b/tty.c
index 20b7070a..b545dc33 100644
--- a/tty.c
+++ b/tty.c
@@ -128,7 +128,7 @@ tty_set_size(struct tty *tty, u_int sx, u_int sy) {
 }
 
 int
-tty_open(struct tty *tty, const char *overrides, char **cause)
+tty_open(struct tty *tty, char **cause)
 {
 	char	out[64];
 	int	fd;
@@ -141,7 +141,7 @@ tty_open(struct tty *tty, const char *overrides, char **cause)
 		tty->log_fd = fd;
 	}
 
-	tty->term = tty_term_find(tty->termname, tty->fd, overrides, cause);
+	tty->term = tty_term_find(tty->termname, tty->fd, cause);
 	if (tty->term == NULL) {
 		tty_close(tty);
 		return (-1);

From 04f469a3245c528abc7865841d51bc0d222a94f9 Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:32:00 +0000
Subject: [PATCH 02/23] Change secondary device attributes response to
 \033[>84;0;0c which is unique for tmux.

---
 input.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/input.c b/input.c
index 58064ddd..40c9d225 100644
--- a/input.c
+++ b/input.c
@@ -1147,7 +1147,7 @@ input_csi_dispatch(struct input_ctx *ictx)
 	case INPUT_CSI_DA_TWO:
 		switch (input_get(ictx, 0, 0, 0)) {
 		case 0:
-			input_reply(ictx, "\033[>0;95;0c");
+			input_reply(ictx, "\033[>84;0;0c");
 			break;
 		default:
 			log_debug("%s: unknown '%c'", __func__, ictx->ch);

From 18cb13521840f678290b0a78d4e058c92795fabb Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:32:31 +0000
Subject: [PATCH 03/23] Don't write into buffer if no arguments, reported by
 Filipe Rosset.

---
 cmd.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/cmd.c b/cmd.c
index fe55109b..62f4c73d 100644
--- a/cmd.c
+++ b/cmd.c
@@ -139,6 +139,9 @@ cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
 	size_t	arglen;
 	int	i;
 
+	if (argc == 0)
+		return (0);
+
 	*buf = '\0';
 	for (i = 0; i < argc; i++) {
 		if (strlcpy(buf, argv[i], len) >= len)

From 175f215187b1c978ca4cc4988a78d067122e2b0c Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:34:08 +0000
Subject: [PATCH 04/23] Having three *clock* files is ridiculous, remove
 clock.c.

---
 Makefile        |   1 -
 clock.c         | 166 ------------------------------------------------
 screen-redraw.c |   2 +-
 tmux.h          |   5 +-
 window-clock.c  | 143 ++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 143 insertions(+), 174 deletions(-)
 delete mode 100644 clock.c

diff --git a/Makefile b/Makefile
index e566bb2a..63363f51 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,6 @@ SRCS=	arguments.c \
 	attributes.c \
 	cfg.c \
 	client.c \
-	clock.c \
 	cmd-attach-session.c \
 	cmd-bind-key.c \
 	cmd-break-pane.c \
diff --git a/clock.c b/clock.c
deleted file mode 100644
index 283a4a1e..00000000
--- a/clock.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/* $OpenBSD$ */
-
-/*
- * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-
-#include <string.h>
-#include <time.h>
-
-#include "tmux.h"
-
-const char clock_table[14][5][5] = {
-	{ { 1,1,1,1,1 }, /* 0 */
-	  { 1,0,0,0,1 },
-	  { 1,0,0,0,1 },
-	  { 1,0,0,0,1 },
-	  { 1,1,1,1,1 } },
-	{ { 0,0,0,0,1 }, /* 1 */
-	  { 0,0,0,0,1 },
-	  { 0,0,0,0,1 },
-	  { 0,0,0,0,1 },
-	  { 0,0,0,0,1 } },
-	{ { 1,1,1,1,1 }, /* 2 */
-	  { 0,0,0,0,1 },
-	  { 1,1,1,1,1 },
-	  { 1,0,0,0,0 },
-	  { 1,1,1,1,1 } },
-	{ { 1,1,1,1,1 }, /* 3 */
-	  { 0,0,0,0,1 },
-	  { 1,1,1,1,1 },
-	  { 0,0,0,0,1 },
-	  { 1,1,1,1,1 } },
-	{ { 1,0,0,0,1 }, /* 4 */
-	  { 1,0,0,0,1 },
-	  { 1,1,1,1,1 },
-	  { 0,0,0,0,1 },
-	  { 0,0,0,0,1 } },
-	{ { 1,1,1,1,1 }, /* 5 */
-	  { 1,0,0,0,0 },
-	  { 1,1,1,1,1 },
-	  { 0,0,0,0,1 },
-	  { 1,1,1,1,1 } },
-	{ { 1,1,1,1,1 }, /* 6 */
-	  { 1,0,0,0,0 },
-	  { 1,1,1,1,1 },
-	  { 1,0,0,0,1 },
-	  { 1,1,1,1,1 } },
-	{ { 1,1,1,1,1 }, /* 7 */
-	  { 0,0,0,0,1 },
-	  { 0,0,0,0,1 },
-	  { 0,0,0,0,1 },
-	  { 0,0,0,0,1 } },
-	{ { 1,1,1,1,1 }, /* 8 */
-	  { 1,0,0,0,1 },
-	  { 1,1,1,1,1 },
-	  { 1,0,0,0,1 },
-	  { 1,1,1,1,1 } },
-	{ { 1,1,1,1,1 }, /* 9 */
-	  { 1,0,0,0,1 },
-	  { 1,1,1,1,1 },
-	  { 0,0,0,0,1 },
-	  { 1,1,1,1,1 } },
-	{ { 0,0,0,0,0 }, /* : */
-	  { 0,0,1,0,0 },
-	  { 0,0,0,0,0 },
-	  { 0,0,1,0,0 },
-	  { 0,0,0,0,0 } },
-	{ { 1,1,1,1,1 }, /* A */
-	  { 1,0,0,0,1 },
-	  { 1,1,1,1,1 },
-	  { 1,0,0,0,1 },
-	  { 1,0,0,0,1 } },
-	{ { 1,1,1,1,1 }, /* P */
-	  { 1,0,0,0,1 },
-	  { 1,1,1,1,1 },
-	  { 1,0,0,0,0 },
-	  { 1,0,0,0,0 } },
-	{ { 1,0,0,0,1 }, /* M */
-	  { 1,1,0,1,1 },
-	  { 1,0,1,0,1 },
-	  { 1,0,0,0,1 },
-	  { 1,0,0,0,1 } },
-};
-
-void
-clock_draw(struct screen_write_ctx *ctx, int colour, int style)
-{
-	struct screen		*s = ctx->s;
-	struct grid_cell	 gc;
-	char			 tim[64], *ptr;
-	time_t			 t;
-	struct tm		*tm;
-	u_int			 i, j, x, y, idx;
-
-	t = time(NULL);
-	tm = localtime(&t);
-	if (style == 0) {
-		strftime(tim, sizeof tim, "%l:%M ", localtime(&t));
-		if (tm->tm_hour >= 12)
-			strlcat(tim, "PM", sizeof tim);
-		else
-			strlcat(tim, "AM", sizeof tim);
-	} else
-		strftime(tim, sizeof tim, "%H:%M", tm);
-
-
-	screen_write_clearscreen(ctx);
-
-	if (screen_size_x(s) < 6 * strlen(tim) || screen_size_y(s) < 6) {
-		if (screen_size_x(s) >= strlen(tim) && screen_size_y(s) != 0) {
-			x = (screen_size_x(s) / 2) - (strlen(tim) / 2);
-			y = screen_size_y(s) / 2;
-			screen_write_cursormove(ctx, x, y);
-
-			memcpy(&gc, &grid_default_cell, sizeof gc);
-			colour_set_fg(&gc, colour);
-			screen_write_puts(ctx, &gc, "%s", tim);
-		}
-		return;
-	}
-
-	x = (screen_size_x(s) / 2) - 3 * strlen(tim);
-	y = (screen_size_y(s) / 2) - 3;
-
-	memcpy(&gc, &grid_default_cell, sizeof gc);
-	colour_set_bg(&gc, colour);
-	for (ptr = tim; *ptr != '\0'; ptr++) {
-		if (*ptr >= '0' && *ptr <= '9')
-			idx = *ptr - '0';
-		else if (*ptr == ':')
-			idx = 10;
-		else if (*ptr == 'A')
-			idx = 11;
-		else if (*ptr == 'P')
-			idx = 12;
-		else if (*ptr == 'M')
-			idx = 13;
-		else {
-			x += 6;
-			continue;
-		}
-
-		for (j = 0; j < 5; j++) {
-			for (i = 0; i < 5; i++) {
-				screen_write_cursormove(ctx, x + i, y + j);
-				if (clock_table[idx][j][i])
-					screen_write_putc(ctx, &gc, ' ');
-			}
-		}
-		x += 6;
-	}
-}
diff --git a/screen-redraw.c b/screen-redraw.c
index 3a082cbf..a7f713a5 100644
--- a/screen-redraw.c
+++ b/screen-redraw.c
@@ -381,7 +381,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp)
 		for (j = 0; j < 5; j++) {
 			for (i = px; i < px + 5; i++) {
 				tty_cursor(tty, xoff + i, yoff + py + j);
-				if (clock_table[idx][j][i - px])
+				if (window_clock_table[idx][j][i - px])
 					tty_putc(tty, ' ');
 			}
 		}
diff --git a/tmux.h b/tmux.h
index 5801b35e..9900489e 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1713,10 +1713,6 @@ char		*paste_print(struct paste_buffer *, size_t);
 void		 paste_send_pane(struct paste_buffer *, struct window_pane *,
 		     const char *, int);
 
-/* clock.c */
-extern const char clock_table[14][5][5];
-void		 clock_draw(struct screen_write_ctx *, int, int);
-
 /* arguments.c */
 int		 args_cmp(struct args_entry *, struct args_entry *);
 RB_PROTOTYPE(args_tree, args_entry, entry, args_cmp);
@@ -2222,6 +2218,7 @@ void		 layout_set_active_changed(struct window *);
 
 /* window-clock.c */
 extern const struct window_mode window_clock_mode;
+extern const char window_clock_table[14][5][5];
 
 /* window-copy.c */
 extern const struct window_mode window_copy_mode;
diff --git a/window-clock.c b/window-clock.c
index 8ec1671e..ede8df5b 100644
--- a/window-clock.c
+++ b/window-clock.c
@@ -46,6 +46,79 @@ struct window_clock_mode_data {
 	time_t			tim;
 };
 
+const char window_clock_table[14][5][5] = {
+	{ { 1,1,1,1,1 }, /* 0 */
+	  { 1,0,0,0,1 },
+	  { 1,0,0,0,1 },
+	  { 1,0,0,0,1 },
+	  { 1,1,1,1,1 } },
+	{ { 0,0,0,0,1 }, /* 1 */
+	  { 0,0,0,0,1 },
+	  { 0,0,0,0,1 },
+	  { 0,0,0,0,1 },
+	  { 0,0,0,0,1 } },
+	{ { 1,1,1,1,1 }, /* 2 */
+	  { 0,0,0,0,1 },
+	  { 1,1,1,1,1 },
+	  { 1,0,0,0,0 },
+	  { 1,1,1,1,1 } },
+	{ { 1,1,1,1,1 }, /* 3 */
+	  { 0,0,0,0,1 },
+	  { 1,1,1,1,1 },
+	  { 0,0,0,0,1 },
+	  { 1,1,1,1,1 } },
+	{ { 1,0,0,0,1 }, /* 4 */
+	  { 1,0,0,0,1 },
+	  { 1,1,1,1,1 },
+	  { 0,0,0,0,1 },
+	  { 0,0,0,0,1 } },
+	{ { 1,1,1,1,1 }, /* 5 */
+	  { 1,0,0,0,0 },
+	  { 1,1,1,1,1 },
+	  { 0,0,0,0,1 },
+	  { 1,1,1,1,1 } },
+	{ { 1,1,1,1,1 }, /* 6 */
+	  { 1,0,0,0,0 },
+	  { 1,1,1,1,1 },
+	  { 1,0,0,0,1 },
+	  { 1,1,1,1,1 } },
+	{ { 1,1,1,1,1 }, /* 7 */
+	  { 0,0,0,0,1 },
+	  { 0,0,0,0,1 },
+	  { 0,0,0,0,1 },
+	  { 0,0,0,0,1 } },
+	{ { 1,1,1,1,1 }, /* 8 */
+	  { 1,0,0,0,1 },
+	  { 1,1,1,1,1 },
+	  { 1,0,0,0,1 },
+	  { 1,1,1,1,1 } },
+	{ { 1,1,1,1,1 }, /* 9 */
+	  { 1,0,0,0,1 },
+	  { 1,1,1,1,1 },
+	  { 0,0,0,0,1 },
+	  { 1,1,1,1,1 } },
+	{ { 0,0,0,0,0 }, /* : */
+	  { 0,0,1,0,0 },
+	  { 0,0,0,0,0 },
+	  { 0,0,1,0,0 },
+	  { 0,0,0,0,0 } },
+	{ { 1,1,1,1,1 }, /* A */
+	  { 1,0,0,0,1 },
+	  { 1,1,1,1,1 },
+	  { 1,0,0,0,1 },
+	  { 1,0,0,0,1 } },
+	{ { 1,1,1,1,1 }, /* P */
+	  { 1,0,0,0,1 },
+	  { 1,1,1,1,1 },
+	  { 1,0,0,0,0 },
+	  { 1,0,0,0,0 } },
+	{ { 1,0,0,0,1 }, /* M */
+	  { 1,1,0,1,1 },
+	  { 1,0,1,0,1 },
+	  { 1,0,0,0,1 },
+	  { 1,0,0,0,1 } },
+};
+
 struct screen *
 window_clock_init(struct window_pane *wp)
 {
@@ -114,11 +187,77 @@ window_clock_draw_screen(struct window_pane *wp)
 	struct window_clock_mode_data	*data = wp->modedata;
 	struct screen_write_ctx	 	 ctx;
 	int				 colour, style;
+	struct screen			*s = &data->screen;
+	struct grid_cell		 gc;
+	char				 tim[64], *ptr;
+	time_t				 t;
+	struct tm			*tm;
+	u_int				 i, j, x, y, idx;
 
 	colour = options_get_number(&wp->window->options, "clock-mode-colour");
 	style = options_get_number(&wp->window->options, "clock-mode-style");
 
-	screen_write_start(&ctx, NULL, &data->screen);
-	clock_draw(&ctx, colour, style);
+	screen_write_start(&ctx, NULL, s);
+
+	t = time(NULL);
+	tm = localtime(&t);
+	if (style == 0) {
+		strftime(tim, sizeof tim, "%l:%M ", localtime(&t));
+		if (tm->tm_hour >= 12)
+			strlcat(tim, "PM", sizeof tim);
+		else
+			strlcat(tim, "AM", sizeof tim);
+	} else
+		strftime(tim, sizeof tim, "%H:%M", tm);
+
+	screen_write_clearscreen(&ctx);
+
+	if (screen_size_x(s) < 6 * strlen(tim) || screen_size_y(s) < 6) {
+		if (screen_size_x(s) >= strlen(tim) && screen_size_y(s) != 0) {
+			x = (screen_size_x(s) / 2) - (strlen(tim) / 2);
+			y = screen_size_y(s) / 2;
+			screen_write_cursormove(&ctx, x, y);
+
+			memcpy(&gc, &grid_default_cell, sizeof gc);
+			colour_set_fg(&gc, colour);
+			screen_write_puts(&ctx, &gc, "%s", tim);
+		}
+
+
+		screen_write_stop(&ctx);
+		return;
+	}
+
+	x = (screen_size_x(s) / 2) - 3 * strlen(tim);
+	y = (screen_size_y(s) / 2) - 3;
+
+	memcpy(&gc, &grid_default_cell, sizeof gc);
+	colour_set_bg(&gc, colour);
+	for (ptr = tim; *ptr != '\0'; ptr++) {
+		if (*ptr >= '0' && *ptr <= '9')
+			idx = *ptr - '0';
+		else if (*ptr == ':')
+			idx = 10;
+		else if (*ptr == 'A')
+			idx = 11;
+		else if (*ptr == 'P')
+			idx = 12;
+		else if (*ptr == 'M')
+			idx = 13;
+		else {
+			x += 6;
+			continue;
+		}
+
+		for (j = 0; j < 5; j++) {
+			for (i = 0; i < 5; i++) {
+				screen_write_cursormove(&ctx, x + i, y + j);
+				if (window_clock_table[idx][j][i])
+					screen_write_putc(&ctx, &gc, ' ');
+			}
+		}
+		x += 6;
+	}
+
 	screen_write_stop(&ctx);
 }

From 9368914ee782f6ea9d7ea8f6b28b9d87ffae8023 Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:36:43 +0000
Subject: [PATCH 05/23] Add start-of-list, end-of-list, top-line and
 bottom-line in choice mode, from madmaverick9 at roxxmail dot eu, similar
 diff a few days later from Marcel Partap.

---
 mode-key.c      | 15 +++++++++++++++
 tmux.h          |  4 ++++
 window-choose.c | 23 +++++++++++++++++++++++
 3 files changed, 42 insertions(+)

diff --git a/mode-key.c b/mode-key.c
index 80a943e4..80a2464d 100644
--- a/mode-key.c
+++ b/mode-key.c
@@ -76,14 +76,18 @@ const struct mode_key_cmdstr mode_key_cmdstr_edit[] = {
 /* Choice keys command strings. */
 const struct mode_key_cmdstr mode_key_cmdstr_choice[] = {
 	{ MODEKEYCHOICE_BACKSPACE, "backspace" },
+	{ MODEKEYCHOICE_BOTTOMLINE, "bottom-line"},
 	{ MODEKEYCHOICE_CANCEL, "cancel" },
 	{ MODEKEYCHOICE_CHOOSE, "choose" },
 	{ MODEKEYCHOICE_DOWN, "down" },
+	{ MODEKEYCHOICE_ENDOFLIST, "end-of-list"},
 	{ MODEKEYCHOICE_PAGEDOWN, "page-down" },
 	{ MODEKEYCHOICE_PAGEUP, "page-up" },
 	{ MODEKEYCHOICE_SCROLLDOWN, "scroll-down" },
 	{ MODEKEYCHOICE_SCROLLUP, "scroll-up" },
 	{ MODEKEYCHOICE_STARTNUMBERPREFIX, "start-number-prefix" },
+	{ MODEKEYCHOICE_STARTOFLIST, "start-of-list"},
+	{ MODEKEYCHOICE_TOPLINE, "top-line"},
 	{ MODEKEYCHOICE_TREE_COLLAPSE, "tree-collapse" },
 	{ MODEKEYCHOICE_TREE_COLLAPSE_ALL, "tree-collapse-all" },
 	{ MODEKEYCHOICE_TREE_EXPAND, "tree-expand" },
@@ -226,6 +230,12 @@ const struct mode_key_entry mode_key_vi_choice[] = {
 	{ 'j',			    0, MODEKEYCHOICE_DOWN },
 	{ 'k',			    0, MODEKEYCHOICE_UP },
 	{ 'q',			    0, MODEKEYCHOICE_CANCEL },
+	{ KEYC_HOME,                0, MODEKEYCHOICE_STARTOFLIST },
+	{ 'g',                      0, MODEKEYCHOICE_STARTOFLIST },
+	{ 'H',                      0, MODEKEYCHOICE_TOPLINE },
+	{ 'L',                      0, MODEKEYCHOICE_BOTTOMLINE },
+	{ 'G',                      0, MODEKEYCHOICE_ENDOFLIST },
+	{ KEYC_END,                 0, MODEKEYCHOICE_ENDOFLIST },
 	{ KEYC_BSPACE,		    0, MODEKEYCHOICE_BACKSPACE },
 	{ KEYC_DOWN | KEYC_CTRL,    0, MODEKEYCHOICE_SCROLLDOWN },
 	{ KEYC_DOWN,		    0, MODEKEYCHOICE_DOWN },
@@ -372,6 +382,11 @@ const struct mode_key_entry mode_key_emacs_choice[] = {
 	{ '\r',			    0, MODEKEYCHOICE_CHOOSE },
 	{ 'q',			    0, MODEKEYCHOICE_CANCEL },
 	{ 'v' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_PAGEUP },
+	{ KEYC_HOME,                0, MODEKEYCHOICE_STARTOFLIST },
+	{ '<' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTOFLIST },
+	{ 'R' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_TOPLINE },
+	{ '>' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_ENDOFLIST },
+	{ KEYC_END,                 0, MODEKEYCHOICE_ENDOFLIST },
 	{ KEYC_BSPACE,		    0, MODEKEYCHOICE_BACKSPACE },
 	{ KEYC_DOWN | KEYC_CTRL,    0, MODEKEYCHOICE_SCROLLDOWN },
 	{ KEYC_DOWN,		    0, MODEKEYCHOICE_DOWN },
diff --git a/tmux.h b/tmux.h
index 9900489e..3a73dece 100644
--- a/tmux.h
+++ b/tmux.h
@@ -520,14 +520,18 @@ enum mode_key_cmd {
 
 	/* Menu (choice) keys. */
 	MODEKEYCHOICE_BACKSPACE,
+	MODEKEYCHOICE_BOTTOMLINE,
 	MODEKEYCHOICE_CANCEL,
 	MODEKEYCHOICE_CHOOSE,
 	MODEKEYCHOICE_DOWN,
+	MODEKEYCHOICE_ENDOFLIST,
 	MODEKEYCHOICE_PAGEDOWN,
 	MODEKEYCHOICE_PAGEUP,
 	MODEKEYCHOICE_SCROLLDOWN,
 	MODEKEYCHOICE_SCROLLUP,
 	MODEKEYCHOICE_STARTNUMBERPREFIX,
+	MODEKEYCHOICE_STARTOFLIST,
+	MODEKEYCHOICE_TOPLINE,
 	MODEKEYCHOICE_TREE_COLLAPSE,
 	MODEKEYCHOICE_TREE_COLLAPSE_ALL,
 	MODEKEYCHOICE_TREE_EXPAND,
diff --git a/window-choose.c b/window-choose.c
index 0cf7f66b..bb881aa5 100644
--- a/window-choose.c
+++ b/window-choose.c
@@ -679,6 +679,29 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
 		window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM,
 		    "Goto Item", wp, key);
 		break;
+	case MODEKEYCHOICE_STARTOFLIST:
+		data->selected = 0;
+		data->top = 0;
+		window_choose_redraw_screen(wp);
+		break;
+	case MODEKEYCHOICE_TOPLINE:
+		data->selected = data->top;
+		window_choose_redraw_screen(wp);
+		break;
+	case MODEKEYCHOICE_BOTTOMLINE:
+		data->selected = data->top + screen_size_y(s) - 1;
+		if (data->selected > items - 1)
+			data->selected = items - 1;
+		window_choose_redraw_screen(wp);
+		break;
+	case MODEKEYCHOICE_ENDOFLIST:
+		data->selected = items - 1;
+		if (screen_size_y(s) < items)
+			data->top = items - screen_size_y(s);
+		else
+			data->top = 0;
+		window_choose_redraw_screen(wp);
+		break;
 	default:
 		idx = window_choose_index_key(data, key);
 		if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list))

From b11de5adc7a89a23af2a778d4de12ac697c902a0 Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:37:55 +0000
Subject: [PATCH 06/23] Make session_attached a count and add
 session_many_attached flag.

---
 format.c | 6 ++----
 resize.c | 2 ++
 tmux.1   | 3 ++-
 tmux.h   | 2 ++
 4 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/format.c b/format.c
index bcb897d6..1dca6011 100644
--- a/format.c
+++ b/format.c
@@ -401,10 +401,8 @@ format_session(struct format_tree *ft, struct session *s)
 	*strchr(tim, '\n') = '\0';
 	format_add(ft, "session_created_string", "%s", tim);
 
-	if (s->flags & SESSION_UNATTACHED)
-		format_add(ft, "session_attached", "%d", 0);
-	else
-		format_add(ft, "session_attached", "%d", 1);
+	format_add(ft, "session_attached", "%u", s->attached);
+	format_add(ft, "session_many_attached", "%u", s->attached > 1);
 }
 
 /* Set default format keys for a client. */
diff --git a/resize.c b/resize.c
index ff3ec6c5..70379420 100644
--- a/resize.c
+++ b/resize.c
@@ -55,6 +55,7 @@ recalculate_sizes(void)
 	RB_FOREACH(s, sessions, &sessions) {
 		has_status = options_get_number(&s->options, "status");
 
+		s->attached = 0;
 		ssx = ssy = UINT_MAX;
 		for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
 			c = ARRAY_ITEM(&clients, j);
@@ -69,6 +70,7 @@ recalculate_sizes(void)
 					ssy = c->tty.sy - 1;
 				else if (c->tty.sy < ssy)
 					ssy = c->tty.sy;
+				s->attached++;
 			}
 		}
 		if (ssx == UINT_MAX || ssy == UINT_MAX) {
diff --git a/tmux.1 b/tmux.1
index ba4c8537..81626faa 100644
--- a/tmux.1
+++ b/tmux.1
@@ -3136,13 +3136,14 @@ The following variables are available, where appropriate:
 .It Li "saved_cursor_y" Ta "" Ta "Saved cursor Y in pane"
 .It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane"
 .It Li "scroll_region_upper" Ta "" Ta "Top of scroll region in pane"
-.It Li "session_attached" Ta "" Ta "1 if session attached"
+.It Li "session_attached" Ta "" Ta "Number of clients session is attached to"
 .It Li "session_created" Ta "" Ta "Integer time session created"
 .It Li "session_created_string" Ta "" Ta "String time session created"
 .It Li "session_group" Ta "" Ta "Number of session group"
 .It Li "session_grouped" Ta "" Ta "1 if session in a group"
 .It Li "session_height" Ta "" Ta "Height of session"
 .It Li "session_id" Ta "" Ta "Unique session ID"
+.It Li "session_many_attached" Ta "" Ta "1 if multiple clients attached"
 .It Li "session_name" Ta "#S" Ta "Name of session"
 .It Li "session_width" Ta "" Ta "Width of session"
 .It Li "session_windows" Ta "" Ta "Number of windows in session"
diff --git a/tmux.h b/tmux.h
index 3a73dece..fe4a697b 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1086,6 +1086,8 @@ struct session {
 #define SESSION_UNATTACHED 0x1	/* not attached to any clients */
 	int		 flags;
 
+	u_int            attached;
+
 	struct termios	*tio;
 
 	struct environ	 environ;

From 0e4d1d8493564ce908b002d8e9dddc105184039e Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:39:31 +0000
Subject: [PATCH 07/23] Add setb -a to append and a copy mode append command,
 from J Raynor with minor changes.

---
 cmd-set-buffer.c | 74 ++++++++++++++++++++++++++++++------------------
 mode-key.c       |  2 ++
 paste.c          |  2 +-
 tmux.1           |  5 ++++
 tmux.h           |  1 +
 window-copy.c    | 48 +++++++++++++++++++++++++++++++
 6 files changed, 104 insertions(+), 28 deletions(-)

diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c
index f67f7a0c..0942da9a 100644
--- a/cmd-set-buffer.c
+++ b/cmd-set-buffer.c
@@ -24,15 +24,15 @@
 #include "tmux.h"
 
 /*
- * Add or set a paste buffer.
+ * Add, set, or append to a paste buffer.
  */
 
 enum cmd_retval	 cmd_set_buffer_exec(struct cmd *, struct cmd_q *);
 
 const struct cmd_entry cmd_set_buffer_entry = {
 	"set-buffer", "setb",
-	"b:", 1, 1,
-	CMD_BUFFER_USAGE " data",
+	"ab:", 1, 1,
+	"[-a] " CMD_BUFFER_USAGE " data",
 	0,
 	NULL,
 	cmd_set_buffer_exec
@@ -41,35 +41,55 @@ const struct cmd_entry cmd_set_buffer_entry = {
 enum cmd_retval
 cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 {
-	struct args	*args = self->args;
-	u_int		 limit;
-	char		*pdata, *cause;
-	size_t		 psize;
-	int		 buffer;
+	struct args		*args = self->args;
+	struct paste_buffer	*pb;
+	u_int			 limit;
+	char			*pdata, *cause;
+	size_t			 psize, newsize;
+	int			 buffer;
 
 	limit = options_get_number(&global_options, "buffer-limit");
 
-	pdata = xstrdup(args->argv[0]);
-	psize = strlen(pdata);
+	psize = 0;
+	pdata = NULL;
 
-	if (!args_has(args, 'b')) {
+	pb = NULL;
+	buffer = -1;
+
+	if (args_has(args, 'b')) {
+		buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
+		if (cause != NULL) {
+			cmdq_error(cmdq, "buffer %s", cause);
+			free(cause);
+			return (CMD_RETURN_ERROR);
+		}
+		pb = paste_get_index(&global_buffers, buffer);
+		if (pb == NULL) {
+			cmdq_error(cmdq, "no buffer %d", buffer);
+			return (CMD_RETURN_ERROR);
+		}
+	} else if (args_has(args, 'a')) {
+		pb = paste_get_top(&global_buffers);
+		if (pb != NULL)
+			buffer = 0;
+	}
+
+	if (args_has(args, 'a') && pb != NULL) {
+		psize = pb->size;
+		pdata = xmalloc(psize);
+		memcpy(pdata, pb->data, psize);
+	}
+
+	newsize = strlen(args->argv[0]);
+
+	pdata = xrealloc(pdata, 1, psize + newsize);
+	memcpy(pdata + psize, args->argv[0], newsize);
+	psize += newsize;
+
+	if (buffer == -1)
 		paste_add(&global_buffers, pdata, psize, limit);
-		return (CMD_RETURN_NORMAL);
-	}
-
-	buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
-	if (cause != NULL) {
-		cmdq_error(cmdq, "buffer %s", cause);
-		free(cause);
-		free(pdata);
-		return (CMD_RETURN_ERROR);
-	}
-
-	if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
-		cmdq_error(cmdq, "no buffer %d", buffer);
-		free(pdata);
-		return (CMD_RETURN_ERROR);
-	}
+	else
+		paste_replace(&global_buffers, buffer, pdata, psize);
 
 	return (CMD_RETURN_NORMAL);
 }
diff --git a/mode-key.c b/mode-key.c
index 80a2464d..7f2b9471 100644
--- a/mode-key.c
+++ b/mode-key.c
@@ -100,6 +100,7 @@ const struct mode_key_cmdstr mode_key_cmdstr_choice[] = {
 
 /* Copy keys command strings. */
 const struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
+	{ MODEKEYCOPY_APPENDSELECTION, "append-selection" },
 	{ MODEKEYCOPY_BACKTOINDENTATION, "back-to-indentation" },
 	{ MODEKEYCOPY_BOTTOMLINE, "bottom-line" },
 	{ MODEKEYCOPY_CANCEL, "cancel" },
@@ -272,6 +273,7 @@ const struct mode_key_entry mode_key_vi_copy[] = {
 	{ '9',			    0, MODEKEYCOPY_STARTNUMBERPREFIX },
 	{ ':',			    0, MODEKEYCOPY_GOTOLINE },
 	{ '?',			    0, MODEKEYCOPY_SEARCHUP },
+	{ 'A',			    0, MODEKEYCOPY_APPENDSELECTION },
 	{ 'B',			    0, MODEKEYCOPY_PREVIOUSSPACE },
 	{ 'D',			    0, MODEKEYCOPY_COPYENDOFLINE },
 	{ 'E',			    0, MODEKEYCOPY_NEXTSPACEEND },
diff --git a/paste.c b/paste.c
index 946935a3..4ec87f35 100644
--- a/paste.c
+++ b/paste.c
@@ -172,7 +172,7 @@ paste_print(struct paste_buffer *pb, size_t width)
 
 /* Paste into a window pane, filtering '\n' according to separator. */
 void
-paste_send_pane (struct paste_buffer *pb, struct window_pane *wp,
+paste_send_pane(struct paste_buffer *pb, struct window_pane *wp,
     const char *sep, int bracket)
 {
 	const char	*data = pb->data, *end = data + pb->size, *lf;
diff --git a/tmux.1 b/tmux.1
index 81626faa..8fd63dc4 100644
--- a/tmux.1
+++ b/tmux.1
@@ -851,6 +851,7 @@ option).
 The following keys are supported as appropriate for the mode:
 .Bl -column "FunctionXXXXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent
 .It Sy "Function" Ta Sy "vi" Ta Sy "emacs"
+.It Li "Append selection" Ta "A" Ta ""
 .It Li "Back to indentation" Ta "^" Ta "M-m"
 .It Li "Bottom of history" Ta "G" Ta "M-<"
 .It Li "Clear selection" Ta "Escape" Ta "C-g"
@@ -3543,12 +3544,16 @@ The
 .Fl a
 option appends to rather than overwriting the file.
 .It Xo Ic set-buffer
+.Op Fl a
 .Op Fl b Ar buffer-index
 .Ar data
 .Xc
 .D1 (alias: Ic setb )
 Set the contents of the specified buffer to
 .Ar data .
+The
+.Fl a
+option appends to rather than overwriting the buffer.
 .It Xo Ic show-buffer
 .Op Fl b Ar buffer-index
 .Xc
diff --git a/tmux.h b/tmux.h
index fe4a697b..b30f2080 100644
--- a/tmux.h
+++ b/tmux.h
@@ -540,6 +540,7 @@ enum mode_key_cmd {
 	MODEKEYCHOICE_UP,
 
 	/* Copy keys. */
+	MODEKEYCOPY_APPENDSELECTION,
 	MODEKEYCOPY_BACKTOINDENTATION,
 	MODEKEYCOPY_BOTTOMLINE,
 	MODEKEYCOPY_CANCEL,
diff --git a/window-copy.c b/window-copy.c
index 76c9c3ce..7d7f3a20 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -58,6 +58,7 @@ void	window_copy_copy_buffer(struct window_pane *, int, void *, size_t);
 void	window_copy_copy_pipe(
 	    struct window_pane *, struct session *, int, const char *);
 void	window_copy_copy_selection(struct window_pane *, int);
+void	window_copy_append_selection(struct window_pane *, int);
 void	window_copy_clear_selection(struct window_pane *);
 void	window_copy_copy_line(
 	    struct window_pane *, char **, size_t *, u_int, u_int, u_int);
@@ -414,6 +415,13 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
 
 	cmd = mode_key_lookup(&data->mdata, key, &arg);
 	switch (cmd) {
+	case MODEKEYCOPY_APPENDSELECTION:
+		if (sess != NULL) {
+			window_copy_append_selection(wp, data->numprefix);
+			window_pane_reset_mode(wp);
+			return;
+		}
+		break;
 	case MODEKEYCOPY_CANCEL:
 		window_pane_reset_mode(wp);
 		return;
@@ -1491,6 +1499,46 @@ window_copy_copy_selection(struct window_pane *wp, int idx)
 	window_copy_copy_buffer(wp, idx, buf, len);
 }
 
+void
+window_copy_append_selection(struct window_pane *wp, int idx)
+{
+	char			*buf;
+	struct paste_buffer	*pb;
+	size_t			 len;
+	u_int			 limit;
+	struct screen_write_ctx	 ctx;
+
+	buf = window_copy_get_selection(wp, &len);
+	if (buf == NULL)
+		return;
+
+	if (options_get_number(&global_options, "set-clipboard")) {
+		screen_write_start(&ctx, wp, NULL);
+		screen_write_setselection(&ctx, buf, len);
+		screen_write_stop(&ctx);
+	}
+
+	if (idx == -1)
+		idx = 0;
+
+	if (idx == 0 && paste_get_top(&global_buffers) == NULL) {
+		limit = options_get_number(&global_options, "buffer-limit");
+		paste_add(&global_buffers, buf, len, limit);
+		return;
+	}
+
+	pb = paste_get_index(&global_buffers, idx);
+	if (pb != NULL) {
+		buf = xrealloc(buf, 1, len + pb->size);
+		memmove(buf + pb->size, buf, len);
+		memcpy(buf, pb->data, pb->size);
+		len += pb->size;
+	}
+
+	if (paste_replace(&global_buffers, idx, buf, len) != 0)
+		free(buf);
+}
+
 void
 window_copy_copy_line(struct window_pane *wp,
     char **buf, size_t *off, u_int sy, u_int sx, u_int ex)

From fcdae6925a08dc06860f9552ba7a300669f4a038 Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:39:59 +0000
Subject: [PATCH 08/23] Use hex constants rather than shifts for mouse events
 and flags, pointed out by Marcel Partap.

---
 tmux.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/tmux.h b/tmux.h
index b30f2080..b7d53727 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1133,14 +1133,14 @@ LIST_HEAD(tty_terms, tty_term);
 #define MOUSE_WHEEL_DOWN 1
 
 /* Mouse events. */
-#define MOUSE_EVENT_DOWN (1 << 0)
-#define MOUSE_EVENT_DRAG (1 << 1)
-#define MOUSE_EVENT_UP (1 << 2)
-#define MOUSE_EVENT_CLICK (1 << 3)
-#define MOUSE_EVENT_WHEEL (1 << 4)
+#define MOUSE_EVENT_DOWN 0x1
+#define MOUSE_EVENT_DRAG 0x2
+#define MOUSE_EVENT_UP 0x4
+#define MOUSE_EVENT_CLICK 0x8
+#define MOUSE_EVENT_WHEEL 0x10
 
 /* Mouse flags. */
-#define MOUSE_RESIZE_PANE (1 << 0)
+#define MOUSE_RESIZE_PANE 0x1
 
 /*
  * Mouse input. When sent by xterm:

From 46593e7aa26b83f0ba1b0d36a700d7158ac2b178 Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:40:21 +0000
Subject: [PATCH 09/23] Add names for mouse button bits rather than using magic
 numbers, from Marcel Partap.

---
 tmux.h     | 12 ++++++++++--
 tty-keys.c | 10 +++++-----
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/tmux.h b/tmux.h
index b7d53727..94eb5b8f 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1128,18 +1128,26 @@ struct tty_term {
 };
 LIST_HEAD(tty_terms, tty_term);
 
+/* Mouse button masks. */
+#define MOUSE_MASK_BUTTONS 3
+#define MOUSE_MASK_SHIFT 4
+#define MOUSE_MASK_META 8
+#define MOUSE_MASK_CTRL 16
+#define MOUSE_MASK_DRAG 32
+#define MOUSE_MASK_WHEEL 64
+
 /* Mouse wheel states. */
 #define MOUSE_WHEEL_UP 0
 #define MOUSE_WHEEL_DOWN 1
 
-/* Mouse events. */
+/* Mouse event bits. */
 #define MOUSE_EVENT_DOWN 0x1
 #define MOUSE_EVENT_DRAG 0x2
 #define MOUSE_EVENT_UP 0x4
 #define MOUSE_EVENT_CLICK 0x8
 #define MOUSE_EVENT_WHEEL 0x10
 
-/* Mouse flags. */
+/* Mouse flag bits. */
 #define MOUSE_RESIZE_PANE 0x1
 
 /*
diff --git a/tty-keys.c b/tty-keys.c
index 4492df1e..e0e794cc 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -748,21 +748,21 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
 	m->sgr_rel = sgr_rel;
 	m->x = x;
 	m->y = y;
-	if (b & 64) { /* wheel button */
-		b &= 3;
+	if (b & MOUSE_MASK_WHEEL) {
+		b &= MOUSE_MASK_BUTTONS;
 		if (b == 0)
 			m->wheel = MOUSE_WHEEL_UP;
 		else if (b == 1)
 			m->wheel = MOUSE_WHEEL_DOWN;
 		m->event = MOUSE_EVENT_WHEEL;
-	} else if ((b & 3) == 3) {
+	} else if ((b & MOUSE_MASK_BUTTONS) == 3) {
 		if (~m->event & MOUSE_EVENT_DRAG && x == m->x && y == m->y) {
 			m->event = MOUSE_EVENT_CLICK;
 		} else
 			m->event = MOUSE_EVENT_DRAG;
 		m->event |= MOUSE_EVENT_UP;
 	} else {
-		if (b & 32) /* drag motion */
+		if (b & MOUSE_MASK_DRAG)
 			m->event = MOUSE_EVENT_DRAG;
 		else {
 			if (m->event & MOUSE_EVENT_UP && x == m->x && y == m->y)
@@ -773,7 +773,7 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
 			m->sy = y;
 			m->event = MOUSE_EVENT_DOWN;
 		}
-		m->button = (b & 3);
+		m->button = (b & MOUSE_MASK_BUTTONS);
 	}
 
 	return (0);

From 1704d4a6b799525f510860919b8c8c4315154a05 Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:41:07 +0000
Subject: [PATCH 10/23] Don't segfaut when the parent of the layout cell is
 NULL, from Thomas Adam.

---
 window.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/window.c b/window.c
index 842a5c63..bb69c0bc 100644
--- a/window.c
+++ b/window.c
@@ -423,10 +423,15 @@ window_pane_active_set(struct window_pane *wp, struct window_pane *nextwp)
 void
 window_pane_active_lost(struct window_pane *wp, struct window_pane *nextwp)
 {
-	struct layout_cell	*lc, *lc2;
+	struct layout_cell	*lc, *lc2, *lcparent;
+
+	/* Get the parent cell. */
+	lcparent = nextwp->layout_cell->parent;
+	if (lcparent == NULL)
+		return;
 
 	/* Save the target pane in its parent. */
-	nextwp->layout_cell->parent->lastwp = nextwp;
+	lcparent->lastwp = nextwp;
 
 	/*
 	 * Save the source pane in all of its parents up to, but not including,
@@ -435,8 +440,7 @@ window_pane_active_lost(struct window_pane *wp, struct window_pane *nextwp)
 	if (wp == NULL)
 		return;
 	for (lc = wp->layout_cell->parent; lc != NULL; lc = lc->parent) {
-		lc2 = nextwp->layout_cell->parent;
-		for (; lc2 != NULL; lc2 = lc2->parent) {
+		for (lc2 = lcparent; lc2 != NULL; lc2 = lc2->parent) {
 			if (lc == lc2)
 				return;
 		}

From dca7d1c0fd9dc16aca2337c078da7441dbf97eeb Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:41:35 +0000
Subject: [PATCH 11/23] Make message-limit a server option.

---
 options-table.c | 14 +++++++-------
 status.c        |  6 +-----
 tmux.1          | 10 +++++-----
 3 files changed, 13 insertions(+), 17 deletions(-)

diff --git a/options-table.c b/options-table.c
index ea848259..bc25573a 100644
--- a/options-table.c
+++ b/options-table.c
@@ -81,6 +81,13 @@ const struct options_table_entry server_options_table[] = {
 	  .default_num = 0
 	},
 
+	{ .name = "message-limit",
+	  .type = OPTIONS_TABLE_NUMBER,
+	  .minimum = 0,
+	  .maximum = INT_MAX,
+	  .default_num = 100
+	},
+
 	{ .name = "quiet",
 	  .type = OPTIONS_TABLE_FLAG,
 	  .default_num = 0 /* overridden in main() */
@@ -243,13 +250,6 @@ const struct options_table_entry session_options_table[] = {
 	  .style = "message-style"
 	},
 
-	{ .name = "message-limit",
-	  .type = OPTIONS_TABLE_NUMBER,
-	  .minimum = 0,
-	  .maximum = INT_MAX,
-	  .default_num = 20
-	},
-
 	{ .name = "message-style",
 	  .type = OPTIONS_TABLE_STYLE,
 	  .default_str = "bg=yellow,fg=black"
diff --git a/status.c b/status.c
index 84589427..bf528b0d 100644
--- a/status.c
+++ b/status.c
@@ -655,7 +655,6 @@ void printflike2
 status_message_set(struct client *c, const char *fmt, ...)
 {
 	struct timeval		 tv;
-	struct session		*s = c->session;
 	struct message_entry	*msg;
 	va_list			 ap;
 	int			 delay;
@@ -673,10 +672,7 @@ status_message_set(struct client *c, const char *fmt, ...)
 	msg->msg_time = time(NULL);
 	msg->msg = xstrdup(c->message_string);
 
-	if (s == NULL)
-		limit = 0;
-	else
-		limit = options_get_number(&s->options, "message-limit");
+	limit = options_get_number(&global_options, "message-limit");
 	if (ARRAY_LENGTH(&c->message_log) > limit) {
 		limit = ARRAY_LENGTH(&c->message_log) - limit;
 		for (i = 0; i < limit; i++) {
diff --git a/tmux.1 b/tmux.1
index 8fd63dc4..3167a05a 100644
--- a/tmux.1
+++ b/tmux.1
@@ -778,7 +778,7 @@ Show client messages or server information.
 Any messages displayed on the status line are saved in a per-client message
 log, up to a maximum of the limit set by the
 .Ar message-limit
-session option for the session attached to that client.
+server option.
 With
 .Fl t ,
 display the log for
@@ -2134,6 +2134,10 @@ passed through to applications running in
 .Nm .
 Attached clients should be detached and attached again after changing this
 option.
+.It Ic message-limit Ar number
+Set the number of error or information messages to save in the message log for
+each client.
+The default is 100.
 .It Xo Ic quiet
 .Op Ic on | off
 .Xc
@@ -2391,10 +2395,6 @@ With the
 flag to the
 .Ic set-option
 command the new style is added otherwise the existing style is replaced.
-.It Ic message-limit Ar number
-Set the number of error or information messages to save in the message log for
-each client.
-The default is 20.
 .It Ic message-style Ar style
 Set status line message style.
 For how to specify

From f155316be7f24d76dd8fe6eb3dd34c5cf0aae86d Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:42:05 +0000
Subject: [PATCH 12/23] Remove unused log functions.

---
 log.c  | 41 +----------------------------------------
 tmux.h |  3 ---
 2 files changed, 1 insertion(+), 43 deletions(-)

diff --git a/log.c b/log.c
index 2f1400cb..8a922c0a 100644
--- a/log.c
+++ b/log.c
@@ -41,7 +41,7 @@ __dead void	 log_vfatal(const char *, va_list);
 void
 log_event_cb(unused int severity, const char *msg)
 {
-	log_warnx("%s", msg);
+	log_debug("%s", msg);
 }
 
 /* Open logging to file. */
@@ -86,45 +86,6 @@ log_vwrite(const char *msg, va_list ap)
 	free(fmt);
 }
 
-/* Log a warning with error string. */
-void printflike1
-log_warn(const char *msg, ...)
-{
-	va_list	 ap;
-	char	*fmt;
-
-	va_start(ap, msg);
-	if (asprintf(&fmt, "%s: %s", msg, strerror(errno)) == -1)
-		exit(1);
-	log_vwrite(fmt, ap);
-	free(fmt);
-	va_end(ap);
-}
-
-/* Log a warning. */
-void printflike1
-log_warnx(const char *msg, ...)
-{
-	va_list	ap;
-
-	va_start(ap, msg);
-	log_vwrite(msg, ap);
-	va_end(ap);
-}
-
-/* Log an informational message. */
-void printflike1
-log_info(const char *msg, ...)
-{
-	va_list	ap;
-
-	if (log_level > -1) {
-		va_start(ap, msg);
-		log_vwrite(msg, ap);
-		va_end(ap);
-	}
-}
-
 /* Log a debug message. */
 void printflike1
 log_debug(const char *msg, ...)
diff --git a/tmux.h b/tmux.h
index 94eb5b8f..9990ccfe 100644
--- a/tmux.h
+++ b/tmux.h
@@ -2343,9 +2343,6 @@ char   *get_proc_name(int, char *);
 /* log.c */
 void		 log_open(int, const char *);
 void		 log_close(void);
-void printflike1 log_warn(const char *, ...);
-void printflike1 log_warnx(const char *, ...);
-void printflike1 log_info(const char *, ...);
 void printflike1 log_debug(const char *, ...);
 void printflike1 log_debug2(const char *, ...);
 __dead void printflike1 log_fatal(const char *, ...);

From 7bdb675469336e1c8c7c5039aff369f8245dc450 Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:42:27 +0000
Subject: [PATCH 13/23] GRID_DEBUG is no longer needed.

---
 grid-view.c | 22 ----------------------
 grid.c      | 18 ------------------
 tmux.h      | 10 ----------
 3 files changed, 50 deletions(-)

diff --git a/grid-view.c b/grid-view.c
index 4fe38fed..fca5fd54 100644
--- a/grid-view.c
+++ b/grid-view.c
@@ -59,8 +59,6 @@ grid_view_clear_history(struct grid *gd)
 	struct grid_line	*gl;
 	u_int			 yy, last;
 
-	GRID_DEBUG(gd, "");
-
 	/* Find the last used line. */
 	last = 0;
 	for (yy = 0; yy < gd->sy; yy++) {
@@ -82,8 +80,6 @@ grid_view_clear_history(struct grid *gd)
 void
 grid_view_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny)
 {
-	GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny);
-
 	px = grid_view_x(gd, px);
 	py = grid_view_y(gd, py);
 
@@ -94,8 +90,6 @@ grid_view_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny)
 void
 grid_view_scroll_region_up(struct grid *gd, u_int rupper, u_int rlower)
 {
-	GRID_DEBUG(gd, "rupper=%u, rlower=%u", rupper, rlower);
-
 	if (gd->flags & GRID_HISTORY) {
 		grid_collect_history(gd);
 		if (rupper == 0 && rlower == gd->sy - 1)
@@ -116,8 +110,6 @@ grid_view_scroll_region_up(struct grid *gd, u_int rupper, u_int rlower)
 void
 grid_view_scroll_region_down(struct grid *gd, u_int rupper, u_int rlower)
 {
-	GRID_DEBUG(gd, "rupper=%u, rlower=%u", rupper, rlower);
-
 	rupper = grid_view_y(gd, rupper);
 	rlower = grid_view_y(gd, rlower);
 
@@ -130,8 +122,6 @@ grid_view_insert_lines(struct grid *gd, u_int py, u_int ny)
 {
 	u_int	sy;
 
-	GRID_DEBUG(gd, "py=%u, ny=%u", py, ny);
-
 	py = grid_view_y(gd, py);
 
 	sy = grid_view_y(gd, gd->sy);
@@ -145,8 +135,6 @@ grid_view_insert_lines_region(struct grid *gd, u_int rlower, u_int py, u_int ny)
 {
 	u_int	ny2;
 
-	GRID_DEBUG(gd, "rlower=%u, py=%u, ny=%u", rlower, py, ny);
-
 	rlower = grid_view_y(gd, rlower);
 
 	py = grid_view_y(gd, py);
@@ -162,8 +150,6 @@ grid_view_delete_lines(struct grid *gd, u_int py, u_int ny)
 {
 	u_int	sy;
 
-	GRID_DEBUG(gd, "py=%u, ny=%u", py, ny);
-
 	py = grid_view_y(gd, py);
 
 	sy = grid_view_y(gd, gd->sy);
@@ -178,8 +164,6 @@ grid_view_delete_lines_region(struct grid *gd, u_int rlower, u_int py, u_int ny)
 {
 	u_int	ny2;
 
-	GRID_DEBUG(gd, "rlower=%u, py=%u, ny=%u", rlower, py, ny);
-
 	rlower = grid_view_y(gd, rlower);
 
 	py = grid_view_y(gd, py);
@@ -195,8 +179,6 @@ grid_view_insert_cells(struct grid *gd, u_int px, u_int py, u_int nx)
 {
 	u_int	sx;
 
-	GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx);
-
 	px = grid_view_x(gd, px);
 	py = grid_view_y(gd, py);
 
@@ -214,8 +196,6 @@ grid_view_delete_cells(struct grid *gd, u_int px, u_int py, u_int nx)
 {
 	u_int	sx;
 
-	GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx);
-
 	px = grid_view_x(gd, px);
 	py = grid_view_y(gd, py);
 
@@ -229,8 +209,6 @@ grid_view_delete_cells(struct grid *gd, u_int px, u_int py, u_int nx)
 char *
 grid_view_string_cells(struct grid *gd, u_int px, u_int py, u_int nx)
 {
-	GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx);
-
 	px = grid_view_x(gd, px);
 	py = grid_view_y(gd, py);
 
diff --git a/grid.c b/grid.c
index 7fb15dc3..df2f8b16 100644
--- a/grid.c
+++ b/grid.c
@@ -151,8 +151,6 @@ grid_collect_history(struct grid *gd)
 {
 	u_int	yy;
 
-	GRID_DEBUG(gd, "");
-
 	if (gd->hsize < gd->hlimit)
 		return;
 
@@ -173,8 +171,6 @@ grid_scroll_history(struct grid *gd)
 {
 	u_int	yy;
 
-	GRID_DEBUG(gd, "");
-
 	yy = gd->hsize + gd->sy;
 	gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata);
 	memset(&gd->linedata[yy], 0, sizeof gd->linedata[yy]);
@@ -189,8 +185,6 @@ grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower)
 	struct grid_line	*gl_history, *gl_upper, *gl_lower;
 	u_int			 yy;
 
-	GRID_DEBUG(gd, "upper=%u, lower=%u", upper, lower);
-
 	/* Create a space for a new line. */
 	yy = gd->hsize + gd->sy;
 	gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata);
@@ -282,8 +276,6 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny)
 {
 	u_int	xx, yy;
 
-	GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny);
-
 	if (nx == 0 || ny == 0)
 		return;
 
@@ -319,8 +311,6 @@ grid_clear_lines(struct grid *gd, u_int py, u_int ny)
 	struct grid_line	*gl;
 	u_int			 yy;
 
-	GRID_DEBUG(gd, "py=%u, ny=%u", py, ny);
-
 	if (ny == 0)
 		return;
 
@@ -342,8 +332,6 @@ grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny)
 {
 	u_int	yy;
 
-	GRID_DEBUG(gd, "dy=%u, py=%u, ny=%u", dy, py, ny);
-
 	if (ny == 0 || py == dy)
 		return;
 
@@ -381,8 +369,6 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx)
 	struct grid_line	*gl;
 	u_int			 xx;
 
-	GRID_DEBUG(gd, "dx=%u, px=%u, py=%u, nx=%u", dx, px, py, nx);
-
 	if (nx == 0 || px == dx)
 		return;
 
@@ -592,8 +578,6 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
 	u_int			 xx;
 	const struct grid_line	*gl;
 
-	GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx);
-
 	if (lastgc != NULL && *lastgc == NULL) {
 		memcpy(&lastgc1, &grid_default_cell, sizeof lastgc1);
 		*lastgc = &lastgc1;
@@ -661,8 +645,6 @@ grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy,
 	struct grid_line	*dstl, *srcl;
 	u_int			 yy;
 
-	GRID_DEBUG(src, "dy=%u, sy=%u, ny=%u", dy, sy, ny);
-
 	if (dy + ny > dst->hsize + dst->sy)
 		ny = dst->hsize + dst->sy - dy;
 	if (sy + ny > src->hsize + src->sy)
diff --git a/tmux.h b/tmux.h
index 9990ccfe..df7b5d16 100644
--- a/tmux.h
+++ b/tmux.h
@@ -663,16 +663,6 @@ struct utf8_data {
 	u_int	width;
 };
 
-/* Grid output. */
-#if defined(DEBUG) && \
-    ((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
-     (defined(__GNUC__) && __GNUC__ >= 3))
-#define GRID_DEBUG(gd, fmt, ...) log_debug2("%s: (sx=%u, sy=%u, hsize=%u) " \
-    fmt, __func__, (gd)->sx, (gd)->sy, (gd)->hsize, ## __VA_ARGS__)
-#else
-#define GRID_DEBUG(...)
-#endif
-
 /* Grid attributes. */
 #define GRID_ATTR_BRIGHT 0x1
 #define GRID_ATTR_DIM 0x2

From 48478ea0a990cc14d61722f9f8d3f1490d8f417a Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:42:45 +0000
Subject: [PATCH 14/23] Remove log_debug2 as well and simplify log.c.

---
 input-keys.c |  6 ++--
 log.c        | 77 ++++++++++++++--------------------------------------
 tmux.c       |  2 +-
 3 files changed, 25 insertions(+), 60 deletions(-)

diff --git a/input-keys.c b/input-keys.c
index 2de48e97..9247a995 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -143,7 +143,7 @@ input_key(struct window_pane *wp, int key)
 	char			       *out;
 	u_char				ch;
 
-	log_debug2("writing key 0x%x", key);
+	log_debug("writing key 0x%x", key);
 
 	/*
 	 * If this is a normal 7-bit key, just send it, with a leading escape
@@ -186,11 +186,11 @@ input_key(struct window_pane *wp, int key)
 			break;
 	}
 	if (i == nitems(input_keys)) {
-		log_debug2("key 0x%x missing", key);
+		log_debug("key 0x%x missing", key);
 		return;
 	}
 	dlen = strlen(ike->data);
-	log_debug2("found key 0x%x: \"%s\"", key, ike->data);
+	log_debug("found key 0x%x: \"%s\"", key, ike->data);
 
 	/* Prefix a \033 for escape. */
 	if (key & KEYC_ESCAPE)
diff --git a/log.c b/log.c
index 8a922c0a..f329107c 100644
--- a/log.c
+++ b/log.c
@@ -22,20 +22,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <syslog.h>
-#include <time.h>
 
 #include "tmux.h"
 
-/* Log file, if needed. */
-FILE		*log_file;
+FILE	*log_file;
 
-/* Debug level. */
-int		 log_level = 0;
-
-void		 log_event_cb(int, const char *);
-void		 log_vwrite(const char *, va_list);
-__dead void	 log_vfatal(const char *, va_list);
+void	 log_event_cb(int, const char *);
+void	 log_vwrite(const char *, va_list);
 
 /* Log callback for libevent. */
 void
@@ -46,12 +39,11 @@ log_event_cb(unused int severity, const char *msg)
 
 /* Open logging to file. */
 void
-log_open(int level, const char *path)
+log_open(const char *path)
 {
 	log_file = fopen(path, "w");
 	if (log_file == NULL)
 		return;
-	log_level = level;
 
 	setlinebuf(log_file);
 	event_set_log_callback(log_event_cb);
@@ -65,6 +57,7 @@ log_close(void)
 {
 	if (log_file != NULL)
 		fclose(log_file);
+	log_file = NULL;
 
 	event_set_log_callback(NULL);
 }
@@ -92,63 +85,35 @@ log_debug(const char *msg, ...)
 {
 	va_list	ap;
 
-	if (log_level > 0) {
-		va_start(ap, msg);
-		log_vwrite(msg, ap);
-		va_end(ap);
-	}
+	va_start(ap, msg);
+	log_vwrite(msg, ap);
+	va_end(ap);
 }
 
-/* Log a debug message at level 2. */
-void printflike1
-log_debug2(const char *msg, ...)
-{
-	va_list	ap;
-
-	if (log_level > 1) {
-		va_start(ap, msg);
-		log_vwrite(msg, ap);
-		va_end(ap);
-	}
-}
-
-/* Log a critical error, with error string if necessary, and die. */
-__dead void
-log_vfatal(const char *msg, va_list ap)
-{
-	char	*fmt;
-
-	if (errno != 0) {
-		if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1)
-			exit(1);
-		log_vwrite(fmt, ap);
-	} else {
-		if (asprintf(&fmt, "fatal: %s", msg) == -1)
-			exit(1);
-		log_vwrite(fmt, ap);
-	}
-	free(fmt);
-
-	exit(1);
-}
-
-/* Log a critical error, with error string, and die. */
+/* Log a critical error with error string and die. */
 __dead void printflike1
 log_fatal(const char *msg, ...)
 {
-	va_list	ap;
+	char	*fmt;
+	va_list	 ap;
 
 	va_start(ap, msg);
-	log_vfatal(msg, ap);
+	if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1)
+		exit(1);
+	log_vwrite(fmt, ap);
+	exit(1);
 }
 
 /* Log a critical error and die. */
 __dead void printflike1
 log_fatalx(const char *msg, ...)
 {
-	va_list	ap;
+	char	*fmt;
+	va_list	 ap;
 
-	errno = 0;
 	va_start(ap, msg);
-	log_vfatal(msg, ap);
+	if (asprintf(&fmt, "fatal: %s", msg) == -1)
+		exit(1);
+	log_vwrite(fmt, ap);
+	exit(1);
 }
diff --git a/tmux.c b/tmux.c
index 6de96ce1..8f9e520d 100644
--- a/tmux.c
+++ b/tmux.c
@@ -70,7 +70,7 @@ logfile(const char *name)
 
 	if (debug_level > 0) {
 		xasprintf(&path, "tmux-%s-%ld.log", name, (long) getpid());
-		log_open(debug_level, path);
+		log_open(path);
 		free(path);
 	}
 }

From ee19d304ff366741f6f94334bbc82124a4c44dbc Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:43:35 +0000
Subject: [PATCH 15/23] In four byte UTF-8 sequences, only three bits of the
 first byte should be used. Fix from Koga Osamu.

---
 utf8.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utf8.c b/utf8.c
index 1c81392b..85889dcb 100644
--- a/utf8.c
+++ b/utf8.c
@@ -311,7 +311,7 @@ utf8_combine(const struct utf8_data *utf8data)
 		value = utf8data->data[3] & 0x3f;
 		value |= (utf8data->data[2] & 0x3f) << 6;
 		value |= (utf8data->data[1] & 0x3f) << 12;
-		value |= (utf8data->data[0] & 0x3f) << 18;
+		value |= (utf8data->data[0] & 0x07) << 18;
 		break;
 	}
 	return (value);

From 3c06bec03fe269b8a2548c147fe7b4f2eb4d3c7a Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Mon, 31 Mar 2014 21:43:55 +0000
Subject: [PATCH 16/23] Don't crash with a zero-length argument to setb, from J
 Raynor.

---
 cmd-set-buffer.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c
index 0942da9a..a206760c 100644
--- a/cmd-set-buffer.c
+++ b/cmd-set-buffer.c
@@ -56,6 +56,9 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 	pb = NULL;
 	buffer = -1;
 
+	if ((newsize = strlen(args->argv[0])) == 0)
+		return (CMD_RETURN_NORMAL);
+
 	if (args_has(args, 'b')) {
 		buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
 		if (cause != NULL) {
@@ -80,8 +83,6 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 		memcpy(pdata, pb->data, psize);
 	}
 
-	newsize = strlen(args->argv[0]);
-
 	pdata = xrealloc(pdata, 1, psize + newsize);
 	memcpy(pdata + psize, args->argv[0], newsize);
 	psize += newsize;

From d9960b2d4d4cb6697086d32b24e9e6cbc74df483 Mon Sep 17 00:00:00 2001
From: deraadt <deraadt>
Date: Tue, 1 Apr 2014 05:50:30 +0000
Subject: [PATCH 17/23] missed commit matching log.c

---
 tmux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tmux.h b/tmux.h
index df7b5d16..6b35e175 100644
--- a/tmux.h
+++ b/tmux.h
@@ -2331,7 +2331,7 @@ u_int	utf8_split2(u_int, u_char *);
 char   *get_proc_name(int, char *);
 
 /* log.c */
-void		 log_open(int, const char *);
+void		 log_open(const char *);
 void		 log_close(void);
 void printflike1 log_debug(const char *, ...);
 void printflike1 log_debug2(const char *, ...);

From b52b40b2bc9e90e2e585aa2158aee45fcbe1db86 Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Wed, 2 Apr 2014 07:55:09 +0000
Subject: [PATCH 18/23] pane_start_path has gone away.

---
 tmux.1 | 1 -
 1 file changed, 1 deletion(-)

diff --git a/tmux.1 b/tmux.1
index 3167a05a..eb0be916 100644
--- a/tmux.1
+++ b/tmux.1
@@ -3128,7 +3128,6 @@ The following variables are available, where appropriate:
 .It Li "pane_index" Ta "#P" Ta "Index of pane"
 .It Li "pane_pid" Ta "" Ta "PID of first process in pane"
 .It Li "pane_start_command" Ta "" Ta "Command pane started with"
-.It Li "pane_start_path" Ta "" Ta "Path pane started with"
 .It Li "pane_tabs" Ta "" Ta "Pane tab positions"
 .It Li "pane_title" Ta "#T" Ta "Title of pane"
 .It Li "pane_tty" Ta "" Ta "Pseudo terminal of pane"

From 8880bdb67c9d939ec53506d05f5ce1d75be10c97 Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Wed, 2 Apr 2014 17:08:23 +0000
Subject: [PATCH 19/23] Do not replace ## with # in status_replace1 because
 it'll be done later by the format code.

---
 status.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/status.c b/status.c
index bf528b0d..029be4c8 100644
--- a/status.c
+++ b/status.c
@@ -396,9 +396,6 @@ status_replace1(struct client *c, char **iptr, char **optr, char *out,
 	case '{':
 		ptr = (char *) "#{";
 		goto do_replace;
-	case '#':
-		*(*optr)++ = '#';
-		break;
 	default:
 		xsnprintf(tmp, sizeof tmp, "#%c", *(*iptr - 1));
 		ptr = tmp;

From 82f3e0e9e68d4078555cd6270473c45a3e60273b Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Wed, 2 Apr 2014 17:14:24 +0000
Subject: [PATCH 20/23] Use the same logic for bell with and without
 visual-bell, from Filip Moc.

---
 server-window.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/server-window.c b/server-window.c
index 39699c37..86beeef4 100644
--- a/server-window.c
+++ b/server-window.c
@@ -85,10 +85,11 @@ server_window_check_bell(struct session *s, struct winlink *wl)
 		return (0);
 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
 		c = ARRAY_ITEM(&clients, i);
-		if (c == NULL || c->session != s || (c->flags & CLIENT_CONTROL))
+		if (c == NULL || c->session != s || c->flags & CLIENT_CONTROL)
 			continue;
 		if (!visual) {
-			tty_bell(&c->tty);
+			if (c->session->curw->window == w || action == BELL_ANY)
+				tty_bell(&c->tty);
 			continue;
 		}
 		if (c->session->curw->window == w)

From 252a7373d69646ae866e3a4fa18d46f673864c0e Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Wed, 2 Apr 2014 18:12:18 +0000
Subject: [PATCH 21/23] Support UTF-8 with choose-buffer, from Kosuke ASAMI.
 Also make buffer_sample bigger to let it trim at window right edge.

---
 cmd-choose-buffer.c |  4 +++-
 cmd-list-buffers.c  |  2 +-
 format.c            | 10 ++++++----
 paste.c             | 23 ++++++++++++-----------
 tmux.1              |  2 +-
 tmux.h              |  7 ++++---
 utf8.c              | 43 +++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 70 insertions(+), 21 deletions(-)

diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c
index 359de068..1e0edaa6 100644
--- a/cmd-choose-buffer.c
+++ b/cmd-choose-buffer.c
@@ -49,6 +49,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 	char				*action, *action_data;
 	const char			*template;
 	u_int				 idx;
+	int				 utf8flag;
 
 	if ((c = cmd_current_client(cmdq)) == NULL) {
 		cmdq_error(cmdq, "no client available");
@@ -60,6 +61,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 
 	if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
 		return (CMD_RETURN_ERROR);
+	utf8flag = options_get_number(&wl->window->options, "utf8");
 
 	if (paste_get_top(&global_buffers) == NULL)
 		return (CMD_RETURN_NORMAL);
@@ -79,7 +81,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 
 		cdata->ft_template = xstrdup(template);
 		format_add(cdata->ft, "line", "%u", idx - 1);
-		format_paste_buffer(cdata->ft, pb);
+		format_paste_buffer(cdata->ft, pb, utf8flag);
 
 		xasprintf(&action_data, "%u", idx - 1);
 		cdata->command = cmd_template_replace(action, action_data, 1);
diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c
index e36a7cd0..7051eae8 100644
--- a/cmd-list-buffers.c
+++ b/cmd-list-buffers.c
@@ -55,7 +55,7 @@ cmd_list_buffers_exec(unused struct cmd *self, struct cmd_q *cmdq)
 	while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) {
 		ft = format_create();
 		format_add(ft, "line", "%u", idx - 1);
-		format_paste_buffer(ft, pb);
+		format_paste_buffer(ft, pb, 0);
 
 		line = format_expand(ft, template);
 		cmdq_print(cmdq, "%s", line);
diff --git a/format.c b/format.c
index 1dca6011..5fc76b2b 100644
--- a/format.c
+++ b/format.c
@@ -601,12 +601,14 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp)
 
 /* Set default format keys for paste buffer. */
 void
-format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb)
+format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb,
+    int utf8flag)
 {
-	char	*pb_print = paste_print(pb, 50);
+	char	*s;
 
 	format_add(ft, "buffer_size", "%zu", pb->size);
-	format_add(ft, "buffer_sample", "%s", pb_print);
 
-	free(pb_print);
+	s = paste_make_sample(pb, utf8flag);
+	format_add(ft, "buffer_sample", "%s", s);
+	free(s);
 }
diff --git a/paste.c b/paste.c
index 4ec87f35..98d71a07 100644
--- a/paste.c
+++ b/paste.c
@@ -148,25 +148,26 @@ paste_replace(struct paste_stack *ps, u_int idx, char *data, size_t size)
 	return (0);
 }
 
-/* Convert a buffer into a visible string. */
+/* Convert start of buffer into a nice string. */
 char *
-paste_print(struct paste_buffer *pb, size_t width)
+paste_make_sample(struct paste_buffer *pb, int utf8flag)
 {
-	char	*buf;
-	size_t	 len, used;
-
-	if (width < 3)
-		width = 3;
-	buf = xmalloc(width * 4 + 1);
+	char		*buf;
+	size_t		 len, used;
+	const int	 flags = VIS_OCTAL|VIS_TAB|VIS_NL;
+	const size_t	 width = 200;
 
 	len = pb->size;
 	if (len > width)
 		len = width;
+	buf = xmalloc(len * 4 + 4);
 
-	used = strvisx(buf, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL);
+	if (utf8flag)
+		used = utf8_strvis(buf, pb->data, len, flags);
+	else
+		used = strvisx(buf, pb->data, len, flags);
 	if (pb->size > width || used > width)
-		strlcpy(buf + width - 3, "...", 4);
-
+		strlcpy(buf + width, "...", 4);
 	return (buf);
 }
 
diff --git a/tmux.1 b/tmux.1
index eb0be916..8205e026 100644
--- a/tmux.1
+++ b/tmux.1
@@ -3087,7 +3087,7 @@ The following variables are available, where appropriate:
 .It Li "alternate_on" Ta "" Ta "If pane is in alternate screen"
 .It Li "alternate_saved_x" Ta "" Ta "Saved cursor X in alternate screen"
 .It Li "alternate_saved_y" Ta "" Ta "Saved cursor Y in alternate screen"
-.It Li "buffer_sample" Ta "" Ta "First 50 characters from buffer"
+.It Li "buffer_sample" Ta "" Ta "Sample of start of buffer"
 .It Li "buffer_size" Ta "" Ta "Size of the specified buffer in bytes"
 .It Li "client_activity" Ta "" Ta "Integer time client last had activity"
 .It Li "client_activity_string" Ta "" Ta "String time client last had activity"
diff --git a/tmux.h b/tmux.h
index 6b35e175..7e541458 100644
--- a/tmux.h
+++ b/tmux.h
@@ -85,7 +85,7 @@ extern char   **environ;
 
 /* Default template for choose-buffer. */
 #define CHOOSE_BUFFER_TEMPLATE					\
-	"#{line}: #{buffer_size} bytes: \"#{buffer_sample}\""
+	"#{line}: #{buffer_size} bytes: #{buffer_sample}"
 
 /* Default template for choose-client. */
 #define CHOOSE_CLIENT_TEMPLATE					\
@@ -1544,7 +1544,7 @@ void		 format_winlink(struct format_tree *, struct session *,
 void		 format_window_pane(struct format_tree *,
 		     struct window_pane *);
 void		 format_paste_buffer(struct format_tree *,
-		     struct paste_buffer *);
+		     struct paste_buffer *, int);
 
 /* mode-key.c */
 extern const struct mode_key_table mode_key_tables[];
@@ -1714,7 +1714,7 @@ int		 paste_free_top(struct paste_stack *);
 int		 paste_free_index(struct paste_stack *, u_int);
 void		 paste_add(struct paste_stack *, char *, size_t, u_int);
 int		 paste_replace(struct paste_stack *, u_int, char *, size_t);
-char		*paste_print(struct paste_buffer *, size_t);
+char		*paste_make_sample(struct paste_buffer *, int);
 void		 paste_send_pane(struct paste_buffer *, struct window_pane *,
 		     const char *, int);
 
@@ -2326,6 +2326,7 @@ int	utf8_open(struct utf8_data *, u_char);
 int	utf8_append(struct utf8_data *, u_char);
 u_int	utf8_combine(const struct utf8_data *);
 u_int	utf8_split2(u_int, u_char *);
+int	utf8_strvis(char *, const char *, size_t, int);
 
 /* procname.c */
 char   *get_proc_name(int, char *);
diff --git a/utf8.c b/utf8.c
index 85889dcb..082683e8 100644
--- a/utf8.c
+++ b/utf8.c
@@ -19,6 +19,7 @@
 #include <sys/types.h>
 
 #include <string.h>
+#include <vis.h>
 
 #include "tmux.h"
 
@@ -350,3 +351,45 @@ utf8_width(const struct utf8_data *utf8data)
 	}
 	return (1);
 }
+
+/*
+ * Encode len characters from src into dst, which is guaranteed to have four
+ * bytes available for each character from src (for \abc or UTF-8) plus space
+ * for \0.
+ */
+int
+utf8_strvis(char *dst, const char *src, size_t len, int flag)
+{
+	struct utf8_data	 utf8data;
+	const char		*start, *end;
+	int			 more;
+	size_t			 i;
+
+	start = dst;
+	end = src + len;
+
+	while (src < end) {
+		if (utf8_open(&utf8data, *src)) {
+			more = 1;
+			while (++src < end && more)
+				more = utf8_append(&utf8data, *src);
+			if (!more) {
+				/* UTF-8 character finished. */
+				for (i = 0; i < utf8data.size; i++)
+					*dst++ = utf8data.data[i];
+				continue;
+			} else if (utf8data.have > 0) {
+				/* Not a complete UTF-8 character. */
+				src -= utf8data.have;
+			}
+		}
+		if (src < end - 1)
+			dst = vis(dst, src[0], flag, src[1]);
+		else if (src < end)
+			dst = vis(dst, src[0], flag, '\0');
+		src++;
+	}
+
+	*dst = '\0';
+	return (dst - start);
+}

From 8824dae6f7b21f95ea824ecc1abc31140763c971 Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Thu, 3 Apr 2014 08:15:17 +0000
Subject: [PATCH 22/23] A couple of trivial mouse-related style nits.

---
 input-keys.c | 2 +-
 tty-keys.c   | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/input-keys.c b/input-keys.c
index 9247a995..0370a684 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -245,7 +245,7 @@ input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m)
 			paste_send_pane(pb, wp, "\r",
 			    wp->screen->mode & MODE_BRACKETPASTE);
 		}
-	} else if ((m->xb & 3) != 1 &&
+	} else if (m->button != 1 &&
 	    options_get_number(&wp->window->options, "mode-mouse") == 1) {
 		if (window_pane_set_mode(wp, &window_copy_mode) == 0) {
 			window_copy_init_from_pane(wp);
diff --git a/tty-keys.c b/tty-keys.c
index e0e794cc..1116df2b 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -756,9 +756,9 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
 			m->wheel = MOUSE_WHEEL_DOWN;
 		m->event = MOUSE_EVENT_WHEEL;
 	} else if ((b & MOUSE_MASK_BUTTONS) == 3) {
-		if (~m->event & MOUSE_EVENT_DRAG && x == m->x && y == m->y) {
+		if (~m->event & MOUSE_EVENT_DRAG && x == m->x && y == m->y)
 			m->event = MOUSE_EVENT_CLICK;
-		} else
+		else
 			m->event = MOUSE_EVENT_DRAG;
 		m->event |= MOUSE_EVENT_UP;
 	} else {

From acef311fe356f408690e9f94727ed63a934b742f Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Thu, 3 Apr 2014 08:20:29 +0000
Subject: [PATCH 23/23] Work out mouse scroll wheel effect when the mouse is
 first detected and store it in struct mouse_event, reduce the scroll size the
 3 but allow shift to reduce it to 1 and meta and ctrl to multiply by 3 if the
 terminal supports them, also support wheel in choose mode. From Marcel
 Partap.

---
 tmux.h          |  1 +
 tty-keys.c      |  9 +++++++++
 window-choose.c | 12 +++++++++++-
 window-copy.c   | 21 +++++++++++----------
 4 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/tmux.h b/tmux.h
index 7e541458..a9edf8ff 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1168,6 +1168,7 @@ struct mouse_event {
 
 	u_int	button;
 	u_int	clicks;
+	u_int	scroll;
 
 	int	wheel;
 	int     event;
diff --git a/tty-keys.c b/tty-keys.c
index 1116df2b..4f55a80c 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -749,6 +749,15 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
 	m->x = x;
 	m->y = y;
 	if (b & MOUSE_MASK_WHEEL) {
+		if (b & MOUSE_MASK_SHIFT)
+			m->scroll = 1;
+		else
+			m->scroll = 3;
+		if (b & MOUSE_MASK_META)
+			m->scroll *= 3;
+		if (b & MOUSE_MASK_CTRL)
+			m->scroll *= 3;
+
 		b &= MOUSE_MASK_BUTTONS;
 		if (b == 0)
 			m->wheel = MOUSE_WHEEL_UP;
diff --git a/window-choose.c b/window-choose.c
index bb881aa5..c354d46f 100644
--- a/window-choose.c
+++ b/window-choose.c
@@ -721,7 +721,17 @@ window_choose_mouse(
 	struct window_choose_mode_data	*data = wp->modedata;
 	struct screen			*s = &data->screen;
 	struct window_choose_mode_item	*item;
-	u_int				 idx;
+	u_int				 i, idx;
+
+	if (m->event == MOUSE_EVENT_WHEEL) {
+		for (i = 0; i < m->scroll; i++) {
+			if (m->wheel == MOUSE_WHEEL_UP)
+				window_choose_key(wp, sess, KEYC_UP);
+			else
+				window_choose_key(wp, sess, KEYC_DOWN);
+		}
+		return;
+	}
 
 	if (~m->event & MOUSE_EVENT_CLICK)
 		return;
diff --git a/window-copy.c b/window-copy.c
index 7d7f3a20..6e4d6704 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -871,18 +871,19 @@ window_copy_mouse(
 
 	/* If mouse wheel (buttons 4 and 5), scroll. */
 	if (m->event == MOUSE_EVENT_WHEEL) {
-		if (m->wheel == MOUSE_WHEEL_UP) {
-			for (i = 0; i < 5; i++)
+		for (i = 0; i < m->scroll; i++) {
+			if (m->wheel == MOUSE_WHEEL_UP)
 				window_copy_cursor_up(wp, 1);
-		} else if (m->wheel == MOUSE_WHEEL_DOWN) {
-			for (i = 0; i < 5; i++)
+			else {
 				window_copy_cursor_down(wp, 1);
-			/*
-			 * We reached the bottom, leave copy mode,
-			 * but only if no selection is in progress.
-			 */
-			if (data->oy == 0 && !s->sel.flag)
-			    goto reset_mode;
+
+				/*
+				 * We reached the bottom, leave copy mode, but
+				 * only if no selection is in progress.
+				 */
+				if (data->oy == 0 && !s->sel.flag)
+					goto reset_mode;
+			}
 		}
 		return;
 	}