Add support to minimise panes, both tiled and floating. New PREFIX _ key binding to minimise a pane. New functions minimise-pane and unminimise-pane. Add double-click on pane in status to minimise pane. Single click on pane in status unminimises pane.

This commit is contained in:
Michael Grant
2025-12-18 18:19:17 +00:00
parent 263529e886
commit 6a4a4a432b
10 changed files with 152 additions and 11 deletions

View File

@@ -106,6 +106,7 @@ dist_tmux_SOURCES = \
cmd-list-windows.c \
cmd-load-buffer.c \
cmd-lock-server.c \
cmd-minimise-pane.c \
cmd-move-window.c \
cmd-new-pane.c \
cmd-new-session.c \

View File

@@ -977,15 +977,20 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
} else if (cmd_find_from_client(&current, cmdq_get_client(item),
flags) == 0) {
fs->current = &current;
/* No active pane, window empty, return the window instead. */
if (current.wp == NULL) {
type = CMD_FIND_WINDOW;
}
log_debug("%s: current is from client", __func__);
} else {
if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "no current target");
goto error;
}
/*
if (!cmd_find_valid_state(fs->current))
fatalx("invalid current find state");
*/
/* An empty or NULL target is the current. */
if (target == NULL || *target == '\0')
goto current;
@@ -1010,7 +1015,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
fs->w = fs->wl->window;
fs->wp = fs->w->active;
}
break;
goto found;
}
if (fs->wp == NULL) {
if (~flags & CMD_FIND_QUIET)

View File

@@ -62,6 +62,11 @@ cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
if (wp == NULL) {
/* No active window pane. */
cmdq_error(item, "No active pane to kill.");
return (CMD_RETURN_ERROR);
}
server_kill_pane(wp);
return (CMD_RETURN_NORMAL);
}

8
cmd.c
View File

