Add a way for floating panes to stay above zoom (-A) flag. Use by

default for modal panes to match popups.
This commit is contained in:
nicm
2026-08-20 09:19:24 +00:00
committed by tmux update bot
parent 50d0348b64
commit 95a7170709
11 changed files with 191 additions and 79 deletions

View File

@@ -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> * 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; char *title;
const char *style; const char *style;
struct options_entry *o; struct options_entry *o;
int visible, Zflag = args_has(args, 'Z');
if (entry == &cmd_last_pane_entry || args_has(args, 'l')) { 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_redraw_window_borders(lastwp->window);
server_status_window(lastwp->window); server_status_window(lastwp->window);
} else { } 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); server_redraw_window(w);
window_redraw_active_switch(w, lastwp); window_redraw_active_switch(w, lastwp);
if (window_set_active_pane(w, lastwp, 1)) { if (window_set_active_pane(w, lastwp, 1)) {
cmd_find_from_winlink(current, wl, 0); cmd_find_from_winlink(current, wl, 0);
cmd_select_pane_redraw(w); cmd_select_pane_redraw(w);
} }
if (window_pop_zoom(w)) if (!visible && window_pop_zoom(w))
server_redraw_window(w); server_redraw_window(w);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -268,14 +273,18 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
if (wp == w->active) if (wp == w->active)
return (CMD_RETURN_NORMAL); 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); server_redraw_window(w);
window_redraw_active_switch(w, wp); window_redraw_active_switch(w, wp);
if (window_set_active_pane(w, wp, 1)) if (window_set_active_pane(w, wp, 1))
cmd_find_from_winlink_pane(current, wl, wp, 0); cmd_find_from_winlink_pane(current, wl, wp, 0);
cmdq_insert_hook(s, item, current, "after-select-pane"); cmdq_insert_hook(s, item, current, "after-select-pane");
cmd_select_pane_redraw(w); cmd_select_pane_redraw(w);
if (window_pop_zoom(w)) if (!visible && window_pop_zoom(w))
server_redraw_window(w); server_redraw_window(w);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -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> * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -41,8 +41,8 @@ const struct cmd_entry cmd_new_pane_entry = {
.name = "new-pane", .name = "new-pane",
.alias = "newp", .alias = "newp",
.args = { "bB:Cc:de:EfF:hIkl:KLMm:Op:PR:s:S:t:T:vWx:X:y:Y:Z", 0, -1, NULL }, .args = { "AbB:Cc:de:EfF:hIkl:KLMm:Op:PR:s:S:t:T:vWx:X:y:Y:Z", 0, -1, NULL },
.usage = "[-bCdefhIkKLMOPvWZ] [-B border-lines] " .usage = "[-AbCdefhIkKLMOPvWZ] [-B border-lines] "
"[-c start-directory] [-e environment] " "[-c start-directory] [-e environment] "
"[-F format] [-l size] [-m message] [-p percentage] " "[-F format] [-l size] [-m message] [-p percentage] "
"[-s style] [-S active-border-style] " "[-s style] [-S active-border-style] "
@@ -90,6 +90,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
struct cmd_find_state fs; struct cmd_find_state fs;
struct key_event *event = cmdq_get_event(item); struct key_event *event = cmdq_get_event(item);
int input, empty, is_floating, flags = 0; int input, empty, is_floating, flags = 0;
int restore_zoom = 0;
const char *template, *style, *value; const char *template, *style, *value;
char *cause = NULL, *cp, *title; char *cause = NULL, *cp, *title;
const struct options_table_entry *oe; const struct options_table_entry *oe;
@@ -97,10 +98,16 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
enum pane_lines lines; enum pane_lines lines;
u_int count = args_count(args); 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) if (cmd_get_entry(self) == &cmd_new_pane_entry)
is_floating = !args_has(args, 'L'); is_floating = !args_has(args, 'L');
else { 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); is_floating = window_pane_is_floating(wp);
flags |= SPAWN_SPLIT; flags |= SPAWN_SPLIT;
} }
@@ -134,7 +141,11 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'Z')) if (args_has(args, 'Z'))
flags |= SPAWN_ZOOM; flags |= SPAWN_ZOOM;
if (args_has(args, 'O')) 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'); input = args_has(args, 'I');
if (input || (count == 1 && *args_string(args, 0) == '\0')) if (input || (count == 1 && *args_string(args, 0) == '\0'))
@@ -170,6 +181,8 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (cause != NULL) { if (cause != NULL) {
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
if (restore_zoom)
window_pop_zoom(w);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -274,7 +287,10 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (~flags & SPAWN_DETACHED) if (~flags & SPAWN_DETACHED)
cmd_find_from_winlink_pane(current, wl, new_wp, 0); 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); window_pop_zoom(wp->window);
server_redraw_window(wp->window); server_redraw_window(wp->window);
} }
@@ -325,8 +341,9 @@ fail:
if (!is_floating) if (!is_floating)
layout_close_pane(new_wp); layout_close_pane(new_wp);
window_remove_pane(wp->window, 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) if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv); cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ); environ_free(sc.environ);

