Let move-pane reorder zoomed panes, and record zoom in layouts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Michael Grant
2026-10-01 08:23:17 +01:00
parent 7810f8abf3
commit 7f84dfd3c7
5 changed files with 86 additions and 26 deletions

View File

@@ -459,7 +459,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
struct window_pane *src_wp, *dst_wp;
const char *s;
char *cause = NULL;
int flags = 0, dst_idx;
int flags = 0, dst_idx, raised;
struct layout_cell *lc;
dst_s = target->s;
@@ -479,17 +479,22 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
args_has(args, 'D') ||
args_has(args, 'L') ||
args_has(args, 'R')) {
if (!window_pane_is_floating(dst_wp)) {
s = args_get(args, 'P');
if (args_has(args, 'z') ||
(s != NULL && cmd_join_pane_is_stacking(s)))
raised = window_pane_is_raised(dst_wp);
else
raised = window_pane_is_floating(dst_wp);
if (!raised) {
cmdq_error(item, "pane is not floating");
return (CMD_RETURN_ERROR);
}
/* Moving unzooms a zoomed pane; reordering does not. */
s = args_get(args, 'P');
if ((dst_wp->flags & PANE_ZOOMED) &&
!args_has(args, 'z') &&
(s == NULL || !cmd_join_pane_is_stacking(s)))
window_unzoom_pane(dst_wp, 1);
if ((s = args_get(args, 'P')) != NULL)
if (s != NULL)
return (cmd_join_pane_place(item, dst_wl, dst_wp, s));
if ((s = args_get(args, 'z')) != NULL)
return (cmd_join_pane_zindex(item, dst_wl, dst_wp, s));

View File

@@ -79,7 +79,8 @@
" 'Kill' 'X' {kill-pane}" \
" 'Respawn' 'R' {respawn-pane -k}" \
" '#{?pane_marked,Unmark,Mark}' 'm' {select-pane -m}" \
" '#{?#{>:#{window_panes},1},,-}#{?window_zoomed_flag,Unzoom,Zoom}' 'z' {resize-pane -Z}"
" '#{?#{>:#{window_panes},1},,-}#{?pane_zoomed_flag,Unzoom,Zoom}' 'z' {resize-pane -Z}" \
" '#{?#{||:#{pane_floating_flag},#{pane_zoomed_flag}},Bring To Front,}' 'F' {move-pane -P front}"
#define DEFAULT_MOVE_MENU \
" 'Centre' 'c' {move-pane -P centre}" \
" ''" \
@@ -536,6 +537,8 @@ key_bindings_init(void)
/* Mouse button 1 down on default pane-border-format */
"bind -n MouseDown1Control9 { display-menu -t= -xM -yM -O -T 'Kill pane #{pane_index}?' 'Yes' 'y' { kill-pane -t= } 'No' 'n' {}}",
"bind -n MouseDown1Control8 { resize-pane -Z }",
"bind -n M-MouseDown1Control8 { move-pane -P front }",
"bind -n S-MouseDown1Control8 { move-pane -P front }",
"bind -n MouseDown1Control7 { if -Ft= '#{pane_floating_flag}' { join-pane } { break-pane -W } }",
/* Mouse wheel down on status line. */

View File

@@ -74,6 +74,7 @@ struct layout_parse_cell_ctx {
int last;
int index;
int zindex;
int zoomed;
};
/* Layout parse context. */
@@ -220,7 +221,7 @@ layout_parse_free_ctx(struct layout_parse_ctx *pctx)
/* Add a cell context to the parse context. */
static void
layout_parse_add_cctx(struct layout_parse_ctx *pctx, struct layout_cell *lc,
int active, int last, int index, int zindex)
int active, int last, int index, int zindex, int zoomed)
{
struct layout_parse_cell_ctx *cctx;
@@ -236,6 +237,7 @@ layout_parse_add_cctx(struct layout_parse_ctx *pctx, struct layout_cell *lc,
cctx->last = last;
cctx->index = index;
cctx->zindex = zindex;
cctx->zoomed = zoomed;
}
/* Remove a cell context from the parse context. Does not preserve ordering. */
@@ -423,6 +425,8 @@ layout_append_v2(struct layout_cell *lc, struct layout_string *ls)
if (window_pane_index(wp, &i) != 0)
return (-1);
layout_string_write(ls, ",\"i\":%u", i);
if (wp->flags & PANE_ZOOMED)
layout_string_write(ls, ",\"Z\":true");
if (lc->flags & LAYOUT_CELL_FLOATING) {
z = layout_cell_zindex(lc);
layout_string_write(ls, ",\"z\":%u", z);
@@ -1012,7 +1016,7 @@ layout_parse_json_layout(struct json_node *node, struct layout_cell *lcparent,
int64_t num;
char **cause = pctx->cause;
int boolean, index, zindex, active = -1;
int last = -1;
int last = -1, zoomed = 0;
if (json_find_string(node, "t", &str, cause) != 0)
goto fail;
@@ -1102,7 +1106,14 @@ layout_parse_json_layout(struct json_node *node, struct layout_cell *lcparent,
} else
zindex = INT_MAX;
layout_parse_add_cctx(pctx, lc, active, last, index, zindex);
if (json_find(node, "Z") != NULL) {
if (json_find_boolean(node, "Z", &boolean, cause) != 0)
goto fail;
zoomed = boolean;
}
layout_parse_add_cctx(pctx, lc, active, last, index, zindex,
zoomed);
} else {
if (json_find_array(node, "c", &array, cause) != 0)
goto fail;
@@ -1212,6 +1223,13 @@ layout_parse_apply_ctx(struct window *w, struct layout_parse_ctx *pctx)
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
}
/* Zoom panes. */
for (i = 0; i < pctx->size; i++) {
cctx = &pctx->cctxs[i];
if (cctx->zoomed)
window_zoom(cctx->lc->wp);
}
/* Set the active pane. */
for (i = 0; i < pctx->size; i++) {
cctx = &pctx->cctxs[i];

View File

@@ -729,7 +729,8 @@ for flags in '' A mixed; do
legacy=$(v1_layout L:zoom)
check_ok resize-pane -Z -t "L:zoom.$pane"
during=$(raw_layout L:zoom)
must_equal 'Layout while zoomed' "$during" "$before"
must_equal 'Layout while zoomed' \
"$(echo "$during" | sed 's/"Z":true,//')" "$before"
must_equal 'Legacy layout while zoomed' \
"$(v1_layout L:zoom)" "$legacy"
must_equal 'Zoom after dumping layout' \
@@ -738,6 +739,9 @@ for flags in '' A mixed; do
"$(visible_layout L:zoom)" "$(layout L:zoom)"
check_ok select-layout -t L:zoom "$during"
must_equal 'Round trip from zoomed layout' \
"$(raw_layout L:zoom)" "$during"
check_ok resize-pane -a -Z -t L:zoom
must_equal 'Unzoomed after round trip' \
"$(raw_layout L:zoom)" "$before"
done
check_ok kill-window -t L:zoom

64
tmux.1
View File

@@ -1742,7 +1742,8 @@ or
to change session, window and pane.
In that case,
.Fl Z
keeps the window zoomed if it was zoomed.
moves the zoom to the pane selected if it was covered by a zoomed pane,
instead of the window being unzoomed.
If
.Fl l ,
.Fl n
@@ -2792,8 +2793,8 @@ options.
If
.Fl d
is given, the active pane is not changed.
The pane must not already be floating or hidden, and the window must not
be zoomed.
The pane must not already be floating.
A zoomed pane stays zoomed.
.Tg capturep
.It Xo Ic capture\-pane
.Op Fl aeFHILpPRqCJMN
@@ -3348,7 +3349,8 @@ Only windows for which the filter is true are killed.
.D1 Pq alias: Ic lastp
Select the last (previously selected) pane.
.Fl Z
keeps the window zoomed if it was zoomed.
moves the zoom to the pane selected if it was covered by a zoomed pane,
instead of the window being unzoomed.
.Fl e
enables or
.Fl d
@@ -3527,10 +3529,10 @@ which may be one of:
.It Li "top-right-centre" Ta "Centre of top-right quadrant"
.It Li "bottom-left-centre" Ta "Centre of bottom-left quadrant"
.It Li "bottom-right-centre" Ta "Centre of bottom-right quadrant"
.It Li "front" Ta "Front of floating panes"
.It Li "back" Ta "Back of floating panes"
.It Li "forward" Ta "Forward one floating pane"
.It Li "backward" Ta "Backward one floating pane"
.It Li "front" Ta "Front of floating and zoomed panes"
.It Li "back" Ta "Back of floating and zoomed panes"
.It Li "forward" Ta "Forward one floating or zoomed pane"
.It Li "backward" Ta "Backward one floating or zoomed pane"
.It Li "forward-loop" Ta "Forward but back if already at front"
.It Li "backward-loop" Ta "Backward but front if already at back"
.El
@@ -3711,7 +3713,9 @@ sets the pane border lines for floating panes; see
may be used when bound to a mouse drag key; the new floating pane is resized to
follow the mouse drag.
.Fl A
creates a floating pane which remains visible above a zoomed pane.
creates a floating pane which is always on top: it stays in front of other
floating and zoomed panes, apart from a modal pane, even when they are
selected or zoomed.
.Fl O
creates a modal pane.
A modal pane is always the active pane and prevents interaction with any other
@@ -3832,7 +3836,7 @@ if specified, to
.Ar new\-name .
.Tg resizep
.It Xo Ic resize\-pane
.Op Fl MTZ
.Op Fl aMTZ
.Op Fl D Ar lines
.Op Fl L Ar columns
.Op Fl R Ar columns
@@ -3879,8 +3883,15 @@ and
target their respective borders, and negative values may be given.
With
.Fl Z ,
the active pane is toggled between zoomed (occupying the whole of the window)
and unzoomed (its normal position in the layout).
the target pane is toggled between zoomed (occupying the whole of the window
above the layout and above any panes behind it in the stacking order) and
unzoomed (its normal position).
Any number of panes may be zoomed and a zoomed pane may be floating or tiled;
floating panes in front of a zoomed pane stay visible above it.
.Fl a
with
.Fl Z
unzooms every pane in the window.
.Pp
.Fl M
begins mouse resizing (only valid if bound to a mouse key binding, see
@@ -3991,7 +4002,8 @@ lower) with
.Fl U
or downward (numerically higher).
.Fl Z
keeps the window zoomed if it was zoomed.
moves the zoom to the pane selected if it was covered by a zoomed pane,
instead of the window being unzoomed.
.Tg selectl
.It Xo Ic select\-layout
.Op Fl Enop
@@ -4034,7 +4046,8 @@ or
is used, respectively the pane below, to the left, to the right, or above the
target pane is used.
.Fl Z
keeps the window zoomed if it was zoomed.
moves the zoom to the pane selected if it was covered by a zoomed pane,
instead of the window being unzoomed.
.Fl l
is the same as using the
.Ic last\-pane
@@ -4226,7 +4239,8 @@ instructs
.Nm
not to change the active pane and
.Fl Z
keeps the window zoomed if it was zoomed.
moves the zoom to the pane selected if it was covered by a zoomed pane,
instead of the window being unzoomed.
.Pp
If
.Fl s
@@ -6031,6 +6045,22 @@ see the
section.
Attributes are ignored.
.Pp
.It Xo Ic pane\-raise\-on\-focus
.Op Ic floating | all | off
.Xc
Which panes are raised to the front when they are made active.
.Ic floating
raises floating panes, so that activating a floating pane brings it to the
front, but not zoomed panes, so that the active pane of a zoomed window can be
used without floating panes above it being covered.
.Ic all
also raises zoomed panes and
.Ic off
raises none.
A floating or zoomed pane that is covered by a zoomed pane is always raised
when it is made active; a tiled pane that is covered unzooms every pane
instead.
.Pp
.It Xo Ic pane\-scrollbars
.Op Ic off | modal | on | auto\-hide
.Xc
@@ -7536,7 +7566,7 @@ The following variables are available, where appropriate:
.It Li "window_start_flag" Ta "" Ta "1 if window has the lowest index"
.It Li "window_visible_layout" Ta "" Ta "Window layout description, respecting zoomed window panes"
.It Li "window_width" Ta "" Ta "Width of window"
.It Li "window_zoomed_flag" Ta "" Ta "1 if window is zoomed"
.It Li "window_zoomed_flag" Ta "" Ta "1 if any pane in the window is zoomed"
.It Li "wrap_flag" Ta "" Ta "Pane wrap flag"
.El
.Sh STYLES
@@ -7946,7 +7976,7 @@ The flag is one of the following symbols appended to the window name:
.Ic monitor\-silence
interval.
.It Li "M" Ta "The window contains the marked pane."
.It Li "Z" Ta "The window's active pane is zoomed."
.It Li "Z" Ta "A pane in the window is zoomed."
.El
.Pp
The # symbol relates to the