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) {