View File

@@ -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> * 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; struct cmd_find_state target;
const char *tflag = args_get(args, 't'); const char *tflag = args_get(args, 't');
enum cmd_find_type type; enum cmd_find_type type;
int flags; int flags, visible, Zflag = args_has(args, 'Z');
struct client *c = cmdq_get_client(item); struct client *c = cmdq_get_client(item);
struct client *tc = cmdq_get_target_client(item); struct client *tc = cmdq_get_target_client(item);
struct session *s; struct session *s;
@@ -139,11 +139,15 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (wl != NULL && wp != NULL && wp != wl->window->active) { if (wl != NULL && wp != NULL && wp != wl->window->active) {
w = wl->window; 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); server_redraw_window(w);
window_redraw_active_switch(w, wp); window_redraw_active_switch(w, wp);
window_set_active_pane(w, wp, 1); window_set_active_pane(w, wp, 1);
if (window_pop_zoom(w)) if (!visible && window_pop_zoom(w))
server_redraw_window(w); server_redraw_window(w);
} }
if (wl != NULL) { if (wl != NULL) {

View File

@@ -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> * 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); 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); lc = layout_split_pane(wp, type, size, flags);
if (lc == NULL) if (lc == NULL)
*cause = xstrdup("no space for a new pane"); *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); return (NULL);
} }
if (flags & SPAWN_MODAL) if (flags & SPAWN_FLOATOVERZOOM)
window_push_modal_zoom(w); window_push_zoom(wp->window, 0, 1);
else if (window_active_pane_is_over_zoom(w))
window_push_zoom(wp->window, 0, 1);
else else
window_push_zoom(wp->window, 1, (flags & SPAWN_ZOOM)); window_push_zoom(wp->window, 1, (flags & SPAWN_ZOOM));
lcnew = layout_floating_pane(w, wp, &fg); lcnew = layout_floating_pane(w, wp, &fg);

View File

@@ -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> * 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 void
resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel) 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; struct window_pane *zwp;
int zoomed; u_int old_sx = w->sx, old_sy = w->sy;
/* Check size limits. */ /* Check size limits. */
if (sx < WINDOW_MINIMUM) 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; sy = WINDOW_MAXIMUM;
/* If the window is zoomed, unzoom. */ /* If the window is zoomed, unzoom. */
zoomed = w->flags & WINDOW_ZOOMED; zwp = window_zoomed_pane(w);
if (zoomed) if (zwp != NULL)
window_unzoom(w, 1); window_unzoom(w, 1);
/* Resize the layout first. */ /* 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); sx, sy, w->layout_root->g.sx, w->layout_root->g.sy);
/* Restore the window zoom state. */ /* Restore the window zoom state. */
if (zoomed) if (zwp != NULL && window_has_pane(w, zwp))
window_zoom(w->active); window_zoom(zwp);
tty_update_window_offset(w); tty_update_window_offset(w);
server_redraw_window(w); server_redraw_window(w);

