From de34436d4c2d4ba72f37b80ed3804d057b95c0dc Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Thu, 19 Mar 2020 14:03:48 +0000
Subject: [PATCH 1/2] Change input path so it doesn't require a pane.

---
 cmd-capture-pane.c |   2 +-
 cmd-send-keys.c    |   2 +-
 input-keys.c       |  52 +++++++-----
 input.c            | 200 ++++++++++++++++++++++++++++-----------------
 spawn.c            |   3 +-
 tmux.h             |  19 +++--
 window.c           |  10 +--
 7 files changed, 175 insertions(+), 113 deletions(-)

diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c
index 18be3f77..2c8dd920 100644
--- a/cmd-capture-pane.c
+++ b/cmd-capture-pane.c
@@ -80,7 +80,7 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
 	size_t		 linelen;
 	u_int		 i;
 
-	pending = input_pending(wp);
+	pending = input_pending(wp->ictx);
 	if (pending == NULL)
 		return (xstrdup(""));
 
diff --git a/cmd-send-keys.c b/cmd-send-keys.c
index cc04a73f..5770572a 100644
--- a/cmd-send-keys.c
+++ b/cmd-send-keys.c
@@ -192,7 +192,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
 
 	if (args_has(args, 'R')) {
 		window_pane_reset_palette(wp);
-		input_reset(wp, 1);
+		input_reset(wp->ictx, 1);
 	}
 
 	for (; np != 0; np--) {
diff --git a/input-keys.c b/input-keys.c
index d09bf8fb..9d4043ef 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -149,9 +149,25 @@ input_split2(u_int c, u_char *dst)
 	return (1);
 }
 
+/* Translate a key code into an output key sequence for a pane. */
+int
+input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m)
+{
+	log_debug("writing key 0x%llx (%s) to %%%u", key,
+	    key_string_lookup_key(key), wp->id);
+
+	if (KEYC_IS_MOUSE(key)) {
+		if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id)
+			input_key_mouse(wp, m);
+		return (0);
+	}
+	return (input_key(wp, wp->screen, wp->event, key));
+}
+
 /* Translate a key code into an output key sequence. */
 int
-input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
+input_key(struct window_pane *wp, struct screen *s, struct bufferevent *bev,
+    key_code key)
 {
 	const struct input_key_ent	*ike;
 	u_int				 i;
@@ -160,20 +176,14 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
 	key_code			 justkey, newkey;
 	struct utf8_data		 ud;
 
-	log_debug("writing key 0x%llx (%s) to %%%u", key,
-	    key_string_lookup_key(key), wp->id);
-
-	/* If this is a mouse key, pass off to mouse function. */
-	if (KEYC_IS_MOUSE(key)) {
-		if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id)
-			input_key_mouse(wp, m);
+	/* Mouse keys need a pane. */
+	if (KEYC_IS_MOUSE(key))
 		return (0);
-	}
 
 	/* Literal keys go as themselves (can't be more than eight bits). */
 	if (key & KEYC_LITERAL) {
 		ud.data[0] = (u_char)key;
-		bufferevent_write(wp->event, &ud.data[0], 1);
+		bufferevent_write(bev, &ud.data[0], 1);
 		return (0);
 	}
 
@@ -192,17 +202,17 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
 	justkey = (key & ~(KEYC_XTERM|KEYC_ESCAPE));
 	if (justkey <= 0x7f) {
 		if (key & KEYC_ESCAPE)
-			bufferevent_write(wp->event, "\033", 1);
+			bufferevent_write(bev, "\033", 1);
 		ud.data[0] = justkey;
-		bufferevent_write(wp->event, &ud.data[0], 1);
+		bufferevent_write(bev, &ud.data[0], 1);
 		return (0);
 	}
 	if (justkey > 0x7f && justkey < KEYC_BASE) {
 		if (utf8_split(justkey, &ud) != UTF8_DONE)
 			return (-1);
 		if (key & KEYC_ESCAPE)
-			bufferevent_write(wp->event, "\033", 1);
-		bufferevent_write(wp->event, ud.data, ud.size);
+			bufferevent_write(bev, "\033", 1);
+		bufferevent_write(bev, ud.data, ud.size);
 		return (0);
 	}
 
