diff --git a/cmd-break-pane.c b/cmd-break-pane.c index d0b60cfe3..ecad7dff7 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -65,13 +65,15 @@ cmd_break_pane_float(struct cmdq_item *item, struct args *args, free(cause); return (CMD_RETURN_ERROR); } - layout_remove_tile(w, lc); + /* A hidden pane has already given up its space. */ + if (~wp->flags & PANE_HIDDEN) + layout_remove_tile(w, lc); layout_set_size(lc, fg->sx, fg->sy, fg->xoff, fg->yoff); lc->flags |= LAYOUT_CELL_FLOATING; window_raise_pane(wp); - if (!args_has(args, 'd')) + if (!args_has(args, 'd') && (~wp->flags & PANE_HIDDEN)) window_set_active_pane(w, wp, 1); layout_fix_offsets(w); layout_fix_panes(w, NULL); @@ -149,6 +151,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) window_lost_pane(w, wp); layout_close_pane(wp); + wp->flags &= ~(PANE_HIDDEN|PANE_HIDDENALL); w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel); window_add_ref(w, __func__); options_set_parent(wp->options, w->options); diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 55a709c1f..7443af56a 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -429,7 +429,12 @@ cmd_join_pane_tile(struct cmdq_item *item, struct args *args, struct window *w, lc->fg.xoff = lc->g.xoff; lc->fg.yoff = lc->g.yoff; - if (layout_insert_tile(w, lc) != 0) { + if (wp->flags & PANE_HIDDEN) { + /* It takes its space when it is shown. */ + if (lc->parent != NULL) + layout_set_size(lc, 0, 0, 0, 0); + lc->tg.sx = UINT_MAX; + } else if (layout_insert_tile(w, lc) != 0) { cmdq_error(item, "no space for a new pane"); return (CMD_RETURN_ERROR); } @@ -440,7 +445,7 @@ cmd_join_pane_tile(struct cmdq_item *item, struct args *args, struct window *w, TAILQ_INSERT_TAIL(&w->z_index, wp, zentry); } - if (!args_has(args, 'd')) + if (!args_has(args, 'd') && (~wp->flags & PANE_HIDDEN)) window_set_active_pane(w, wp, 1); layout_fix_offsets(w); layout_fix_panes(w, NULL); @@ -545,6 +550,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) TAILQ_REMOVE(&src_w->z_index, src_wp, zentry); src_wp->window = dst_w; + src_wp->flags &= ~(PANE_HIDDEN|PANE_HIDDENALL); options_set_parent(src_wp->options, dst_w->options); src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED); if (flags & SPAWN_BEFORE) diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index fb760b3fd..dd27b83bf 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -41,8 +41,8 @@ const struct cmd_entry cmd_resize_pane_entry = { .name = "resize-pane", .alias = "resizep", - .args = { "aD::L::MR::Tt:U::x:y:Z", 0, 1, NULL }, - .usage = "[-aMTZ] [-D lines] [-L columns] [-R columns] [-U lines] " + .args = { "aD::HL::MR::Tt:U::x:y:Z", 0, 1, NULL }, + .usage = "[-aHMTZ] [-D lines] [-L columns] [-R columns] [-U lines] " "[-x width] [-y height] " CMD_TARGET_PANE_USAGE, .target = { 't', CMD_FIND_PANE, 0 }, @@ -51,6 +51,35 @@ const struct cmd_entry cmd_resize_pane_entry = { .exec = cmd_resize_pane_exec }; +/* + * Show the desktop: hide every pane above the layout, remembering which, or if + * any were hidden like that show just those again. + */ +static void +cmd_resize_pane_desktop(struct window *w) +{ + struct window_pane *wp; + int marked = 0; + + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->flags & PANE_HIDDENALL) + marked = 1; + } + TAILQ_FOREACH(wp, &w->panes, entry) { + if (marked) { + if (wp->flags & PANE_HIDDENALL) + window_show_pane(wp); + continue; + } + if (wp == w->modal || (wp->flags & PANE_HIDDEN)) + continue; + if (!window_pane_is_raised(wp)) + continue; + window_hide_pane(wp); + wp->flags |= PANE_HIDDENALL; + } +} + static enum cmd_retval cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) { @@ -83,6 +112,16 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) if (args_has(args, 'M')) return (cmd_resize_pane_mouse_update(self, item)); + if (args_has(args, 'H')) { + if (args_has(args, 'a')) + cmd_resize_pane_desktop(w); + else if (wp->flags & PANE_HIDDEN) + window_set_active_pane(w, wp, 1); + else + window_hide_pane(wp); + server_redraw_window(w); + return (CMD_RETURN_NORMAL); + } if (args_has(args, 'Z')) { if (args_has(args, 'a')) window_unzoom(w, 1); @@ -93,6 +132,8 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) server_redraw_window(w); return (CMD_RETURN_NORMAL); } + if ((wp->flags & PANE_HIDDEN) && !window_pane_is_floating(wp)) + window_show_pane(wp); if (wp->flags & PANE_ZOOMED) window_unzoom_pane(wp, 1); diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 847b42c0d..6c9185a6c 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -264,7 +264,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_NORMAL); } - if (wp == w->active) + if (wp == w->active && (~wp->flags & PANE_HIDDEN)) return (CMD_RETURN_NORMAL); if (w->modal != NULL && wp != w->modal) visible = 1; diff --git a/cmd-split-window.c b/cmd-split-window.c index 7fafaadf9..73baaf049 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -101,6 +101,8 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) else { is_floating = window_pane_is_floating(wp); flags |= SPAWN_SPLIT; + if (!is_floating && (wp->flags & PANE_HIDDEN)) + window_show_pane(wp); } if (args_has(args, 'O')) { diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 568e7a08f..7dc6a4358 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -75,7 +75,8 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item) struct window_pane *tmp_wp, *src_wp, *dst_wp; struct layout_cell *src_lc, *dst_lc; u_int sx, sy, xoff, yoff; - int src_idx, dst_idx, src_zoomed, dst_zoomed; + int src_idx, dst_idx, flags; + int src_zoomed, dst_zoomed; dst_w = target->wl->window; dst_wp = target->wp; @@ -119,7 +120,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item) src_zoomed = (args_has(args, 'Z') && (src_w->flags & WINDOW_ZOOMED)); - if (src_wp == dst_wp) + if (src_wp == NULL || src_wp == dst_wp) goto out; server_client_remove_pane(src_wp); @@ -145,11 +146,11 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item) else TAILQ_INSERT_AFTER(&dst_w->z_index, tmp_wp, src_wp, zentry); - /* Zoom belongs to the position in the window, like the cell. */ - if ((src_wp->flags ^ dst_wp->flags) & PANE_ZOOMED) { - src_wp->flags ^= PANE_ZOOMED; - dst_wp->flags ^= PANE_ZOOMED; - } + /* Zoom and being hidden belong to the position, like the cell. */ + flags = (src_wp->flags ^ dst_wp->flags) & + (PANE_ZOOMED|PANE_HIDDEN|PANE_HIDDENALL); + src_wp->flags ^= flags; + dst_wp->flags ^= flags; src_lc = src_wp->layout_cell; dst_lc = dst_wp->layout_cell; diff --git a/format.c b/format.c index 51fb02dff..7ea836f5e 100644 --- a/format.c +++ b/format.c @@ -1110,6 +1110,20 @@ format_cb_pane_floating_flag(struct format_tree *ft) return (NULL); } +/* Callback for pane_hidden_flag. */ +static void * +format_cb_pane_hidden_flag(struct format_tree *ft) +{ + struct window_pane *wp = ft->wp; + + if (wp != NULL) { + if (wp->flags & PANE_HIDDEN) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + /* Callback for pane_modal_flag. */ static void * format_cb_pane_modal_flag(struct format_tree *ft) @@ -3831,6 +3845,9 @@ static const struct format_table_entry format_table[] = { { "pane_height", FORMAT_TABLE_STRING, format_cb_pane_height }, + { "pane_hidden_flag", FORMAT_TABLE_STRING, + format_cb_pane_hidden_flag + }, { "pane_id", FORMAT_TABLE_STRING, format_cb_pane_id }, diff --git a/key-bindings.c b/key-bindings.c index c885e0cd2..6557ec46b 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -80,6 +80,7 @@ " 'Respawn' 'R' {respawn-pane -k}" \ " '#{?pane_marked,Unmark,Mark}' 'm' {select-pane -m}" \ " '#{?#{>:#{window_panes},1},,-}#{?pane_zoomed_flag,Unzoom,Zoom}' 'z' {resize-pane -Z}" \ + " 'Hide' 'H' {resize-pane -H}" \ " '#{?#{||:#{pane_floating_flag},#{pane_zoomed_flag}},Bring To Front,}' 'F' {move-pane -P front}" #define DEFAULT_MOVE_MENU \ " 'Centre' 'c' {move-pane -P centre}" \ @@ -397,6 +398,7 @@ key_bindings_init(void) "bind -N 'Kill current window' & { confirm-before -p\"kill-window #W? (y/n)\" kill-window }", "bind -N 'Prompt for window index to select' \"'\" { command-prompt -pindex { select-window -t ':%%' } }", "bind -N 'New floating pane' * { new-pane }", + "bind -N 'Hide pane' _ { resize-pane -H }", "bind -N 'Toggle pane between floating and tiled' @ { if -F '#{pane_floating_flag}' { join-pane } { break-pane -W } }", "bind -N 'Switch to previous client' ( { switch-client -p }", "bind -N 'Switch to next client' ) { switch-client -n }", @@ -531,7 +533,7 @@ key_bindings_init(void) "bind -n M-MouseDrag1Border { move-pane -M }", /* Mouse button 1 down on status line. */ - "bind -n MouseDown1Status { switch-client -t= }", + "bind -n MouseDown1Status { if -F '#{==:#{mouse_status_range},desktop}' { resize-pane -a -H } { if -Ft= '#{&&:#{==:#{mouse_status_range},pane},#{&&:#{pane_active},#{!:#{pane_hidden_flag}}}}' { resize-pane -H -t= } { switch-client -t= } } }", "bind -n C-MouseDown1Status { swap-window -t@ }", /* Mouse button 1 down on default pane-border-format */ diff --git a/layout-custom.c b/layout-custom.c index 8f961add9..0e550a435 100644 --- a/layout-custom.c +++ b/layout-custom.c @@ -75,6 +75,7 @@ struct layout_parse_cell_ctx { int index; int zindex; int zoomed; + int hidden; }; /* Layout parse context. */ @@ -221,7 +222,7 @@ layout_parse_free_ctx(struct layout_parse_ctx *pctx) /* Add a cell context to the parse context. */ static void layout_parse_add_cctx(struct layout_parse_ctx *pctx, struct layout_cell *lc, - int active, int last, int index, int zindex, int zoomed) + int active, int last, int index, int zindex, int zoomed, int hidden) { struct layout_parse_cell_ctx *cctx; @@ -238,6 +239,7 @@ layout_parse_add_cctx(struct layout_parse_ctx *pctx, struct layout_cell *lc, cctx->index = index; cctx->zindex = zindex; cctx->zoomed = zoomed; + cctx->hidden = hidden; } /* Remove a cell context from the parse context. Does not preserve ordering. */ @@ -429,6 +431,8 @@ layout_append_v2(struct layout_cell *lc, struct layout_string *ls) layout_string_write(ls, ",\"i\":%u", i); if (wp->flags & PANE_ZOOMED) layout_string_write(ls, ",\"Z\":true"); + if (wp->flags & PANE_HIDDEN) + layout_string_write(ls, ",\"H\":true"); if (lc->flags & LAYOUT_CELL_FLOATING) { z = layout_cell_zindex(lc); layout_string_write(ls, ",\"z\":%u", z); @@ -481,18 +485,23 @@ layout_append_v1(struct layout_cell *lc, struct layout_string *ls) } /* - * Copies the tiled part of a layout. Only populates what is necessary to dump a - * V1 layout string. + * Copies the part of a layout that is shown, which leaves out hidden tiled + * panes and, unless asked to keep them, floating panes. Only populates what is + * necessary to dump a layout string. */ static struct layout_cell * -layout_custom_copy_layout(struct layout_cell *lc) +layout_custom_copy_layout(struct layout_cell *lc, int keep_floating) { struct layout_cell *lcchild, *lcnewchild, *lconly; struct layout_cell *lcnew; - if (lc->type == LAYOUT_WINDOWPANE && - (lc->flags & LAYOUT_CELL_FLOATING)) - return (NULL); + if (lc->type == LAYOUT_WINDOWPANE) { + if (lc->flags & LAYOUT_CELL_FLOATING) { + if (!keep_floating) + return (NULL); + } else if (lc->wp != NULL && (lc->wp->flags & PANE_HIDDEN)) + return (NULL); + } lcnew = layout_create_cell(NULL); @@ -508,7 +517,8 @@ layout_custom_copy_layout(struct layout_cell *lc) case LAYOUT_TOPBOTTOM: case LAYOUT_LEFTRIGHT: TAILQ_FOREACH(lcchild, &lc->cells, entry) { - lcnewchild = layout_custom_copy_layout(lcchild); + lcnewchild = layout_custom_copy_layout(lcchild, + keep_floating); if (lcnewchild == NULL) continue; TAILQ_INSERT_TAIL(&lcnew->cells, lcnewchild, entry); @@ -534,11 +544,11 @@ layout_custom_copy_layout(struct layout_cell *lc) /* Create a compatibility layout for dumping a V1 layout string. */ static struct layout_cell * -layout_custom_create_compat(struct layout_cell *lcroot) +layout_custom_create_compat(struct layout_cell *lcroot, int keep_floating) { struct layout_cell *lccompat; - lccompat = layout_custom_copy_layout(lcroot); + lccompat = layout_custom_copy_layout(lcroot, keep_floating); if (lccompat != NULL && layout_cell_is_tiled(lccompat)) { lccompat->g.xoff = 0; lccompat->g.yoff = 0; @@ -586,11 +596,18 @@ layout_append(struct layout_cell *lcroot, struct layout_string *ls, int flags) if (!layout_cell_is_tiled(lcroot) && !layout_cell_has_tiled_child(lcroot)) return (-1); - lccompat = layout_custom_create_compat(lcroot); + lccompat = layout_custom_create_compat(lcroot, 0); result = layout_append_v1(lccompat, ls); layout_custom_free_compat(lccompat); - } else - result = layout_append_v2(lcroot, ls); + } else { + lccompat = layout_custom_create_compat(lcroot, 1); + if (lccompat == NULL) + result = layout_append_v2(lcroot, ls); + else { + result = layout_append_v2(lccompat, ls); + layout_custom_free_compat(lccompat); + } + } return (result); } @@ -743,6 +760,12 @@ layout_parse(struct window *w, const char *input, char **cause) } } + /* Hidden tiled panes are in the new layout like the rest. */ + TAILQ_FOREACH(wp, &w->panes, entry) { + if (!window_pane_is_floating(wp)) + wp->flags &= ~(PANE_HIDDEN|PANE_HIDDENALL); + } + /* Destroy the old layout and swap to the new. */ layout_free_cell(w->layout_root, 0); w->layout_root = lc; @@ -1018,7 +1041,7 @@ layout_parse_json_layout(struct json_node *node, struct layout_cell *lcparent, int64_t num; char **cause = pctx->cause; int boolean, index, zindex, active = -1; - int last = -1, zoomed = 0; + int last = -1, zoomed, hidden; if (json_find_string(node, "t", &str, cause) != 0) goto fail; @@ -1108,14 +1131,20 @@ layout_parse_json_layout(struct json_node *node, struct layout_cell *lcparent, } else zindex = INT_MAX; + zoomed = hidden = 0; if (json_find(node, "Z") != NULL) { if (json_find_boolean(node, "Z", &boolean, cause) != 0) goto fail; zoomed = boolean; } + if (json_find(node, "H") != NULL) { + if (json_find_boolean(node, "H", &boolean, cause) != 0) + goto fail; + hidden = boolean; + } layout_parse_add_cctx(pctx, lc, active, last, index, zindex, - zoomed); + zoomed, hidden); } else { if (json_find_array(node, "c", &array, cause) != 0) goto fail; @@ -1225,11 +1254,18 @@ layout_parse_apply_ctx(struct window *w, struct layout_parse_ctx *pctx) TAILQ_INSERT_HEAD(&w->z_index, wp, zentry); } - /* Zoom panes. */ + /* Zoom and hide panes. */ for (i = 0; i < pctx->size; i++) { cctx = &pctx->cctxs[i]; + wp = cctx->lc->wp; if (cctx->zoomed) - window_zoom(cctx->lc->wp); + window_zoom(wp); + } + for (i = 0; i < pctx->size; i++) { + cctx = &pctx->cctxs[i]; + wp = cctx->lc->wp; + if (cctx->hidden && window_pane_is_floating(wp)) + window_hide_pane(wp); } /* Set the active pane. */ diff --git a/layout.c b/layout.c index 639340532..723e61c51 100644 --- a/layout.c +++ b/layout.c @@ -79,6 +79,7 @@ layout_create_cell(struct layout_cell *lcparent) layout_geometry_init(&lc->g); layout_geometry_init(&lc->fg); + layout_geometry_init(&lc->tg); return (lc); } @@ -238,8 +239,9 @@ layout_cell_is_tiled(struct layout_cell *lc) { int is_leaf = lc->type == LAYOUT_WINDOWPANE; int is_floating = lc->flags & LAYOUT_CELL_FLOATING; + int is_hidden = lc->wp != NULL && (lc->wp->flags & PANE_HIDDEN); - return is_leaf && !is_floating; + return is_leaf && !is_floating && !is_hidden; } int @@ -499,6 +501,8 @@ layout_fix_panes(struct window *w, struct window_pane *skip) TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->layout_cell == NULL || wp == skip) continue; + if (wp->flags & PANE_HIDDEN) + continue; old_xoff = wp->xoff; old_yoff = wp->yoff; diff --git a/options-table.c b/options-table.c index c28f13863..0f3623df1 100644 --- a/options-table.c +++ b/options-table.c @@ -209,7 +209,10 @@ static const char *options_table_copy_mode_line_numbers_list[] = { "#{T:window-pane-current-status-format}" \ "#[pop-default]" \ "#[norange list=on default] " \ - "}" + "}" \ + "#[nolist align=right range=user|desktop]" \ + "[_]" \ + "#[norange default]" #define OPTIONS_TABLE_STATUS_FORMAT3 \ "#[align=left]#{R: ,#{n:#{session_name}}}S: " \ "#[norange default]" \ diff --git a/tmux.1 b/tmux.1 index 54dbf28af..c4d19774c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -364,6 +364,8 @@ Choose the current window interactively. Kill the current pane. .It z Toggle zoom state of the current pane. +.It _ +Hide the current pane. .It Tab Choose a new window and session by fuzzy matching. .It { @@ -2794,7 +2796,7 @@ If .Fl d is given, the active pane is not changed. The pane must not already be floating. -A zoomed pane stays zoomed. +A hidden or zoomed pane stays hidden or zoomed. .Tg capturep .It Xo Ic capture\-pane .Op Fl aeFHILpPRqCJMN @@ -3836,7 +3838,7 @@ if specified, to .Ar new\-name . .Tg resizep .It Xo Ic resize\-pane -.Op Fl aMTZ +.Op Fl aHMTZ .Op Fl D Ar lines .Op Fl L Ar columns .Op Fl R Ar columns @@ -3893,6 +3895,19 @@ with .Fl Z unzooms every pane in the window. .Pp +.Fl H +hides the target pane, or shows it if it is hidden. +A hidden pane is not shown, cannot be selected with the mouse and is skipped +when moving to the next or previous pane, but it is otherwise unchanged: a +hidden tiled pane gives its space to a neighbour and takes it back when shown, +and a pane that is zoomed or floating is still zoomed or floating when shown. +Selecting a hidden pane shows it. +.Fl a +with +.Fl H +hides every floating or zoomed pane in the window, or, if any were hidden in +this way, shows just those again. +.Pp .Fl M begins mouse resizing (only valid if bound to a mouse key binding, see .Sx MOUSE SUPPORT ) . @@ -6058,8 +6073,9 @@ also raises zoomed panes and .Ic off raises none. A floating or zoomed pane that is covered by a zoomed pane is always raised -when it is made active; a tiled pane that is covered unzooms every pane -instead. +when it is made active, and a hidden pane is shown; a tiled pane that is +covered hides the zoomed panes instead, as the desktop does, so that the tiled +panes are shown, and the desktop shows them again. Moving the mouse onto a pane with .Ic focus\-follows\-mouse makes it active without raising it, so @@ -7445,6 +7461,7 @@ The following variables are available, where appropriate: .It Li "pane_floating_flag" Ta "" Ta "1 if pane is floating" .It Li "pane_format" Ta "" Ta "1 if format is for a pane" .It Li "pane_height" Ta "" Ta "Height of pane" +.It Li "pane_hidden_flag" Ta "" Ta "1 if pane is hidden" .It Li "pane_id" Ta "#D" Ta "Unique pane ID" .It Li "pane_in_mode" Ta "" Ta "Number of modes pane is in" .It Li "pane_index" Ta "#P" Ta "Index of pane" diff --git a/tmux.h b/tmux.h index 083fe203e..bf115b420 100644 --- a/tmux.h +++ b/tmux.h @@ -1348,6 +1348,8 @@ struct window_pane { #define PANE_CAPTUREALLKEYS 0x100000 #define PANE_FLOATOVERZOOM 0x200000 #define PANE_CLOSEONCANCEL 0x400000 +#define PANE_HIDDEN 0x800000 +#define PANE_HIDDENALL 0x1000000 bitstr_t *sync_dirty; u_int sync_dirty_size; @@ -1593,6 +1595,7 @@ struct layout_cell { struct layout_geometry g; struct layout_geometry fg; /* saved floating pane */ + struct layout_geometry tg; /* saved tiled pane, when hidden */ struct window_pane *wp; struct layout_cells cells; @@ -3721,6 +3724,8 @@ struct window_pane *window_add_pane(struct window *, struct window_pane *, u_int, int); 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_hide_pane(struct window_pane *); +int window_show_pane(struct window_pane *); void window_raise_pane(struct window_pane *); void window_lower_pane(struct window_pane *); int window_zoom(struct window_pane *); diff --git a/window.c b/window.c index e55fd4dd0..68344d7f7 100644 --- a/window.c +++ b/window.c @@ -677,7 +677,7 @@ window_pane_floating_overlaps(struct window_pane *fwp, struct window_pane *wp) int fxoff, fyoff, xoff, yoff, border = 0; u_int fsx, fsy, sx, sy; - if (!window_pane_is_raised(fwp)) + if (!window_pane_is_raised(fwp) || !window_pane_is_visible(fwp)) return (0); window_pane_full_size_offset(fwp, &fxoff, &fyoff, &fsx, &fsy); @@ -763,10 +763,12 @@ window_activate_pane(struct window *w, struct window_pane *wp, int notify, log_debug("%s: pane %%%u", __func__, wp->id); - if (wp == w->active) - return (0); if (w->modal != NULL && wp != w->modal) return (0); + if (wp->flags & PANE_HIDDEN) + window_show_pane(wp); + if (wp == w->active) + return (0); if (!window_pane_is_visible(wp)) { /* * The pane is covered by a zoomed pane. A tiled pane that is @@ -1012,6 +1014,82 @@ window_raise_pane(struct window_pane *wp) redraw_invalidate_scene(w); } +/* + * Hide a pane. It keeps its place in the layout and in the stacking order and + * stays zoomed or floating, so showing it again puts it back as it was. + */ +void +window_hide_pane(struct window_pane *wp) +{ + struct window *w = wp->window; + struct layout_cell *lc = wp->layout_cell; + struct window_pane *wp1; + + if ((wp->flags & PANE_HIDDEN) || wp == w->modal || lc == NULL) + return; + + /* A tiled pane gives its space to a neighbour. */ + if (layout_cell_is_tiled(lc)) { + memcpy(&lc->tg, &lc->g, sizeof lc->tg); + layout_remove_tile(w, lc); + } + wp->flags |= PANE_HIDDEN; + layout_fix_offsets(w); + layout_fix_panes(w, NULL); + + /* Move the focus to the last used pane or the top one that is seen. */ + if (wp == w->active) { + TAILQ_FOREACH(wp1, &w->last_panes, sentry) { + if (wp1 != wp && window_pane_is_visible(wp1)) + break; + } + if (wp1 == NULL) { + TAILQ_FOREACH(wp1, &w->z_index, zentry) { + if (wp1 != wp && window_pane_is_visible(wp1)) + break; + } + } + if (wp1 != NULL) + window_set_active_pane(w, wp1, 1); + } + + events_fire_window("window-layout-changed", w); + redraw_invalidate_scene(w); + server_redraw_window(w); +} + +/* Show a hidden pane. Returns -1 if a tiled pane has no room. */ +int +window_show_pane(struct window_pane *wp) +{ + struct window *w = wp->window; + struct layout_cell *lc = wp->layout_cell; + int tiled; + + if (~wp->flags & PANE_HIDDEN) + return (0); + + tiled = (lc != NULL && !window_pane_is_floating(wp)); + if (tiled && layout_insert_tile(w, lc) != 0) + return (-1); + wp->flags &= ~(PANE_HIDDEN|PANE_HIDDENALL); + + /* Try to get back the size the pane had. */ + if (tiled && lc->parent != NULL && lc->tg.sx != UINT_MAX) { + if (lc->parent->type == LAYOUT_LEFTRIGHT) + layout_resize_pane_to(wp, lc->parent->type, lc->tg.sx); + else + layout_resize_pane_to(wp, lc->parent->type, lc->tg.sy); + } + layout_fix_offsets(w); + layout_fix_panes(w, NULL); + + events_fire_window("window-layout-changed", w); + redraw_invalidate_scene(w); + server_redraw_window(w); + return (0); +} + /* Move a pane to the back of the panes it is stacked with. */ void window_lower_pane(struct window_pane *wp) @@ -1150,7 +1228,7 @@ window_zoomed_pane(struct window *w) if (~w->flags & WINDOW_ZOOMED) return (NULL); TAILQ_FOREACH(wp, &w->z_index, zentry) { - if (wp->flags & PANE_ZOOMED) + if ((wp->flags & PANE_ZOOMED) && (~wp->flags & PANE_HIDDEN)) return (wp); } return (NULL); @@ -1296,9 +1374,14 @@ window_pane_at_index(struct window *w, u_int idx) struct window_pane * window_pane_next_by_number(struct window *w, struct window_pane *wp, u_int n) { + struct window_pane *start; + for (; n > 0; n--) { - if ((wp = TAILQ_NEXT(wp, entry)) == NULL) - wp = TAILQ_FIRST(&w->panes); + start = wp; + do { + if ((wp = TAILQ_NEXT(wp, entry)) == NULL) + wp = TAILQ_FIRST(&w->panes); + } while ((wp->flags & PANE_HIDDEN) && wp != start); } return (wp); @@ -1308,9 +1391,15 @@ struct window_pane * window_pane_previous_by_number(struct window *w, struct window_pane *wp, u_int n) { + struct window_pane *start; + for (; n > 0; n--) { - if ((wp = TAILQ_PREV(wp, window_panes, entry)) == NULL) - wp = TAILQ_LAST(&w->panes, window_panes); + start = wp; + do { + wp = TAILQ_PREV(wp, window_panes, entry); + if (wp == NULL) + wp = TAILQ_LAST(&w->panes, window_panes); + } while ((wp->flags & PANE_HIDDEN) && wp != start); } return (wp); @@ -1375,7 +1464,10 @@ window_count_panes(struct window *w, int with_floating) u_int n = 0; TAILQ_FOREACH(wp, &w->panes, entry) { - if (with_floating || !window_pane_is_floating(wp)) + if (with_floating) + n++; + else if (!window_pane_is_floating(wp) && + (~wp->flags & PANE_HIDDEN)) n++; } return (n); @@ -1444,6 +1536,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_HIDDEN) + flags[pos++] = 'H'; if (wp->flags & PANE_FLOATOVERZOOM) flags[pos++] = 'A'; if (wp == w->modal) @@ -2155,6 +2249,8 @@ window_pane_is_visible(struct window_pane *wp) struct window *w = wp->window; struct window_pane *wp1; + if (wp->flags & PANE_HIDDEN) + return (0); if (~w->flags & WINDOW_ZOOMED) return (1); @@ -2162,7 +2258,7 @@ window_pane_is_visible(struct window_pane *wp) TAILQ_FOREACH(wp1, &w->z_index, zentry) { if (wp1 == wp) return (1); - if (wp1->flags & PANE_ZOOMED) + if ((wp1->flags & PANE_ZOOMED) && (~wp1->flags & PANE_HIDDEN)) return (0); } return (1);