View File

@@ -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> * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -806,8 +806,7 @@ server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
} else { } else {
/* Try the pane borders. */ /* Try the pane borders. */
TAILQ_FOREACH(fwp, &w->panes, entry) { TAILQ_FOREACH(fwp, &w->panes, entry) {
if ((w->flags & WINDOW_ZOOMED) && if (!window_pane_is_visible(fwp))
(~fwp->flags & PANE_ZOOMED))
continue; continue;
if (window_pane_is_floating(fwp) && if (window_pane_is_floating(fwp) &&
window_pane_get_pane_lines(fwp) == PANE_LINES_NONE) window_pane_get_pane_lines(fwp) == PANE_LINES_NONE)

View File

@@ -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> * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -227,10 +227,11 @@ server_kill_pane(struct window_pane *wp)
server_kill_window(w, 1); server_kill_window(w, 1);
recalculate_sizes(); recalculate_sizes();
} else { } else {
server_unzoom_window(w); window_push_zoom(w, 0, wp->flags & PANE_FLOATOVERZOOM);
server_client_remove_pane(wp); server_client_remove_pane(wp);
layout_close_pane(wp); layout_close_pane(wp);
window_remove_pane(w, wp); window_remove_pane(w, wp);
window_pop_zoom(w);
server_redraw_window(w); server_redraw_window(w);
} }
} }
@@ -418,15 +419,17 @@ server_destroy_pane(struct window_pane *wp, int notify)
if (notify) if (notify)
server_fire_pane_exit("pane-exited", wp); 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); server_client_remove_pane(wp);
layout_close_pane(wp); layout_close_pane(wp);
window_remove_pane(w, wp); window_remove_pane(w, wp);
if (TAILQ_EMPTY(&w->panes)) if (TAILQ_EMPTY(&w->panes))
server_kill_window(w, 1); server_kill_window(w, 1);
else else {
window_pop_zoom(w);
server_redraw_window(w); server_redraw_window(w);
}
} }
static void static void

13
spawn.c
View File