@@ -210,9 +220,9 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
 	 * Then try to look this up as an xterm key, if the flag to output them
 	 * is set.
 	 */
-	if (options_get_number(wp->window->options, "xterm-keys")) {
+	if (wp == NULL || options_get_number(wp->window->options, "xterm-keys")) {
 		if ((out = xterm_keys_lookup(key)) != NULL) {
-			bufferevent_write(wp->event, out, strlen(out));
+			bufferevent_write(bev, out, strlen(out));
 			free(out);
 			return (0);
 		}
@@ -223,11 +233,9 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
 	for (i = 0; i < nitems(input_keys); i++) {
 		ike = &input_keys[i];
 
-		if ((ike->flags & INPUTKEY_KEYPAD) &&
-		    !(wp->screen->mode & MODE_KKEYPAD))
+		if ((ike->flags & INPUTKEY_KEYPAD) && (~s->mode & MODE_KKEYPAD))
 			continue;
-		if ((ike->flags & INPUTKEY_CURSOR) &&
-		    !(wp->screen->mode & MODE_KCURSOR))
+		if ((ike->flags & INPUTKEY_CURSOR) && (~s->mode & MODE_KCURSOR))
 			continue;
 
 		if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key)
@@ -244,8 +252,8 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
 
 	/* Prefix a \033 for escape. */
 	if (key & KEYC_ESCAPE)
-		bufferevent_write(wp->event, "\033", 1);
-	bufferevent_write(wp->event, ike->data, dlen);
+		bufferevent_write(bev, "\033", 1);
+	bufferevent_write(bev, ike->data, dlen);
 	return (0);
 }
 
diff --git a/input.c b/input.c
index 82d2b398..c7d67b82 100644
--- a/input.c
+++ b/input.c
@@ -128,7 +128,7 @@ struct input_transition;
 static int	input_split(struct input_ctx *);
 static int	input_get(struct input_ctx *, u_int, int, int);
 static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...);
-static void	input_set_state(struct window_pane *,
+static void	input_set_state(struct input_ctx *,
 		    const struct input_transition *);
 static void	input_reset_cell(struct input_ctx *);
 
@@ -731,10 +731,9 @@ static void
 input_timer_callback(__unused int fd, __unused short events, void *arg)
 {
 	struct input_ctx	*ictx = arg;
-	struct window_pane	*wp = ictx->wp;
 
-	log_debug("%s: %%%u %s expired" , __func__, wp->id, ictx->state->name);
-	input_reset(wp, 0);
+	log_debug("%s: %s expired" , __func__, ictx->state->name);
+	input_reset(ictx, 0);
 }
 
 /* Start the timer. */
@@ -788,12 +787,13 @@ input_restore_state(struct input_ctx *ictx)
 }
 
 /* Initialise input parser. */
-void
+struct input_ctx *
 input_init(struct window_pane *wp)
 {
 	struct input_ctx	*ictx;
 
-	ictx = wp->ictx = xcalloc(1, sizeof *ictx);
+	ictx = xcalloc(1, sizeof *ictx);
+	ictx->wp = wp;
 
 	ictx->input_space = INPUT_BUF_START;
 	ictx->input_buf = xmalloc(INPUT_BUF_START);
@@ -804,15 +804,15 @@ input_init(struct window_pane *wp)
 
 	evtimer_set(&ictx->timer, input_timer_callback, ictx);
 
-	input_reset(wp, 0);
+	input_reset(ictx, 0);
+	return (ictx);
 }
 
 /* Destroy input parser. */
 void
