mirror of
https://github.com/tmux/tmux.git
synced 2026-09-05 13:10:45 +00:00
Merge branch 'master' into no_more_overlays
# Conflicts: # regress/modal-pane.sh
This commit is contained in:
@@ -402,7 +402,6 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
const char *value, *style = args_get(args, 's');
|
||||
const char *border_style = args_get(args, 'S');
|
||||
char *cause = NULL, *title = NULL;
|
||||
int flags = SPAWN_FLOATING|SPAWN_MODAL;
|
||||
enum pane_lines lines = PANE_LINES_SINGLE;
|
||||
u_int px, py, sx, sy, count = args_count(args);
|
||||
struct args_value *av;
|
||||
@@ -468,10 +467,10 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
lg.yoff++;
|
||||
}
|
||||
|
||||
window_push_modal_zoom(w);
|
||||
window_push_zoom(w, 0, 1);
|
||||
lc = layout_floating_pane(w, wp, &lg);
|
||||
if (lc == NULL) {
|
||||
window_pop_modal_zoom(w);
|
||||
window_pop_zoom(w);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -483,7 +482,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
sc.lc = lc;
|
||||
sc.idx = -1;
|
||||
sc.cwd = args_get(args, 'd');
|
||||
sc.flags = flags;
|
||||
sc.flags = (SPAWN_FLOATING|SPAWN_MODAL|SPAWN_FLOATOVERZOOM);
|
||||
|
||||
if (count != 1 || *args_string(args, 0) != '\0')
|
||||
args_to_vector(args, &sc.argc, &sc.argv);
|
||||
@@ -499,9 +498,10 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cmdq_error(item, "create pane failed: %s", cause);
|
||||
free(cause);
|
||||
cause = NULL;
|
||||
window_pop_modal_zoom(w);
|
||||
window_pop_zoom(w);
|
||||
goto fail;
|
||||
}
|
||||
window_pop_zoom(w);
|
||||
new_wp->flags |= PANE_CAPTUREALLKEYS;
|
||||
|
||||
options_set_number(new_wp->options, "pane-border-lines", lines);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-select-pane.c,v 1.77 2026/07/17 12:42:51 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-select-pane.c,v 1.78 2026/08/20 09:19:24 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -160,6 +160,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
char *title;
|
||||
const char *style;
|
||||
struct options_entry *o;
|
||||
int visible, Zflag = args_has(args, 'Z');
|
||||
|
||||
if (entry == &cmd_last_pane_entry || args_has(args, 'l')) {
|
||||
/*
|
||||
@@ -185,14 +186,18 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
server_redraw_window_borders(lastwp->window);
|
||||
server_status_window(lastwp->window);
|
||||
} else {
|
||||
if (window_push_zoom(w, 0, args_has(args, 'Z')))
|
||||
if (w->modal != NULL && lastwp != w->modal)
|
||||
visible = 1;
|
||||
else
|
||||
visible = window_pane_is_visible(lastwp);
|
||||
if (!visible && window_push_zoom(w, 0, Zflag))
|
||||
server_redraw_window(w);
|
||||
window_redraw_active_switch(w, lastwp);
|
||||
if (window_set_active_pane(w, lastwp, 1)) {
|
||||
cmd_find_from_winlink(current, wl, 0);
|
||||
cmd_select_pane_redraw(w);
|
||||
}
|
||||
if (window_pop_zoom(w))
|
||||
if (!visible && window_pop_zoom(w))
|
||||
server_redraw_window(w);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
@@ -268,14 +273,18 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if (wp == w->active)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (window_push_zoom(w, 0, args_has(args, 'Z')))
|
||||
if (w->modal != NULL && wp != w->modal)
|
||||
visible = 1;
|
||||
else
|
||||
visible = window_pane_is_visible(wp);
|
||||
if (!visible && window_push_zoom(w, 0, Zflag))
|
||||
server_redraw_window(w);
|
||||
window_redraw_active_switch(w, wp);
|
||||
if (window_set_active_pane(w, wp, 1))
|
||||
cmd_find_from_winlink_pane(current, wl, wp, 0);
|
||||
cmdq_insert_hook(s, item, current, "after-select-pane");
|
||||
cmd_select_pane_redraw(w);
|
||||
if (window_pop_zoom(w))
|
||||
if (!visible && window_pop_zoom(w))
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-split-window.c,v 1.149 2026/08/19 10:56:10 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-split-window.c,v 1.150 2026/08/20 09:19:24 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -40,8 +40,8 @@ const struct cmd_entry cmd_new_pane_entry = {
|
||||
.name = "new-pane",
|
||||
.alias = "newp",
|
||||
|
||||
.args = { "bB:Cc:de:EfF:hIkl:KLMm:Op:PR:s:S:t:T:vWx:X:y:Y:Z", 0, -1, NULL },
|
||||
.usage = "[-bCdefhIkKLMOPvWZ] [-B border-lines] "
|
||||
.args = { "AbB:Cc:de:EfF:hIkl:KLMm:Op:PR:s:S:t:T:vWx:X:y:Y:Z", 0, -1, NULL },
|
||||
.usage = "[-AbCdefhIkKLMOPvWZ] [-B border-lines] "
|
||||
"[-c start-directory] [-e environment] "
|
||||
"[-F format] [-l size] [-m message] [-p percentage] "
|
||||
"[-s style] [-S active-border-style] "
|
||||
@@ -89,6 +89,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state fs;
|
||||
struct key_event *event = cmdq_get_event(item);
|
||||
int input, empty, is_floating, flags = 0;
|
||||
int restore_zoom = 0;
|
||||
const char *template, *style, *value;
|
||||
char *cause = NULL, *cp, *title;
|
||||
const struct options_table_entry *oe;
|
||||
@@ -96,10 +97,16 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
enum pane_lines lines;
|
||||
u_int count = args_count(args);
|
||||
|
||||
if (window_active_pane_is_over_zoom(w))
|
||||
restore_zoom = 1;
|
||||
|
||||
if (cmd_get_entry(self) == &cmd_new_pane_entry)
|
||||
is_floating = !args_has(args, 'L');
|
||||
else {
|
||||
window_unzoom(w, 1);
|
||||
if (!window_pane_is_visible(wp))
|
||||
restore_zoom = 0;
|
||||
if (!restore_zoom)
|
||||
window_unzoom(w, 1);
|
||||
is_floating = window_pane_is_floating(wp);
|
||||
flags |= SPAWN_SPLIT;
|
||||
}
|
||||
@@ -133,7 +140,11 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'Z'))
|
||||
flags |= SPAWN_ZOOM;
|
||||
if (args_has(args, 'O'))
|
||||
flags |= SPAWN_MODAL;
|
||||
flags |= SPAWN_MODAL|SPAWN_FLOATOVERZOOM;
|
||||
if (is_floating && args_has(args, 'A'))
|
||||
flags |= SPAWN_FLOATOVERZOOM;
|
||||
if ((w->flags & WINDOW_ZOOMED) && (flags & SPAWN_FLOATOVERZOOM))
|
||||
restore_zoom = 1;
|
||||
|
||||
input = args_has(args, 'I');
|
||||
if (input || (count == 1 && *args_string(args, 0) == '\0'))
|
||||
@@ -169,6 +180,8 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
if (restore_zoom)
|
||||
window_pop_zoom(w);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
@@ -273,7 +286,10 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (~flags & SPAWN_DETACHED)
|
||||
cmd_find_from_winlink_pane(current, wl, new_wp, 0);
|
||||
|
||||
if ((~flags & SPAWN_FLOATING) && !args_has(args, 'O')) {
|
||||
if (restore_zoom) {
|
||||
window_pop_zoom(wp->window);
|
||||
server_redraw_window(wp->window);
|
||||
} else if ((~flags & SPAWN_FLOATING) && !args_has(args, 'O')) {
|
||||
window_pop_zoom(wp->window);
|
||||
server_redraw_window(wp->window);
|
||||
}
|
||||
@@ -324,8 +340,9 @@ fail:
|
||||
if (!is_floating)
|
||||
layout_close_pane(new_wp);
|
||||
window_remove_pane(wp->window, new_wp);
|
||||
} else if (args_has(args, 'O'))
|
||||
window_pop_modal_zoom(wp->window);
|
||||
}
|
||||
if (restore_zoom || (~flags & SPAWN_FLOATING))
|
||||
window_pop_zoom(wp->window);
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
environ_free(sc.environ);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-switch-client.c,v 1.74 2026/05/22 15:22:43 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-switch-client.c,v 1.75 2026/08/20 09:19:24 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -53,7 +53,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state target;
|
||||
const char *tflag = args_get(args, 't');
|
||||
enum cmd_find_type type;
|
||||
int flags;
|
||||
int flags, visible, Zflag = args_has(args, 'Z');
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct session *s;
|
||||
@@ -139,11 +139,15 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (wl != NULL && wp != NULL && wp != wl->window->active) {
|
||||
w = wl->window;
|
||||
if (window_push_zoom(w, 0, args_has(args, 'Z')))
|
||||
if (w->modal != NULL && wp != w->modal)
|
||||
visible = 1;
|
||||
else
|
||||
visible = window_pane_is_visible(wp);
|
||||
if (!visible && window_push_zoom(w, 0, Zflag))
|
||||
server_redraw_window(w);
|
||||
window_redraw_active_switch(w, wp);
|
||||
window_set_active_pane(w, wp, 1);
|
||||
if (window_pop_zoom(w))
|
||||
if (!visible && window_pop_zoom(w))
|
||||
server_redraw_window(w);
|
||||
}
|
||||
if (wl != NULL) {
|
||||
|
||||
13
layout.c
13
layout.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: layout.c,v 1.96 2026/07/15 13:02:33 nicm Exp $ */
|
||||
/* $OpenBSD: layout.c,v 1.97 2026/08/20 09:19:24 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1650,7 +1650,10 @@ layout_get_tiled_cell(struct cmdq_item *item, struct args *args,
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
window_push_zoom(wp->window, 1, (flags & SPAWN_ZOOM));
|
||||
if (window_active_pane_is_over_zoom(w))
|
||||
window_push_zoom(w, 0, 1);
|
||||
else
|
||||
window_push_zoom(w, 1, (flags & SPAWN_ZOOM));
|
||||
lc = layout_split_pane(wp, type, size, flags);
|
||||
if (lc == NULL)
|
||||
*cause = xstrdup("no space for a new pane");
|
||||
@@ -1677,8 +1680,10 @@ layout_get_floating_cell(struct cmdq_item *item, struct args *args,
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (flags & SPAWN_MODAL)
|
||||
window_push_modal_zoom(w);
|
||||
if (flags & SPAWN_FLOATOVERZOOM)
|
||||
window_push_zoom(wp->window, 0, 1);
|
||||
else if (window_active_pane_is_over_zoom(w))
|
||||
window_push_zoom(wp->window, 0, 1);
|
||||
else
|
||||
window_push_zoom(wp->window, 1, (flags & SPAWN_ZOOM));
|
||||
lcnew = layout_floating_pane(w, wp, &fg);
|
||||
|
||||
@@ -145,12 +145,16 @@ case "$(fmt "$modal" '#{pane_flags}')" in
|
||||
*O*) ;;
|
||||
*) fail "modal pane flags do not include O" ;;
|
||||
esac
|
||||
case "$(fmt "$modal" '#{pane_flags}')" in
|
||||
*A*) ;;
|
||||
*) fail "modal pane flags do not include A" ;;
|
||||
esac
|
||||
case "$(fmt modal:0 '#{window_flags}')" in
|
||||
*O*) ;;
|
||||
*) fail "modal window flags do not include O" ;;
|
||||
esac
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" "$modal"
|
||||
must_equal "$(fmt modal:0 '#{window_zoomed_flag}')" 0
|
||||
must_equal "$(fmt modal:0 '#{window_zoomed_flag}')" 1
|
||||
|
||||
check_fail "window already has a modal pane" \
|
||||
new-pane -O -x 10 -y 4 'cat'
|
||||
@@ -177,12 +181,14 @@ under=$($TMUX split-window -PF '#{pane_id}' -t "$p0" 'cat') ||
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:0 '#{pane_id}')" "$modal"
|
||||
must_equal "$(fmt "$under" '#{pane_active}')" 0
|
||||
must_equal "$(fmt modal:0 '#{window_zoomed_flag}')" 1
|
||||
|
||||
float=$($TMUX new-pane -PF '#{pane_id}' -x 10 -y 4 -X 5 -Y 3 'cat') ||
|
||||
fail "new floating pane under modal failed"
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:0 '#{pane_id}')" "$modal"
|
||||
must_equal "$(fmt "$float" '#{pane_active}')" 0
|
||||
must_equal "$(fmt modal:0 '#{window_zoomed_flag}')" 1
|
||||
|
||||
check_ok new-window -d -t modal: -n other 'cat'
|
||||
check_ok select-window -t modal:other
|
||||
@@ -321,6 +327,7 @@ check_ok kill-pane -t "$modal"
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" ''
|
||||
must_equal "$(fmt modal:0 '#{pane_id}')" "$p0"
|
||||
must_equal "$(fmt "$p0" '#{window_zoomed_flag}:#{pane_zoomed_flag}')" 0:0
|
||||
|
||||
ignored=$($TMUX new-pane -KdPF '#{pane_id}' -t "$p0" 'cat') ||
|
||||
fail "new-pane -K without -O failed"
|
||||
@@ -378,5 +385,132 @@ $TMUX2 send-keys -t "$OUTER" a
|
||||
sleep 1
|
||||
must_equal "$(fmt modal:0 '#{window_modal_pane}')" ''
|
||||
|
||||
# A nonmodal floating pane may remain above zoom, and switching between it and
|
||||
# the zoomed tiled pane must not unzoom the window.
|
||||
check_ok new-window -d -t modal: -n float-over-zoom 'cat'
|
||||
base=$(fmt modal:float-over-zoom '#{pane_id}')
|
||||
check_ok split-window -dh -t "$base" 'cat'
|
||||
check_ok resize-pane -Z -t "$base"
|
||||
over=$($TMUX new-pane -APF '#{pane_id}' -t "$base" \
|
||||
-x 20 -y 5 -X 20 -Y 10 'cat') ||
|
||||
fail "new-pane -A failed"
|
||||
must_equal "$(fmt "$over" '#{pane_floating_flag}:#{pane_active}')" 1:1
|
||||
case "$(fmt "$over" '#{pane_flags}')" in
|
||||
*A*) ;;
|
||||
*) fail "float-over-zoom pane flags do not include A" ;;
|
||||
esac
|
||||
must_equal "$(fmt "$base" '#{window_zoomed_flag}:#{pane_zoomed_flag}')" 1:1
|
||||
check_ok select-pane -t "$base"
|
||||
must_equal "$(fmt "$base" '#{window_zoomed_flag}:#{pane_active}')" 1:1
|
||||
check_ok select-pane -t "$over"
|
||||
must_equal "$(fmt "$over" '#{window_zoomed_flag}:#{pane_active}')" 1:1
|
||||
client=$($TMUX list-clients -F '#{client_name}' | head -1)
|
||||
[ -n "$client" ] || fail "no client for switch-client test"
|
||||
check_ok switch-client -c "$client" -t "$base"
|
||||
must_equal "$(fmt "$base" '#{window_zoomed_flag}:#{pane_active}')" 1:1
|
||||
check_ok switch-client -c "$client" -t "$over"
|
||||
must_equal "$(fmt "$over" '#{window_zoomed_flag}:#{pane_active}')" 1:1
|
||||
check_ok kill-pane -t "$over"
|
||||
must_equal "$(fmt "$base" '#{window_zoomed_flag}:#{pane_zoomed_flag}')" 1:1
|
||||
check_ok resize-pane -Z -t "$base"
|
||||
|
||||
ignored=$($TMUX new-pane -ALdPF '#{pane_id}' -t "$base" 'cat') ||
|
||||
fail "new-pane -A -L failed"
|
||||
case "$(fmt "$ignored" '#{pane_flags}')" in
|
||||
*A*) fail "tiled pane flags include A" ;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
# Existing floating panes are filtered when zoom begins: -A panes remain in the
|
||||
# visible layout and ordinary floating panes do not.
|
||||
check_ok new-window -d -t modal: -n existing-over-zoom 'cat'
|
||||
base=$(fmt modal:existing-over-zoom '#{pane_id}')
|
||||
check_ok split-window -dh -t "$base" 'cat'
|
||||
over=$($TMUX new-pane -AdPF '#{pane_id}' -t "$base" \
|
||||
-x 20 -y 5 -X 20 -Y 10 'cat') ||
|
||||
fail "pre-existing new-pane -A failed"
|
||||
under=$($TMUX new-pane -dPF '#{pane_id}' -t "$base" \
|
||||
-x 15 -y 4 -X 2 -Y 2 'cat') ||
|
||||
fail "pre-existing ordinary new-pane failed"
|
||||
check_ok select-window -t modal:existing-over-zoom
|
||||
check_ok select-pane -t "$base"
|
||||
check_ok resize-pane -Z -t "$base"
|
||||
must_equal "$(fmt "$over" '#{pane_floating_flag}')" 1
|
||||
must_equal "$(fmt "$under" '#{pane_floating_flag}')" 0
|
||||
must_equal "$(fmt "$base" '#{window_zoomed_flag}:#{pane_zoomed_flag}')" 1:1
|
||||
|
||||
# Geometry changed in the visible zoom layout is copied back when unzooming.
|
||||
check_ok select-pane -t "$over"
|
||||
left=$(fmt "$over" '#{pane_left}')
|
||||
top=$(fmt "$over" '#{pane_top}')
|
||||
meta_drag $((left + 2)) $((top + 2)) $((left + 7)) $((top + 4))
|
||||
new_left=$(fmt "$over" '#{pane_left}')
|
||||
new_top=$(fmt "$over" '#{pane_top}')
|
||||
[ "$new_left" -gt "$left" ] || [ "$new_top" -gt "$top" ] ||
|
||||
fail "float-over-zoom pane did not move"
|
||||
must_equal "$(fmt "$base" '#{window_zoomed_flag}:#{pane_zoomed_flag}')" 1:1
|
||||
check_ok resize-pane -Z -t "$base"
|
||||
must_equal "$(fmt "$over" '#{pane_left}:#{pane_top}')" \
|
||||
"$new_left:$new_top"
|
||||
must_equal "$(fmt "$under" '#{pane_floating_flag}')" 1
|
||||
|
||||
# Resizing with the over-zoom pane active restores the original zoom target.
|
||||
check_ok resize-pane -Z -t "$base"
|
||||
check_ok select-pane -t "$over"
|
||||
check_ok resize-window -t modal:existing-over-zoom -x 90 -y 30
|
||||
must_equal "$(fmt "$base" \
|
||||
'#{window_width}x#{window_height}:#{window_zoomed_flag}:#{pane_zoomed_flag}')" \
|
||||
90x30:1:1
|
||||
must_equal "$(fmt "$over" '#{pane_floating_flag}:#{pane_active}')" 1:1
|
||||
|
||||
# Natural pane exit uses a different removal path from kill-pane and must also
|
||||
# preserve zoom.
|
||||
dying=$($TMUX new-pane -AdPF '#{pane_id}' -t "$base" \
|
||||
-x 12 -y 4 -X 4 -Y 3 'true') ||
|
||||
fail "short-lived new-pane -A failed"
|
||||
i=0
|
||||
while $TMUX list-panes -a -F '#{pane_id}' | grep -qx "$dying"; do
|
||||
i=$((i + 1))
|
||||
[ $i -gt 50 ] && fail "short-lived float-over-zoom pane did not exit"
|
||||
sleep 0.1
|
||||
done
|
||||
must_equal "$(fmt "$base" '#{window_zoomed_flag}:#{pane_zoomed_flag}')" 1:1
|
||||
|
||||
# A pane with -A is also above a zoom target which was itself floating. The
|
||||
# temporary tiled target must sit behind retained floating panes, then return
|
||||
# to the normal floating z order when unzoomed.
|
||||
check_ok new-window -d -t modal: -n floating-zoom-target 'cat'
|
||||
base=$(fmt modal:floating-zoom-target '#{pane_id}')
|
||||
check_ok split-window -dh -t "$base" 'cat'
|
||||
target=$($TMUX new-pane -dPF '#{pane_id}' -t "$base" \
|
||||
-x 30 -y 10 -X 10 -Y 5 'cat') ||
|
||||
fail "floating zoom target creation failed"
|
||||
over=$($TMUX new-pane -AdPF '#{pane_id}' -t "$base" \
|
||||
-x 15 -y 5 -X 15 -Y 8 'cat') ||
|
||||
fail "float-over-zoom pane creation failed"
|
||||
check_ok select-window -t modal:floating-zoom-target
|
||||
check_ok select-pane -t "$target"
|
||||
must_equal "$(fmt "$target" '#{pane_z}')" 0
|
||||
must_equal "$(fmt "$over" '#{pane_z}')" 1
|
||||
|
||||
check_ok resize-pane -Z -t "$target"
|
||||
must_equal "$(fmt "$target" \
|
||||
'#{window_zoomed_flag}:#{pane_zoomed_flag}:#{pane_floating_flag}:#{pane_z}')" \
|
||||
1:1:0:2
|
||||
must_equal "$(fmt "$over" '#{pane_floating_flag}:#{pane_z}')" 1:0
|
||||
check_ok select-pane -t "$over"
|
||||
must_equal "$(fmt "$over" '#{window_zoomed_flag}:#{pane_active}')" 1:1
|
||||
check_ok resize-pane -Z -t "$target"
|
||||
must_equal "$(fmt "$over" '#{pane_active}:#{pane_z}')" 1:0
|
||||
must_equal "$(fmt "$target" '#{pane_floating_flag}:#{pane_z}')" 1:1
|
||||
|
||||
# If the target remains active, it returns to the front on unzoom.
|
||||
check_ok select-pane -t "$target"
|
||||
check_ok resize-pane -Z -t "$target"
|
||||
must_equal "$(fmt "$over" '#{pane_floating_flag}:#{pane_z}')" 1:0
|
||||
check_ok resize-pane -Z -t "$target"
|
||||
must_equal "$(fmt "$target" '#{pane_active}:#{pane_z}')" 1:0
|
||||
must_equal "$(fmt "$over" '#{pane_z}')" 1
|
||||
|
||||
cleanup
|
||||
exit 0
|
||||
|
||||
@@ -19,7 +19,10 @@
|
||||
# - respawn-pane/respawn-window refusing a live pane without -k, working on a
|
||||
# dead pane (remain-on-exit) and killing with -k;
|
||||
# - resize-pane -x/-y in cells and percent, -L/-R/-U/-D adjustments and -Z
|
||||
# zoom/unzoom (including implicit unzoom on split).
|
||||
# zoom/unzoom, layout round trips, zoom target selection, pane removal,
|
||||
# window resizing and implicit unzoom on layout changes;
|
||||
# - swap-pane preserving one or two zoomed windows, including cross-window
|
||||
# swaps of hidden panes and zoom targets.
|
||||
#
|
||||
# window-ops.sh covers window-level commands and buffers.sh paste buffers.
|
||||
|
||||
@@ -144,7 +147,8 @@ check_panes P:0 "0:$p3 1:$p0 2:$p2 3:$p1"
|
||||
# break-pane and join-pane.
|
||||
|
||||
# break-pane moves a pane to a new window; -P -F prints where it went and -n
|
||||
# names the new window.
|
||||
# names the new window. Moving a pane out of a zoomed window unzooms it first.
|
||||
check_ok resize-pane -Z -t "$p0"
|
||||
out=$($TMUX break-pane -d -P -F '#{window_index}:#{pane_id}' -n broken \
|
||||
-s "$p1" -t P:)
|
||||
if [ "$out" != "1:$p1" ]; then
|
||||
@@ -153,10 +157,14 @@ if [ "$out" != "1:$p1" ]; then
|
||||
fi
|
||||
check_fmt 'P:1' '#{window_name}:#{window_panes}' 'broken:1'
|
||||
check_fmt 'P:0' '#{window_panes}' '3'
|
||||
check_fmt 'P:0' '#{window_zoomed_flag}' '0'
|
||||
|
||||
# join-pane -v moves it back (the source window, left empty, is destroyed).
|
||||
# join-pane -v moves it back (the source window, left empty, is destroyed) and
|
||||
# also unzooms the destination before changing its layout.
|
||||
check_ok resize-pane -Z -t "$p0"
|
||||
check_ok join-pane -d -v -s P:broken.0 -t "$p2"
|
||||
check_fmt 'P:0' '#{window_panes}' '4'
|
||||
check_fmt 'P:0' '#{window_zoomed_flag}' '0'
|
||||
if $TMUX has-session -t P:broken 2>/dev/null; then
|
||||
echo "Window 'broken' still exists after join-pane."
|
||||
exit 1
|
||||
@@ -299,6 +307,122 @@ check_fmt 'P:0' '#{window_panes}' '5'
|
||||
p6=$($TMUX display-message -p -t P:0.2 '#{pane_id}')
|
||||
check_ok kill-pane -t "$p6"
|
||||
|
||||
# Zoom and unzoom preserve the exact tiled layout. Selecting another pane
|
||||
# without -Z unzooms, while -Z transfers zoom to the selected pane.
|
||||
layout=$($TMUX display-message -p -t P:0 '#{window_layout}')
|
||||
check_ok select-pane -t "$p0"
|
||||
check_ok resize-pane -Z -t "$p0"
|
||||
check_ok select-pane -t "$p2"
|
||||
check_fmt "$p2" '#{window_zoomed_flag}:#{pane_active}' '0:1'
|
||||
check_fmt P:0 '#{window_layout}' "$layout"
|
||||
|
||||
check_ok select-pane -t "$p0"
|
||||
check_ok resize-pane -Z -t "$p0"
|
||||
check_ok select-pane -Z -t "$p2"
|
||||
check_fmt "$p2" '#{window_zoomed_flag}:#{pane_zoomed_flag}:#{pane_active}' \
|
||||
'1:1:1'
|
||||
check_ok resize-pane -Z -t "$p2"
|
||||
check_fmt P:0 '#{window_layout}' "$layout"
|
||||
|
||||
# Directional selection temporarily restores the full layout to find its
|
||||
# neighbour, then follows the same unzoom or -Z transfer rules.
|
||||
check_ok select-pane -t "$p0"
|
||||
check_ok resize-pane -Z -t "$p0"
|
||||
check_ok select-pane -t "$p0"
|
||||
check_fmt "$p0" '#{window_zoomed_flag}:#{pane_zoomed_flag}:#{pane_active}' \
|
||||
'1:1:1'
|
||||
check_ok select-pane -D -t "$p0"
|
||||
check_fmt "$p2" '#{window_zoomed_flag}:#{pane_active}' '0:1'
|
||||
|
||||
check_ok select-pane -t "$p0"
|
||||
check_ok resize-pane -Z -t "$p0"
|
||||
check_ok select-pane -D -Z -t "$p0"
|
||||
check_fmt "$p2" '#{window_zoomed_flag}:#{pane_zoomed_flag}:#{pane_active}' \
|
||||
'1:1:1'
|
||||
check_ok resize-pane -Z -t "$p2"
|
||||
check_fmt P:0 '#{window_layout}' "$layout"
|
||||
|
||||
# The last-pane path has separate zoom handling, both with and without -Z.
|
||||
check_ok select-pane -t "$p0"
|
||||
check_ok select-pane -t "$p2"
|
||||
check_ok resize-pane -Z -t "$p2"
|
||||
check_ok select-pane -l -t P:0
|
||||
check_fmt "$p0" '#{window_zoomed_flag}:#{pane_zoomed_flag}:#{pane_active}' \
|
||||
'0:0:1'
|
||||
|
||||
check_ok select-pane -t "$p0"
|
||||
check_ok select-pane -t "$p2"
|
||||
check_ok resize-pane -Z -t "$p2"
|
||||
check_ok select-pane -l -Z -t P:0
|
||||
check_fmt "$p0" '#{window_zoomed_flag}:#{pane_zoomed_flag}:#{pane_active}' \
|
||||
'1:1:1'
|
||||
check_ok resize-pane -Z -t "$p0"
|
||||
check_fmt P:0 '#{window_layout}' "$layout"
|
||||
|
||||
# Killing either a hidden ordinary pane or the zoom target unzooms.
|
||||
check_ok new-window -d -t P:12 -n zoom-kill 'cat'
|
||||
zk0=$($TMUX display-message -p -t P:12.0 '#{pane_id}')
|
||||
zk1=$($TMUX split-window -d -P -F '#{pane_id}' -t P:12.0 'cat')
|
||||
zk2=$($TMUX split-window -d -P -F '#{pane_id}' -t P:12.0 'cat')
|
||||
check_ok resize-pane -Z -t "$zk0"
|
||||
check_ok kill-pane -t "$zk1"
|
||||
check_fmt "$zk0" '#{window_panes}:#{window_zoomed_flag}:#{pane_zoomed_flag}' \
|
||||
'2:0:0'
|
||||
check_ok resize-pane -Z -t "$zk0"
|
||||
check_ok kill-pane -t "$zk0"
|
||||
check_fmt "$zk2" '#{window_panes}:#{window_zoomed_flag}:#{pane_zoomed_flag}' \
|
||||
'1:0:0'
|
||||
check_ok kill-window -t P:12
|
||||
|
||||
# The same cases through natural process exit exercise server_destroy_pane.
|
||||
check_ok new-window -d -t P:13 -n zoom-exit 'cat'
|
||||
ze0=$($TMUX display-message -p -t P:13.0 '#{pane_id}')
|
||||
ze1=$($TMUX split-window -d -P -F '#{pane_id}' -t P:13.0 'cat')
|
||||
ze2=$($TMUX split-window -d -P -F '#{pane_id}' -t P:13.0 'cat')
|
||||
check_ok resize-pane -Z -t "$ze0"
|
||||
check_ok send-keys -t "$ze1" C-d
|
||||
i=0
|
||||
while [ "$($TMUX display-message -p -t P:13 '#{window_panes}')" != 2 ]; do
|
||||
i=$((i + 1))
|
||||
[ $i -gt 50 ] && { echo "Hidden pane did not exit."; exit 1; }
|
||||
sleep 0.1
|
||||
done
|
||||
check_fmt "$ze0" '#{window_zoomed_flag}:#{pane_zoomed_flag}' '0:0'
|
||||
check_ok resize-pane -Z -t "$ze2"
|
||||
check_ok send-keys -t "$ze2" C-d
|
||||
i=0
|
||||
while [ "$($TMUX display-message -p -t P:13 '#{window_panes}')" != 1 ]; do
|
||||
i=$((i + 1))
|
||||
[ $i -gt 50 ] && { echo "Zoomed pane did not exit."; exit 1; }
|
||||
sleep 0.1
|
||||
done
|
||||
check_fmt "$ze0" '#{window_zoomed_flag}:#{pane_zoomed_flag}' '0:0'
|
||||
check_ok kill-window -t P:13
|
||||
|
||||
# resize-window restores both tiled and floating zoom targets after rebuilding
|
||||
# the layout at the new size.
|
||||
check_ok new-window -d -t P:14 -n zoom-resize 'cat'
|
||||
zr0=$($TMUX display-message -p -t P:14.0 '#{pane_id}')
|
||||
check_ok split-window -d -t P:14.0 'cat'
|
||||
check_ok resize-pane -Z -t "$zr0"
|
||||
check_ok resize-window -t P:14 -x 90 -y 30
|
||||
check_fmt "$zr0" \
|
||||
'#{window_width}x#{window_height}:#{window_zoomed_flag}:#{pane_zoomed_flag}' \
|
||||
'90x30:1:1'
|
||||
check_ok resize-pane -Z -t "$zr0"
|
||||
zrf=$($TMUX new-pane -dP -F '#{pane_id}' -t P:14 -x 20 -y 6 'cat')
|
||||
zrf_size=$($TMUX display-message -p -t "$zrf" \
|
||||
'#{pane_width}x#{pane_height}')
|
||||
check_ok resize-pane -Z -t "$zrf"
|
||||
check_ok resize-window -t P:14 -x 100 -y 32
|
||||
check_fmt "$zrf" \
|
||||
'#{window_width}x#{window_height}:#{window_zoomed_flag}:#{pane_zoomed_flag}' \
|
||||
'100x32:1:1'
|
||||
check_ok resize-pane -Z -t "$zrf"
|
||||
check_fmt "$zrf" '#{pane_floating_flag}:#{pane_width}x#{pane_height}' \
|
||||
"1:$zrf_size"
|
||||
check_ok kill-window -t P:14
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# kill-pane.
|
||||
|
||||
@@ -307,8 +431,10 @@ check_ok kill-pane -t "$p3"
|
||||
check_panes P:0 "0:$p0 1:$p2 2:$p1"
|
||||
|
||||
# -a kills every pane except the target.
|
||||
check_ok resize-pane -Z -t "$p0"
|
||||
check_ok kill-pane -a -t "$p0"
|
||||
check_panes P:0 "0:$p0"
|
||||
check_fmt "$p0" '#{window_zoomed_flag}:#{pane_zoomed_flag}' '0:0'
|
||||
|
||||
# Killing the last pane in a window kills the window.
|
||||
check_ok new-window -d -t P:7 -n goner
|
||||
@@ -516,6 +642,10 @@ check_panes P:3 "0:$r0 1:$r1 2:$r2"
|
||||
# Swapping a pane with itself quietly does nothing.
|
||||
check_ok swap-pane -d -s "$r1" -t "$r1"
|
||||
check_panes P:3 "0:$r0 1:$r1 2:$r2"
|
||||
check_ok resize-pane -Z -t "$r1"
|
||||
check_ok swap-pane -d -Z -s "$r1" -t "$r1"
|
||||
check_fmt "$r1" '#{window_zoomed_flag}:#{pane_zoomed_flag}' '1:1'
|
||||
check_ok resize-pane -Z -t "$r1"
|
||||
|
||||
# Panes can be swapped between different windows.
|
||||
check_ok swap-pane -d -s "$o0" -t "$r1"
|
||||
@@ -525,10 +655,38 @@ check_ok swap-pane -d -s "$r1" -t "$o0"
|
||||
check_panes P:3 "0:$r0 1:$r1 2:$r2"
|
||||
check_panes P:5 "0:$o0"
|
||||
|
||||
# With both windows zoomed, -Z preserves each window's zoom when hidden panes
|
||||
# are exchanged and when the zoom targets themselves are exchanged.
|
||||
o1=$($TMUX split-window -dP -F '#{pane_id}' -t P:5.0)
|
||||
check_ok resize-pane -Z -t "$r0"
|
||||
check_ok resize-pane -Z -t "$o0"
|
||||
check_ok swap-pane -d -Z -s "$r1" -t "$o1"
|
||||
check_fmt "$r0" \
|
||||
'#{window_name}:#{window_zoomed_flag}:#{pane_zoomed_flag}' 'swaps:1:1'
|
||||
check_fmt "$o0" \
|
||||
'#{window_name}:#{window_zoomed_flag}:#{pane_zoomed_flag}' 'other:1:1'
|
||||
check_fmt "$r1" '#{window_name}' 'other'
|
||||
check_fmt "$o1" '#{window_name}' 'swaps'
|
||||
|
||||
check_ok swap-pane -d -Z -s "$r0" -t "$o0"
|
||||
check_fmt "$o0" \
|
||||
'#{window_name}:#{window_zoomed_flag}:#{pane_zoomed_flag}' 'swaps:1:1'
|
||||
check_fmt "$r0" \
|
||||
'#{window_name}:#{window_zoomed_flag}:#{pane_zoomed_flag}' 'other:1:1'
|
||||
check_ok resize-pane -Z -t "$o0"
|
||||
check_ok resize-pane -Z -t "$r0"
|
||||
|
||||
# Restore the original panes before the remaining swap tests.
|
||||
check_ok swap-pane -d -s "$r0" -t "$o0"
|
||||
check_ok swap-pane -d -s "$r1" -t "$o1"
|
||||
check_ok kill-pane -t "$o1"
|
||||
check_panes P:3 "0:$r0 1:$r1 2:$r2"
|
||||
check_panes P:5 "0:$o0"
|
||||
|
||||
# -Z keeps the window zoomed across the swap.
|
||||
check_ok resize-pane -Z -t "$r0"
|
||||
check_ok swap-pane -d -Z -s "$r0" -t "$r1"
|
||||
check_fmt 'P:3' '#{window_zoomed_flag}' '1'
|
||||
check_fmt "$r0" '#{window_zoomed_flag}:#{pane_zoomed_flag}' '1:1'
|
||||
check_ok resize-pane -Z -t P:3
|
||||
check_panes P:3 "0:$r1 1:$r0 2:$r2"
|
||||
|
||||
|
||||
@@ -105,6 +105,21 @@ sleep 1
|
||||
CLIENT=$($TMUX2 list-clients -F '#{client_name}' | head -1)
|
||||
[ -n "$CLIENT" ] || fail "no inner client"
|
||||
|
||||
# A variation selector which widens the previous character must use window
|
||||
# coordinates when checking visibility in a pane with a nonzero x offset.
|
||||
$TMUX2 set -s variation-selector-always-wide on || exit 1
|
||||
WINDOW=$($TMUX2 neww -dPF '#{window_id}' "exec sleep 100") || exit 1
|
||||
PANE=$($TMUX2 splitw -dhPF '#{pane_id}' -t "$WINDOW" \
|
||||
"exec sleep 100") || exit 1
|
||||
$TMUX2 selectw -t "$WINDOW" || exit 1
|
||||
$TMUX2 respawnp -k -t "$PANE" \
|
||||
"printf '\nA\342\234\217\357\270\217B'; exec sleep 100" || exit 1
|
||||
sleep 1
|
||||
$TMUX2 capturep -p -t "$PANE" >$TMP || exit 1
|
||||
EXPECTED=$(printf 'A\342\234\217\357\270\217B')
|
||||
check_line 2 "$EXPECTED"
|
||||
$TMUX2 killw -t "$WINDOW" || exit 1
|
||||
|
||||
# Long line, then short line: default cells after cellsize must clear stale text.
|
||||
capture
|
||||
check_line 1 "abcdefghijklmnopqrst"
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
# unlink the last link without -k;
|
||||
# - swap-window within and between sessions, -d keeping the active window,
|
||||
# and the grouped-sessions error;
|
||||
# - rotate-window -U/-D rotating pane positions;
|
||||
# - rotate-window -U/-D rotating pane positions, with and without preserving
|
||||
# zoom using -Z;
|
||||
# - kill-window switching to the last (previously current) window, kill-window
|
||||
# -a killing all other windows and the "-f only valid with -a" guard.
|
||||
#
|
||||
@@ -306,6 +307,24 @@ check_fmt 'R:0' '#{pane_index}:#{pane_id}' "0:$p1"
|
||||
check_ok rotate-window -D -t R:0
|
||||
check_fmt 'R:0' '#{pane_index}:#{pane_id}' "0:$p0"
|
||||
|
||||
# Rotation without -Z unzooms. With -Z it preserves zoom and transfers it to
|
||||
# the pane which arrives at the active position.
|
||||
layout=$($TMUX display-message -p -t R:0 '#{window_layout}')
|
||||
check_ok resize-pane -Z -t "$p0"
|
||||
check_ok rotate-window -U -t R:0
|
||||
check_fmt "$p1" '#{window_zoomed_flag}:#{pane_zoomed_flag}:#{pane_active}' \
|
||||
'0:0:1'
|
||||
check_ok rotate-window -D -t R:0
|
||||
check_fmt 'R:0' '#{window_layout}' "$layout"
|
||||
|
||||
check_ok resize-pane -Z -t "$p0"
|
||||
check_ok rotate-window -U -Z -t R:0
|
||||
check_fmt "$p1" '#{window_zoomed_flag}:#{pane_zoomed_flag}:#{pane_active}' \
|
||||
'1:1:1'
|
||||
check_ok resize-pane -Z -t "$p1"
|
||||
check_ok rotate-window -D -t R:0
|
||||
check_fmt 'R:0' '#{window_layout}' "$layout"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# kill-window.
|
||||
|
||||
|
||||
14
resize.c
14
resize.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: resize.c,v 1.58 2026/07/17 08:37:29 nicm Exp $ */
|
||||
/* $OpenBSD: resize.c,v 1.59 2026/08/20 09:19:24 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -42,8 +42,8 @@ resize_fire_window_resized(struct window *w, u_int old_sx, u_int old_sy)
|
||||
void
|
||||
resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
|
||||
{
|
||||
u_int old_sx = w->sx, old_sy = w->sy;
|
||||
int zoomed;
|
||||
struct window_pane *zwp;
|
||||
u_int old_sx = w->sx, old_sy = w->sy;
|
||||
|
||||
/* Check size limits. */
|
||||
if (sx < WINDOW_MINIMUM)
|
||||
@@ -56,8 +56,8 @@ resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
|
||||
sy = WINDOW_MAXIMUM;
|
||||
|
||||
/* If the window is zoomed, unzoom. */
|
||||
zoomed = w->flags & WINDOW_ZOOMED;
|
||||
if (zoomed)
|
||||
zwp = window_zoomed_pane(w);
|
||||
if (zwp != NULL)
|
||||
window_unzoom(w, 1);
|
||||
|
||||
/* Resize the layout first. */
|
||||
@@ -73,8 +73,8 @@ resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
|
||||
sx, sy, w->layout_root->g.sx, w->layout_root->g.sy);
|
||||
|
||||
/* Restore the window zoom state. */
|
||||
if (zoomed)
|
||||
window_zoom(w->active);
|
||||
if (zwp != NULL && window_has_pane(w, zwp))
|
||||
window_zoom(zwp);
|
||||
|
||||
tty_update_window_offset(w);
|
||||
server_redraw_window(w);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: screen-write.c,v 1.287 2026/08/17 20:04:00 nicm Exp $ */
|
||||
/* $OpenBSD: screen-write.c,v 1.288 2026/08/21 09:53:04 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -2847,10 +2847,11 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc)
|
||||
struct grid *gd = s->grid;
|
||||
const struct utf8_data *ud = &gc->data;
|
||||
struct options *oo = global_options;
|
||||
u_int i, n, cx = s->cx, cy = s->cy, vis, yoff = 0;
|
||||
u_int i, n, cx = s->cx, cy = s->cy, vis;
|
||||
struct grid_cell last;
|
||||
struct tty_ctx ttyctx;
|
||||
int force_wide = 0, zero_width = 0;
|
||||
int xoff = 0, yoff = 0;
|
||||
struct visible_ranges *r;
|
||||
|
||||
/* Ignore U+3164 HANGUL_FILLER entirely. */
|
||||
@@ -2944,9 +2945,11 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc)
|
||||
* obscured in the middle, only on left or right, but there could be an
|
||||
* empty range in the visible ranges so we add them all up.
|
||||
*/
|
||||
if (wp != NULL)
|
||||
if (wp != NULL) {
|
||||
xoff = wp->xoff;
|
||||
yoff = wp->yoff;
|
||||
r = window_visible_ranges(wp, cx - n, cy + yoff, n, NULL);
|
||||
}
|
||||
r = window_visible_ranges(wp, xoff + cx - n, cy + yoff, n, NULL);
|
||||
for (i = 0, vis = 0; i < r->used; i++)
|
||||
vis += r->ranges[i].nx;
|
||||
if (vis < n) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: server-client.c,v 1.504 2026/08/19 10:56:10 nicm Exp $ */
|
||||
/* $OpenBSD: server-client.c,v 1.505 2026/08/20 09:19:24 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -683,8 +683,7 @@ server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
|
||||
} else {
|
||||
/* Try the pane borders. */
|
||||
TAILQ_FOREACH(fwp, &w->panes, entry) {
|
||||
if ((w->flags & WINDOW_ZOOMED) &&
|
||||
(~fwp->flags & PANE_ZOOMED))
|
||||
if (!window_pane_is_visible(fwp))
|
||||
continue;
|
||||
if (window_pane_is_floating(fwp) &&
|
||||
window_pane_get_pane_lines(fwp) == PANE_LINES_NONE)
|
||||
|
||||
11
server-fn.c
11
server-fn.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: server-fn.c,v 1.150 2026/08/18 07:32:09 nicm Exp $ */
|
||||
/* $OpenBSD: server-fn.c,v 1.151 2026/08/20 09:19:24 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -226,10 +226,11 @@ server_kill_pane(struct window_pane *wp)
|
||||
server_kill_window(w, 1);
|
||||
recalculate_sizes();
|
||||
} else {
|
||||
server_unzoom_window(w);
|
||||
window_push_zoom(w, 0, wp->flags & PANE_FLOATOVERZOOM);
|
||||
server_client_remove_pane(wp);
|
||||
layout_close_pane(wp);
|
||||
window_remove_pane(w, wp);
|
||||
window_pop_zoom(w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
}
|
||||
@@ -421,15 +422,17 @@ server_destroy_pane(struct window_pane *wp, int notify)
|
||||
if (notify)
|
||||
server_fire_pane_exit("pane-exited", wp);
|
||||
|
||||
server_unzoom_window(w);
|
||||
window_push_zoom(w, 0, wp->flags & PANE_FLOATOVERZOOM);
|
||||
server_client_remove_pane(wp);
|
||||
layout_close_pane(wp);
|
||||
window_remove_pane(w, wp);
|
||||
|
||||
if (TAILQ_EMPTY(&w->panes))
|
||||
server_kill_window(w, 1);
|
||||
else
|
||||
else {
|
||||
window_pop_zoom(w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
13
spawn.c
13
spawn.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: spawn.c,v 1.51 2026/08/18 07:43:44 nicm Exp $ */
|
||||
/* $OpenBSD: spawn.c,v 1.52 2026/08/20 09:19:24 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -360,6 +360,8 @@ spawn_pane(struct spawn_context *sc, char **cause)
|
||||
}
|
||||
if (sc->flags & SPAWN_FLOATING)
|
||||
new_wp->layout_cell->flags |= LAYOUT_CELL_FLOATING;
|
||||
if (sc->flags & SPAWN_FLOATOVERZOOM)
|
||||
new_wp->flags |= PANE_FLOATOVERZOOM;
|
||||
|
||||
/*
|
||||
* If window currently zoomed, window_set_active_pane calls
|
||||
@@ -745,10 +747,10 @@ spawn_editor(struct client *c, const char *buf, size_t len,
|
||||
lg.sy = w->sy * 9 / 10;
|
||||
lg.xoff = w->sx / 2 - lg.sx / 2;
|
||||
lg.yoff = w->sy / 2 - lg.sy / 2;
|
||||
window_push_modal_zoom(w);
|
||||
window_push_zoom(w, 0, 1);
|
||||
lc = layout_floating_pane(w, NULL, &lg);
|
||||
if (lc == NULL) {
|
||||
window_pop_modal_zoom(w);
|
||||
window_pop_zoom(w);
|
||||
spawn_editor_free(es);
|
||||
return (NULL);
|
||||
}
|
||||
@@ -765,17 +767,18 @@ spawn_editor(struct client *c, const char *buf, size_t len,
|
||||
sc.environ = env;
|
||||
sc.idx = -1;
|
||||
sc.cwd = _PATH_TMP;
|
||||
sc.flags = SPAWN_FLOATING|SPAWN_MODAL;
|
||||
sc.flags = SPAWN_FLOATING|SPAWN_MODAL|SPAWN_FLOATOVERZOOM;
|
||||
|
||||
wp = spawn_pane(&sc, &cause);
|
||||
free(cmd);
|
||||
environ_free(env);
|
||||
if (wp == NULL) {
|
||||
free(cause);
|
||||
window_pop_modal_zoom(w);
|
||||
window_pop_zoom(w);
|
||||
spawn_editor_free(es);
|
||||
return (NULL);
|
||||
}
|
||||
window_pop_zoom(w);
|
||||
options_set_number(wp->options, "remain-on-exit", 0);
|
||||
es->pid = wp->pid;
|
||||
wp->editor = es;
|
||||
|
||||
10
tmux.1
10
tmux.1
@@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: tmux.1,v 1.1157 2026/08/19 10:56:10 nicm Exp $
|
||||
.\" $OpenBSD: tmux.1,v 1.1158 2026/08/20 09:19:24 nicm Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
.\"
|
||||
@@ -14,7 +14,7 @@
|
||||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: August 19 2026 $
|
||||
.Dd $Mdocdate: August 20 2026 $
|
||||
.Dt TMUX 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -3644,7 +3644,7 @@ but a different format may be specified with
|
||||
.Fl F .
|
||||
.Tg newp
|
||||
.It Xo Ic new\-pane
|
||||
.Op Fl bCdefhIkKLMOPvWZ
|
||||
.Op Fl AbCdefhIkKLMOPvWZ
|
||||
.Op Fl B Ar border\-lines
|
||||
.Op Fl c Ar start\-directory
|
||||
.Op Fl e Ar environment
|
||||
@@ -3693,8 +3693,8 @@ sets the pane border lines for floating panes; see
|
||||
.Fl M
|
||||
may be used when bound to a mouse drag key; the new floating pane is resized to
|
||||
follow the mouse drag.
|
||||
It has no effect with
|
||||
.Fl L .
|
||||
.Fl A
|
||||
creates a floating pane which remains visible above a zoomed pane.
|
||||
.Fl O
|
||||
creates a modal pane.
|
||||
A modal pane is always the active pane and prevents interaction with any other
|
||||
|
||||
10
tmux.h
10
tmux.h
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tmux.h,v 1.1428 2026/08/19 10:56:10 nicm Exp $ */
|
||||
/* $OpenBSD: tmux.h,v 1.1429 2026/08/20 09:19:24 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1336,6 +1336,7 @@ struct window_pane {
|
||||
#define PANE_ACTIVITY 0x40000
|
||||
#define PANE_CLOSEONCLICK 0x80000
|
||||
#define PANE_CAPTUREALLKEYS 0x100000
|
||||
#define PANE_FLOATOVERZOOM 0x200000
|
||||
|
||||
bitstr_t *sync_dirty;
|
||||
u_int sync_dirty_size;
|
||||
@@ -1442,6 +1443,7 @@ struct window {
|
||||
struct window_pane *active;
|
||||
struct window_pane *modal;
|
||||
struct window_pane *modal_last;
|
||||
struct window_pane *was_zoomed;
|
||||
struct window_panes last_panes;
|
||||
struct window_panes z_index;
|
||||
struct window_panes panes;
|
||||
@@ -1484,7 +1486,6 @@ struct window {
|
||||
#define WINDOW_ZOOMED 0x8
|
||||
#define WINDOW_WASZOOMED 0x10
|
||||
#define WINDOW_RESIZE 0x20
|
||||
#define WINDOW_WASMODALZOOMED 0x40
|
||||
#define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE)
|
||||
|
||||
int alerts_queued;
|
||||
@@ -2514,6 +2515,7 @@ struct spawn_context {
|
||||
#define SPAWN_HORIZONTAL 0x200
|
||||
#define SPAWN_SPLIT 0x400
|
||||
#define SPAWN_MODAL 0x800
|
||||
#define SPAWN_FLOATOVERZOOM 0x1000
|
||||
};
|
||||
|
||||
/* Paste buffer. */
|
||||
@@ -3703,8 +3705,8 @@ void window_resize(struct window *, u_int, u_int, int, int);
|
||||
void window_pane_send_resize(struct window_pane *, u_int, u_int);
|
||||
int window_zoom(struct window_pane *);
|
||||
int window_unzoom(struct window *, int);
|
||||
void window_push_modal_zoom(struct window *);
|
||||
int window_pop_modal_zoom(struct window *);
|
||||
int window_active_pane_is_over_zoom(struct window *);
|
||||
struct window_pane *window_zoomed_pane(struct window *);
|
||||
int window_push_zoom(struct window *, int, int);
|
||||
int window_pop_zoom(struct window *);
|
||||
void window_lost_pane(struct window *, struct window_pane *);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-copy.c,v 1.425 2026/08/05 12:23:25 nicm Exp $ */
|
||||
/* $OpenBSD: window-copy.c,v 1.426 2026/08/19 19:55:04 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -4093,7 +4093,7 @@ window_copy_search_lr_regex(struct grid *gd, u_int *ppx, u_int *psx, u_int py,
|
||||
endline = gd->hsize + gd->sy - 1;
|
||||
pywrap = py;
|
||||
while (buf != NULL &&
|
||||
pywrap <= endline &&
|
||||
pywrap < endline &&
|
||||
len < WINDOW_COPY_SEARCH_MAX_LINE) {
|
||||
gl = grid_get_line(gd, pywrap);
|
||||
if (~gl->flags & GRID_LINE_WRAPPED)
|
||||
@@ -4152,7 +4152,7 @@ window_copy_search_rl_regex(struct grid *gd, u_int *ppx, u_int *psx, u_int py,
|
||||
endline = gd->hsize + gd->sy - 1;
|
||||
pywrap = py;
|
||||
while (buf != NULL &&
|
||||
pywrap <= endline &&
|
||||
pywrap < endline &&
|
||||
len < WINDOW_COPY_SEARCH_MAX_LINE) {
|
||||
gl = grid_get_line(gd, pywrap);
|
||||
if (~gl->flags & GRID_LINE_WRAPPED)
|
||||
@@ -4353,6 +4353,7 @@ window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy,
|
||||
break;
|
||||
}
|
||||
}
|
||||
ncells = cell;
|
||||
|
||||
/* Locate starting cell. */
|
||||
cell = 0;
|
||||
|
||||
130
window.c
130
window.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window.c,v 1.369 2026/07/29 14:06:32 nicm Exp $ */
|
||||
/* $OpenBSD: window.c,v 1.370 2026/08/20 09:19:24 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -717,7 +717,7 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
|
||||
return (0);
|
||||
if (w->modal != NULL && wp != w->modal)
|
||||
return (0);
|
||||
if (w->flags & WINDOW_ZOOMED)
|
||||
if ((w->flags & WINDOW_ZOOMED) && !window_pane_is_visible(wp))
|
||||
window_unzoom(w, 1);
|
||||
lastwp = w->active;
|
||||
|
||||
@@ -917,13 +917,18 @@ window_zoom(struct window_pane *wp)
|
||||
{
|
||||
struct window *w = wp->window;
|
||||
struct window_pane *wp1;
|
||||
struct layout_cell *lc;
|
||||
struct layout_geometry lg;
|
||||
|
||||
if (w->flags & WINDOW_ZOOMED)
|
||||
return (-1);
|
||||
if (window_count_panes(w, 1) == 1)
|
||||
return (-1);
|
||||
|
||||
if (w->active != wp)
|
||||
if (w->active != wp &&
|
||||
(w->active == NULL ||
|
||||
(~w->active->flags & PANE_FLOATOVERZOOM) ||
|
||||
!window_pane_is_floating(w->active)))
|
||||
window_set_active_pane(w, wp, 1);
|
||||
wp->flags |= PANE_ZOOMED;
|
||||
|
||||
@@ -934,6 +939,22 @@ window_zoom(struct window_pane *wp)
|
||||
|
||||
w->saved_layout_root = w->layout_root;
|
||||
layout_init(w, wp);
|
||||
TAILQ_FOREACH(wp1, &w->panes, entry) {
|
||||
lc = wp1->saved_layout_cell;
|
||||
if (wp1 == wp ||
|
||||
(~wp1->flags & PANE_FLOATOVERZOOM) ||
|
||||
lc == NULL ||
|
||||
(~lc->flags & LAYOUT_CELL_FLOATING))
|
||||
continue;
|
||||
memcpy(&lg, &lc->g, sizeof lg);
|
||||
lc = layout_floating_pane(w, wp, &lg);
|
||||
layout_assign_pane(lc, wp1, 0);
|
||||
}
|
||||
/* A floating zoom target is now tiled, so put it behind the floats. */
|
||||
if (wp->saved_layout_cell->flags & LAYOUT_CELL_FLOATING) {
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
|
||||
}
|
||||
w->flags |= WINDOW_ZOOMED;
|
||||
events_fire_window("window-zoomed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
@@ -945,11 +966,26 @@ window_zoom(struct window_pane *wp)
|
||||
int
|
||||
window_unzoom(struct window *w, int notify)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
struct window_pane *wp, *zoomed = NULL;
|
||||
struct layout_cell *slc;
|
||||
|
||||
if (!(w->flags & WINDOW_ZOOMED))
|
||||
if (~w->flags & WINDOW_ZOOMED)
|
||||
return (-1);
|
||||
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (wp->flags & PANE_ZOOMED)
|
||||
zoomed = wp;
|
||||
if (~wp->flags & PANE_FLOATOVERZOOM)
|
||||
continue;
|
||||
if (wp->flags & PANE_ZOOMED)
|
||||
continue;
|
||||
slc = wp->saved_layout_cell;
|
||||
if (slc == NULL || wp->layout_cell == NULL)
|
||||
continue;
|
||||
memcpy(&slc->g, &wp->layout_cell->g, sizeof slc->g);
|
||||
memcpy(&slc->fg, &wp->layout_cell->fg, sizeof slc->fg);
|
||||
}
|
||||
|
||||
w->flags &= ~WINDOW_ZOOMED;
|
||||
layout_free(w, 0);
|
||||
w->layout_root = w->saved_layout_root;
|
||||
@@ -960,6 +996,22 @@ window_unzoom(struct window *w, int notify)
|
||||
wp->saved_layout_cell = NULL;
|
||||
wp->flags &= ~PANE_ZOOMED;
|
||||
}
|
||||
/* Put a floating zoom target back into the floating part of the list. */
|
||||
if (zoomed != NULL && window_pane_is_floating(zoomed)) {
|
||||
TAILQ_REMOVE(&w->z_index, zoomed, zentry);
|
||||
if (zoomed == w->active)
|
||||
TAILQ_INSERT_HEAD(&w->z_index, zoomed, zentry);
|
||||
else {
|
||||
TAILQ_FOREACH(wp, &w->z_index, zentry) {
|
||||
if (!window_pane_is_floating(wp))
|
||||
break;
|
||||
}
|
||||
if (wp == NULL)
|
||||
TAILQ_INSERT_TAIL(&w->z_index, zoomed, zentry);
|
||||
else
|
||||
TAILQ_INSERT_BEFORE(wp, zoomed, zentry);
|
||||
}
|
||||
}
|
||||
layout_fix_panes(w, NULL);
|
||||
|
||||
if (notify) {
|
||||
@@ -971,48 +1023,69 @@ window_unzoom(struct window *w, int notify)
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
window_push_modal_zoom(struct window *w)
|
||||
struct window_pane *
|
||||
window_zoomed_pane(struct window *w)
|
||||
{
|
||||
if (w->flags & WINDOW_ZOOMED)
|
||||
w->flags |= WINDOW_WASMODALZOOMED;
|
||||
else
|
||||
w->flags &= ~WINDOW_WASMODALZOOMED;
|
||||
window_unzoom(w, 1);
|
||||
struct window_pane *wp;
|
||||
|
||||
if (~w->flags & WINDOW_ZOOMED)
|
||||
return (NULL);
|
||||
TAILQ_FOREACH_REVERSE(wp, &w->z_index, window_panes_zindex, zentry) {
|
||||
if (wp->layout_cell != NULL && !window_pane_is_floating(wp))
|
||||
return (wp);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
window_pop_modal_zoom(struct window *w)
|
||||
window_active_pane_is_over_zoom(struct window *w)
|
||||
{
|
||||
struct window_pane *wp = w->active;
|
||||
|
||||
if (~w->flags & WINDOW_WASMODALZOOMED)
|
||||
if (~w->flags & WINDOW_ZOOMED)
|
||||
return (0);
|
||||
w->flags &= ~WINDOW_WASMODALZOOMED;
|
||||
if (wp != NULL && window_has_pane(w, wp))
|
||||
return (window_zoom(wp) == 0);
|
||||
return (0);
|
||||
if (w->active == NULL)
|
||||
return (0);
|
||||
if (~w->active->flags & PANE_FLOATOVERZOOM)
|
||||
return (0);
|
||||
return (window_pane_is_floating(w->active));
|
||||
}
|
||||
|
||||
int
|
||||
window_push_zoom(struct window *w, int always, int flag)
|
||||
{
|
||||
struct window_pane *wp = window_zoomed_pane(w);
|
||||
|
||||
log_debug("%s: @%u %d", __func__, w->id,
|
||||
flag && (w->flags & WINDOW_ZOOMED));
|
||||
if (flag && (always || (w->flags & WINDOW_ZOOMED)))
|
||||
w->flags |= WINDOW_WASZOOMED;
|
||||
else
|
||||
w->flags &= ~WINDOW_WASZOOMED;
|
||||
if (w->flags & WINDOW_WASZOOMED)
|
||||
w->was_zoomed = wp;
|
||||
else
|
||||
w->was_zoomed = NULL;
|
||||
return (window_unzoom(w, 1) == 0);
|
||||
}
|
||||
|
||||
int
|
||||
window_pop_zoom(struct window *w)
|
||||
{
|
||||
struct window_pane *wp = w->was_zoomed;
|
||||
|
||||
log_debug("%s: @%u %d", __func__, w->id,
|
||||
!!(w->flags & WINDOW_WASZOOMED));
|
||||
if (w->flags & WINDOW_WASZOOMED)
|
||||
return (window_zoom(w->active) == 0);
|
||||
if (w->flags & WINDOW_WASZOOMED) {
|
||||
w->flags &= ~WINDOW_WASZOOMED;
|
||||
w->was_zoomed = NULL;
|
||||
if (w->active != NULL &&
|
||||
((~w->active->flags & PANE_FLOATOVERZOOM) ||
|
||||
!window_pane_is_floating(w->active)))
|
||||
wp = w->active;
|
||||
if (wp == NULL || !window_has_pane(w, wp))
|
||||
wp = w->active;
|
||||
if (wp != NULL)
|
||||
return (window_zoom(wp) == 0);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1064,8 +1137,8 @@ window_lost_pane(struct window *w, struct window_pane *wp)
|
||||
server_clear_marked();
|
||||
if (wp == w->modal_last)
|
||||
w->modal_last = NULL;
|
||||
if (w->modal_last == NULL)
|
||||
w->flags &= ~WINDOW_WASMODALZOOMED;
|
||||
if (wp == w->was_zoomed)
|
||||
w->was_zoomed = NULL;
|
||||
|
||||
window_pane_stack_remove(&w->last_panes, wp);
|
||||
if (wp == w->active) {
|
||||
@@ -1092,7 +1165,6 @@ window_lost_pane(struct window *w, struct window_pane *wp)
|
||||
}
|
||||
} else if (wp == w->modal) {
|
||||
w->modal = w->modal_last = NULL;
|
||||
w->flags &= ~WINDOW_WASMODALZOOMED;
|
||||
}
|
||||
redraw_invalidate_scene(w);
|
||||
}
|
||||
@@ -1100,13 +1172,9 @@ window_lost_pane(struct window *w, struct window_pane *wp)
|
||||
void
|
||||
window_remove_pane(struct window *w, struct window_pane *wp)
|
||||
{
|
||||
int pop = (wp == w->modal);
|
||||
|
||||
window_lost_pane(w, wp);
|
||||
TAILQ_REMOVE(&w->panes, wp, entry);
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
if (pop && window_pop_modal_zoom(w))
|
||||
server_redraw_window(w);
|
||||
redraw_invalidate_scene(w);
|
||||
window_pane_destroy(wp);
|
||||
}
|
||||
@@ -1262,6 +1330,8 @@ window_pane_printable_flags(struct window_pane *wp)
|
||||
flags[pos++] = 'Z';
|
||||
if (window_pane_is_floating(wp))
|
||||
flags[pos++] = 'F';
|
||||
if (wp->flags & PANE_FLOATOVERZOOM)
|
||||
flags[pos++] = 'A';
|
||||
if (wp == w->modal)
|
||||
flags[pos++] = 'O';
|
||||
flags[pos] = '\0';
|
||||
@@ -1968,7 +2038,7 @@ window_pane_is_visible(struct window_pane *wp)
|
||||
{
|
||||
if (~wp->window->flags & WINDOW_ZOOMED)
|
||||
return (1);
|
||||
return (wp == wp->window->active);
|
||||
return (wp->layout_cell != NULL);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
Reference in New Issue
Block a user