@@ -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> * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -362,6 +362,8 @@ spawn_pane(struct spawn_context *sc, char **cause)
} }
if (sc->flags & SPAWN_FLOATING) if (sc->flags & SPAWN_FLOATING)
new_wp->layout_cell->flags |= LAYOUT_CELL_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 * If window currently zoomed, window_set_active_pane calls
@@ -725,10 +727,10 @@ spawn_editor(struct client *c, const char *buf, size_t len,
lg.sy = w->sy * 9 / 10; lg.sy = w->sy * 9 / 10;
lg.xoff = w->sx / 2 - lg.sx / 2; lg.xoff = w->sx / 2 - lg.sx / 2;
lg.yoff = w->sy / 2 - lg.sy / 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); lc = layout_floating_pane(w, NULL, &lg);
if (lc == NULL) { if (lc == NULL) {
window_pop_modal_zoom(w); window_pop_zoom(w);
spawn_editor_free(es); spawn_editor_free(es);
return (NULL); return (NULL);
} }
@@ -745,17 +747,18 @@ spawn_editor(struct client *c, const char *buf, size_t len,
sc.environ = env; sc.environ = env;
sc.idx = -1; sc.idx = -1;
sc.cwd = _PATH_TMP; sc.cwd = _PATH_TMP;
sc.flags = SPAWN_FLOATING|SPAWN_MODAL; sc.flags = SPAWN_FLOATING|SPAWN_MODAL|SPAWN_FLOATOVERZOOM;
wp = spawn_pane(&sc, &cause); wp = spawn_pane(&sc, &cause);
free(cmd); free(cmd);
environ_free(env); environ_free(env);
if (wp == NULL) { if (wp == NULL) {
free(cause); free(cause);
window_pop_modal_zoom(w); window_pop_zoom(w);
spawn_editor_free(es); spawn_editor_free(es);
return (NULL); return (NULL);
} }
window_pop_zoom(w);
options_set_number(wp->options, "remain-on-exit", 0); options_set_number(wp->options, "remain-on-exit", 0);
es->pid = wp->pid; es->pid = wp->pid;
wp->editor = es; wp->editor = es;

10
tmux.1
View File

@@ -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> .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
.\" .\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" 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 .Dt TMUX 1
.Os .Os
.Sh NAME .Sh NAME
@@ -3642,7 +3642,7 @@ but a different format may be specified with
.Fl F . .Fl F .
.Tg newp .Tg newp
.It Xo Ic new\-pane .It Xo Ic new\-pane
.Op Fl bCdefhIkKLMOPvWZ .Op Fl AbCdefhIkKLMOPvWZ
.Op Fl B Ar border\-lines .Op Fl B Ar border\-lines
.Op Fl c Ar start\-directory .Op Fl c Ar start\-directory
.Op Fl e Ar environment .Op Fl e Ar environment
@@ -3691,8 +3691,8 @@ sets the pane border lines for floating panes; see
.Fl M .Fl M
may be used when bound to a mouse drag key; the new floating pane is resized to may be used when bound to a mouse drag key; the new floating pane is resized to
follow the mouse drag. follow the mouse drag.
It has no effect with .Fl A
.Fl L . creates a floating pane which remains visible above a zoomed pane.
.Fl O .Fl O
creates a modal pane. creates a modal pane.
A modal pane is always the active pane and prevents interaction with any other A modal pane is always the active pane and prevents interaction with any other

10
tmux.h
View File

@@ -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> * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1302,6 +1302,7 @@ struct window_pane {
#define PANE_ACTIVITY 0x40000 #define PANE_ACTIVITY 0x40000
#define PANE_CLOSEONCLICK 0x80000 #define PANE_CLOSEONCLICK 0x80000
#define PANE_CAPTUREALLKEYS 0x100000 #define PANE_CAPTUREALLKEYS 0x100000
#define PANE_FLOATOVERZOOM 0x200000
bitstr_t *sync_dirty; bitstr_t *sync_dirty;
u_int sync_dirty_size; u_int sync_dirty_size;
@@ -1408,6 +1409,7 @@ struct window {
struct window_pane *active; struct window_pane *active;
struct window_pane *modal; struct window_pane *modal;
struct window_pane *modal_last; struct window_pane *modal_last;
struct window_pane *was_zoomed;
struct window_panes last_panes; struct window_panes last_panes;
struct window_panes z_index; struct window_panes z_index;
struct window_panes panes; struct window_panes panes;
@@ -1450,7 +1452,6 @@ struct window {
#define WINDOW_ZOOMED 0x8 #define WINDOW_ZOOMED 0x8
#define WINDOW_WASZOOMED 0x10 #define WINDOW_WASZOOMED 0x10
#define WINDOW_RESIZE 0x20 #define WINDOW_RESIZE 0x20
#define WINDOW_WASMODALZOOMED 0x40
#define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE) #define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE)
int alerts_queued; int alerts_queued;
@@ -2494,6 +2495,7 @@ struct spawn_context {
#define SPAWN_HORIZONTAL 0x200 #define SPAWN_HORIZONTAL 0x200
#define SPAWN_SPLIT 0x400 #define SPAWN_SPLIT 0x400
#define SPAWN_MODAL 0x800 #define SPAWN_MODAL 0x800
#define SPAWN_FLOATOVERZOOM 0x1000
}; };
/* Paste buffer. */ /* Paste buffer. */
@@ -3682,8 +3684,8 @@ void window_resize(struct window *, u_int, u_int, int, int);
void window_pane_send_resize(struct window_pane *, u_int, u_int); void window_pane_send_resize(struct window_pane *, u_int, u_int);
int window_zoom(struct window_pane *); int window_zoom(struct window_pane *);
int window_unzoom(struct window *, int); int window_unzoom(struct window *, int);
void window_push_modal_zoom(struct window *); int window_active_pane_is_over_zoom(struct window *);
int window_pop_modal_zoom(struct window *); struct window_pane *window_zoomed_pane(struct window *);
int window_push_zoom(struct window *, int, int); int window_push_zoom(struct window *, int, int);
int window_pop_zoom(struct window *); int window_pop_zoom(struct window *);
void window_lost_pane(struct window *, struct window_pane *); void window_lost_pane(struct window *, struct window_pane *);

130
window.c
View File

@@ -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> * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -711,7 +711,7 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
return (0); return (0);
if (w->modal != NULL && wp != w->modal) if (w->modal != NULL && wp != w->modal)
return (0); return (0);
if (w->flags & WINDOW_ZOOMED) if ((w->flags & WINDOW_ZOOMED) && !window_pane_is_visible(wp))
window_unzoom(w, 1); window_unzoom(w, 1);
lastwp = w->active; lastwp = w->active;
@@ -911,13 +911,18 @@ window_zoom(struct window_pane *wp)
{ {
struct window *w = wp->window; struct window *w = wp->window;
struct window_pane *wp1; struct window_pane *wp1;
struct layout_cell *lc;
struct layout_geometry lg;
if (w->flags & WINDOW_ZOOMED) if (w->flags & WINDOW_ZOOMED)
return (-1); return (-1);
if (window_count_panes(w, 1) == 1) if (window_count_panes(w, 1) == 1)
return (-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); window_set_active_pane(w, wp, 1);
wp->flags |= PANE_ZOOMED; wp->flags |= PANE_ZOOMED;
@@ -928,6 +933,22 @@ window_zoom(struct window_pane *wp)
w->saved_layout_root = w->layout_root; w->saved_layout_root = w->layout_root;
layout_init(w, wp); 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; w->flags |= WINDOW_ZOOMED;
events_fire_window("window-zoomed", w); events_fire_window("window-zoomed", w);
events_fire_window("window-layout-changed", w); events_fire_window("window-layout-changed", w);
@@ -939,11 +960,26 @@ window_zoom(struct window_pane *wp)
int int
window_unzoom(struct window *w, int notify) 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); 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; w->flags &= ~WINDOW_ZOOMED;
layout_free(w, 0); layout_free(w, 0);
w->layout_root = w->saved_layout_root; w->layout_root = w->saved_layout_root;
@@ -954,6 +990,22 @@ window_unzoom(struct window *w, int notify)
wp->saved_layout_cell = NULL; wp->saved_layout_cell = NULL;
wp->flags &= ~PANE_ZOOMED; 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); layout_fix_panes(w, NULL);
if (notify) { if (notify) {
@@ -965,48 +1017,69 @@ window_unzoom(struct window *w, int notify)
return (0); return (0);
} }
void struct window_pane *
window_push_modal_zoom(struct window *w) window_zoomed_pane(struct window *w)
{ {
if (w->flags & WINDOW_ZOOMED) struct window_pane *wp;
w->flags |= WINDOW_WASMODALZOOMED;
else if (~w->flags & WINDOW_ZOOMED)
w->flags &= ~WINDOW_WASMODALZOOMED; return (NULL);
window_unzoom(w, 1); 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 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_ZOOMED)
if (~w->flags & WINDOW_WASMODALZOOMED)
return (0); return (0);
w->flags &= ~WINDOW_WASMODALZOOMED; if (w->active == NULL)
if (wp != NULL && window_has_pane(w, wp)) return (0);
return (window_zoom(wp) == 0); if (~w->active->flags & PANE_FLOATOVERZOOM)
return (0); return (0);
return (window_pane_is_floating(w->active));
} }
int int
window_push_zoom(struct window *w, int always, int flag) 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, log_debug("%s: @%u %d", __func__, w->id,
flag && (w->flags & WINDOW_ZOOMED)); flag && (w->flags & WINDOW_ZOOMED));
if (flag && (always || (w->flags & WINDOW_ZOOMED))) if (flag && (always || (w->flags & WINDOW_ZOOMED)))
w->flags |= WINDOW_WASZOOMED; w->flags |= WINDOW_WASZOOMED;
else else
w->flags &= ~WINDOW_WASZOOMED; w->flags &= ~WINDOW_WASZOOMED;
if (w->flags & WINDOW_WASZOOMED)
w->was_zoomed = wp;
else
w->was_zoomed = NULL;
return (window_unzoom(w, 1) == 0); return (window_unzoom(w, 1) == 0);
} }
int int
window_pop_zoom(struct window *w) window_pop_zoom(struct window *w)
{ {
struct window_pane *wp = w->was_zoomed;
log_debug("%s: @%u %d", __func__, w->id, log_debug("%s: @%u %d", __func__, w->id,
!!(w->flags & WINDOW_WASZOOMED)); !!(w->flags & WINDOW_WASZOOMED));
if (w->flags & WINDOW_WASZOOMED) if (w->flags & WINDOW_WASZOOMED) {
return (window_zoom(w->active) == 0); 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); return (0);
} }
@@ -1058,8 +1131,8 @@ window_lost_pane(struct window *w, struct window_pane *wp)
server_clear_marked(); server_clear_marked();
if (wp == w->modal_last) if (wp == w->modal_last)
w->modal_last = NULL; w->modal_last = NULL;
if (w->modal_last == NULL) if (wp == w->was_zoomed)
w->flags &= ~WINDOW_WASMODALZOOMED; w->was_zoomed = NULL;
window_pane_stack_remove(&w->last_panes, wp); window_pane_stack_remove(&w->last_panes, wp);
if (wp == w->active) { if (wp == w->active) {
@@ -1086,7 +1159,6 @@ window_lost_pane(struct window *w, struct window_pane *wp)
} }
} else if (wp == w->modal) { } else if (wp == w->modal) {
w->modal = w->modal_last = NULL; w->modal = w->modal_last = NULL;
w->flags &= ~WINDOW_WASMODALZOOMED;
} }
redraw_invalidate_scene(w); redraw_invalidate_scene(w);
} }
@@ -1094,13 +1166,9 @@ window_lost_pane(struct window *w, struct window_pane *wp)
void void
window_remove_pane(struct window *w, struct window_pane *wp) window_remove_pane(struct window *w, struct window_pane *wp)
{ {
int pop = (wp == w->modal);
window_lost_pane(w, wp); window_lost_pane(w, wp);
TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_REMOVE(&w->panes, wp, entry);
TAILQ_REMOVE(&w->z_index, wp, zentry); TAILQ_REMOVE(&w->z_index, wp, zentry);
if (pop && window_pop_modal_zoom(w))
server_redraw_window(w);
redraw_invalidate_scene(w); redraw_invalidate_scene(w);
window_pane_destroy(wp); window_pane_destroy(wp);
} }
@@ -1256,6 +1324,8 @@ window_pane_printable_flags(struct window_pane *wp)
flags[pos++] = 'Z'; flags[pos++] = 'Z';
if (window_pane_is_floating(wp)) if (window_pane_is_floating(wp))
flags[pos++] = 'F'; flags[pos++] = 'F';
if (wp->flags & PANE_FLOATOVERZOOM)
flags[pos++] = 'A';
if (wp == w->modal) if (wp == w->modal)
flags[pos++] = 'O'; flags[pos++] = 'O';
flags[pos] = '\0'; flags[pos] = '\0';
@@ -1958,7 +2028,7 @@ window_pane_is_visible(struct window_pane *wp)
{ {
if (~wp->window->flags & WINDOW_ZOOMED) if (~wp->window->flags & WINDOW_ZOOMED)
return (1); return (1);
return (wp == wp->window->active); return (wp->layout_cell != NULL);
} }
int int