From 8b3e2eab5afde62a4eb87b132b4196105c1cfaa6 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 10 Jul 2023 09:24:53 +0000 Subject: Use a stack for last panes line windows, from Thomas Bertschinger in GitHub issue 3588. --- cmd-find.c | 2 +- cmd-select-pane.c | 6 +++++- cmd-swap-pane.c | 6 ++---- format.c | 2 +- spawn.c | 1 + tmux.h | 12 +++++++++--- window.c | 56 +++++++++++++++++++++++++++++++++++++++---------------- 7 files changed, 59 insertions(+), 26 deletions(-) diff --git a/cmd-find.c b/cmd-find.c index 2929bbc9..c651448d 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -583,7 +583,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane) /* Try special characters. */ if (strcmp(pane, "!") == 0) { - fs->wp = fs->w->last; + fs->wp = TAILQ_FIRST(&fs->w->last_panes); if (fs->wp == NULL) return (-1); return (0); diff --git a/cmd-select-pane.c b/cmd-select-pane.c index ae21d4ce..135729f5 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -98,7 +98,11 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) struct options_entry *o; if (entry == &cmd_last_pane_entry || args_has(args, 'l')) { - lastwp = w->last; + /* + * Check for no last pane found in case the other pane was + * spawned without being visited (for example split-window -d). + */ + lastwp = TAILQ_FIRST(&w->last_panes); if (lastwp == NULL && window_count_panes(w) == 2) { lastwp = TAILQ_PREV(w->active, window_panes, entry); if (lastwp == NULL) diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 80c20c80..6931bd16 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -128,10 +128,8 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item) window_set_active_pane(dst_w, src_wp, 1); } if (src_w != dst_w) { - if (src_w->last == src_wp) - src_w->last = NULL; - if (dst_w->last == dst_wp) - dst_w->last = NULL; + window_pane_stack_remove(&src_w->last_panes, src_wp); + window_pane_stack_remove(&dst_w->last_panes, dst_wp); colour_palette_from_option(&src_wp->palette, src_wp->options); colour_palette_from_option(&dst_wp->palette, dst_wp->options); } diff --git a/format.c b/format.c index 3f745141..0c3bd3ba 100644 --- a/format.c +++ b/format.c @@ -1902,7 +1902,7 @@ static void * format_cb_pane_last(struct format_tree *ft) { if (ft->wp != NULL) { - if (ft->wp == ft->wp->window->last) + if (ft->wp == TAILQ_FIRST(&ft->wp->window->last_panes)) return (xstrdup("1")); return (xstrdup("0")); } diff --git a/spawn.c b/spawn.c index dd3f6f50..7ae3f938 100644 --- a/spawn.c +++ b/spawn.c @@ -115,6 +115,7 @@ spawn_window(struct spawn_context *sc, char **cause) window_pane_resize(sc->wp0, w->sx, w->sy); layout_init(w, sc->wp0); + w->active = NULL; window_set_active_pane(w, sc->wp0, 0); } diff --git a/tmux.h b/tmux.h index d2a5671b..9588c285 100644 --- a/tmux.h +++ b/tmux.h @@ -1038,7 +1038,7 @@ struct window_pane { #define PANE_REDRAW 0x1 #define PANE_DROP 0x2 #define PANE_FOCUSED 0x4 -/* 0x8 unused */ +#define PANE_VISITED 0x8 /* 0x10 unused */ /* 0x20 unused */ #define PANE_INPUTOFF 0x40 @@ -1093,7 +1093,8 @@ struct window_pane { int border_gc_set; struct grid_cell border_gc; - TAILQ_ENTRY(window_pane) entry; + TAILQ_ENTRY(window_pane) entry; /* link in list of all panes */ + TAILQ_ENTRY(window_pane) sentry; /* link in list of last visited */ RB_ENTRY(window_pane) tree_entry; }; TAILQ_HEAD(window_panes, window_pane); @@ -1114,7 +1115,7 @@ struct window { struct timeval activity_time; struct window_pane *active; - struct window_pane *last; + struct window_panes last_panes; struct window_panes panes; int lastlayout; @@ -1167,6 +1168,7 @@ struct winlink { #define WINLINK_ACTIVITY 0x2 #define WINLINK_SILENCE 0x4 #define WINLINK_ALERTFLAGS (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_SILENCE) +#define WINLINK_VISITED 0x8 RB_ENTRY(winlink) entry; TAILQ_ENTRY(winlink) wentry; @@ -3041,6 +3043,10 @@ struct window_pane *window_pane_find_up(struct window_pane *); struct window_pane *window_pane_find_down(struct window_pane *); struct window_pane *window_pane_find_left(struct window_pane *); struct window_pane *window_pane_find_right(struct window_pane *); +void window_pane_stack_push(struct window_panes *, + struct window_pane *); +void window_pane_stack_remove(struct window_panes *, + struct window_pane *); void window_set_name(struct window *, const char *); void window_add_ref(struct window *, const char *); void window_remove_ref(struct window *, const char *); diff --git a/window.c b/window.c index 8f650a96..c1365993 100644 --- a/window.c +++ b/window.c @@ -248,21 +248,15 @@ winlink_stack_push(struct winlink_stack *stack, struct winlink *wl) winlink_stack_remove(stack, wl); TAILQ_INSERT_HEAD(stack, wl, sentry); + wl->flags |= WINLINK_VISITED; } void winlink_stack_remove(struct winlink_stack *stack, struct winlink *wl) { - struct winlink *wl2; - - if (wl == NULL) - return; - - TAILQ_FOREACH(wl2, stack, sentry) { - if (wl2 == wl) { - TAILQ_REMOVE(stack, wl, sentry); - return; - } + if (wl != NULL && (wl->flags & WINLINK_VISITED)) { + TAILQ_REMOVE(stack, wl, sentry); + wl->flags &= ~WINLINK_VISITED; } } @@ -312,6 +306,7 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel) w->flags = 0; TAILQ_INIT(&w->panes); + TAILQ_INIT(&w->last_panes); w->active = NULL; w->lastlayout = -1; @@ -512,18 +507,23 @@ window_pane_update_focus(struct window_pane *wp) int window_set_active_pane(struct window *w, struct window_pane *wp, int notify) { + struct window_pane *lastwp; + log_debug("%s: pane %%%u", __func__, wp->id); if (wp == w->active) return (0); - w->last = w->active; + lastwp = w->active; + + window_pane_stack_remove(&w->last_panes, wp); + window_pane_stack_push(&w->last_panes, lastwp); w->active = wp; w->active->active_point = next_active_point++; w->active->flags |= PANE_CHANGED; if (options_get_number(global_options, "focus-events")) { - window_pane_update_focus(w->last); + window_pane_update_focus(lastwp); window_pane_update_focus(w->active); } @@ -746,21 +746,21 @@ window_lost_pane(struct window *w, struct window_pane *wp) if (wp == marked_pane.wp) server_clear_marked(); + window_pane_stack_remove(&w->last_panes, wp); if (wp == w->active) { - w->active = w->last; - w->last = NULL; + w->active = TAILQ_FIRST(&w->last_panes); if (w->active == NULL) { w->active = TAILQ_PREV(wp, window_panes, entry); if (w->active == NULL) w->active = TAILQ_NEXT(wp, entry); } if (w->active != NULL) { + window_pane_stack_remove(&w->last_panes, w->active); w->active->flags |= PANE_CHANGED; notify_window("window-pane-changed", w); window_update_focus(w); } - } else if (wp == w->last) - w->last = NULL; + } } void @@ -844,6 +844,11 @@ window_destroy_panes(struct window *w) { struct window_pane *wp; + while (!TAILQ_EMPTY(&w->last_panes)) { + wp = TAILQ_FIRST(&w->last_panes); + window_pane_stack_remove(&w->last_panes, wp); + } + while (!TAILQ_EMPTY(&w->panes)) { wp = TAILQ_FIRST(&w->panes); TAILQ_REMOVE(&w->panes, wp, entry); @@ -1478,6 +1483,25 @@ window_pane_find_right(struct window_pane *wp) return (best); } +void +window_pane_stack_push(struct window_panes *stack, struct window_pane *wp) +{ + if (wp != NULL) { + window_pane_stack_remove(stack, wp); + TAILQ_INSERT_HEAD(stack, wp, sentry); + wp->flags |= PANE_VISITED; + } +} + +void +window_pane_stack_remove(struct window_panes *stack, struct window_pane *wp) +{ + if (wp != NULL && (wp->flags & PANE_VISITED)) { + TAILQ_REMOVE(stack, wp, sentry); + wp->flags &= ~PANE_VISITED; + } +} + /* Clear alert flags for a winlink */ void winlink_clear_flags(struct winlink *wl) -- cgit v1.2.3