From 647887b794c00285047aa54ac0d44ae50c7847d7 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 19 Sep 2019 09:02:30 +0000 Subject: [PATCH] Add a "latest" window-size option which tries to size windows based on the most recently used client. From Tommie Gannert in GitHub issue 1869 based on earlier changes from me. --- cmd-break-pane.c | 1 + cmd-new-session.c | 1 + cmd-new-window.c | 1 + cmd-respawn-window.c | 1 + options-table.c | 2 +- resize.c | 183 ++++++++++++++++++++++++++----------------- server-client.c | 21 +++++ spawn.c | 1 + tmux.1 | 6 +- tmux.h | 4 + 10 files changed, 147 insertions(+), 74 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index b4c5b7cd..8b430ff7 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -81,6 +81,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) wp->flags |= PANE_STYLECHANGED; TAILQ_INSERT_HEAD(&w->panes, wp, entry); w->active = wp; + w->latest = c; if (!args_has(args, 'n')) { name = default_window_name(w); diff --git a/cmd-new-session.c b/cmd-new-session.c index e0540815..c7c407c6 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -259,6 +259,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) memset(&sc, 0, sizeof sc); sc.item = item; sc.s = s; + sc.c = c; sc.name = args_get(args, 'n'); sc.argc = args->argc; diff --git a/cmd-new-window.c b/cmd-new-window.c index 6cb33dd9..9a1025e9 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -72,6 +72,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) memset(&sc, 0, sizeof sc); sc.item = item; sc.s = s; + sc.c = c; sc.name = args_get(args, 'n'); sc.argc = args->argc; diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index aec22912..497e401e 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -59,6 +59,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item) sc.item = item; sc.s = s; sc.wl = wl; + sc.c = cmd_find_client(item, NULL, 1); sc.name = NULL; sc.argc = args->argc; diff --git a/options-table.c b/options-table.c index d012f448..77dbfb13 100644 --- a/options-table.c +++ b/options-table.c @@ -64,7 +64,7 @@ static const char *options_table_set_clipboard_list[] = { "off", "external", "on", NULL }; static const char *options_table_window_size_list[] = { - "largest", "smallest", "manual", NULL + "largest", "smallest", "manual", "latest", NULL }; /* Status line format. */ diff --git a/resize.c b/resize.c index 0e0b070d..b1a4b590 100644 --- a/resize.c +++ b/resize.c @@ -149,14 +149,121 @@ done: *sy = WINDOW_MAXIMUM; } +void +recalculate_size(struct window *w) +{ + struct session *s; + struct client *c; + u_int sx, sy, cx, cy; + int type, current, has, changed; + + if (w->active == NULL) + return; + log_debug("%s: @%u is %u,%u", __func__, w->id, w->sx, w->sy); + + type = options_get_number(w->options, "window-size"); + current = options_get_number(w->options, "aggressive-resize"); + + changed = 1; + switch (type) { + case WINDOW_SIZE_LARGEST: + sx = sy = 0; + TAILQ_FOREACH(c, &clients, entry) { + if (ignore_client_size(c)) + continue; + s = c->session; + + if (current) + has = (s->curw->window == w); + else + has = session_has(s, w); + if (!has) + continue; + + cx = c->tty.sx; + cy = c->tty.sy - status_line_size(c); + + if (cx > sx) + sx = cx; + if (cy > sy) + sy = cy; + } + if (sx == 0 || sy == 0) + changed = 0; + break; + case WINDOW_SIZE_SMALLEST: + sx = sy = UINT_MAX; + TAILQ_FOREACH(c, &clients, entry) { + if (ignore_client_size(c)) + continue; + s = c->session; + + if (current) + has = (s->curw->window == w); + else + has = session_has(s, w); + if (!has) + continue; + + cx = c->tty.sx; + cy = c->tty.sy - status_line_size(c); + + if (cx < sx) + sx = cx; + if (cy < sy) + sy = cy; + } + if (sx == UINT_MAX || sy == UINT_MAX) + changed = 0; + break; + case WINDOW_SIZE_LATEST: + sx = sy = UINT_MAX; + TAILQ_FOREACH(c, &clients, entry) { + if (ignore_client_size(c)) + continue; + if (c != w->latest) + continue; + s = c->session; + + if (current) + has = (s->curw->window == w); + else + has = session_has(s, w); + if (!has) + continue; + + cx = c->tty.sx; + cy = c->tty.sy - status_line_size(c); + + if (cx < sx) + sx = cx; + if (cy < sy) + sy = cy; + } + if (sx == UINT_MAX || sy == UINT_MAX) + changed = 0; + break; + case WINDOW_SIZE_MANUAL: + changed = 0; + break; + } + if (changed && w->sx == sx && w->sy == sy) + changed = 0; + + if (!changed) { + tty_update_window_offset(w); + return; + } + log_debug("%s: @%u changed to %u,%u", __func__, w->id, sx, sy); + resize_window(w, sx, sy); +} + void recalculate_sizes(void) { struct session *s; struct client *c; struct window *w; - u_int sx, sy, cx, cy; - int type, current, has, changed; /* * Clear attached count and update saved status line information for @@ -183,74 +290,6 @@ recalculate_sizes(void) } /* Walk each window and adjust the size. */ - RB_FOREACH(w, windows, &windows) { - if (w->active == NULL) - continue; - log_debug("%s: @%u is %u,%u", __func__, w->id, w->sx, w->sy); - - type = options_get_number(w->options, "window-size"); - if (type == WINDOW_SIZE_MANUAL) - continue; - current = options_get_number(w->options, "aggressive-resize"); - - changed = 1; - if (type == WINDOW_SIZE_LARGEST) { - sx = sy = 0; - TAILQ_FOREACH(c, &clients, entry) { - if (ignore_client_size(c)) - continue; - s = c->session; - - if (current) - has = (s->curw->window == w); - else - has = session_has(s, w); - if (!has) - continue; - - cx = c->tty.sx; - cy = c->tty.sy - status_line_size(c); - - if (cx > sx) - sx = cx; - if (cy > sy) - sy = cy; - } - if (sx == 0 || sy == 0) - changed = 0; - } else { - sx = sy = UINT_MAX; - TAILQ_FOREACH(c, &clients, entry) { - if (ignore_client_size(c)) - continue; - s = c->session; - - if (current) - has = (s->curw->window == w); - else - has = session_has(s, w); - if (!has) - continue; - - cx = c->tty.sx; - cy = c->tty.sy - status_line_size(c); - - if (cx < sx) - sx = cx; - if (cy < sy) - sy = cy; - } - if (sx == UINT_MAX || sy == UINT_MAX) - changed = 0; - } - if (w->sx == sx && w->sy == sy) - changed = 0; - - if (!changed) { - tty_update_window_offset(w); - continue; - } - log_debug("%s: @%u changed to %u,%u", __func__, w->id, sx, sy); - resize_window(w, sx, sy); - } + RB_FOREACH(w, windows, &windows) + recalculate_size(w); } diff --git a/server-client.c b/server-client.c index 4b60f5c0..36ebf85b 100644 --- a/server-client.c +++ b/server-client.c @@ -996,6 +996,24 @@ server_client_assume_paste(struct session *s) return (0); } +/* Has the latest client changed? */ +static void +server_client_update_latest(struct client *c) +{ + struct window *w; + + if (c->session == NULL) + return; + w = c->session->curw->window; + + if (w->latest == c) + return; + w->latest = c; + + if (options_get_number(w->options, "window-size") == WINDOW_SIZE_LATEST) + recalculate_size(w); +} + /* * Handle data key input from client. This owns and can modify the key event it * is given and is responsible for freeing it. @@ -1192,6 +1210,8 @@ forward_key: window_pane_key(wp, c, s, wl, key, m); out: + if (s != NULL) + server_client_update_latest(c); free(event); return (CMD_RETURN_NORMAL); } @@ -1737,6 +1757,7 @@ server_client_dispatch(struct imsg *imsg, void *arg) if (c->flags & CLIENT_CONTROL) break; + server_client_update_latest(c); server_client_clear_overlay(c); tty_resize(&c->tty); recalculate_sizes(); diff --git a/spawn.c b/spawn.c index 52763083..1917955e 100644 --- a/spawn.c +++ b/spawn.c @@ -164,6 +164,7 @@ spawn_window(struct spawn_context *sc, char **cause) if (s->curw == NULL) s->curw = sc->wl; sc->wl->session = s; + w->latest = sc->c; winlink_set_window(sc->wl, w); } else w = NULL; diff --git a/tmux.1 b/tmux.1 index c99e506c..ff19c225 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3659,7 +3659,7 @@ see the section. .Pp .It Xo Ic window-size -.Ar largest | Ar smallest | Ar manual +.Ar largest | Ar smallest | Ar manual | Ar latest .Xc Configure how .Nm @@ -3674,6 +3674,10 @@ If the size of a new window is set from the .Ic default-size option and windows are resized automatically. +With +.Ar latest , +.Nm +uses the size of the client that had the most recent activity. See also the .Ic resize-window command and the diff --git a/tmux.h b/tmux.h index 5f7e5104..6e6fee96 100644 --- a/tmux.h +++ b/tmux.h @@ -905,6 +905,7 @@ RB_HEAD(window_pane_tree, window_pane); /* Window structure. */ struct window { u_int id; + void *latest; char *name; struct event name_event; @@ -970,6 +971,7 @@ TAILQ_HEAD(winlink_stack, winlink); #define WINDOW_SIZE_LARGEST 0 #define WINDOW_SIZE_SMALLEST 1 #define WINDOW_SIZE_MANUAL 2 +#define WINDOW_SIZE_LATEST 3 /* Pane border status option. */ #define PANE_STATUS_OFF 0 @@ -1670,6 +1672,7 @@ struct spawn_context { struct session *s; struct winlink *wl; + struct client *c; struct window_pane *wp0; struct layout_cell *lc; @@ -2195,6 +2198,7 @@ void status_prompt_save_history(void); void resize_window(struct window *, u_int, u_int); void default_window_size(struct session *, struct window *, u_int *, u_int *, int); +void recalculate_size(struct window *); void recalculate_sizes(void); /* input.c */