Make show desktop a cycle and ignore hidden zooms in window_zoomed_flag.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Michael Grant
2026-10-01 17:16:42 +01:00
parent 2345f71df9
commit 42f6f3ca26
7 changed files with 127 additions and 19 deletions

View File

@@ -53,19 +53,29 @@ const struct cmd_entry cmd_resize_pane_entry = {
/* /*
* Show the desktop: hide every pane above the layout, remembering which, or if * Show the desktop: hide every pane above the layout, remembering which, or if
* any were hidden like that show just those again. * any were hidden like that show just those again: floating panes first, then
* zoomed panes.
*/ */
static void static void
cmd_resize_pane_desktop(struct window *w) cmd_resize_pane_desktop(struct window *w)
{ {
struct window_pane *wp; struct window_pane *wp;
int shown = 0; int shown = 0, zoomed;
TAILQ_FOREACH(wp, &w->panes, entry) { /*
if (~wp->flags & PANE_HIDDENALL) * Panes hidden by an earlier call are marked. Show the marked panes
continue; * that are not zoomed first, then the zoomed ones on the next call; if
window_show_pane(wp); * none are left hide every floating and zoomed pane.
shown = 1; */
for (zoomed = 0; zoomed <= 1 && !shown; zoomed++) {
TAILQ_FOREACH(wp, &w->panes, entry) {
if (~wp->flags & PANE_HIDDENALL)
continue;
if (zoomed != ((wp->flags & PANE_ZOOMED) != 0))
continue;
window_show_pane(wp);
shown = 1;
}
} }
if (shown) if (shown)
return; return;

View File

@@ -3393,7 +3393,7 @@ static void *
format_cb_window_zoomed_flag(struct format_tree *ft) format_cb_window_zoomed_flag(struct format_tree *ft)
{ {
if (ft->w != NULL) { if (ft->w != NULL) {
if (ft->w->flags & WINDOW_ZOOMED) if (window_has_visible_zoom(ft->w))
return (xstrdup("1")); return (xstrdup("1"));
return (xstrdup("0")); return (xstrdup("0"));
} }

View File

@@ -159,8 +159,8 @@ run select-pane -t "$B"
hidden "$B" 0 hidden "$B" 0
check "$B" '#{pane_active}' 1 check "$B" '#{pane_active}' 1
# resize-pane -a -H hides every visible float and zoomed pane and a second # resize-pane -a -H hides every visible float and zoomed pane and later calls
# call shows only those, leaving panes that were already hidden alone. # show only those, floats first, leaving panes that were already hidden alone.
reset reset
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1 X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1
Y=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 30 -Y 6 '') || exit 1 Y=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 30 -Y 6 '') || exit 1
@@ -179,9 +179,64 @@ run resize-pane -a -H -t "$A"
hidden "$B" 1 hidden "$B" 1
hidden "$X" 1 hidden "$X" 1
run resize-pane -a -H -t "$A" run resize-pane -a -H -t "$A"
hidden "$X" 0
hidden "$B" 1
run resize-pane -a -H -t "$A"
hidden "$B" 0 hidden "$B" 0
check "$B" '#{pane_zoomed_flag}' 1 check "$B" '#{pane_zoomed_flag}' 1
# With two zoomed panes and a float the calls cycle: hide all, show the float,
# show the zooms, hide all again. Hidden zoomed panes are not a zoomed window.
reset
run resize-pane -Z -t "$A"
run resize-pane -Z -t "$B"
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1
check "$A" '#{window_zoomed_flag}' 1
for i in 1 2; do
run resize-pane -a -H -t "$A"
for p in "$A" "$B" "$X"; do
hidden "$p" 1
done
check "$A" '#{window_zoomed_flag}:#{pane_zoomed_flag}' '0:1'
check "$A" '#{window_flags}' '*'
run resize-pane -a -H -t "$A"
hidden "$X" 0
hidden "$A" 1
hidden "$B" 1
check "$A" '#{window_zoomed_flag}' 0
run resize-pane -a -H -t "$A"
for p in "$A" "$B" "$X"; do
hidden "$p" 0
done
check "$A" '#{window_zoomed_flag}:#{window_flags}' '1:*Z'
done
# A stage with nothing to show is skipped, so every call changes something.
reset
run resize-pane -Z -t "$A"
run resize-pane -a -H -t "$A"
hidden "$A" 1
run resize-pane -a -H -t "$A"
hidden "$A" 0
reset
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1
run resize-pane -a -H -t "$A"
hidden "$X" 1
run resize-pane -a -H -t "$A"
hidden "$X" 0
# Showing a pane by hand takes it out of the cycle.
reset
run resize-pane -Z -t "$A"
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1
run resize-pane -a -H -t "$A"
run select-pane -t "$X"
hidden "$X" 0
hidden "$A" 1
run resize-pane -a -H -t "$A"
hidden "$A" 0
hidden "$X" 0
# Floating and tiling a hidden pane keeps it hidden. # Floating and tiling a hidden pane keeps it hidden.
reset reset
run resize-pane -H -t "$B" run resize-pane -H -t "$B"

View File

@@ -9,7 +9,8 @@
# expectation from the state before. This covers: # expectation from the state before. This covers:
# - select-pane, including -Z and moving to the next, last or a directional pane; # - select-pane, including -Z and moving to the next, last or a directional pane;
# - resize-pane -Z (toggle a zoom), -H (hide or show), -a -Z (unzoom all) and # - resize-pane -Z (toggle a zoom), -H (hide or show), -a -Z (unzoom all) and
# -a -H (show desktop), which is run twice to check it restores the panes; # -a -H (show desktop), which is run once, twice and three times to check
# the hide, floats and zoomed panes steps;
# - break-pane -W and join-pane to float and tile panes; # - break-pane -W and join-pane to float and tile panes;
# - split-window, new-pane and kill-pane; # - split-window, new-pane and kill-pane;
# - next-layout, select-layout, rotate-window and resize-window. # - next-layout, select-layout, rotate-window and resize-window.
@@ -19,7 +20,7 @@
# #
# It also checks properties that must hold after every command: the active pane # It also checks properties that must hold after every command: the active pane
# is not hidden if any pane is not, there is one active pane, a window with one # is not hidden if any pane is not, there is one active pane, a window with one
# pane is not zoomed, window_zoomed_flag matches the panes and visible panes have # pane is not zoomed, window_zoomed_flag matches the visible zoomed panes and visible panes have
# a size. The status line clicks and the cursor are in other tests. # a size. The status line clicks and the cursor are in other tests.
PATH=/bin:/usr/bin PATH=/bin:/usr/bin
@@ -147,7 +148,7 @@ END {
for (i = 1; i <= na; i++) { for (i = 1; i <= na; i++) {
id = aid[i] id = aid[i]
if (aA[id] == 1) { nact++; act = id } if (aA[id] == 1) { nact++; act = id }
if (aZ[id]) anyZ = 1 if (aZ[id] && !aH[id]) anyZ = 1
if (!aH[id]) anyvis = 1 if (!aH[id]) anyvis = 1
} }
if (nact != 1) if (nact != 1)
@@ -155,7 +156,7 @@ END {
for (i = 1; i <= na; i++) { for (i = 1; i <= na; i++) {
id = aid[i] id = aid[i]
if (aWZ[id] != anyZ) if (aWZ[id] != anyZ)
fail("window_zoomed_flag " aWZ[id] " with zoomed panes " anyZ) fail("window_zoomed_flag " aWZ[id] " with visible zoomed panes " anyZ)
if (!aH[id] && (aW[id] < 1 || aT[id] < 1)) if (!aH[id] && (aW[id] < 1 || aT[id] < 1))
fail("pane " id " is " aW[id] "x" aT[id]) fail("pane " id " is " aW[id] "x" aT[id])
} }
@@ -209,8 +210,31 @@ END {
fail("pane " id " hidden " bH[id] " floating " bF[id] \ fail("pane " id " hidden " bH[id] " floating " bF[id] \
" zoomed " bZ[id] " became hidden " aH[id]) " zoomed " bZ[id] " became hidden " aH[id])
} }
} else if (op == "desktop2") { } else if (op == "desktop2" || op == "desktop3") {
sameF(""); sameZ(""); sameH("") # The first call hides every floating and zoomed pane, the
# second shows the floats and the third the zoomed panes. A
# call with nothing to show is skipped, so with only one kind
# the second call restores them and the third hides them again.
nf = 0; nz = 0
for (i = 1; i <= nb; i++) {
id = bid[i]
if (bH[id]) continue
if (bZ[id]) nz++
else if (bF[id]) nf++
}
sameF(""); sameZ("")
for (i = 1; i <= nb; i++) {
id = bid[i]
want = bH[id]
if (!bH[id] && bZ[id])
want = (op == "desktop2") ? (nf > 0) : (nf == 0 || nz == 0)
else if (!bH[id] && bF[id])
want = (op == "desktop3") ? (nf == 0 || nz == 0) : 0
if (aH[id] != want)
fail("pane " id " hidden " bH[id] " floating " bF[id] \
" zoomed " bZ[id] " became hidden " aH[id] \
" after " op " (floats " nf ", zooms " nz ")")
}
} else if (op == "unzoomall") { } else if (op == "unzoomall") {
sameF(""); sameH(""); noZoom() sameF(""); sameH(""); noZoom()
} else if (op == "break") { } else if (op == "break") {
@@ -349,6 +373,11 @@ run_one()
tm resize-pane -a -H -t %0 || rc=$? tm resize-pane -a -H -t %0 || rc=$?
tm resize-pane -a -H -t %0 || rc=$? tm resize-pane -a -H -t %0 || rc=$?
;; ;;
desktop3)
tm resize-pane -a -H -t %0 || rc=$?
tm resize-pane -a -H -t %0 || rc=$?
tm resize-pane -a -H -t %0 || rc=$?
;;
unzoomall) tm resize-pane -a -Z -t %0 || rc=$? ;; unzoomall) tm resize-pane -a -Z -t %0 || rc=$? ;;
nextlayout) tm next-layout -t %0 || rc=$? ;; nextlayout) tm next-layout -t %0 || rc=$? ;;
tiled) tm select-layout -t %0 tiled || rc=$? ;; tiled) tm select-layout -t %0 tiled || rc=$? ;;
@@ -378,7 +407,7 @@ run_one()
} }
PER_PANE="select selectZ zoom hide break join kill split newpane" PER_PANE="select selectZ zoom hide break join kill split newpane"
GLOBAL="desktop desktop2 unzoomall nextlayout tiled rotate nextpane lastpane \ GLOBAL="desktop desktop2 desktop3 unzoomall nextlayout tiled rotate nextpane lastpane \
left right up down resize" left right up down resize"
# Two panes: every state, every operation. # Two panes: every state, every operation.

