diff --git a/Makefile.am b/Makefile.am index 79d4458a..b59ca9e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/cmd-find.c b/cmd-find.c index 8a3499a1..c5d9e0f3 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -977,15 +977,20 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item, } else if (cmd_find_from_client(¤t, cmdq_get_client(item), flags) == 0) { fs->current = ¤t; + /* 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) diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index e1134a1e..7c352b86 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -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); } diff --git a/cmd.c b/cmd.c index 233c6dc9..dfb9ca55 100644 --- a/cmd.c +++ b/cmd.c @@ -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 }; diff --git a/key-bindings.c b/key-bindings.c index 436bf032..1275bf84 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -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 }", diff --git a/layout.c b/layout.c index 885398a7..29912810 100644 --- a/layout.c +++ b/layout.c @@ -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) { diff --git a/screen-redraw.c b/screen-redraw.c index 90ee88de..108648bb 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -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); diff --git a/server-client.c b/server-client.c index 1d892bdb..0bdff34c 100644 --- a/server-client.c +++ b/server-client.c @@ -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); diff --git a/tmux.h b/tmux.h index 48e7af87..d67e96ef 100644 --- a/tmux.h +++ b/tmux.h @@ -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); diff --git a/window.c b/window.c index a6cf9457..916fb7d4 100644 --- a/window.c +++ b/window.c @@ -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; } }