-input_free(struct window_pane *wp)
+input_free(struct input_ctx *ictx)
 {
-	struct input_ctx	*ictx = wp->ictx;
-	u_int			 i;
+	u_int	i;
 
 	for (i = 0; i < ictx->param_list_len; i++) {
 		if (ictx->param_list[i].type == INPUT_STRING)
@@ -825,19 +825,18 @@ input_free(struct window_pane *wp)
 	evbuffer_free(ictx->since_ground);
 
 	free(ictx);
-	wp->ictx = NULL;
 }
 
 /* Reset input state and clear screen. */
 void
-input_reset(struct window_pane *wp, int clear)
+input_reset(struct input_ctx *ictx, int clear)
 {
-	struct input_ctx	*ictx = wp->ictx;
 	struct screen_write_ctx	*sctx = &ictx->ctx;
+	struct window_pane	*wp = ictx->wp;
 
 	input_reset_cell(ictx);
 
-	if (clear) {
+	if (clear && wp != NULL) {
 		if (TAILQ_EMPTY(&wp->modes))
 			screen_write_start(sctx, wp, &wp->base);
 		else
@@ -856,17 +855,15 @@ input_reset(struct window_pane *wp, int clear)
 
 /* Return pending data. */
 struct evbuffer *
-input_pending(struct window_pane *wp)
+input_pending(struct input_ctx *ictx)
 {
-	return (wp->ictx->since_ground);
+	return (ictx->since_ground);
 }
 
 /* Change input state. */
 static void
-input_set_state(struct window_pane *wp, const struct input_transition *itr)
+input_set_state(struct input_ctx *ictx, const struct input_transition *itr)
 {
-	struct input_ctx	*ictx = wp->ictx;
-
 	if (ictx->state->exit != NULL)
 		ictx->state->exit(ictx);
 	ictx->state = itr->state;
@@ -874,46 +871,15 @@ input_set_state(struct window_pane *wp, const struct input_transition *itr)
 		ictx->state->enter(ictx);
 }
 
-/* Parse input. */
-void
-input_parse(struct window_pane *wp)
+/* Parse data. */
+static void
+input_parse(struct input_ctx *ictx, u_char *buf, size_t len)
 {
-	struct evbuffer	*evb = wp->event->input;
-
-	input_parse_buffer(wp, EVBUFFER_DATA(evb), EVBUFFER_LENGTH(evb));
-	evbuffer_drain(evb, EVBUFFER_LENGTH(evb));
-}
-
-/* Parse given input. */
-void
-input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
-{
-	struct input_ctx		*ictx = wp->ictx;
 	struct screen_write_ctx		*sctx = &ictx->ctx;
 	const struct input_state	*state = NULL;
 	const struct input_transition	*itr = NULL;
 	size_t				 off = 0;
 
-	if (len == 0)
-		return;
-
-	window_update_activity(wp->window);
-	wp->flags |= PANE_CHANGED;
-	notify_input(wp, buf, len);
-
-	/*
-	 * Open the screen. Use NULL wp if there is a mode set as don't want to
-	 * update the tty.
-	 */
-	if (TAILQ_EMPTY(&wp->modes))
-		screen_write_start(sctx, wp, &wp->base);
-	else
-		screen_write_start(sctx, NULL, &wp->base);
-	ictx->wp = wp;
-
-	log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
-	    ictx->state->name, len, (int)len, buf);
-
 	/* Parse the input. */
 	while (off < len) {
 		ictx->ch = buf[off++];
@@ -956,14 +922,63 @@ input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
 
 		/* And switch state, if necessary. */
 		if (itr->state != NULL)
-			input_set_state(wp, itr);
+			input_set_state(ictx, itr);
 
 		/* If not in ground state, save input. */
 		if (ictx->state != &input_state_ground)
 			evbuffer_add(ictx->since_ground, &ictx->ch, 1);
 	}
+}
 
-	/* Close the screen. */
+/* Parse input from pane. */
+void
+input_parse_pane(struct window_pane *wp)
+{
+	struct evbuffer	*evb = wp->event->input;
+
+	input_parse_buffer(wp, EVBUFFER_DATA(evb), EVBUFFER_LENGTH(evb));
+	evbuffer_drain(evb, EVBUFFER_LENGTH(evb));
+}
+
+/* Parse given input. */
+void
+input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
+{
+	struct input_ctx	*ictx = wp->ictx;
+	struct screen_write_ctx	*sctx = &ictx->ctx;
+
+	if (len == 0)
+		return;
+
+	window_update_activity(wp->window);
+	wp->flags |= PANE_CHANGED;
+	notify_input(wp, buf, len);
+
+	/* NULL wp if there is a mode set as don't want to update the tty. */
+	if (TAILQ_EMPTY(&wp->modes))
+		screen_write_start(sctx, wp, &wp->base);
+	else
+		screen_write_start(sctx, NULL, &wp->base);
+
+	log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
+	    ictx->state->name, len, (int)len, buf);
+
+	input_parse(ictx, buf, len);
+	screen_write_stop(sctx);
+}
+
+/* Parse given input for screen. */
+void
+input_parse_screen(struct input_ctx *ictx, struct screen *s, u_char *buf,
+    size_t len)
+{
+	struct screen_write_ctx	*sctx = &ictx->ctx;
+
+	if (len == 0)
+		return;
+
+	screen_write_start(sctx, NULL, s);
+	input_parse(ictx, buf, len);
 	screen_write_stop(sctx);
 }
 
@@ -1043,14 +1058,18 @@ input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
 static void
 input_reply(struct input_ctx *ictx, const char *fmt, ...)
 {
-	va_list	 ap;
-	char	*reply;
+	struct window_pane	*wp = ictx->wp;
+	va_list			 ap;
+	char			*reply;
+
+	if (wp == NULL)
+		return;
 
 	va_start(ap, fmt);
 	xvasprintf(&reply, fmt, ap);
 	va_end(ap);
 
-	bufferevent_write(ictx->wp->event, reply, strlen(reply));
+	bufferevent_write(wp->event, reply, strlen(reply));
 	free(reply);
 }
 
@@ -1177,7 +1196,8 @@ input_c0_dispatch(struct input_ctx *ictx)
 	case '\000':	/* NUL */
 		break;
 	case '\007':	/* BEL */
-		alerts_queue(wp->window, WINDOW_BELL);
+		if (wp != NULL)
+			alerts_queue(wp->window, WINDOW_BELL);
 		break;
 	case '\010':	/* BS */
 		screen_write_backspace(sctx);
@@ -1224,6 +1244,7 @@ static int
 input_esc_dispatch(struct input_ctx *ictx)
 {
 	struct screen_write_ctx		*sctx = &ictx->ctx;
+	struct window_pane		*wp = ictx->wp;
 	struct screen			*s = sctx->s;
 	struct input_table_entry	*entry;
 
@@ -1240,7 +1261,8 @@ input_esc_dispatch(struct input_ctx *ictx)
 
 	switch (entry->type) {
 	case INPUT_ESC_RIS:
-		window_pane_reset_palette(ictx->wp);
+		if (wp != NULL)
+			window_pane_reset_palette(wp);
 		input_reset_cell(ictx);
 		screen_write_reset(sctx);
 		break;
@@ -1612,6 +1634,7 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
 {
 	struct screen_write_ctx	*sctx = &ictx->ctx;
 	struct window_pane	*wp = ictx->wp;
+	struct grid_cell	*gc = &ictx->cell.cell;
 	u_int			 i;
 
 	for (i = 0; i < ictx->param_list_len; i++) {
@@ -1623,7 +1646,7 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
 			break;
 		case 3:		/* DECCOLM */
 			screen_write_cursormove(sctx, 0, 0, 1);
-			screen_write_clearscreen(sctx, ictx->cell.cell.bg);
+			screen_write_clearscreen(sctx, gc->bg);
 			break;
 		case 6:		/* DECOM */
 			screen_write_mode_clear(sctx, MODE_ORIGIN);
@@ -1655,10 +1678,12 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
 			break;
 		case 47:
 		case 1047:
-			window_pane_alternate_off(wp, &ictx->cell.cell, 0);
+			if (wp != NULL)
+				window_pane_alternate_off(wp, gc, 0);
 			break;
 		case 1049:
-			window_pane_alternate_off(wp, &ictx->cell.cell, 1);
+			if (wp != NULL)
+				window_pane_alternate_off(wp, gc, 1);
 			break;
 		case 2004:
 			screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
@@ -1700,6 +1725,7 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
 {
 	struct screen_write_ctx	*sctx = &ictx->ctx;
 	struct window_pane	*wp = ictx->wp;
+	struct grid_cell	*gc = &ictx->cell.cell;
 	u_int			 i;
 
 	for (i = 0; i < ictx->param_list_len; i++) {
@@ -1742,7 +1768,8 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
 			if (sctx->s->mode & MODE_FOCUSON)
 				break;
 			screen_write_mode_set(sctx, MODE_FOCUSON);
-			wp->flags |= PANE_FOCUSPUSH; /* force update */
+			if (wp != NULL)
+				wp->flags |= PANE_FOCUSPUSH; /* force update */
 			break;
 		case 1005:
 			screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
@@ -1752,10 +1779,12 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
 			break;
 		case 47:
 		case 1047:
-			window_pane_alternate_on(wp, &ictx->cell.cell, 0);
+			if (wp != NULL)
+				window_pane_alternate_on(wp, gc, 0);
 			break;
 		case 1049:
-			window_pane_alternate_on(wp, &ictx->cell.cell, 1);
+			if (wp != NULL)
+				window_pane_alternate_on(wp, gc, 1);
 			break;
 		case 2004:
 			screen_write_mode_set(sctx, MODE_BRACKETPASTE);
@@ -1823,12 +1852,16 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
 			case 0:
 			case 2:
 				screen_pop_title(sctx->s);
-				server_status_window(ictx->wp->window);
+				if (wp != NULL)
+					server_status_window(wp->window);
 				break;
 			}
 			break;
 		case 18:
-			input_reply(ictx, "\033[8;%u;%ut", wp->sy, wp->sx);
+			if (wp != NULL) {
+				input_reply(ictx, "\033[8;%u;%ut", wp->sy,
+				    wp->sx);
+			}
 			break;
 		default:
 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
@@ -2193,6 +2226,7 @@ static void
 input_exit_osc(struct input_ctx *ictx)
 {
 	struct screen_write_ctx	*sctx = &ictx->ctx;
+	struct window_pane	*wp = ictx->wp;
 	u_char			*p = ictx->input_buf;
 	u_int			 option;
 
@@ -2213,7 +2247,7 @@ input_exit_osc(struct input_ctx *ictx)
 	switch (option) {
 	case 0:
 	case 2:
-		if (screen_set_title(sctx->s, p))
+		if (screen_set_title(sctx->s, p) && wp != NULL)
 			server_status_window(ictx->wp->window);
 		break;
 	case 4:
@@ -2222,7 +2256,8 @@ input_exit_osc(struct input_ctx *ictx)
 	case 7:
 		if (utf8_isvalid(p)) {
 			screen_set_path(sctx->s, p);
-			server_status_window(ictx->wp->window);
+			if (wp != NULL)
+				server_status_window(wp->window);
 		}
 		break;
 	case 10:
@@ -2267,13 +2302,14 @@ static void
 input_exit_apc(struct input_ctx *ictx)
 {
 	struct screen_write_ctx	*sctx = &ictx->ctx;
+	struct window_pane	*wp = ictx->wp;
 
 	if (ictx->flags & INPUT_DISCARD)
 		return;
 	log_debug("%s: \"%s\"", __func__, ictx->input_buf);
 
-	if (screen_set_title(sctx->s, ictx->input_buf))
-		server_status_window(ictx->wp->window);
+	if (screen_set_title(sctx->s, ictx->input_buf) && wp != NULL)
+		server_status_window(wp->window);
 }
 
 /* Rename string started. */
@@ -2294,6 +2330,8 @@ input_exit_rename(struct input_ctx *ictx)
 	struct window_pane	*wp = ictx->wp;
 	struct options_entry	*oe;
 
+	if (wp == NULL)
+		return;
 	if (ictx->flags & INPUT_DISCARD)
 		return;
 	if (!options_get_number(ictx->wp->options, "allow-rename"))
@@ -2309,9 +2347,9 @@ input_exit_rename(struct input_ctx *ictx)
 			options_remove(oe);
 		return;
 	}
-	window_set_name(ictx->wp->window, ictx->input_buf);
-	options_set_number(ictx->wp->window->options, "automatic-rename", 0);
-	server_status_window(ictx->wp->window);
+	window_set_name(wp->window, ictx->input_buf);
+	options_set_number(wp->window->options, "automatic-rename", 0);
+	server_status_window(wp->window);
 }
 
 /* Open UTF-8 character. */
@@ -2407,6 +2445,9 @@ input_osc_4(struct input_ctx *ictx, const char *p)
 	long	 		 idx;
 	u_int			 r, g, b;
 
+	if (wp == NULL)
+		return;
+
 	copy = s = xstrdup(p);
 	while (s != NULL && *s != '\0') {
 		idx = strtol(s, &next, 10);
@@ -2441,6 +2482,8 @@ input_osc_10(struct input_ctx *ictx, const char *p)
 	u_int			 r, g, b;
 	char			 tmp[16];
 
+	if (wp == NULL)
+		return;
 	if (strcmp(p, "?") == 0)
 		return;
 
@@ -2465,6 +2508,8 @@ input_osc_11(struct input_ctx *ictx, const char *p)
 	u_int			 r, g, b;
 	char			 tmp[16];
 
+	if (wp == NULL)
+		return;
 	if (strcmp(p, "?") == 0)
 		return;
 
@@ -2494,6 +2539,8 @@ input_osc_52(struct input_ctx *ictx, const char *p)
 	struct screen_write_ctx	 ctx;
 	struct paste_buffer	*pb;
 
+	if (wp == NULL)
+		return;
 	state = options_get_number(global_options, "set-clipboard");
 	if (state != 2)
 		return;
@@ -2555,6 +2602,9 @@ input_osc_104(struct input_ctx *ictx, const char *p)
 	char			*copy, *s;
 	long			 idx;
 
+	if (wp == NULL)
+		return;
+
 	if (*p == '\0') {
 		window_pane_reset_palette(wp);
 		return;
diff --git a/spawn.c b/spawn.c
index 9d2ccdf1..660ee47d 100644
--- a/spawn.c
+++ b/spawn.c
@@ -255,7 +255,8 @@ spawn_pane(struct spawn_context *sc, char **cause)
 		}
 		window_pane_reset_mode_all(sc->wp0);
 		screen_reinit(&sc->wp0->base);
-		input_init(sc->wp0);
+		input_free(sc->wp0->ictx);
+		sc->wp0->ictx = input_init(sc->wp0);
 		new_wp = sc->wp0;
 		new_wp->flags &= ~(PANE_STATUSREADY|PANE_STATUSDRAWN);
 	} else if (sc->lc == NULL) {
diff --git a/tmux.h b/tmux.h
index 043cb070..53372cfe 100644
--- a/tmux.h
+++ b/tmux.h
@@ -810,7 +810,6 @@ struct menu {
 	u_int			 width;
 };
 typedef void (*menu_choice_cb)(struct menu *, u_int, key_code, void *);
-#define MENU_NOMOUSE 0x1
 
 /*
  * Window mode. Windows can be in several modes and this is used to call the
@@ -2288,15 +2287,19 @@ void	 recalculate_size(struct window *);
 void	 recalculate_sizes(void);
 
 /* input.c */
-void	 input_init(struct window_pane *);
-void	 input_free(struct window_pane *);
-void	 input_reset(struct window_pane *, int);
-struct evbuffer *input_pending(struct window_pane *);
-void	 input_parse(struct window_pane *);
+struct input_ctx *input_init(struct window_pane *);
+void	 input_free(struct input_ctx *);
+void	 input_reset(struct input_ctx *, int);
+struct evbuffer *input_pending(struct input_ctx *);
+void	 input_parse_pane(struct window_pane *);
 void	 input_parse_buffer(struct window_pane *, u_char *, size_t);
+void	 input_parse_screen(struct input_ctx *, struct screen *, u_char *,
+	     size_t);
 
 /* input-key.c */
-int	 input_key(struct window_pane *, key_code, struct mouse_event *);
+int	 input_key_pane(struct window_pane *, key_code, struct mouse_event *);
+int	 input_key(struct window_pane *, struct screen *, struct bufferevent *,
+	     key_code);
 
 /* xterm-keys.c */
 char	*xterm_keys_lookup(key_code);
@@ -2731,6 +2734,7 @@ __dead void printflike(1, 2) fatal(const char *, ...);
 __dead void printflike(1, 2) fatalx(const char *, ...);
 
 /* menu.c */
+#define MENU_NOMOUSE 0x1
 struct menu	*menu_create(const char *);
 void		 menu_add_items(struct menu *, const struct menu_item *,
 		    struct cmdq_item *, struct client *,
@@ -2738,7 +2742,6 @@ void		 menu_add_items(struct menu *, const struct menu_item *,
 void 		 menu_add_item(struct menu *, const struct menu_item *,
 		    struct cmdq_item *, struct client *,
 		    struct cmd_find_state *);
-
 void		 menu_free(struct menu *);
 int		 menu_display(struct menu *, int, struct cmdq_item *, u_int,
 		    u_int, struct client *, struct cmd_find_state *,
diff --git a/window.c b/window.c
index ab1d9217..754b9e59 100644
--- a/window.c
+++ b/window.c
@@ -891,7 +891,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
 	if (gethostname(host, sizeof host) == 0)
 		screen_set_title(&wp->base, host);
 
-	input_init(wp);
+	wp->ictx = input_init(wp);
 
 	return (wp);
 }
@@ -907,7 +907,7 @@ window_pane_destroy(struct window_pane *wp)
 		close(wp->fd);
 	}
 
-	input_free(wp);
+	input_free(wp->ictx);
 
 	screen_free(&wp->status_screen);
 
@@ -949,7 +949,7 @@ window_pane_read_callback(__unused struct bufferevent *bufev, void *data)
 	}
 
 	log_debug("%%%u has %zu bytes", wp->id, size);
-	input_parse(wp);
+	input_parse_pane(wp);
 
 	wp->pipe_off = EVBUFFER_LENGTH(evb);
 }
@@ -1257,7 +1257,7 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
 	if (wp->fd == -1 || wp->flags & PANE_INPUTOFF)
 		return (0);
 
-	if (input_key(wp, key, m) != 0)
+	if (input_key_pane(wp, key, m) != 0)
 		return (-1);
 
 	if (KEYC_IS_MOUSE(key))
@@ -1269,7 +1269,7 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
 			    wp2->fd != -1 &&
 			    (~wp2->flags & PANE_INPUTOFF) &&
 			    window_pane_visible(wp2))
-				input_key(wp2, key, NULL);
+				input_key_pane(wp2, key, NULL);
 		}
 	}
 	return (0);

From 74ed17d41bb0f3113052fb4cccaef341d53f9e5b Mon Sep 17 00:00:00 2001
From: nicm <nicm>
Date: Thu, 19 Mar 2020 14:23:58 +0000
Subject: [PATCH 2/2] Little bit of tidying.

---
 menu.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/menu.c b/menu.c
index 6024ba02..049c4836 100644
--- a/menu.c
+++ b/menu.c
@@ -138,16 +138,13 @@ menu_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
 	struct screen		*s = &md->s;
 	struct menu		*menu = md->menu;
 	struct screen_write_ctx	 ctx;
-	u_int			 i, px, py;
+	u_int			 i, px = md->px, py = md->py;
 
 	screen_write_start(&ctx, NULL, s);
 	screen_write_clearscreen(&ctx, 8);
 	screen_write_menu(&ctx, menu, md->choice);
 	screen_write_stop(&ctx);
 
-	px = md->px;
-	py = md->py;
-
 	for (i = 0; i < screen_size_y(&md->s); i++)
 		tty_draw_line(tty, NULL, s, 0, i, menu->width + 4, px, py + i);
 
@@ -270,7 +267,6 @@ chosen:
 	pr = cmd_parse_from_string(item->command, NULL);
 	switch (pr->status) {
 	case CMD_PARSE_EMPTY:
-		new_item = NULL;
 		break;
 	case CMD_PARSE_ERROR:
 		new_item = cmdq_get_error(pr->error);