diff options
| -rw-r--r-- | Makefile.am | 1 | ||||
| -rw-r--r-- | TODO | 12 | ||||
| -rw-r--r-- | cmd-attach-session.c | 2 | ||||
| -rw-r--r-- | cmd-break-pane.c | 2 | ||||
| -rw-r--r-- | cmd-list-sessions.c | 3 | ||||
| -rw-r--r-- | cmd-new-session.c | 60 | ||||
| -rw-r--r-- | cmd-resize-window.c | 109 | ||||
| -rw-r--r-- | cmd-select-pane.c | 37 | ||||
| -rw-r--r-- | cmd-set-option.c | 15 | ||||
| -rw-r--r-- | cmd-split-window.c | 2 | ||||
| -rw-r--r-- | cmd-swap-pane.c | 2 | ||||
| -rw-r--r-- | cmd-switch-client.c | 1 | ||||
| -rw-r--r-- | cmd.c | 2 | ||||
| -rw-r--r-- | format.c | 22 | ||||
| -rw-r--r-- | input-keys.c | 2 | ||||
| -rw-r--r-- | layout-custom.c | 2 | ||||
| -rw-r--r-- | layout-set.c | 8 | ||||
| -rw-r--r-- | layout.c | 65 | ||||
| -rw-r--r-- | options-table.c | 33 | ||||
| -rw-r--r-- | resize.c | 306 | ||||
| -rw-r--r-- | screen-redraw.c | 294 | ||||
| -rw-r--r-- | screen-write.c | 142 | ||||
| -rw-r--r-- | server-client.c | 48 | ||||
| -rw-r--r-- | server-fn.c | 1 | ||||
| -rw-r--r-- | session.c | 15 | ||||
| -rw-r--r-- | tmux.1 | 104 | ||||
| -rw-r--r-- | tmux.h | 53 | ||||
| -rw-r--r-- | tty.c | 448 | ||||
| -rw-r--r-- | window.c | 54 |
29 files changed, 1276 insertions, 569 deletions
diff --git a/Makefile.am b/Makefile.am index a57baa42..e62a161a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -100,6 +100,7 @@ dist_tmux_SOURCES = \ cmd-rename-session.c \ cmd-rename-window.c \ cmd-resize-pane.c \ + cmd-resize-window.c \ cmd-respawn-pane.c \ cmd-respawn-window.c \ cmd-rotate-window.c \ @@ -61,7 +61,6 @@ not attached to a cell at all. this could be the time to introduce panelink to replace layout_cell * way to set hints/limits about pane size for resizing - * panning over window (window larger than visible) * a mode where one application can cross two panes (ie x|y, width = COLUMNS/2 but height = ROWS * 2) * separate active panes for different clients @@ -131,3 +130,14 @@ * finish hooks for notifys * for session_closed, if no sessions at all, perhaps fake up a temporary one + +- pan + * tty_window_offset should try to keep as much as active pane + visible as possible + * rather than centering cursor it might be better if only + moved offset when it gets close to an edge? + * a way to force offset to a particular part of window, scroll + around the window -- command resize-window -d -l -r -u to + move offset and a flag to go back to tracking - but there + is no per-client window data structure so it will have + to forget when the window is changed diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 0db0d855..73ff530d 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -115,6 +115,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, c->session = s; if (~item->shared->flags & CMDQ_SHARED_REPEAT) server_client_set_key_table(c, NULL); + tty_update_client_offset(c); status_timer_start(c); notify_client("client-session-changed", c); session_update_activity(s, NULL); @@ -142,6 +143,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, c->session = s; server_client_set_key_table(c, NULL); + tty_update_client_offset(c); status_timer_start(c); notify_client("client-session-changed", c); session_update_activity(s, NULL); diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 74ecce6f..3b929dee 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -76,7 +76,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) window_lost_pane(w, wp); layout_close_pane(wp); - w = wp->window = window_create(dst_s->sx, dst_s->sy); + w = wp->window = window_create(w->sx, w->sy); TAILQ_INSERT_HEAD(&w->panes, wp, entry); w->active = wp; diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index df8a25bc..72ff47e8 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -30,8 +30,7 @@ #define LIST_SESSIONS_TEMPLATE \ "#{session_name}: #{session_windows} windows " \ - "(created #{t:session_created}) " \ - "[#{session_width}x#{session_height}]" \ + "(created #{t:session_created})" \ "#{?session_grouped, (group ,}" \ "#{session_group}#{?session_grouped,),}" \ "#{?session_attached, (attached),}" diff --git a/cmd-new-session.c b/cmd-new-session.c index e809de24..162a50bd 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -71,14 +71,15 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) struct session *s, *as, *groupwith; struct window *w; struct environ *env; + struct options *oo; struct termios tio, *tiop; struct session_group *sg; const char *errstr, *template, *group, *prefix; - const char *path, *cmd, *tmp; + const char *path, *cmd, *tmp, *value; char **argv, *cause, *cp, *newname, *cwd = NULL; int detached, already_attached, idx, argc; int is_control = 0; - u_int sx, sy; + u_int sx, sy, dsx = 80, dsy = 24; struct environ_entry *envent; struct cmd_find_state fs; enum cmd_retval retval; @@ -189,44 +190,53 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) } } - /* Find new session size. */ - if (!detached) { - sx = c->tty.sx; - sy = c->tty.sy; - if (!is_control && - sy > 0 && - options_get_number(global_s_options, "status")) - sy--; - } else { - sx = 80; - sy = 24; - } - if ((is_control || detached) && args_has(args, 'x')) { + /* Get default session size. */ + if (args_has(args, 'x')) { tmp = args_get(args, 'x'); if (strcmp(tmp, "-") == 0) { if (c != NULL) - sx = c->tty.sx; + dsx = c->tty.sx; } else { - sx = strtonum(tmp, 1, USHRT_MAX, &errstr); + dsx = strtonum(tmp, 1, USHRT_MAX, &errstr); if (errstr != NULL) { cmdq_error(item, "width %s", errstr); goto error; } } } - if ((is_control || detached) && args_has(args, 'y')) { + if (args_has(args, 'y')) { tmp = args_get(args, 'y'); if (strcmp(tmp, "-") == 0) { if (c != NULL) - sy = c->tty.sy; + dsy = c->tty.sy; } else { - sy = strtonum(tmp, 1, USHRT_MAX, &errstr); + dsy = strtonum(tmp, 1, USHRT_MAX, &errstr); if (errstr != NULL) { cmdq_error(item, "height %s", errstr); goto error; } } } + + /* Find new session size. */ + if (!detached && !is_control) { + sx = c->tty.sx; + sy = c->tty.sy; + if (!is_control && + sy > 0 && + options_get_number(global_s_options, "status")) + sy--; + } else { + value = options_get_string(global_s_options, "default-size"); + if (sscanf(value, "%ux%u", &sx, &sy) != 2) { + sx = 80; + sy = 24; + } + if (args_has(args, 'x')) + sx = dsx; + if (args_has(args, 'y')) + sy = dsy; + } if (sx == 0) sx = 1; if (sy == 0) @@ -262,10 +272,15 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) if (c != NULL && !args_has(args, 'E')) environ_update(global_s_options, c->environ, env); + /* Set up the options. */ + oo = options_create(global_s_options); + if (args_has(args, 'x') || args_has(args, 'y')) + options_set_string(oo, "default-size", 0, "%ux%u", dsx, dsy); + /* Create the new session. */ idx = -1 - options_get_number(global_s_options, "base-index"); - s = session_create(prefix, newname, argc, argv, path, cwd, env, tiop, - idx, sx, sy, &cause); + s = session_create(prefix, newname, argc, argv, path, cwd, env, oo, + tiop, idx, &cause); environ_free(env); if (s == NULL) { cmdq_error(item, "create session failed: %s", cause); @@ -313,6 +328,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) c->session = s; if (~item->shared->flags & CMDQ_SHARED_REPEAT) server_client_set_key_table(c, NULL); + tty_update_client_offset(c); status_timer_start(c); notify_client("client-session-changed", c); session_update_activity(s, NULL); diff --git a/cmd-resize-window.c b/cmd-resize-window.c new file mode 100644 index 00000000..8c4bc3f6 --- /dev/null +++ b/cmd-resize-window.c @@ -0,0 +1,109 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2018 Nicholas Marriott <nicholas.marriott@gmail.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <stdlib.h> + +#include "tmux.h" + +/* + * Increase or decrease window size. + */ + +static enum cmd_retval cmd_resize_window_exec(struct cmd *, + struct cmdq_item *); + +const struct cmd_entry cmd_resize_window_entry = { + .name = "resize-window", + .alias = "resizew", + + .args = { "aADLRt:Ux:y:", 0, 1 }, + .usage = "[-aADLRU] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " " + "[adjustment]", + + .target = { 't', CMD_FIND_WINDOW, 0 }, + + .flags = CMD_AFTERHOOK, + .exec = cmd_resize_window_exec +}; + +static enum cmd_retval +cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item) +{ + struct args *args = self->args; + struct winlink *wl = item->target.wl; + struct window *w = wl->window; + struct session *s = item->target.s; + const char *errstr; + char *cause; + u_int adjust, sx, sy; + + if (args->argc == 0) + adjust = 1; + else { + adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr); + if (errstr != NULL) { + cmdq_error(item, "adjustment %s", errstr); + return (CMD_RETURN_ERROR); + } + } + + sx = w->sx; + sy = w->sy; + + if (args_has(args, 'x')) { + sx = args_strtonum(args, 'x', WINDOW_MINIMUM, WINDOW_MAXIMUM, + &cause); + if (cause != NULL) { + cmdq_error(item, "width %s", cause); + free(cause); + return (CMD_RETURN_ERROR); + } + } + if (args_has(args, 'y')) { + sy = args_strtonum(args, 'y', WINDOW_MINIMUM, WINDOW_MAXIMUM, + &cause); + if (cause != NULL) { + cmdq_error(item, "height %s", cause); + free(cause); + return (CMD_RETURN_ERROR); + } + } + + if (args_has(args, 'L')) { + if (sx >= adjust) + sx -= adjust; + } else if (args_has(args, 'R')) + sx += adjust; + else if (args_has(args, 'U')) { + if (sy >= adjust) + sy -= adjust; + } else if (args_has(args, 'D')) + sy += adjust; + + if (args_has(args, 'A')) + default_window_size(s, w, &sx, &sy, WINDOW_SIZE_LARGEST); + else if (args_has(args, 'a')) + default_window_size(s, w, &sx, &sy, WINDOW_SIZE_SMALLEST); + + options_set_number(w->options, "window-size", WINDOW_SIZE_MANUAL); + resize_window(w, sx, sy); + + return (CMD_RETURN_NORMAL); +} diff --git a/cmd-select-pane.c b/cmd-select-pane.c index a2345fe1..5cec82f2 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -54,6 +54,31 @@ const struct cmd_entry cmd_last_pane_entry = { .exec = cmd_select_pane_exec }; +static void +cmd_select_pane_redraw(struct window *w) +{ + struct client *c; + + /* + * Redraw entire window if it is bigger than the client (the + * offset may change), otherwise just draw borders. + */ + + TAILQ_FOREACH(c, &clients, entry) { + if (c->session == NULL) + continue; + if (c->session->curw->window == w && tty_window_bigger(&c->tty)) + server_redraw_client(c); + else { + if (c->session->curw->window == w) + c->flags |= CLIENT_REDRAWBORDERS; + if (session_has(c->session, w)) + c->flags |= CLIENT_REDRAWSTATUS; + } + + } +} + static enum cmd_retval cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) { @@ -87,15 +112,14 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) window_redraw_active_switch(w, lastwp); if (window_set_active_pane(w, lastwp)) { cmd_find_from_winlink(current, wl, 0); - server_status_window(w); - server_redraw_window_borders(w); + cmd_select_pane_redraw(w); } } return (CMD_RETURN_NORMAL); } if (args_has(args, 'm') || args_has(args, 'M')) { - if (args_has(args, 'm') && !window_pane_visible(wp)) + if (args_has(args, 'm')) return (CMD_RETURN_NORMAL); lastwp = marked_pane.wp; @@ -168,16 +192,11 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) if (wp == w->active) return (CMD_RETURN_NORMAL); server_unzoom_window(wp->window); - if (!window_pane_visible(wp)) { - cmdq_error(item, "pane not visible"); - return (CMD_RETURN_ERROR); - } window_redraw_active_switch(w, wp); if (window_set_active_pane(w, wp)) { cmd_find_from_winlink_pane(current, wl, wp, 0); hooks_insert(s->hooks, item, current, "after-select-pane"); - server_status_window(w); - server_redraw_window_borders(w); + cmd_select_pane_redraw(w); } return (CMD_RETURN_NORMAL); diff --git a/cmd-set-option.c b/cmd-set-option.c index bdc42cae..c4b82004 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -18,6 +18,7 @@ #include <sys/types.h> +#include <fnmatch.h> #include <stdlib.h> #include <string.h> @@ -260,7 +261,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item) } if (strcmp(name, "pane-border-status") == 0) { RB_FOREACH(w, windows, &windows) - layout_fix_panes(w, w->sx, w->sy); + layout_fix_panes(w); } RB_FOREACH(s, sessions, &sessions) status_update_saved(s); @@ -297,7 +298,8 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo, int append = args_has(args, 'a'); struct options_entry *o; long long number; - const char *errstr; + const char *errstr, *new; + char *old; key_code key; oe = options_table_entry(parent); @@ -310,7 +312,16 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo, switch (oe->type) { case OPTIONS_TABLE_STRING: + old = xstrdup(options_get_string(oo, oe->name)); options_set_string(oo, oe->name, append, "%s", value); + new = options_get_string(oo, oe->name); + if (oe->pattern != NULL && fnmatch(oe->pattern, new, 0) != 0) { + options_set_string(oo, oe->name, 0, "%s", old); + free(old); + cmdq_error(item, "value is invalid: %s", value); + return (-1); + } + free(old); return (0); case OPTIONS_TABLE_NUMBER: number = strtonum(value, oe->minimum, oe->maximum, &errstr); diff --git a/cmd-split-window.c b/cmd-split-window.c index 378576ff..f5dde751 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -147,7 +147,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) } environ_free(env); - layout_fix_panes(w, w->sx, w->sy); + layout_fix_panes(w); server_redraw_window(w); if (!args_has(args, 'd')) { diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 7283bf53..1de272c4 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -105,8 +105,6 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item) window_set_active_pane(dst_w, src_wp); } else { tmp_wp = dst_wp; - if (!window_pane_visible(tmp_wp)) - tmp_wp = src_wp; window_set_active_pane(src_w, tmp_wp); } } else { diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 180635df..6181073d 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -128,6 +128,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) c->session = s; if (~item->shared->flags & CMDQ_SHARED_REPEAT) server_client_set_key_table(c, NULL); + tty_update_client_offset(c); status_timer_start(c); notify_client("client-session-changed", c); session_update_activity(s, NULL); @@ -80,6 +80,7 @@ extern const struct cmd_entry cmd_refresh_client_entry; extern const struct cmd_entry cmd_rename_session_entry; extern const struct cmd_entry cmd_rename_window_entry; extern const struct cmd_entry cmd_resize_pane_entry; +extern const struct cmd_entry cmd_resize_window_entry; extern const struct cmd_entry cmd_respawn_pane_entry; extern const struct cmd_entry cmd_respawn_window_entry; extern const struct cmd_entry cmd_rotate_window_entry; @@ -166,6 +167,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_rename_session_entry, &cmd_rename_window_entry, &cmd_resize_pane_entry, + &cmd_resize_window_entry, &cmd_respawn_pane_entry, &cmd_respawn_window_entry, &cmd_rotate_window_entry, @@ -1330,8 +1330,6 @@ format_defaults_session(struct format_tree *ft, struct session *s) format_add(ft, "session_name", "%s", s->name); format_add(ft, "session_windows", "%u", winlink_count(&s->windows)); - format_add(ft, "session_width", "%u", s->sx); - format_add(ft, "session_height", "%u", s->sy); format_add(ft, "session_id", "$%u", s->id); sg = session_group_contains(s); @@ -1492,18 +1490,14 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "pane_dead_status", "%d", WEXITSTATUS(status)); format_add(ft, "pane_dead", "%d", wp->fd == -1); - if (window_pane_visible(wp)) { - format_add(ft, "pane_left", "%u", wp->xoff); - format_add(ft, "pane_top", "%u", wp->yoff); - format_add(ft, "pane_right", "%u", wp->xoff + wp->sx - 1); - format_add(ft, "pane_bottom", "%u", wp->yoff + wp->sy - 1); - format_add(ft, "pane_at_left", "%d", wp->xoff == 0); - format_add(ft, "pane_at_top", "%d", wp->yoff == 0); - format_add(ft, "pane_at_right", "%d", - wp->xoff + wp->sx == w->sx); - format_add(ft, "pane_at_bottom", "%d", - wp->yoff + wp->sy == w->sy); - } + format_add(ft, "pane_left", "%u", wp->xoff); + format_add(ft, "pane_top", "%u", wp->yoff); + format_add(ft, "pane_right", "%u", wp->xoff + wp->sx - 1); + format_add(ft, "pane_bottom", "%u", wp->yoff + wp->sy - 1); + format_add(ft, "pane_at_left", "%d", wp->xoff == 0); + format_add(ft, "pane_at_top", "%d", wp->yoff == 0); + format_add(ft, "pane_at_right", "%d", wp->xoff + wp->sx == w->sx); + format_add(ft, "pane_at_bottom", "%d", wp->yoff + wp->sy == w->sy); format_add(ft, "pane_in_mode", "%d", wp->screen != &wp->base); if (wp->mode != NULL) diff --git a/input-keys.c b/input-keys.c index 85dc2591..d3ff0dc0 100644 --- a/input-keys.c +++ b/input-keys.c @@ -247,8 +247,6 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m) if ((mode & ALL_MOUSE_MODES) == 0) return; - if (!window_pane_visible(wp)) - return; if (cmd_mouse_at(wp, m, &x, &y, 0) != 0) return; diff --git a/layout-custom.c b/layout-custom.c index 1b8f576e..9886afe1 100644 --- a/layout-custom.c +++ b/layout-custom.c @@ -167,7 +167,7 @@ layout_parse(struct window *w, const char *layout) /* Update pane offsets and sizes. */ layout_fix_offsets(lc); - layout_fix_panes(w, lc->sx, lc->sy); + layout_fix_panes(w); /* Then resize the layout back to the original window size. */ layout_resize(w, sx, sy); diff --git a/layout-set.c b/layout-set.c index 5055f672..b9769ed5 100644 --- a/layout-set.c +++ b/layout-set.c @@ -148,7 +148,7 @@ layout_set_even(struct window *w, enum layout_type type) /* Fix cell offsets. */ layout_fix_offsets(lc); - layout_fix_panes(w, w->sx, w->sy); + layout_fix_panes(w); layout_print_cell(w->layout_root, __func__, 1); @@ -284,7 +284,7 @@ layout_set_main_h(struct window *w) /* Fix cell offsets. */ layout_fix_offsets(lc); - layout_fix_panes(w, w->sx, w->sy); + layout_fix_panes(w); layout_print_cell(w->layout_root, __func__, 1); @@ -408,7 +408,7 @@ layout_set_main_v(struct window *w) /* Fix cell offsets. */ layout_fix_offsets(lc); - layout_fix_panes(w, w->sx, w->sy); + layout_fix_panes(w); layout_print_cell(w->layout_root, __func__, 1); @@ -511,7 +511,7 @@ layout_set_tiled(struct window *w) /* Fix cell offsets. */ layout_fix_offsets(lc); - layout_fix_panes(w, w->sx, w->sy); + layout_fix_panes(w); layout_print_cell(w->layout_root, __func__, 1); @@ -253,71 +253,29 @@ layout_need_status(struct layout_cell *lc, int at_top) /* Update pane offsets and sizes based on their cells. */ void -layout_fix_panes(struct window *w, u_int wsx, u_int wsy) +layout_fix_panes(struct window *w) { struct window_pane *wp; struct layout_cell *lc; - u_int sx, sy; - int shift, status, at_top; + int shift, status; status = options_get_number(w->options, "pane-border-status"); - at_top = (status == 1); TAILQ_FOREACH(wp, &w->panes, entry) { if ((lc = wp->layout_cell) == NULL) continue; if (status != 0) - shift = layout_need_status(lc, at_top); + shift = layout_need_status(lc, status == 1); else shift = 0; wp->xoff = lc->xoff; wp->yoff = lc->yoff; - if (shift && at_top) + if (shift && status == 1) wp->yoff += 1; - /* - * Layout cells are limited by the smallest size of other cells - * within the same row or column; if this isn't the case - * resizing becomes difficult. - * - * However, panes do not have to take up their entire cell, so - * they can be cropped to the window edge if the layout - * overflows and they are partly visible. - * - * This stops cells being hidden unnecessarily. - */ - - /* - * Work out the horizontal size. If the pane is actually - * outside the window or the entire pane is already visible, - * don't crop. - */ - if (lc->xoff >= wsx || lc->xoff + lc->sx < wsx) - sx = lc->sx; - else { - sx = wsx - lc->xoff; - if (sx < 1) - sx = lc->sx; - } - - /* - * Similarly for the vertical size; the minimum vertical size - * is two because scroll regions cannot be one line. - */ - if (lc->yoff >= wsy || lc->yoff + lc->sy < wsy) - sy = lc->sy; - else { - sy = wsy - lc->yoff; - if (sy < 2) - sy = lc->sy; - } - - if (shift) - sy -= 1; - - window_pane_resize(wp, sx, sy); + window_pane_resize(wp, lc->sx, lc->sy - shift); } } @@ -491,8 +449,7 @@ layout_init(struct window *w, struct window_pane *wp) lc = w->layout_root = layout_create_cell(NULL); layout_set_size(lc, w->sx, w->sy, 0, 0); layout_make_leaf(lc, wp); - - layout_fix_panes(w, w->sx, w->sy); + layout_fix_panes(w); } void @@ -550,7 +507,7 @@ layout_resize(struct window *w, u_int sx, u_int sy) /* Fix cell offsets. */ layout_fix_offsets(lc); - layout_fix_panes(w, sx, sy); + layout_fix_panes(w); } /* Resize a pane to an absolute size. */ @@ -610,7 +567,7 @@ layout_resize_layout(struct window *w, struct layout_cell *lc, /* Fix cell offsets. */ layout_fix_offsets(w->layout_root); - layout_fix_panes(w, w->sx, w->sy); + layout_fix_panes(w); notify_window("window-layout-changed", w); } @@ -717,7 +674,7 @@ void layout_assign_pane(struct layout_cell *lc, struct window_pane *wp) { layout_make_leaf(lc, wp); - layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); + layout_fix_panes(wp->window); } /* Calculate the new pane size for resized parent. */ @@ -1037,7 +994,7 @@ layout_close_pane(struct window_pane *wp) /* Fix pane offsets and sizes. */ if (w->layout_root != NULL) { layout_fix_offsets(w->layout_root); - layout_fix_panes(w, w->sx, w->sy); + layout_fix_panes(w); } notify_window("window-layout-changed", w); } @@ -1094,7 +1051,7 @@ layout_spread_out(struct window_pane *wp) do { if (layout_spread_cell(w, parent)) { layout_fix_offsets(parent); - layout_fix_panes(w, w->sx, w->sy); + layout_fix_panes(w); break; } } while ((parent = parent->parent) != NULL); diff --git a/options-table.c b/options-table.c index 2b6b794b..0776f0b7 100644 --- a/options-table.c +++ b/options-table.c @@ -59,6 +59,9 @@ static const char *options_table_pane_status_list[] = { static const char *options_table_set_clipboard_list[] = { "off", "external", "on", NULL }; +static const char *options_table_window_size_list[] = { + "largest", "smallest", "manual", NULL +}; /* Top-level options. */ const struct options_table_entry options_table[] = { @@ -193,6 +196,13 @@ const struct options_table_entry options_table[] = { .default_str = _PATH_BSHELL }, + { .name = "default-size", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SESSION, + .pattern = "[0-9]*x[0-9]*", + .default_str = "80x24" + }, + { .name = "destroy-unattached", .type = OPTIONS_TABLE_FLAG, .scope = OPTIONS_TABLE_SESSION, @@ -588,22 +598,6 @@ const struct options_table_entry options_table[] = { .default_num = 1 }, - { .name = "force-height", - .type = OPTIONS_TABLE_NUMBER, - .scope = OPTIONS_TABLE_WINDOW, - .minimum = 0, - .maximum = INT_MAX, - .default_num = 0 - }, - - { .name = "force-width", - .type = OPTIONS_TABLE_NUMBER, - .scope = OPTIONS_TABLE_WINDOW, - .minimum = 0, - .maximum = INT_MAX, - .default_num = 0 - }, - { .name = "main-pane-height", .type = OPTIONS_TABLE_NUMBER, .scope = OPTIONS_TABLE_WINDOW, @@ -770,6 +764,13 @@ const struct options_table_entry options_table[] = { .default_str = "default" }, + { .name = "window-size", + .type = OPTIONS_TABLE_CHOICE, + .scope = OPTIONS_TABLE_WINDOW, + .choices = options_table_window_size_list, + .default_num = WINDOW_SIZE_LARGEST + }, + { .name = "window-style", .type = OPTIONS_TABLE_STYLE, .scope = OPTIONS_TABLE_WINDOW, @@ -22,144 +22,224 @@ #include "tmux.h" -/* - * Recalculate window and session sizes. - * - * Every session has the size of the smallest client it is attached to and - * every window the size of the smallest session it is attached to. - * - * So, when a client is resized or a session attached to or detached from a - * client, the window sizes must be recalculated. For each session, find the - * smallest client it is attached to, and resize it to that size. Then for - * every window, find the smallest session it is attached to, resize it to that - * size and clear and redraw every client with it as the current window. - * - * This is quite inefficient - better/additional data structures are needed - * to make it better. - */ +void +resize_window(struct window *w, u_int sx, u_int sy) +{ + int zoomed; + + /* Check size limits. */ + if (sx < WINDOW_MINIMUM) + sx = WINDOW_MINIMUM; + if (sx > WINDOW_MAXIMUM) + sx = WINDOW_MAXIMUM; + if (sy < WINDOW_MINIMUM) + sy = WINDOW_MINIMUM; + if (sy > WINDOW_MAXIMUM) + sy = WINDOW_MAXIMUM; + + /* If the window is zoomed, unzoom. */ + zoomed = w->flags & WINDOW_ZOOMED; + if (zoomed) + window_unzoom(w); + + /* Resize the layout first. */ + layout_resize(w, sx, sy); + + /* Resize the window, it can be no smaller than the layout. */ + if (sx < w->layout_root->sx) + sx = w->layout_root->sx; + if (sy < w->layout_root->sy) + sy = w->layout_root->sy; + window_resize(w, sx, sy); + + /* Restore the window zoom state. */ + if (zoomed) + window_zoom(w->active); + + tty_update_window_offset(w); + server_redraw_window(w); + notify_window("window-layout-changed", w); +} void -recalculate_sizes(void) +default_window_size(struct session *s, struct window *w, u_int *sx, u_int *sy, + int type) { - struct session *s; - struct client *c; - struct window *w; - struct window_pane *wp; - u_int ssx, ssy, has, limit, lines; - int flag, is_zoomed, forced; + struct client *c; + u_int cx, cy; + const char *value; - RB_FOREACH(s, sessions, &sessions) { - lines = status_line_size(s); + if (type == -1) + type = options_get_number(global_w_options, "window-size"); + if (type == WINDOW_SIZE_MANUAL) + goto manual; - s->attached = 0; - ssx = ssy = UINT_MAX; + if (type == WINDOW_SIZE_LARGEST) { + *sx = *sy = 0; TAILQ_FOREACH(c, &clients, entry) { - if (c->flags & CLIENT_SUSPENDED) + if (c->session == NULL) continue; - if ((c->flags & (CLIENT_CONTROL|CLIENT_SIZECHANGED)) == - CLIENT_CONTROL) + if (w != NULL && !session_has(c->session, w)) conti |