aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--TODO12
-rw-r--r--cmd-attach-session.c2
-rw-r--r--cmd-break-pane.c2
-rw-r--r--cmd-list-sessions.c3
-rw-r--r--cmd-new-session.c60
-rw-r--r--cmd-resize-window.c109
-rw-r--r--cmd-select-pane.c37
-rw-r--r--cmd-set-option.c15
-rw-r--r--cmd-split-window.c2
-rw-r--r--cmd-swap-pane.c2
-rw-r--r--cmd-switch-client.c1
-rw-r--r--cmd.c2
-rw-r--r--format.c22
-rw-r--r--input-keys.c2
-rw-r--r--layout-custom.c2
-rw-r--r--layout-set.c8
-rw-r--r--layout.c65
-rw-r--r--options-table.c33
-rw-r--r--resize.c306
-rw-r--r--screen-redraw.c294
-rw-r--r--screen-write.c142
-rw-r--r--server-client.c48
-rw-r--r--server-fn.c1
-rw-r--r--session.c15
-rw-r--r--tmux.1104
-rw-r--r--tmux.h53
-rw-r--r--tty.c448
-rw-r--r--window.c54
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 \
diff --git a/TODO b/TODO
index 32afa197..4a92eee9 100644
--- a/TODO
+++ b/TODO
@@ -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);
diff --git a/cmd.c b/cmd.c
index e432ae4a..5df30798 100644
--- a/cmd.c
+++ b/cmd.c
@@ -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,
diff --git a/format.c b/format.c
index d3da9eb7..cea338a1 100644
--- a/format.c
+++ b/format.c
@@ -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);
diff --git a/layout.c b/layout.c
index e1112ffa..c71dc7e5 100644
--- a/layout.c
+++ b/layout.c
@@ -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,
diff --git a/resize.c b/resize.c
index 1c9694da..faaa044d 100644
--- a/resize.c
+++ b/resize.c
@@ -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