Use a stack for last panes line windows, from Thomas Bertschinger in
authornicm <nicm@openbsd.org>
Mon, 10 Jul 2023 09:24:53 +0000 (09:24 +0000)
committernicm <nicm@openbsd.org>
Mon, 10 Jul 2023 09:24:53 +0000 (09:24 +0000)
GitHub issue 3588.

usr.bin/tmux/cmd-find.c
usr.bin/tmux/cmd-select-pane.c
usr.bin/tmux/cmd-swap-pane.c
usr.bin/tmux/format.c
usr.bin/tmux/spawn.c
usr.bin/tmux/tmux.h
usr.bin/tmux/window.c

index e7cb49a..3353646 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-find.c,v 1.82 2022/11/01 09:46:14 nicm Exp $ */
+/* $OpenBSD: cmd-find.c,v 1.83 2023/07/10 09:24:53 nicm Exp $ */
 
 /*
  * Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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);
index 62b48fd..c067585 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-select-pane.c,v 1.68 2021/08/21 10:22:39 nicm Exp $ */
+/* $OpenBSD: cmd-select-pane.c,v 1.69 2023/07/10 09:24:53 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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)
index 0cc4517..de8c6e7 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-swap-pane.c,v 1.42 2023/01/17 06:50:55 nicm Exp $ */
+/* $OpenBSD: cmd-swap-pane.c,v 1.43 2023/07/10 09:24:53 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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);
        }
index bf89cbe..ff1293e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: format.c,v 1.315 2023/07/03 10:48:26 nicm Exp $ */
+/* $OpenBSD: format.c,v 1.316 2023/07/10 09:24:53 nicm Exp $ */
 
 /*
  * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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"));
        }
index aee6630..3147d1f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: spawn.c,v 1.32 2023/07/09 22:54:52 nicm Exp $ */
+/* $OpenBSD: spawn.c,v 1.33 2023/07/10 09:24:53 nicm Exp $ */
 
 /*
  * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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);
        }
 
index d7b5024..fae976b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1200 2023/07/03 16:47:43 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1201 2023/07/10 09:24:53 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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 *);
index 5e02fc2..f2e7d3d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window.c,v 1.285 2023/03/27 08:47:57 nicm Exp $ */
+/* $OpenBSD: window.c,v 1.286 2023/07/10 09:24:53 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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)