2
tmux.1
View File

@@ -7589,7 +7589,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_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_visible_layout" Ta "" Ta "Window layout description, respecting zoomed window panes"
.It Li "window_width" Ta "" Ta "Width of window" .It Li "window_width" Ta "" Ta "Width of window"
.It Li "window_zoomed_flag" Ta "" Ta "1 if any pane in the window is zoomed" .It Li "window_zoomed_flag" Ta "" Ta "1 if any pane in the window is zoomed and not hidden"
.It Li "wrap_flag" Ta "" Ta "Pane wrap flag" .It Li "wrap_flag" Ta "" Ta "Pane wrap flag"
.El .El
.Sh STYLES .Sh STYLES

1
tmux.h
View File

@@ -3743,6 +3743,7 @@ int window_zoom(struct window_pane *);
int window_unzoom_pane(struct window_pane *, int); int window_unzoom_pane(struct window_pane *, int);
int window_unzoom(struct window *, int); int window_unzoom(struct window *, int);
struct window_pane *window_zoomed_pane(struct window *); struct window_pane *window_zoomed_pane(struct window *);
int window_has_visible_zoom(struct window *);
void window_zoom_move(struct window_pane *, struct window_pane *); void window_zoom_move(struct window_pane *, struct window_pane *);
void window_lost_pane(struct window *, struct window_pane *); void window_lost_pane(struct window *, struct window_pane *);
void window_remove_pane(struct window *, struct window_pane *); void window_remove_pane(struct window *, struct window_pane *);

