From 41ef18debbb808f577adaff135c59e7b160dba05 Mon Sep 17 00:00:00 2001
From: Michael Grant <mgrant@grant.org>
Date: Sun, 19 Jan 2025 16:20:14 -0400
Subject: [PATCH 1/7] initial commit

---
 popup.c         | 12 +++++++++++-
 server-client.c | 22 ++++++++++++----------
 tmux.h          |  1 +
 3 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/popup.c b/popup.c
index fe34f2c0..2a543b6c 100644
--- a/popup.c
+++ b/popup.c
@@ -487,6 +487,8 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
 	size_t			 len;
 	u_int			 px, py, x;
 	enum { NONE, LEFT, RIGHT, TOP, BOTTOM } border = NONE;
+	struct window		*w;
+	struct window_pane	*wp;
 
 	if (pd->md != NULL) {
 		if (menu_key_cb(c, pd->md, event) == 1) {
@@ -505,14 +507,20 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
 			popup_handle_drag(c, pd, m);
 			goto out;
 		}
+		w = c->session->curw->window;
+		wp = w->active;
 		if (m->x < pd->px ||
 		    m->x > pd->px + pd->sx - 1 ||
 		    m->y < pd->py ||
 		    m->y > pd->py + pd->sy - 1) {
 			if (MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_3)
 				goto menu;
+			wp->flags |= PANE_FOCUSED;
+			pd->flags &= ~POPUP_FOCUSED;
 			return (0);
 		}
+		wp->flags &= ~PANE_FOCUSED;
+		pd->flags |= POPUP_FOCUSED;
 		if (pd->border_lines != BOX_LINES_NONE) {
 			if (m->x == pd->px)
 				border = LEFT;
@@ -559,7 +567,8 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
 			bufferevent_write(job_get_event(pd->job), buf, len);
 			return (0);
 		}
-		input_key(&pd->s, job_get_event(pd->job), event->key);
+		if (pd->flags & POPUP_FOCUSED)
+			input_key(&pd->s, job_get_event(pd->job), event->key);
 	}
 	return (0);
 
@@ -723,6 +732,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
 
 	server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
 	    popup_draw_cb, popup_key_cb, popup_free_cb, popup_resize_cb, pd);
+	pd->flags |= POPUP_FOCUSED;
 	return (0);
 }
 
diff --git a/server-client.c b/server-client.c
index 9ced4482..6aed51e8 100644
--- a/server-client.c
+++ b/server-client.c
@@ -2595,6 +2595,8 @@ server_client_handle_key(struct client *c, struct key_event *event)
 {
 	struct session		*s = c->session;
 	struct cmdq_item	*item;
+	struct window_pane	*wp;
+	int			done;
 
 	/* Check the client is good to accept input. */
 	if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
@@ -2612,16 +2614,16 @@ server_client_handle_key(struct client *c, struct key_event *event)
 			status_message_clear(c);
 		}
 		if (c->overlay_key != NULL) {
-			switch (c->overlay_key(c, c->overlay_data, event)) {
-			case 0:
-				return (0);
-			case 1:
-				server_client_clear_overlay(c);
-				return (0);
+			done = c->overlay_key(c, c->overlay_data, event);
+			TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
+				if (wp->flags & PANE_FOCUSED)
+					goto focused;
 			}
+			if (done)
+				server_client_clear_overlay(c);
+			return (0);
 		}
