hide-pane and show-pane now use the new layout mechanics.

This commit is contained in:
Dane Jensen
2026-06-10 23:13:49 -07:00
parent cd4c4bf723
commit 195a9b357a
6 changed files with 111 additions and 250 deletions

View File

@@ -27,12 +27,8 @@
* Hide or show panes.
*/
static enum cmd_retval cmd_hide_pane_hide_exec(struct cmd *, struct cmdq_item *);
static enum cmd_retval cmd_hide_pane_show_exec(struct cmd *, struct cmdq_item *);
static enum cmd_retval cmd_hide_pane_hide(struct window *, struct window_pane *,
struct cmdq_item *);
static enum cmd_retval cmd_hide_pane_show(struct window *, struct window_pane *);
static enum cmd_retval cmd_hide_pane_exec(struct cmd *, struct cmdq_item *);
static enum cmd_retval cmd_show_pane_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_hide_pane_entry = {
.name = "hide-pane",
@@ -44,7 +40,7 @@ const struct cmd_entry cmd_hide_pane_entry = {
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_hide_pane_hide_exec
.exec = cmd_hide_pane_exec
};
const struct cmd_entry cmd_show_pane_entry = {
@@ -57,12 +53,61 @@ const struct cmd_entry cmd_show_pane_entry = {
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_hide_pane_show_exec
.exec = cmd_show_pane_exec
};
static enum cmd_retval
cmd_hide_pane_hide(struct window *w, struct window_pane *wp)
{
struct window_pane *wpp = NULL;
struct layout_cell *lc = wp->layout_cell;
if (window_pane_is_hidden(wp))
return (CMD_RETURN_NORMAL);
if (wp == w->active) {
/* Find previous active pane. */
TAILQ_FOREACH(wpp, &w->last_panes, sentry) {
if (wpp != wp && window_pane_visible(wpp))
break;
}
if (wpp == NULL) {
TAILQ_FOREACH(wpp, &w->z_index, zentry) {
if (wpp != wp &&
window_pane_visible(wpp))
break;
}
}
}
lc->flags |= LAYOUT_CELL_HIDDEN;
layout_remove_tile(w, lc);
layout_fix_offsets(w);
layout_fix_panes(w, NULL);
window_pane_stack_remove(&w->last_panes, wp);
if (wpp != NULL) {
window_set_active_pane(w, wpp, 1);
} else if (wp == w->active) {
/* No visible previous active pane; null active pane
* to show dots background. */
w->active = NULL;
if (options_get_number(global_options, "focus-events"))
window_pane_update_focus(wp);
notify_window("window-pane-changed", w);
notify_window("window-layout-changed", w);
server_redraw_window(w);
} else {
notify_window("window-layout-changed", w);
server_redraw_window(w);
}
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_hide_pane_hide_exec(struct cmd *self, struct cmdq_item *item)
cmd_hide_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
@@ -73,11 +118,13 @@ cmd_hide_pane_hide_exec(struct cmd *self, struct cmdq_item *item)
char *cause = NULL;
enum cmd_retval rv;
window_unzoom(w, 1);
if (args_has(args, 'a')) {
TAILQ_FOREACH(wp, &w->z_index, zentry) {
if (!window_pane_visible(wp) || wp == active_pane)
continue;
rv = cmd_hide_pane_hide(w, wp, item);
rv = cmd_hide_pane_hide(w, wp);
if (rv != CMD_RETURN_NORMAL)
return (rv);
}
@@ -97,12 +144,34 @@ cmd_hide_pane_hide_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "No target pane to hide.");
return (CMD_RETURN_ERROR);
}
return (cmd_hide_pane_hide(w, wp, item));
return (cmd_hide_pane_hide(w, wp));
}
}
static enum cmd_retval
cmd_hide_pane_show_exec(struct cmd *self, struct cmdq_item *item)
cmd_hide_pane_show(struct window *w, struct window_pane *wp)
{
struct layout_cell *lc = wp->layout_cell;
if (!window_pane_is_hidden(wp))
return (CMD_RETURN_NORMAL);
lc->flags &= ~LAYOUT_CELL_HIDDEN;
layout_insert_tile(w, lc);
layout_fix_offsets(w);
layout_fix_panes(w, NULL);
window_set_active_pane(w, wp, 1);
notify_window("window-layout-changed", w);
server_redraw_window(w);
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_show_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
@@ -113,6 +182,8 @@ cmd_hide_pane_show_exec(struct cmd *self, struct cmdq_item *item)
char *cause = NULL;
enum cmd_retval rv;
window_unzoom(w, 1);
if (args_has(args, 'a')) {
TAILQ_FOREACH(wp, &w->z_index, zentry) {
if (!window_pane_visible(wp))
@@ -140,84 +211,3 @@ cmd_hide_pane_show_exec(struct cmd *self, struct cmdq_item *item)
return (cmd_hide_pane_show(w, wp));
}
}
static enum cmd_retval
cmd_hide_pane_hide(struct window *w, struct window_pane *wp,
__unused struct cmdq_item *item)
{
struct window_pane *pwp = NULL;
if (wp->flags & PANE_HIDDEN)
return (CMD_RETURN_NORMAL);
if (wp == w->active) {
/*
* Unzoom before searching: under zoom, window_pane_visible
* returns false for every non-active pane.
*/
if (w->flags & WINDOW_ZOOMED)
window_unzoom(w, 1);
/* Find previous active pane. */
TAILQ_FOREACH(pwp, &w->last_panes, sentry) {
if (pwp != wp && window_pane_visible(pwp))
break;
}
if (pwp == NULL) {
TAILQ_FOREACH(pwp, &w->z_index, zentry) {
if (pwp != wp &&
window_pane_visible(pwp))
break;
}
}
}
wp->flags |= PANE_HIDDEN;
if (w->layout_root != NULL) {
wp->saved_layout_cell = wp->layout_cell;
layout_hide_cell(w, wp->layout_cell);
layout_fix_offsets(w);
layout_fix_panes(w, NULL);
}
window_pane_stack_remove(&w->last_panes, wp);
if (pwp != NULL) {
window_set_active_pane(w, pwp, 1);
} else if (wp == w->active) {
/* No visible previous active pane; null active pane
* to show dots background. */
w->active = NULL;
if (options_get_number(global_options, "focus-events"))
window_pane_update_focus(wp);
notify_window("window-pane-changed", w);
notify_window("window-layout-changed", w);
server_redraw_window(w);
} else {
notify_window("window-layout-changed", w);
server_redraw_window(w);
}
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_hide_pane_show(struct window *w, struct window_pane *wp)
{
wp->flags &= ~PANE_HIDDEN;
/* Fix pane offsets and sizes. */
if (w->layout_root != NULL && wp->saved_layout_cell != NULL) {
wp->layout_cell = wp->saved_layout_cell;
wp->saved_layout_cell = NULL;
layout_show_cell(w, wp->layout_cell);
layout_fix_offsets(w);
layout_fix_panes(w, NULL);
}
window_set_active_pane(w, wp, 1);
notify_window("window-layout-changed", w);
server_redraw_window(w);
return (CMD_RETURN_NORMAL);
}

View File

@@ -2155,7 +2155,7 @@ format_cb_pane_hidden_flag(struct format_tree *ft)
struct window_pane *wp = ft->wp;
if (wp != NULL) {
if (wp->flags & PANE_HIDDEN)
if (window_pane_is_hidden(wp))
return (xstrdup("1"));
return (xstrdup("0"));
}

127
layout.c
View File

@@ -435,7 +435,8 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
TAILQ_FOREACH(wp, &w->panes, entry) {
if ((lc = wp->layout_cell) == NULL || wp == skip)
if ((lc = wp->layout_cell) == NULL || wp == skip ||
!window_pane_visible(wp))
continue;
wp->xoff = lc->xoff;
@@ -625,62 +626,6 @@ layout_resize_set_size(struct window *w, struct layout_cell *lc,
layout_resize_adjust(w, lc, type, change);
}
/*
* Redistribute space equally among all visible (non-hidden WINDOWPANE)
* children of lcparent in the given direction. Hidden WINDOWPANE leaves
* are skipped; their stored sizes are left untouched. Container children
* have their own children resized proportionally via layout_resize_child_cells.
*
* If all children happen to be hidden (n==0), nothing is done.
*/
void
layout_redistribute_cells(struct window *w, struct layout_cell *lcparent,
enum layout_type type)
{
struct layout_cell *lc;
u_int n, total, each, rem, i, target;
/* Count visible cells at this level. */
n = 0;
TAILQ_FOREACH(lc, &lcparent->cells, entry) {
if (lc->type == LAYOUT_WINDOWPANE &&
lc->wp != NULL &&
(lc->wp->flags & PANE_HIDDEN))
continue;
n++;
}
if (n == 0)
return;
total = (type == LAYOUT_LEFTRIGHT) ? lcparent->sx : lcparent->sy;
if (total + 1 < n) /* can't fit even the minimum borders */
return;
/*
* each * n + (n-1) borders = total
* → each = (total - (n-1)) / n, rem = (total - (n-1)) % n
* The first `rem` visible cells get (each+1) to consume the remainder.
*/
each = (total - (n - 1)) / n;
rem = (total - (n - 1)) % n;
i = 0;
TAILQ_FOREACH(lc, &lcparent->cells, entry) {
if (lc->type == LAYOUT_WINDOWPANE &&
lc->wp != NULL &&
(lc->wp->flags & PANE_HIDDEN))
continue;
target = each + (i < rem ? 1 : 0);
if (type == LAYOUT_LEFTRIGHT)
lc->sx = target;
else
lc->sy = target;
if (lc->type != LAYOUT_WINDOWPANE)
layout_resize_child_cells(w, lc);
i++;
}
}
/* Find and return the nearest neighbour to a cell in a specific direction. */
static struct layout_cell *
layout_cell_get_neighbour_direction(struct layout_cell *lc, int direction)
@@ -790,71 +735,6 @@ out:
}
}
/* Hide a cell. Space is redistributed to the nearest neighbour if the cell was
* tiled.
*/
void
layout_hide_cell(struct window *w, struct layout_cell *lc)
{
struct layout_cell *lcother, *lcparent, *lcchild;
u_int shown_children = 0;
int val;
if (lc == NULL)
return;
lcparent = lc->parent;
lc->flags |= LAYOUT_CELL_HIDDEN;
/* Merge the space into the nearest neighbour. */
lcother = layout_cell_get_neighbour(lc);
if (lcother != NULL) {
if (lcparent->type == LAYOUT_LEFTRIGHT)
val = lc->sx + 1;
else
val = lc->sy + 1;
layout_resize_adjust(w, lcother, lcparent->type, val);
}
if (layout_cell_is_tiled(lc))
layout_set_size(lc, 0, 0, 0, 0);
/* If no children are tiled, hide the parent. */
if (lcparent != NULL) {
TAILQ_FOREACH(lcchild, &lcparent->cells, entry) {
if (layout_cell_is_tiled(lcchild)) {
shown_children = 1;
break;
}
}
if (shown_children == 0)
layout_hide_cell(w, lcparent);
}
}
/* Show a cell and redistribute the space in tiled cells. */
void
layout_show_cell(struct window *w, struct layout_cell *lc)
{
struct layout_cell *lcparent;
if (lc == NULL)
return;
lcparent = lc->parent;
if (lcparent == NULL)
return;
/*
* Redistribute the parent's space equally among all visible (non-
* hidden) children, including lc which has just been shown.
* This ensures every pane at this level gets an equal share rather
* than one pane losing most of its space to the restored pane.
*/
layout_redistribute_cells(w, lcparent, lcparent->type);
}
/* Initialize layout for pane. */
void
layout_init(struct window *w, struct window_pane *wp)
@@ -1866,6 +1746,9 @@ layout_insert_tile(struct window *w, struct layout_cell *lc)
if (lc == NULL)
fatalx("layout cell cannot be null when tiling");
if (lc->flags & LAYOUT_CELL_FLOATING)
return (1);
if (lcparent == NULL) {
/* Only pane in the layout. */
layout_set_size(lc, w->sx, w->sy, 0, 0);

View File

@@ -146,7 +146,7 @@ screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
if (wp->layout_cell == NULL)
return (0);
if (wp->flags & PANE_HIDDEN)
if (window_pane_is_hidden(wp))
return (0);
if (wp->flags & (PANE_REDRAW|PANE_DROP))

3
tmux.h
View File

@@ -1289,7 +1289,6 @@ struct window_pane {
#define PANE_THEMECHANGED 0x2000
#define PANE_UNSEENCHANGES 0x4000
#define PANE_REDRAWSCROLLBAR 0x8000
#define PANE_HIDDEN 0x20000
/* Last floating position/size, saved when the pane is tiled. */
int saved_float_xoff;
@@ -3545,8 +3544,6 @@ void layout_destroy_cell(struct window *, struct layout_cell *,
struct layout_cell **);
void layout_hide_cell(struct window *, struct layout_cell *);
void layout_show_cell(struct window *, struct layout_cell *);
void layout_redistribute_cells(struct window *, struct layout_cell *,
enum layout_type);
void layout_resize_layout(struct window *, struct layout_cell *,
enum layout_type, int, int);
struct layout_cell *layout_search_by_border(struct layout_cell *, u_int, u_int);

View File

@@ -543,7 +543,8 @@ window_pane_update_focus(struct window_pane *wp)
int
window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
{
struct window_pane *lastwp;
struct window_pane *lastwp;
struct layout_cell *lc;
log_debug("%s: pane %%%u", __func__, wp->id);
@@ -557,18 +558,15 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
window_pane_stack_push(&w->last_panes, lastwp);
w->active = wp;
w->active->active_point = next_active_point++;
w->active->flags |= PANE_CHANGED;
wp->active_point = next_active_point++;
wp->flags |= PANE_CHANGED;
lc = wp->layout_cell;
if (wp->flags & PANE_HIDDEN) {
wp->flags &= ~PANE_HIDDEN;
if (w->layout_root != NULL && wp->saved_layout_cell != NULL) {
wp->layout_cell = wp->saved_layout_cell;
wp->saved_layout_cell = NULL;
layout_show_cell(w, wp->layout_cell);
layout_fix_offsets(w);
layout_fix_panes(w, NULL);
}
if (window_pane_is_hidden(wp)) {
lc->flags &= ~LAYOUT_CELL_HIDDEN;
layout_insert_tile(w, lc);
layout_fix_offsets(w);
layout_fix_panes(w, NULL);
}
notify_window("window-layout-changed", w);
server_redraw_window(w);
@@ -864,19 +862,19 @@ window_lost_pane(struct window *w, struct window_pane *wp)
/* Try to find a good fit. */
wpp = TAILQ_FIRST(&w->last_panes);
if (wpp == NULL || wpp->flags & PANE_HIDDEN) {
if (wpp == NULL || window_pane_is_hidden(wpp)) {
wpp = TAILQ_PREV(wp, window_panes, entry);
if (wpp == NULL || wpp->flags & PANE_HIDDEN)
if (wpp == NULL || window_pane_is_hidden(wpp))
wpp = TAILQ_NEXT(wp, entry);
}
/* Try to find any fit. */
if (wpp == NULL || (wpp->flags & PANE_HIDDEN)) {
if (wpp == NULL || window_pane_is_hidden(wpp)) {
TAILQ_FOREACH_SAFE(wpp, &w->panes, entry, twpp) {
if (wpp != wp && (~wpp->flags & PANE_HIDDEN))
if (wpp != wp && !window_pane_is_hidden(wpp))
break;
}
}
if (wpp != NULL && (wpp->flags & PANE_HIDDEN))
if (wpp != NULL && window_pane_is_hidden(wpp))
wpp = NULL;
w->active = wpp;
@@ -1046,7 +1044,7 @@ window_pane_printable_flags(struct window_pane *wp)
flags[pos++] = 'Z';
if (window_pane_is_floating(wp))
flags[pos++] = 'F';
if (wp->flags & PANE_HIDDEN)
if (window_pane_is_hidden(wp))
flags[pos++] = 'm';
flags[pos] = '\0';
@@ -1463,8 +1461,9 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
int
window_pane_visible(struct window_pane *wp)
{
if (~wp->window->flags & WINDOW_ZOOMED &&
~wp->flags & PANE_HIDDEN)
if (window_pane_is_hidden(wp))
return (0);
if (~wp->window->flags & WINDOW_ZOOMED)
return (1);
return (wp == wp->window->active);
@@ -2202,19 +2201,11 @@ window_get_pane_status(struct window *w)
int
window_pane_is_floating(struct window_pane *wp)
{
struct layout_cell *lc = wp->layout_cell;
if (lc == NULL || (lc->flags & LAYOUT_CELL_FLOATING) == 0)
return (0);
return (1);
return (wp->layout_cell->flags & LAYOUT_CELL_FLOATING);
}
int
window_pane_is_hidden(struct window_pane *wp)
{
struct layout_cell *lc = wp->layout_cell;
if ((lc->flags & LAYOUT_CELL_HIDDEN) == 0)
return (0);
return (1);
return (wp->layout_cell->flags & LAYOUT_CELL_HIDDEN);
}