View File

@@ -1174,6 +1174,19 @@ window_lower_pane(struct window_pane *wp)
redraw_invalidate_scene(w); redraw_invalidate_scene(w);
} }
/* Is any pane that is not hidden zoomed? */
int
window_has_visible_zoom(struct window *w)
{
struct window_pane *wp;
TAILQ_FOREACH(wp, &w->panes, entry) {
if ((wp->flags & PANE_ZOOMED) && (~wp->flags & PANE_HIDDEN))
return (1);
}
return (0);
}
/* Set or clear WINDOW_ZOOMED depending on whether any pane is zoomed. */ /* Set or clear WINDOW_ZOOMED depending on whether any pane is zoomed. */
static void static void
window_update_zoomed(struct window *w) window_update_zoomed(struct window *w)
@@ -1570,7 +1583,7 @@ window_printable_flags(struct winlink *wl, int escape)
flags[pos++] = 'M'; flags[pos++] = 'M';
if (wl->window->modal != NULL) if (wl->window->modal != NULL)
flags[pos++] = 'O'; flags[pos++] = 'O';
if (wl->window->flags & WINDOW_ZOOMED) if (window_has_visible_zoom(wl->window))
flags[pos++] = 'Z'; flags[pos++] = 'Z';
flags[pos] = '\0'; flags[pos] = '\0';
return (flags); return (flags);