@@ -69,8 +69,10 @@ extern const struct cmd_entry cmd_load_buffer_entry;
extern const struct cmd_entry cmd_lock_client_entry;
extern const struct cmd_entry cmd_lock_server_entry;
extern const struct cmd_entry cmd_lock_session_entry;
extern const struct cmd_entry cmd_minimise_pane_entry;
extern const struct cmd_entry cmd_move_pane_entry;
extern const struct cmd_entry cmd_move_window_entry;
extern const struct cmd_entry cmd_new_pane_entry;
extern const struct cmd_entry cmd_new_session_entry;
extern const struct cmd_entry cmd_new_window_entry;
extern const struct cmd_entry cmd_next_layout_entry;
@@ -109,7 +111,6 @@ extern const struct cmd_entry cmd_show_prompt_history_entry;
extern const struct cmd_entry cmd_show_window_options_entry;
extern const struct cmd_entry cmd_source_file_entry;
extern const struct cmd_entry cmd_split_window_entry;
extern const struct cmd_entry cmd_new_pane_entry;
extern const struct cmd_entry cmd_start_server_entry;
extern const struct cmd_entry cmd_suspend_client_entry;
extern const struct cmd_entry cmd_swap_pane_entry;
@@ -117,6 +118,7 @@ extern const struct cmd_entry cmd_swap_window_entry;
extern const struct cmd_entry cmd_switch_client_entry;
extern const struct cmd_entry cmd_unbind_key_entry;
extern const struct cmd_entry cmd_unlink_window_entry;
extern const struct cmd_entry cmd_unminimise_pane_entry;
extern const struct cmd_entry cmd_wait_for_entry;
const struct cmd_entry *cmd_table[] = {
@@ -162,8 +164,10 @@ const struct cmd_entry *cmd_table[] = {
&cmd_lock_client_entry,
&cmd_lock_server_entry,
&cmd_lock_session_entry,
&cmd_minimise_pane_entry,
&cmd_move_pane_entry,
&cmd_move_window_entry,
&cmd_new_pane_entry,
&cmd_new_session_entry,
&cmd_new_window_entry,
&cmd_next_layout_entry,
@@ -202,7 +206,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_show_window_options_entry,
&cmd_source_file_entry,
&cmd_split_window_entry,
&cmd_new_pane_entry,
&cmd_start_server_entry,
&cmd_suspend_client_entry,
&cmd_swap_pane_entry,
@@ -210,6 +213,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_switch_client_entry,
&cmd_unbind_key_entry,
&cmd_unlink_window_entry,
&cmd_unminimise_pane_entry,
&cmd_wait_for_entry,
NULL
};

View File

@@ -347,6 +347,10 @@ key_bindings_init(void)
{
static const char *const defaults[] = {
/* Prefix keys. */
"bind -N 'Minimise pane' _ { minimise-pane }",
/* Mouse button 1 double click on status line. */
"bind -n DoubleClick1Status { minimise-pane -t= }",
"bind -N 'Send the prefix key' C-b { send-prefix }",
"bind -N 'Rotate through the panes' C-o { rotate-window }",
"bind -N 'Suspend the current client' C-z { suspend-client }",

View File

@@ -254,6 +254,9 @@ layout_fix_offsets1(struct layout_cell *lc)
if (lc->type == LAYOUT_LEFTRIGHT) {
xoff = lc->xoff;
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (lcchild->type == LAYOUT_WINDOWPANE &&
lcchild->wp->flags & PANE_MINIMISED)
continue;
lcchild->xoff = xoff;
lcchild->yoff = lc->yoff;
if (lcchild->type != LAYOUT_WINDOWPANE)
@@ -263,6 +266,8 @@ layout_fix_offsets1(struct layout_cell *lc)
} else {
yoff = lc->yoff;
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (lcchild->wp->flags & PANE_MINIMISED)
continue;
lcchild->xoff = lc->xoff;
lcchild->yoff = yoff;
if (lcchild->type != LAYOUT_WINDOWPANE)
@@ -526,8 +531,7 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc,
if (lcparent == NULL) {
if (lc->wp != NULL && ~lc->wp->flags & PANE_FLOATING)
*lcroot = NULL;
/* xxx if (lc->type == LAYOUT_WINDOWPANE) */
layout_free_cell(lc);
layout_free_cell(lc);
return;
}
@@ -569,6 +573,70 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc,
}
}
/* Minimise a cell and redistribute the space in tiled cells. */
void
layout_minimise_cell(struct window *w, struct layout_cell *lc)
{
struct layout_cell *lcother, *lcparent, *lcchild;
u_int space = 0;
lcparent = lc->parent;
if (lcparent == NULL ||
lcparent->type == LAYOUT_FLOATING) {
return;
}
/* Merge the space into the previous or next cell. */
if (lc == TAILQ_FIRST(&lcparent->cells))
lcother = TAILQ_NEXT(lc, entry);
else
lcother = TAILQ_PREV(lc, layout_cells, entry);
if (lcother != NULL && lcparent->type == LAYOUT_LEFTRIGHT)
layout_resize_adjust(w, lcother, lcparent->type, lc->sx + 1);
else if (lcother != NULL)
layout_resize_adjust(w, lcother, lcparent->type, lc->sy + 1);
/* If the parent cells are all minimised, minimise it too. */
if (lcparent != NULL) {
TAILQ_FOREACH(lcchild, &lcparent->cells, entry) {
if (lcchild->wp == NULL ||
lcchild->wp->flags & PANE_MINIMISED)
continue;
if (lcparent->type == LAYOUT_LEFTRIGHT) {
space += lcchild->sx;
} else if (lcparent->type == LAYOUT_TOPBOTTOM) {
space += lcchild->sy;
}
}
if (space == 0)
layout_minimise_cell(w, lcparent);
}
}
/* Unminimise a cell and redistribute the space in tiled cells. */
void
layout_unminimise_cell(struct window *w, struct layout_cell *lc)
{
struct layout_cell *lcother, *lcparent;
lcparent = lc->parent;
if (lcparent == NULL) {
return;
}
/* In tiled layouts, merge the space into the previous or next cell. */
if (lcparent->type != LAYOUT_FLOATING) {
if (lc == TAILQ_FIRST(&lcparent->cells))
lcother = TAILQ_NEXT(lc, entry);
else
lcother = TAILQ_PREV(lc, layout_cells, entry);
if (lcother != NULL && lcparent->type == LAYOUT_LEFTRIGHT)
layout_resize_adjust(w, lcother, lcparent->type, -(lc->sx + 1));
else if (lcother != NULL)
layout_resize_adjust(w, lcother, lcparent->type, -(lc->sy + 1));
}
}
void
layout_init(struct window *w, struct window_pane *wp)
{

View File

@@ -439,10 +439,13 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py,
(int)py <= wp->yoff + (int)wp->sy))
break;
}
if (wp == NULL)
if (wp == NULL) {
start = wp = server_client_get_pane(c);
else
if (wp == NULL)
return (CELL_OUTSIDE);
} else {
start = wp;
}
if (px == sx || py == sy) /* window border */
return (screen_redraw_type_of_cell(ctx, wp, px, py));
@@ -538,6 +541,8 @@ screen_redraw_check_is(struct screen_redraw_ctx *ctx, u_int px, u_int py,
{
enum screen_redraw_border_type border;
if (wp == NULL)
return (0); /* No active pane. */
border = screen_redraw_pane_border(ctx, wp, px, py);
if (border != SCREEN_REDRAW_INSIDE && border != SCREEN_REDRAW_OUTSIDE)
return (1);

View File

@@ -2957,7 +2957,7 @@ server_client_reset_state(struct client *c)
if (c->overlay_draw != NULL) {
if (c->overlay_mode != NULL)
s = c->overlay_mode(c, c->overlay_data, &cx, &cy);
} else if (c->prompt_string == NULL)
} else if (wp != NULL && c->prompt_string == NULL)
s = wp->screen;
else
s = c->status.active;
@@ -2985,7 +2985,7 @@ server_client_reset_state(struct client *c)
cy = tty->sy - 1;
}
cx = c->prompt_cursor;
} else if (c->overlay_draw == NULL) {
} else if (wp != NULL && c->overlay_draw == NULL) {
cursor = 0;
tty_window_offset(tty, &ox, &oy, &sx, &sy);
if (wp->xoff + s->cx >= ox && wp->xoff + s->cx <= ox + sx &&
@@ -3004,7 +3004,9 @@ server_client_reset_state(struct client *c)
if (!cursor)
mode &= ~MODE_CURSOR;
}
} else
mode &= ~MODE_CURSOR;
log_debug("%s: cursor to %u,%u", __func__, cx, cy);
tty_cursor(tty, cx, cy);

