mirror of
https://github.com/tmux/tmux.git
synced 2026-10-11 04:44:25 +00:00
@@ -115,9 +115,13 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (args_has(args, 'H')) {
|
if (args_has(args, 'H')) {
|
||||||
if (args_has(args, 'a'))
|
if (args_has(args, 'a'))
|
||||||
cmd_resize_pane_desktop(w);
|
cmd_resize_pane_desktop(w);
|
||||||
else if (wp->flags & PANE_HIDDEN)
|
else if (wp->flags & PANE_HIDDEN) {
|
||||||
window_set_active_pane(w, wp, 1);
|
window_set_active_pane(w, wp, 1);
|
||||||
else
|
if (wp->flags & PANE_HIDDEN) {
|
||||||
|
cmdq_error(item, "no space to show pane");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
} else
|
||||||
window_hide_pane(wp);
|
window_hide_pane(wp);
|
||||||
server_redraw_window(w);
|
server_redraw_window(w);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|||||||
@@ -371,4 +371,181 @@ run select-pane -L -t "$A"
|
|||||||
check "$A" '#{pane_active}' 1
|
check "$A" '#{pane_active}' 1
|
||||||
hidden "$X" 1
|
hidden "$X" 1
|
||||||
|
|
||||||
|
# Mixed vertical and horizontal splits, including three or more panes side by
|
||||||
|
# side. Hiding and showing each pane puts every pane back where it was. Hiding
|
||||||
|
# several panes and showing them again in the reverse order they were hidden
|
||||||
|
# leaves every pane within two cells of where it was. In the same order the panes
|
||||||
|
# have the wrong neighbours when they are shown so their sizes cannot be exact,
|
||||||
|
# but every pane must be back, tiled and not squeezed. Floating panes, including
|
||||||
|
# ones that were never tiled, are part of this: they are not moved by hiding
|
||||||
|
# other panes and tile somewhere in the layout without squeezing it.
|
||||||
|
#
|
||||||
|
# geom: id, left, top, width and height of every pane, sorted by id.
|
||||||
|
geom()
|
||||||
|
{
|
||||||
|
run list-panes -F '#{pane_id} #{pane_left} #{pane_top} #{pane_width} #{pane_height}' |
|
||||||
|
sort
|
||||||
|
}
|
||||||
|
|
||||||
|
# near $name $base $now $tolerance
|
||||||
|
near()
|
||||||
|
{
|
||||||
|
echo "$2
|
||||||
|
$3" | awk -v tol="$4" -v name="$1" '
|
||||||
|
NF == 5 && ($1 in seen) {
|
||||||
|
for (i = 2; i <= 5; i++) {
|
||||||
|
d = $i - seen[$1, i]
|
||||||
|
if (d < 0) d = -d
|
||||||
|
if (d > tol) {
|
||||||
|
printf "%s: %s differs by %d (%s became %s)\n", name, $1, d, seen[$1, 0], $0
|
||||||
|
bad = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next
|
||||||
|
}
|
||||||
|
NF == 5 { seen[$1] = 1; for (i = 2; i <= 5; i++) seen[$1, i] = $i; seen[$1, 0] = $0 }
|
||||||
|
END { exit bad }' || fail "layout not restored"
|
||||||
|
}
|
||||||
|
|
||||||
|
# usable $name $panes $minimum: the panes are tiled, shown and at least the
|
||||||
|
# minimum size in both directions.
|
||||||
|
usable()
|
||||||
|
{
|
||||||
|
for p in $2; do
|
||||||
|
check "$p" '#{pane_floating_flag}:#{pane_hidden_flag}' 0:0
|
||||||
|
w=$(run display-message -p -t "$p" '#{pane_width}') || exit 1
|
||||||
|
h=$(run display-message -p -t "$p" '#{pane_height}') || exit 1
|
||||||
|
[ "$w" -ge "$3" ] && [ "$h" -ge "$3" ] ||
|
||||||
|
fail "$1: $p is only ${w}x$h"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# build $size $splits...: a window made of splits, each a flag and a target.
|
||||||
|
build()
|
||||||
|
{
|
||||||
|
size=$1
|
||||||
|
shift
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
run new-session -d -x "${size%x*}" -y "${size#*x}" cat
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
run split-window -d "$1" -t "$2" ''
|
||||||
|
shift 2
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
mixed()
|
||||||
|
{
|
||||||
|
name=$1
|
||||||
|
size=$2
|
||||||
|
shift 2
|
||||||
|
splits="$*"
|
||||||
|
build $size $splits
|
||||||
|
base=$(geom)
|
||||||
|
ids=$(run list-panes -F '#{pane_id}' | sort)
|
||||||
|
n=$(echo "$ids" | wc -l)
|
||||||
|
last=$(echo "$ids" | tail -1)
|
||||||
|
|
||||||
|
# Each pane in turn.
|
||||||
|
for p in $ids; do
|
||||||
|
run resize-pane -H -t "$p"
|
||||||
|
hidden "$p" 1
|
||||||
|
run resize-pane -H -t "$p"
|
||||||
|
hidden "$p" 0
|
||||||
|
near "$name hiding $p" "$base" "$(geom)" 0
|
||||||
|
done
|
||||||
|
|
||||||
|
# Every pane but the last, shown in the reverse and in the same order.
|
||||||
|
for order in reverse forward; do
|
||||||
|
hide=
|
||||||
|
for p in $ids; do
|
||||||
|
[ "$p" = "$last" ] && continue
|
||||||
|
hide="$hide $p"
|
||||||
|
run resize-pane -H -t "$p"
|
||||||
|
done
|
||||||
|
show=$hide
|
||||||
|
if [ "$order" = reverse ]; then
|
||||||
|
show=
|
||||||
|
for p in $hide; do
|
||||||
|
show="$p $show"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
for p in $show; do
|
||||||
|
run resize-pane -H -t "$p"
|
||||||
|
done
|
||||||
|
for p in $ids; do
|
||||||
|
hidden "$p" 0
|
||||||
|
done
|
||||||
|
if [ "$order" = reverse ]; then
|
||||||
|
near "$name hiding $((n - 1)) panes, $order" "$base" "$(geom)" 2
|
||||||
|
else
|
||||||
|
usable "$name hiding $((n - 1)) panes, $order" "$ids" 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Any two panes, hidden and shown in the same order, even if they are
|
||||||
|
# next to each other: nothing is squeezed.
|
||||||
|
if [ "$size" = 120x40 ]; then
|
||||||
|
for p in $ids; do
|
||||||
|
for q in $ids; do
|
||||||
|
[ "$p" = "$q" ] && continue
|
||||||
|
build $size $splits
|
||||||
|
run resize-pane -H -t "$p"
|
||||||
|
run resize-pane -H -t "$q"
|
||||||
|
run resize-pane -H -t "$p"
|
||||||
|
run resize-pane -H -t "$q"
|
||||||
|
usable "$name hiding $p and $q" "$ids" 2
|
||||||
|
done
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# A floating pane that was never tiled: hiding and showing it, or any
|
||||||
|
# tiled pane, changes nothing else.
|
||||||
|
build $size $splits
|
||||||
|
f=$(run new-pane -dPF '#{pane_id}' -x 20 -y 6 -X 5 -Y 5 '') || exit 1
|
||||||
|
base=$(geom)
|
||||||
|
for p in $ids $f; do
|
||||||
|
run resize-pane -H -t "$p"
|
||||||
|
run resize-pane -H -t "$p"
|
||||||
|
near "$name with a float, hiding $p" "$base" "$(geom)" 0
|
||||||
|
done
|
||||||
|
check "$f" '#{pane_floating_flag}' 1
|
||||||
|
|
||||||
|
# Tiling it puts it in the layout without squeezing the others, and it
|
||||||
|
# can be floated and tiled again.
|
||||||
|
run join-pane -s "$f" -t "$f"
|
||||||
|
usable "$name tiling a new float" "$ids $f" 1
|
||||||
|
run break-pane -W -s "$f"
|
||||||
|
check "$f" '#{pane_floating_flag}' 1
|
||||||
|
run join-pane -s "$f" -t "$f"
|
||||||
|
usable "$name tiling the float again" "$ids $f" 1
|
||||||
|
|
||||||
|
# Floating, hiding and tiling panes together.
|
||||||
|
for p in $ids; do
|
||||||
|
[ "$p" = "$last" ] && continue
|
||||||
|
build $size $splits
|
||||||
|
f=$(run new-pane -dPF '#{pane_id}' -x 20 -y 6 -X 5 -Y 5 '') || exit 1
|
||||||
|
run break-pane -d -W -s "$p"
|
||||||
|
run resize-pane -H -t "$last"
|
||||||
|
run resize-pane -H -t "$last"
|
||||||
|
run join-pane -d -s "$p" -t "$p"
|
||||||
|
run join-pane -d -s "$f" -t "$f"
|
||||||
|
usable "$name floating $p, hiding $last, tiling both" "$ids $f" 1
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
for size in 80x24 120x40; do
|
||||||
|
mixed "A|(B/C) $size" $size -h %0 -v %1
|
||||||
|
mixed "A/(B|C) $size" $size -v %0 -h %1
|
||||||
|
mixed "(A|C)/B $size" $size -v %0 -h %0
|
||||||
|
mixed "(A/C)|B $size" $size -h %0 -v %0
|
||||||
|
mixed "2x2 $size" $size -v %0 -h %0 -h %1
|
||||||
|
mixed "A|(B/(C|D)) $size" $size -h %0 -v %1 -h %2
|
||||||
|
mixed "A/(B|(C/D)) $size" $size -v %0 -h %1 -v %2
|
||||||
|
done
|
||||||
|
# Three or more side by side need room.
|
||||||
|
mixed "A/(B|C|D)/E 120x40" 120x40 -v %0 -v %1 -v %2 -h %1 -h %1
|
||||||
|
mixed "(A/B/C)|(D|E) 120x40" 120x40 -h %0 -v %0 -v %0 -h %1
|
||||||
|
mixed "A|(B/C/D)|E 120x40" 120x40 -h %0 -h %1 -v %1 -v %1
|
||||||
|
mixed "A/(B|(C/D|E))/F 120x40" 120x40 -v %0 -v %1 -h %1 -v %3 -h %3
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
# - 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.
|
||||||
#
|
#
|
||||||
|
# The tiled panes are laid out in different shapes: split top to bottom or side
|
||||||
|
# by side, and for three panes stacked, in a row or nested.
|
||||||
|
#
|
||||||
# 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 panes and visible panes have
|
||||||
@@ -282,12 +285,22 @@ run_one()
|
|||||||
tgt=$4
|
tgt=$4
|
||||||
RUN=$((RUN + 1))
|
RUN=$((RUN + 1))
|
||||||
|
|
||||||
|
# The tiled panes are split in different ways: top to bottom or side by
|
||||||
|
# side for two, and stacked, in a row or nested for three.
|
||||||
set -- new-session -d -x 80 -y 24 cat
|
set -- new-session -d -x 80 -y 24 cat
|
||||||
i=1
|
if [ "$n" -eq 2 ]; then
|
||||||
while [ $i -lt "$n" ]; do
|
shape=$((RUN % 2))
|
||||||
set -- "$@" ';' split-window -d ''
|
else
|
||||||
i=$((i + 1))
|
shape=$((RUN % 3))
|
||||||
done
|
fi
|
||||||
|
case "$n$shape" in
|
||||||
|
20) set -- "$@" ';' split-window -d '' ;;
|
||||||
|
21) set -- "$@" ';' split-window -d -h '' ;;
|
||||||
|
30) set -- "$@" ';' split-window -d '' ';' split-window -d '' ;;
|
||||||
|
31) set -- "$@" ';' split-window -d -h '' ';' split-window -d -h '' ;;
|
||||||
|
32) set -- "$@" ';' split-window -d -h -t %0 '' \
|
||||||
|
';' split-window -d -v -t %1 '' ;;
|
||||||
|
esac
|
||||||
want=
|
want=
|
||||||
for stage in 1 2 4; do
|
for stage in 1 2 4; do
|
||||||
i=0
|
i=0
|
||||||
@@ -381,7 +394,7 @@ while [ $s -lt 64 ]; do
|
|||||||
s=$((s + 1))
|
s=$((s + 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
# Three panes: every state, and one operation on each, rotating so that every
|
# Three panes: every state, and two operations on each, rotating so that every
|
||||||
# operation and target is used with many different states.
|
# operation and target is used with many different states.
|
||||||
ALL="$GLOBAL"
|
ALL="$GLOBAL"
|
||||||
for op in $PER_PANE; do
|
for op in $PER_PANE; do
|
||||||
@@ -391,13 +404,15 @@ set -- $ALL
|
|||||||
M=$#
|
M=$#
|
||||||
s=0
|
s=0
|
||||||
while [ $s -lt 512 ]; do
|
while [ $s -lt 512 ]; do
|
||||||
set -- $ALL
|
for k in $(( (s * 7 + s / M) % M )) $(( (s * 5 + 11) % M )); do
|
||||||
shift $(( (s * 7 + s / M) % M ))
|
set -- $ALL
|
||||||
item=$1
|
shift $k
|
||||||
case $item in
|
item=$1
|
||||||
*:*) run_one 3 $s "${item%:*}" "%${item#*:}" ;;
|
case $item in
|
||||||
*) run_one 3 $s "$item" %0 ;;
|
*:*) run_one 3 $s "${item%:*}" "%${item#*:}" ;;
|
||||||
esac
|
*) run_one 3 $s "$item" %0 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
s=$((s + 1))
|
s=$((s + 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
10
tmux.h
10
tmux.h
@@ -1581,11 +1581,15 @@ struct layout_geometry {
|
|||||||
int yoff;
|
int yoff;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Size of a tiled cell and of the window when its pane was hidden. */
|
/*
|
||||||
|
* Size of a tiled cell, of its parent cell and the number of tiled cells next to
|
||||||
|
* it when its pane was hidden.
|
||||||
|
*/
|
||||||
struct layout_hidden {
|
struct layout_hidden {
|
||||||
struct layout_geometry g;
|
struct layout_geometry g;
|
||||||
u_int wsx;
|
u_int psx;
|
||||||
u_int wsy;
|
u_int psy;
|
||||||
|
u_int nsib;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Layout cells queue. */
|
/* Layout cells queue. */
|
||||||
|
|||||||
59
window.c
59
window.c
@@ -766,7 +766,8 @@ window_activate_pane(struct window *w, struct window_pane *wp, int notify,
|
|||||||
if (w->modal != NULL && wp != w->modal)
|
if (w->modal != NULL && wp != w->modal)
|
||||||
return (0);
|
return (0);
|
||||||
if (wp->flags & PANE_HIDDEN) {
|
if (wp->flags & PANE_HIDDEN) {
|
||||||
window_show_pane(wp);
|
if (window_show_pane(wp) != 0)
|
||||||
|
return (0);
|
||||||
if (wp == w->active)
|
if (wp == w->active)
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
@@ -1017,6 +1018,23 @@ window_raise_pane(struct window_pane *wp)
|
|||||||
redraw_invalidate_scene(w);
|
redraw_invalidate_scene(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Count the tiled cells next to a cell. */
|
||||||
|
static u_int
|
||||||
|
window_count_tiled_siblings(struct layout_cell *lc)
|
||||||
|
{
|
||||||
|
struct layout_cell *lcsib;
|
||||||
|
u_int n = 0;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(lcsib, &lc->parent->cells, entry) {
|
||||||
|
if (lcsib == lc)
|
||||||
|
continue;
|
||||||
|
if (layout_cell_is_tiled(lcsib) ||
|
||||||
|
layout_cell_has_tiled_child(lcsib))
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
return (n);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hide a pane. It keeps its place in the layout and in the stacking order and
|
* Hide a pane. It keeps its place in the layout and in the stacking order and
|
||||||
* stays zoomed or floating, so showing it again puts it back as it was.
|
* stays zoomed or floating, so showing it again puts it back as it was.
|
||||||
@@ -1031,11 +1049,18 @@ window_hide_pane(struct window_pane *wp)
|
|||||||
if ((wp->flags & PANE_HIDDEN) || wp == w->modal || lc == NULL)
|
if ((wp->flags & PANE_HIDDEN) || wp == w->modal || lc == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* A tiled pane gives its space to a neighbour. */
|
/*
|
||||||
|
* A tiled pane gives its space to a neighbour. Its size is only worth
|
||||||
|
* keeping if it shares the space with one.
|
||||||
|
*/
|
||||||
if (layout_cell_is_tiled(lc)) {
|
if (layout_cell_is_tiled(lc)) {
|
||||||
memcpy(&lc->hidden.g, &lc->g, sizeof lc->hidden.g);
|
if (layout_cell_get_neighbour(lc) != NULL) {
|
||||||
lc->hidden.wsx = w->sx;
|
memcpy(&lc->hidden.g, &lc->g, sizeof lc->hidden.g);
|
||||||
lc->hidden.wsy = w->sy;
|
lc->hidden.psx = lc->parent->g.sx;
|
||||||
|
lc->hidden.psy = lc->parent->g.sy;
|
||||||
|
lc->hidden.nsib = window_count_tiled_siblings(lc);
|
||||||
|
} else
|
||||||
|
lc->hidden.g.sx = UINT_MAX;
|
||||||
layout_remove_tile(w, lc);
|
layout_remove_tile(w, lc);
|
||||||
}
|
}
|
||||||
wp->flags |= PANE_HIDDEN;
|
wp->flags |= PANE_HIDDEN;
|
||||||
@@ -1068,27 +1093,39 @@ int
|
|||||||
window_show_pane(struct window_pane *wp)
|
window_show_pane(struct window_pane *wp)
|
||||||
{
|
{
|
||||||
struct window *w = wp->window;
|
struct window *w = wp->window;
|
||||||
struct layout_cell *lc = wp->layout_cell;
|
struct layout_cell *lc = wp->layout_cell, *lcneighbour = NULL;
|
||||||
enum layout_type type;
|
enum layout_type type;
|
||||||
u_int size, current;
|
u_int size, current, nsib = 0;
|
||||||
int tiled;
|
int tiled;
|
||||||
|
|
||||||
if (~wp->flags & PANE_HIDDEN)
|
if (~wp->flags & PANE_HIDDEN)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
tiled = (lc != NULL && !window_pane_is_floating(wp));
|
tiled = (lc != NULL && !window_pane_is_floating(wp));
|
||||||
|
if (tiled) {
|
||||||
|
lcneighbour = layout_cell_get_neighbour(lc);
|
||||||
|
nsib = window_count_tiled_siblings(lc);
|
||||||
|
}
|
||||||
if (tiled && layout_insert_tile(w, lc) != 0)
|
if (tiled && layout_insert_tile(w, lc) != 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
wp->flags &= ~(PANE_HIDDEN|PANE_HIDDENALL);
|
wp->flags &= ~(PANE_HIDDEN|PANE_HIDDENALL);
|
||||||
|
|
||||||
/* Try to get back the size the pane had, scaled to the window. */
|
/*
|
||||||
if (tiled && lc->parent != NULL && lc->hidden.g.sx != UINT_MAX) {
|
* Try to get back the size the pane had, scaled to how much its parent
|
||||||
|
* has changed. If it has no neighbour it fills the space around it, and
|
||||||
|
* the size is only right if it has the same neighbours as before.
|
||||||
|
*/
|
||||||
|
if (lcneighbour != NULL &&
|
||||||
|
lc->hidden.g.sx != UINT_MAX &&
|
||||||
|
lc->hidden.nsib == nsib) {
|
||||||
type = lc->parent->type;
|
type = lc->parent->type;
|
||||||
if (type == LAYOUT_LEFTRIGHT) {
|
if (type == LAYOUT_LEFTRIGHT) {
|
||||||
size = lc->hidden.g.sx * w->sx / lc->hidden.wsx;
|
size = lc->hidden.g.sx * lc->parent->g.sx /
|
||||||
|
lc->hidden.psx;
|
||||||
current = lc->g.sx;
|
current = lc->g.sx;
|
||||||
} else {
|
} else {
|
||||||
size = lc->hidden.g.sy * w->sy / lc->hidden.wsy;
|
size = lc->hidden.g.sy * lc->parent->g.sy /
|
||||||
|
lc->hidden.psy;
|
||||||
current = lc->g.sy;
|
current = lc->g.sy;
|
||||||
}
|
}
|
||||||
if (size < PANE_MINIMUM)
|
if (size < PANE_MINIMUM)
|
||||||
|
|||||||
Reference in New Issue
Block a user