-		server_client_clear_overlay(c);
-		if (c->prompt_string != NULL) {
+focused:	if (c->prompt_string != NULL) {
 			if (status_prompt_key(c, event->key) == 0)
 				return (0);
 		}
@@ -2893,7 +2895,7 @@ server_client_reset_state(struct client *c)
 	tty->flags &= ~TTY_BLOCK;
 
 	/* Get mode from overlay if any, else from screen. */
-	if (c->overlay_draw != NULL) {
+	if (c->overlay_draw != NULL && ~wp->flags & PANE_FOCUSED) {
 		if (c->overlay_mode != NULL)
 			s = c->overlay_mode(c, c->overlay_data, &cx, &cy);
 	} else if (c->prompt_string == NULL)
@@ -2924,7 +2926,7 @@ server_client_reset_state(struct client *c)
 				cy = tty->sy - n;
 		}
 		cx = c->prompt_cursor;
-	} else if (c->overlay_draw == NULL) {
+	} else if (c->overlay_draw == NULL || wp->flags & PANE_FOCUSED) {
 		cursor = 0;
 		tty_window_offset(tty, &ox, &oy, &sx, &sy);
 		if (wp->xoff + s->cx >= ox && wp->xoff + s->cx <= ox + sx &&
diff --git a/tmux.h b/tmux.h
index 480a22b2..722210da 100644
--- a/tmux.h
+++ b/tmux.h
@@ -3523,6 +3523,7 @@ int		 menu_key_cb(struct client *, void *, struct key_event *);
 #define POPUP_CLOSEEXIT 0x1
 #define POPUP_CLOSEEXITZERO 0x2
 #define POPUP_INTERNAL 0x4
+#define POPUP_FOCUSED 0x8
 typedef void (*popup_close_cb)(int, void *);
 typedef void (*popup_finish_edit_cb)(char *, size_t, void *);
 int		 popup_display(int, enum box_lines, struct cmdq_item *, u_int,

From 5327f3913400794d6c117b6590155515c2f8f449 Mon Sep 17 00:00:00 2001
From: Michael Grant <mgrant@grant.org>
Date: Wed, 12 Mar 2025 13:52:17 -0400
Subject: [PATCH 2/7] Try 2. Move popup focus flag into client struct.

---
 popup.c         | 14 ++++----------
 server-client.c |  6 +++---
 tmux.h          |  2 +-
 3 files changed, 8 insertions(+), 14 deletions(-)

diff --git a/popup.c b/popup.c
index 6d2a0c6c..48a61450 100644
--- a/popup.c
+++ b/popup.c
@@ -489,8 +489,6 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
 	size_t			 len;
 	u_int			 px, py, x;
 	enum { NONE, LEFT, RIGHT, TOP, BOTTOM } border = NONE;
-	struct window		*w;
-	struct window_pane	*wp;
 
 	if (pd->md != NULL) {
 		if (menu_key_cb(c, pd->md, event) == 1) {
@@ -509,20 +507,16 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
 			popup_handle_drag(c, pd, m);
 			goto out;
 		}
-		w = c->session->curw->window;
-		wp = w->active;
 		if (m->x < pd->px ||
 		    m->x > pd->px + pd->sx - 1 ||
 		    m->y < pd->py ||
 		    m->y > pd->py + pd->sy - 1) {
 			if (MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_3)
 				goto menu;
-			wp->flags |= PANE_FOCUSED;
-			pd->flags &= ~POPUP_FOCUSED;
+			c->flags &= ~CLIENT_OVERLAYPOPUP_FOCUSED;
 			return (0);
 		}
-		wp->flags &= ~PANE_FOCUSED;
-		pd->flags |= POPUP_FOCUSED;
+		c->flags |= CLIENT_OVERLAYPOPUP_FOCUSED;
 		if (pd->border_lines != BOX_LINES_NONE) {
 			if (m->x == pd->px)
 				border = LEFT;
@@ -569,7 +563,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
 			bufferevent_write(job_get_event(pd->job), buf, len);
 			return (0);
 		}
-		if (pd->flags & POPUP_FOCUSED)
+		if (c->flags & CLIENT_OVERLAYPOPUP_FOCUSED)
 			input_key(&pd->s, job_get_event(pd->job), event->key);
 	}
 	return (0);
@@ -734,7 +728,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
 
 	server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
 	    popup_draw_cb, popup_key_cb, popup_free_cb, popup_resize_cb, pd);
-	pd->flags |= POPUP_FOCUSED;
+	c->flags |= CLIENT_OVERLAYPOPUP_FOCUSED;
 	return (0);
 }
 
diff --git a/server-client.c b/server-client.c
index ffeb690b..28e7d7af 100644
--- a/server-client.c
+++ b/server-client.c
@@ -2630,7 +2630,7 @@ server_client_handle_key(struct client *c, struct key_event *event)
 		if (c->overlay_key != NULL) {
 			done = c->overlay_key(c, c->overlay_data, event);
 			TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
-				if (wp->flags & PANE_FOCUSED)
+				if (~c->flags & CLIENT_OVERLAYPOPUP_FOCUSED)
 					goto focused;
 			}
 			if (done)
@@ -2915,7 +2915,7 @@ server_client_reset_state(struct client *c)
 	tty->flags &= ~TTY_BLOCK;
 
 	/* Get mode from overlay if any, else from screen. */
-	if (c->overlay_draw != NULL && ~wp->flags & PANE_FOCUSED) {
+	if (c->overlay_draw != NULL && c->flags & CLIENT_OVERLAYPOPUP_FOCUSED) {
 		if (c->overlay_mode != NULL)
 			s = c->overlay_mode(c, c->overlay_data, &cx, &cy);
 	} else if (c->prompt_string == NULL)
@@ -2946,7 +2946,7 @@ server_client_reset_state(struct client *c)
 				cy = tty->sy - n;
 		}
 		cx = c->prompt_cursor;
-	} else if (c->overlay_draw == NULL || wp->flags & PANE_FOCUSED) {
+	} else if (c->overlay_draw == NULL || ~c->flags & CLIENT_OVERLAYPOPUP_FOCUSED) {
 		cursor = 0;
 		tty_window_offset(tty, &ox, &oy, &sx, &sy);
 		if (wp->xoff + s->cx >= ox && wp->xoff + s->cx <= ox + sx &&
diff --git a/tmux.h b/tmux.h
index 73c4ba44..c7602533 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1982,6 +1982,7 @@ struct client {
 #define CLIENT_ASSUMEPASTING 0x2000000000ULL
 #define CLIENT_REDRAWSCROLLBARS 0x4000000000ULL
 #define CLIENT_NO_DETACH_ON_DESTROY 0x8000000000ULL
+#define CLIENT_OVERLAYPOPUP_FOCUSED 0x10000000000ULL
 #define CLIENT_ALLREDRAWFLAGS		\
 	(CLIENT_REDRAWWINDOW|		\
 	 CLIENT_REDRAWSTATUS|		\
@@ -3555,7 +3556,6 @@ int		 menu_key_cb(struct client *, void *, struct key_event *);
 #define POPUP_CLOSEEXIT 0x1
 #define POPUP_CLOSEEXITZERO 0x2
 #define POPUP_INTERNAL 0x4
-#define POPUP_FOCUSED 0x8
 typedef void (*popup_close_cb)(int, void *);
 typedef void (*popup_finish_edit_cb)(char *, size_t, void *);
 int		 popup_display(int, enum box_lines, struct cmdq_item *, u_int,

From c0ff4831fcc6850f4ced8b767ffcd144112ecacb Mon Sep 17 00:00:00 2001
From: Michael Grant <mgrant@grant.org>
Date: Wed, 12 Mar 2025 15:34:48 -0400
Subject: [PATCH 3/7] Add check to check if cursor is behind the overlay popup.

---
 server-client.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/server-client.c b/server-client.c
index 28e7d7af..469bbc60 100644
--- a/server-client.c
+++ b/server-client.c
@@ -2887,6 +2887,23 @@ out:
 		bufferevent_enable(wp->event, EV_READ);
 }
 
+
+static int
+server_client_check_overlay(struct client *c, u_int px, u_int py)
+{
+	struct overlay_ranges	r;
+
+	/*
+	 * A unit width range will always return nx[2] == 0 from a check, even
+	 * with multiple overlays, so it's sufficient to check just the first
+	 * two entries.
+	 */
+	c->overlay_check(c, c->overlay_data, px, py, 1, &r);
+	if (r.nx[0] + r.nx[1] == 0)
+		return (0);
+	return (1);
+}
+
 /*
  * Update cursor position and mode settings. The scroll region and attributes
  * are cleared when idle (waiting for an event) as this is the most likely time
@@ -2896,6 +2913,7 @@ out:
  * tty_region/tty_reset/tty_update_mode already take care of not resetting
  * things that are already in their default state.
  */
+
 static void
 server_client_reset_state(struct client *c)
 {
@@ -2951,13 +2969,17 @@ server_client_reset_state(struct client *c)
 		tty_window_offset(tty, &ox, &oy, &sx, &sy);
 		if (wp->xoff + s->cx >= ox && wp->xoff + s->cx <= ox + sx &&
 		    wp->yoff + s->cy >= oy && wp->yoff + s->cy <= oy + sy) {
-			cursor = 1;
-
 			cx = wp->xoff + s->cx - ox;
 			cy = wp->yoff + s->cy - oy;
 
 			if (status_at_line(c) == 0)
 				cy += status_line_size(c);
+
+			if (c->overlay_draw != NULL &&
+			    !server_client_check_overlay(c, cx, cy))
+				cursor = 0;
+			else
+				cursor = 1;
 		}
 		if (!cursor)
 			mode &= ~MODE_CURSOR;

From 0a0e9852a27588cff87f9afbbdf9416c1c1709fb Mon Sep 17 00:00:00 2001
From: Michael Grant <mgrant@grant.org>
Date: Wed, 12 Mar 2025 15:44:04 -0400
Subject: [PATCH 4/7] Add overlay check to scrollbar code to prevent scrollbars
 obscured by an overlay from flashing while being dragged around.

---
 screen-redraw.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/screen-redraw.c b/screen-redraw.c
index 0d2acad6..9cf01fc4 100644
--- a/screen-redraw.c
+++ b/screen-redraw.c
@@ -1005,6 +1005,7 @@ screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx,
 	struct tty		*tty = &c->tty;
 	struct grid_cell	 gc, slgc, *gcp;
 	struct style		*sb_style = &wp->scrollbar_style;
+	struct overlay_ranges	 r;
 	u_int			 i, j, imax, jmax;
 	u_int			 sb_w = sb_style->width, sb_pad = sb_style->pad;
 	int			 px, py, ox = ctx->ox, oy = ctx->oy;
@@ -1033,6 +1034,11 @@ screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx,
 			    py < yoff - oy - 1 ||
 			    py >= sy || py < 0)
 				continue;
+			if (c->overlay_check != NULL) {
+				c->overlay_check(c, c->overlay_data, px, py, 1, &r);
+				if (r.nx[0] + r.nx[1] == 0)
+					continue;
+			}
 			tty_cursor(tty, px, py);
 			if ((sb_pos == PANE_SCROLLBARS_LEFT &&
 			    i >= sb_w && i < sb_w + sb_pad) ||

From 6ab507c9cef917a51ef914dba0a20c729500f8a1 Mon Sep 17 00:00:00 2001
From: Michael Grant <mgrant@grant.org>
Date: Thu, 27 Mar 2025 14:34:35 +0000
Subject: [PATCH 5/7] rename CLIENT_OVERLAYPOPUP_FOCUSED to
 CLIENT_OVERLAYFOCUSED

---
 popup.c         | 8 ++++----
 server-client.c | 6 +++---
 tmux.h          | 2 +-
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/popup.c b/popup.c
index 48a61450..ca1f9a3f 100644
--- a/popup.c
+++ b/popup.c
@@ -513,10 +513,10 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
 		    m->y > pd->py + pd->sy - 1) {
 			if (MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_3)
 				goto menu;
-			c->flags &= ~CLIENT_OVERLAYPOPUP_FOCUSED;
+			c->flags &= ~CLIENT_OVERLAYFOCUSED;
 			return (0);
 		}
-		c->flags |= CLIENT_OVERLAYPOPUP_FOCUSED;
+		c->flags |= CLIENT_OVERLAYFOCUSED;
 		if (pd->border_lines != BOX_LINES_NONE) {
 			if (m->x == pd->px)
 				border = LEFT;
@@ -563,7 +563,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
 			bufferevent_write(job_get_event(pd->job), buf, len);
 			return (0);
 		}
-		if (c->flags & CLIENT_OVERLAYPOPUP_FOCUSED)
+		if (c->flags & CLIENT_OVERLAYFOCUSED)
 			input_key(&pd->s, job_get_event(pd->job), event->key);
 	}
 	return (0);
@@ -728,7 +728,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
 
 	server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
 	    popup_draw_cb, popup_key_cb, popup_free_cb, popup_resize_cb, pd);
-	c->flags |= CLIENT_OVERLAYPOPUP_FOCUSED;
+	c->flags |= CLIENT_OVERLAYFOCUSED;
 	return (0);
 }
 
diff --git a/server-client.c b/server-client.c
index e9057339..86d84425 100644
--- a/server-client.c
+++ b/server-client.c
@@ -2630,7 +2630,7 @@ server_client_handle_key(struct client *c, struct key_event *event)
 		if (c->overlay_key != NULL) {
 			done = c->overlay_key(c, c->overlay_data, event);
 			TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
-				if (~c->flags & CLIENT_OVERLAYPOPUP_FOCUSED)
+				if (~c->flags & CLIENT_OVERLAYFOCUSED)
 					goto focused;
 			}
 			if (done)
@@ -2933,7 +2933,7 @@ server_client_reset_state(struct client *c)
 	tty->flags &= ~TTY_BLOCK;
 
 	/* Get mode from overlay if any, else from screen. */
-	if (c->overlay_draw != NULL && c->flags & CLIENT_OVERLAYPOPUP_FOCUSED) {
+	if (c->overlay_draw != NULL && c->flags & CLIENT_OVERLAYFOCUSED) {
 		if (c->overlay_mode != NULL)
 			s = c->overlay_mode(c, c->overlay_data, &cx, &cy);
 	} else if (c->prompt_string == NULL)
@@ -2964,7 +2964,7 @@ server_client_reset_state(struct client *c)
 				cy = tty->sy - n;
 		}
 		cx = c->prompt_cursor;
-	} else if (c->overlay_draw == NULL || ~c->flags & CLIENT_OVERLAYPOPUP_FOCUSED) {
+	} else if (c->overlay_draw == NULL || ~c->flags & CLIENT_OVERLAYFOCUSED) {
 		cursor = 0;
 		tty_window_offset(tty, &ox, &oy, &sx, &sy);
 		if (wp->xoff + s->cx >= ox && wp->xoff + s->cx <= ox + sx &&
diff --git a/tmux.h b/tmux.h
index c9745253..2bae04eb 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1982,7 +1982,7 @@ struct client {
 #define CLIENT_ASSUMEPASTING 0x2000000000ULL
 #define CLIENT_REDRAWSCROLLBARS 0x4000000000ULL
 #define CLIENT_NO_DETACH_ON_DESTROY 0x8000000000ULL
-#define CLIENT_OVERLAYPOPUP_FOCUSED 0x10000000000ULL
+#define CLIENT_OVERLAYFOCUSED 0x10000000000ULL
 #define CLIENT_ALLREDRAWFLAGS		\
 	(CLIENT_REDRAWWINDOW|		\
 	 CLIENT_REDRAWSTATUS|		\

From 7fa11dcd2469a68e260397c2e0a9c4830b1d4158 Mon Sep 17 00:00:00 2001
From: Michael Grant <mgrant@grant.org>
Date: Sat, 29 Mar 2025 22:47:49 +0000
Subject: [PATCH 6/7] -D arg to enable do not block

---
 cmd-display-menu.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/cmd-display-menu.c b/cmd-display-menu.c
index 5e742ce1..12b30123 100644
--- a/cmd-display-menu.c
+++ b/cmd-display-menu.c
@@ -54,7 +54,7 @@ const struct cmd_entry cmd_display_popup_entry = {
 	.name = "display-popup",
 	.alias = "popup",
 
-	.args = { "Bb:Cc:d:e:Eh:s:S:t:T:w:x:y:", 0, -1, NULL },
+	.args = { "Bb:Cc:Dd:e:Eh:s:S:t:T:w:x:y:", 0, -1, NULL },
 	.usage = "[-BCE] [-b border-lines] [-c target-client] "
 		 "[-d start-directory] [-e environment] [-h height] "
 		 "[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE
@@ -498,5 +498,8 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
 	free(cwd);
 	free(title);
 	cmd_free_argv(argc, argv);
-	return (CMD_RETURN_WAIT);
+	if (args_has(args, 'D'))
+		return (CMD_RETURN_NORMAL);
+	else
+		return (CMD_RETURN_WAIT);
 }

From 5091236d4d394a5b406a75718697655bf8b3ba51 Mon Sep 17 00:00:00 2001
From: Michael Grant <mgrant@grant.org>
Date: Sat, 29 Mar 2025 23:04:14 +0000
Subject: [PATCH 7/7] skip foreach loop if done

---
 server-client.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/server-client.c b/server-client.c
index 86d84425..09e65a18 100644
--- a/server-client.c
+++ b/server-client.c
@@ -2629,12 +2629,14 @@ server_client_handle_key(struct client *c, struct key_event *event)
 		}
 		if (c->overlay_key != NULL) {
 			done = c->overlay_key(c, c->overlay_data, event);
-			TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
-				if (~c->flags & CLIENT_OVERLAYFOCUSED)
-					goto focused;
-			}
 			if (done)
 				server_client_clear_overlay(c);
+			else {
+				TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
+					if (~c->flags & CLIENT_OVERLAYFOCUSED)
+						goto focused;
+				}
+			}
 			return (0);
 		}
 focused:	if (c->prompt_string != NULL) {