4
tmux.h
View File

@@ -3270,6 +3270,8 @@ struct window_pane *window_find_string(struct window *, const char *);
int window_has_pane(struct window *, struct window_pane *);
int window_set_active_pane(struct window *, struct window_pane *,
int);
int window_deactivate_pane(struct window *, struct window_pane *,
int);
void window_update_focus(struct window *);
void window_pane_update_focus(struct window_pane *);
void window_redraw_active_switch(struct window *,
@@ -3350,6 +3352,8 @@ void layout_free_cell(struct layout_cell *);
void layout_print_cell(struct layout_cell *, const char *, u_int);
void layout_destroy_cell(struct window *, struct layout_cell *,
struct layout_cell **);
void layout_minimise_cell(struct window *, struct layout_cell *);
void layout_unminimise_cell(struct window *, struct layout_cell *);
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

@@ -536,6 +536,20 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
w->active->active_point = next_active_point++;
w->active->flags |= PANE_CHANGED;
if (wp->flags & PANE_MINIMISED) {
wp->flags &= ~PANE_MINIMISED;
if (w->layout_root != NULL) {
wp->layout_cell = wp->saved_layout_cell;
wp->saved_layout_cell = NULL;
layout_unminimise_cell(w, wp->layout_cell);
layout_fix_offsets(w);
layout_fix_panes(w, NULL);
}
}
notify_window("window-layout-changed", w);
server_redraw_window(w);
if (options_get_number(global_options, "focus-events")) {
window_pane_update_focus(lastwp);
window_pane_update_focus(w->active);
@@ -548,6 +562,33 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
return (1);
}
int
window_deactivate_pane(struct window *w, struct window_pane *wp, int notify)
{
struct window_pane *lastwp;
log_debug("%s: pane %%%u", __func__, wp->id);
if (w->flags & WINDOW_ZOOMED)
window_unzoom(w, 1);
lastwp = w->active;
window_pane_stack_remove(&w->last_panes, wp);
window_pane_stack_push(&w->last_panes, lastwp);
w->active = NULL;
if (options_get_number(global_options, "focus-events")) {
window_pane_update_focus(lastwp);
}
tty_update_window_offset(w);
if (notify)
notify_window("window-pane-changed", w);
return (1);
}
static int
window_pane_get_palette(struct window_pane *wp, int c)
{
@@ -600,6 +641,8 @@ window_redraw_active_switch(struct window *w, struct window_pane *wp)
}
wp = w->active;
if (wp == NULL)
break;
}
}