aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-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-refresh-client.c78
-rw-r--r--cmd-resize-window.c109
-rw-r--r--cmd-select-pane.c35
-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.c43
-rw-r--r--input-keys.c4
-rw-r--r--key-bindings.c5
-rw-r--r--key-string.c2
-rw-r--r--layout-custom.c2
-rw-r--r--layout-set.c8
-rw-r--r--layout.c65
-rw-r--r--options-table.c37
-rw-r--r--resize.c310
-rw-r--r--screen-redraw.c282
-rw-r--r--screen-write.c150
-rw-r--r--server-client.c71
-rw-r--r--server-fn.c1
-rw-r--r--session.c15
-rw-r--r--status.c20
-rw-r--r--tmux.h78
-rw-r--r--tty.c495
-rw-r--r--window.c60
31 files changed, 1372 insertions, 588 deletions
diff --git a/Makefile b/Makefile
index e6d9e6b3..8947cd53 100644
--- a/Makefile
+++ b/Makefile
@@ -44,6 +44,7 @@ SRCS= alerts.c \
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/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-refresh-client.c b/cmd-refresh-client.c
index 0f45c2d5..e5ae099f 100644
--- a/cmd-refresh-client.c
+++ b/cmd-refresh-client.c
@@ -18,6 +18,8 @@
#include <sys/types.h>
+#include <stdlib.h>
+
#include "tmux.h"
/*
@@ -31,8 +33,8 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client",
.alias = "refresh",
- .args = { "C:lSt:", 0, 0 },
- .usage = "[-lS] [-C size] " CMD_TARGET_CLIENT_USAGE,
+ .args = { "cC:DlLRSt:U", 0, 1 },
+ .usage = "[-cDlLRSU] [-C size] " CMD_TARGET_CLIENT_USAGE " [adjustment]",
.flags = CMD_AFTERHOOK,
.exec = cmd_refresh_client_exec
@@ -43,11 +45,64 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c;
- const char *size;
- u_int w, h;
+ struct tty *tty;
+ struct window *w;
+ const char *size, *errstr;
+ u_int x, y, adjust;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
+ tty = &c->tty;
+
+ if (args_has(args, 'c') ||
+ args_has(args, 'L') ||
+ args_has(args, 'R') ||
+ args_has(args, 'U') ||
+ args_has(args, 'D'))
+ {
+ 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);
+ }
+ }
+
+ if (args_has(args, 'c'))
+ c->pan_window = NULL;
+ else {
+ w = c->session->curw->window;
+ if (c->pan_window != w) {
+ c->pan_window = w;
+ c->pan_ox = tty->oox;
+ c->pan_oy = tty->ooy;
+ }
+ if (args_has(args, 'L')) {
+ if (c->pan_ox > adjust)
+ c->pan_ox -= adjust;
+ else
+ c->pan_ox = 0;
+ } else if (args_has(args, 'R')) {
+ c->pan_ox += adjust;
+ if (c->pan_ox > w->sx - tty->osx)
+ c->pan_ox = w->sx - tty->osx;
+ } else if (args_has(args, 'U')) {
+ if (c->pan_oy > adjust)
+ c->pan_oy -= adjust;
+ else
+ c->pan_oy = 0;
+ } else if (args_has(args, 'D')) {
+ c->pan_oy += adjust;
+ if (c->pan_oy > w->sy - tty->osy)
+ c->pan_oy = w->sy - tty->osy;
+ }
+ }
+ tty_update_client_offset(c);
+ server_redraw_client(c);
+ return (CMD_RETURN_NORMAL);
+ }
if (args_has(args, 'l')) {
if (c->session != NULL)
@@ -57,12 +112,13 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "missing size");
return (CMD_RETURN_ERROR);
}
- if (sscanf(size, "%u,%u", &w, &h) != 2) {
+ if (sscanf(size, "%u,%u", &x, &y) != 2 &&
+ sscanf(size, "%ux%u", &x, &y)) {
cmdq_error(item, "bad size argument");
return (CMD_RETURN_ERROR);
}
- if (w < PANE_MINIMUM || w > 5000 ||
- h < PANE_MINIMUM || h > 5000) {
+ if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
+ y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR);
}
@@ -70,16 +126,18 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
- tty_set_size(&c->tty, w, h);
+ tty_set_size(&c->tty, x, y);
c->flags |= CLIENT_SIZECHANGED;
recalculate_sizes();
- } else if (args_has(args, 'S')) {
+ return (CMD_RETURN_NORMAL);
+ }
+
+ if (args_has(args, 'S')) {
c->flags |= CLIENT_STATUSFORCE;
server_status_client(c);
} else {
c->flags |= CLIENT_STATUSFORCE;
server_redraw_client(c);
}
-
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-resize-window.c b/cmd-resize-window.c
new file mode 100644
index 00000000..d780b6ee
--- /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_WINDOW_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..90ca46ba 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,8 +112,7 @@ 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);
@@ -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 7b58f81f..28821413 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -148,7 +148,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 b90d5ea2..9226e6c2 100644
--- a/cmd.c
+++ b/cmd.c
@@ -81,6 +81,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;
@@ -167,6 +168,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 126bbc14..21365457 100644
--- a/format.c
+++ b/format.c
@@ -52,8 +52,7 @@ static int format_replace(struct format_tree *, const char *, size_t,
static void format_defaults_session(struct format_tree *,
struct session *);
static void format_defaults_client(struct format_tree *, struct client *);
-static void format_defaults_winlink(struct format_tree *,
- struct winlink *);
+static void format_defaults_winlink(struct format_tree *, struct winlink *);
/* Entry in format job tree. */
struct format_job {
@@ -107,9 +106,10 @@ struct format_entry {
/* Format entry tree. */
struct format_tree {
- struct window *w;
- struct winlink *wl;
+ struct client *c;
struct session *s;
+ struct winlink *wl;
+ struct window *w;
struct window_pane *wp;
struct client *client;
@@ -1347,8 +1347,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);
@@ -1383,6 +1381,7 @@ format_defaults_client(struct format_tree *ft, struct client *c)
if (ft->s == NULL)
ft->s = c->session;
+ ft->c = c;
format_add(ft, "client_name", "%s", c->name);
format_add(ft, "client_pid", "%ld", (long) c->pid);
@@ -1451,8 +1450,11 @@ format_defaults_window(struct format_tree *ft, struct window *w)
static void
format_defaults_winlink(struct format_tree *ft, struct winlink *wl)
{
+ struct client *c = ft->c;
struct session *s = wl->session;
struct window *w = wl->window;
+ int flag;
+ u_int ox, oy, sx, sy;
if (ft->w == NULL)
ft->w = wl->window;
@@ -1460,6 +1462,15 @@ format_defaults_winlink(struct format_tree *ft, struct winlink *wl)
format_defaults_window(ft, w);
+ if (c != NULL) {
+ flag = tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
+ format_add(ft, "window_bigger", "%d", flag);
+ if (flag) {
+ format_add(ft, "window_offset_x", "%u", ox);
+ format_add(ft, "window_offset_y", "%u", oy);
+ }
+ }
+
format_add(ft, "window_index", "%d", wl->idx);
format_add_cb(ft, "window_stack_index", format_cb_window_stack_index);
format_add(ft, "window_flags", "%s", window_printable_flags(wl));
@@ -1509,18 +1520,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 34710dac..39401a38 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -248,10 +248,10 @@ 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;
+ if (!window_pane_visible(wp))
+ return;
/* If this pane is not in button or all mode, discard motion events. */
if (MOUSE_DRAG(m->b) &&
diff --git a/key-bindings.c b/key-bindings.c
index c717f5ae..fbc54fb8 100644
--- a/key-bindings.c
+++ b/key-bindings.c
@@ -258,6 +258,11 @@ key_bindings_init(void)
"bind M-n next-window -a",
"bind M-o rotate-window -D",
"bind M-p previous-window -a",
+ "bind -r S-Up refresh-client -U 10",
+ "bind -r S-Down refresh-client -D 10",
+ "bind -r S-Left refresh-client -L 10",
+ "bind -r S-Right refresh-client -R 10",
+ "bind -r DC refresh-client -c",
"bind -r M-Up resize-pane -U 5",
"bind -r M-Down resize-pane -D 5",
"bind -r M-Left resize-pane -L 5",
diff --git a/key-string.c b/key-string.c
index bb49b59f..8442727d 100644
--- a/key-string.c
+++ b/key-string.c
@@ -43,7 +43,9 @@ static const struct {
{ "F11", KEYC_F11 },
{ "F12", KEYC_F12 },
{ "IC", KEYC_IC },
+ { "Insert", KEYC_IC },
{ "DC", KEYC_DC },
+ { "Delete", KEYC_DC },
{ "Home", KEYC_HOME },
{ "End", KEYC_END },
{ "NPage", KEYC_NPAGE },
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 4ad645e0..89026b91 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);
}
}
@@ -492,8 +450,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
@@ -551,7 +508,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. */
@@ -611,7 +568,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);
}
@@ -718,7 +675,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. */
@@ -1038,7 +995,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);
}
@@ -1095,7 +1052,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 03ee530f..347c23de 100644
--- a/options-table.c
+++ b/options-table.c
@@ -60,6 +60,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[] = {
@@ -194,6 +197,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,
@@ -467,7 +477,9 @@ const struct options_table_entry options_table[] = {
{ .name = "status-right",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
- .default_str = " \"#{=21:pane_title}\" %H:%M %d-%b-%y"
+ .default_str = "#{?window_bigger,"
+ "[#{window_offset_x}#,#{window_offset_y}] ,}"
+ "\"#{=21:pane_title}\" %H:%M %d-%b-%y"
},
{ .name = "status-right-attr",
@@ -589,22 +601,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,
@@ -771,6 +767,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..fef8feeb 100644
--- a/resize.c
+++ b/resize.c
@@ -22,144 +22,228 @@
#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 (c->flags & CLIENT_NOSIZEFLAGS)
continue;
- if (c->session == s) {
- if (c->tty.sx < ssx)
- ssx = c->tty.sx;
- c->flags &= ~CLIENT_STATUSOFF;
- if (lines != 0 && lines + PANE_MINIMUM > c->tty.sy)
- c->flags |= CLIENT_STATUSOFF;
- if ((~c->flags & CLIENT_STATUSOFF) &&
- !(c->flags & CLIENT_CONTROL) &&
- c->tty.sy > lines &&
- c->tty.sy - lines < ssy)
- ssy = c->tty.sy - lines;
- else if (c->tty.sy < ssy)
- ssy = c->tty.sy;
- s->attached++;
- }
+ if (w != NULL && !session_has(c->session, w))
+ continue;
+ if (w == NULL && c->session != s)
+ continue;
+
+ cx = c->tty.sx;
+ cy = c->tty.sy - status_line_size(c);
+
+ if (cx > *sx)
+ *sx = cx;
+ if (cy > *sy)
+ *sy = cy;
}
- if (ssx == UINT_MAX || ssy == UINT_MAX)
- continue;
+ if (*sx == 0 || *sy == 0)
+ goto manual;
+ } else {
+ *sx = *sy = UINT_MAX;
+ TAILQ_FOREACH(c, &clients, entry) {
+ if (c->session == NULL)
+ continue;
+ if (c->flags & CLIENT_NOSIZEFLAGS)
+ continue;
+ if (w != NULL && !session_has(c->session, w))
+ continue;
+ if (w == NULL && c->session != s)
+ continue;
- if (lines != 0 && ssy == 0)
- ssy = lines;
+ cx = c->tty.sx;
+ cy = c->tty.sy - status_line_size(c);
- if (s->sx == ssx && s->sy == ssy)
- continue;
+ if (cx < *sx)
+ *sx = cx;
+ if (cy < *sy)
+ *sy = cy;
+ }
+ if (*sx == UINT_MAX || *sy == UINT_MAX)
+ goto manual;
+ }
+ goto done;
- log_debug("session $%u size %u,%u (was %u,%u)", s->id, ssx, ssy,
- s->sx, s->sy);
+manual:
+ value = options_get_string(s->options, "default-size");
+ if (sscanf(value, "%ux%u", sx, sy) != 2) {
+ *sx = 80;
+ *sy = 24;
+ }
- s->sx = ssx;
- s->sy = ssy;
+done:
+ 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;
+}
+void
+recalculate_sizes(void)
+{
+ struct session *s;
+ struct client *c;
+ struct window *w;
+ u_int sx, sy, cx, cy;
+ int flags, type, current, has, changed;
+
+ /*
+ * Clear attached count and update saved status line information for
+ * each session.
+ */
+ RB_FOREACH(s, sessions, &sessions) {
+ s->attached = 0;
status_update_saved(s);
}
+ /*
+ * Increment attached count and check the status line size for each
+ * client.
+ */
+ TAILQ_FOREACH(c, &clients, entry) {
+ if ((s = c->session) == NULL)
+ continue;
+
+ flags = c->flags;
+ if (flags & CLIENT_SUSPENDED)
+ continue;
+ if ((flags & CLIENT_CONTROL) && (~flags & CLIENT_SIZECHANGED))
+ continue;
+
+ if (c->tty.sy <= status_line_size(c))
+ c->flags |= CLIENT_STATUSOFF;
+ else
+ c->flags &= ~CLIENT_STATUSOFF;
+
+ s->attached++;
+ }
+
+ /* Walk each window and adjust the size. */
RB_FOREACH(w, windows, &windows) {
if (w->active == NULL)
continue;
- flag = options_get_number(w->options, "aggressive-resize");
+ log_debug("%s: @%u is %u,%u", __func__, w->id, w->sx, w->sy);
- ssx = ssy = UINT_MAX;
- RB_FOREACH(s, sessions, &sessions) {
- if (s->attached == 0)
- continue;
- if (flag)
- has = s->curw->window == w;
- else
- has = session_has(s, w);
- if (has) {
- if (s->sx < ssx)
- ssx = s->sx;
- if (s->sy < ssy)
- ssy = s->sy;
- }
- }
- if (ssx == UINT_MAX || ssy == UINT_MAX)
+ type = options_get_number(w->options, "window-size");
+ if (type == WINDOW_SIZE_MANUAL)
continue;
-
- forced = 0;
- limit = options_get_number(w->options, "force-width");
- if (limit >= PANE_MINIMUM && ssx > limit) {
- ssx = limit;
- forced |= WINDOW_FORCEWIDTH;
- }
- limit = options_get_number(w->options, "force-height");
- if (limit >= PANE_MINIMUM && ssy > limit) {
- ssy = limit;
- forced |= WINDOW_FORCEHEIGHT;
+ current = !options_get_number(w->options, "aggressive-resize");
+
+ changed = 1;
+ if (type == WINDOW_SIZE_LARGEST) {
+ sx = sy = 0;
+ TAILQ_FOREACH(c, &clients, entry) {
+ if ((s = c->session) == NULL)
+ continue;
+ if (current)
+ has = (s->curw->window == w);
+ else
+ has = session_has(s, w);
+ if (!has)
+ continue;
+
+ cx = c->tty.sx;
+ cy = c->tty.sy - status_line_size(c);
+
+ if (cx > sx)
+ sx = cx;
+ if (cy > sy)
+ sy = cy;
+ }
+ if (sx == 0 || sy == 0)
+ changed = 0;
+ } else {
+ sx = sy = UINT_MAX;
+ TAILQ_FOREACH(c, &clients, entry) {
+ if ((s = c->session) == NULL)
+ continue;
+ if (current)
+ has = (s->curw->window == w);
+ else
+ has = session_has(s, w);
+ if (!has)
+ continue;
+
+ cx = c->tty.sx;
+ cy = c->tty.sy - status_line_size(c);
+
+ if (cx < sx)
+ sx = cx;
+ if (cy < sy)
+ sy = cy;
+ }
+ if (sx == UINT_MAX || sy == UINT_MAX)
+ changed = 0;
}
+ if (w->sx == sx && w->sy == sy)
+ changed = 0;
- if (w->sx == ssx && w->sy == ssy)
+ if (!changed) {
+ tty_update_window_offset(w);
continue;
- log_debug("window @%u size %u,%u (was %u,%u)", w->id, ssx, ssy,
- w->sx, w->sy);
-
- w->flags &= ~(WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT);
- w->flags |= forced;
-
- is_zoomed = w->flags & WINDOW_ZOOMED;
- if (is_zoomed)
- window_unzoom(w);
- layout_resize(w, ssx, ssy);
- window_resize(w, ssx, ssy);
- if (is_zoomed && window_pane_visible(w->active))
- window_zoom(w->active);
-
- /*
- * If the current pane is now not visible, move to the next
- * that is.
- */
- wp = w->active;
- while (!window_pane_visible(w->active)) {
- w->active = TAILQ_PREV(w->active, window_panes, entry);
- if (w->active == NULL)
- w->active = TAILQ_LAST(&w->panes, window_panes);
- if (w->active == wp)
- break;
}
- if (w->active == w->last)
- w->last = NULL;
-
- server_redraw_window(w);
- notify_window("window-layout-changed", w);
+ log_debug("%s: @%u changed to %u,%u", __func__, w->id, sx, sy);
+ resize_window(w, sx, sy);
}
}
diff --git a/screen-redraw.c b/screen-redraw.c
index 95774633..167389b4 100644
--- a/screen-redraw.c
+++ b/screen-redraw.c
@@ -33,11 +33,15 @@ struct screen_redraw_ctx {
u_int sx;
u_int sy;
+ u_int ox;
+ u_int oy;
};
static void screen_redraw_draw_borders(struct screen_redraw_ctx *);
static void screen_redraw_draw_panes(struct screen_redraw_ctx *);
static void screen_redraw_draw_status(struct screen_redraw_ctx *);
+static void screen_redraw_draw_pane(struct screen_redraw_ctx *,
+ struct window_pane *);
static void screen_redraw_draw_number(struct screen_redraw_ctx *,
struct window_pane *);
@@ -320,25 +324,56 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
{
struct client *c = ctx->c;
struct window *w = c->session->curw->window;
- struct options *oo = c->session->options;
struct tty *tty = &c->tty;
struct window_pane *wp;
- int spos;
- u_int yoff;
+ struct screen *s;
+ u_int i, x, width, xoff, yoff, size;
+
+ log_debug("%s: %s @%u", __func__, c->name, w->id);
- spos = options_get_number(oo, "status-position");
TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp))
continue;
+ s = &wp->status_screen;
+
+ size = wp->status_size;
if (ctx->pane_status == CELL_STATUS_TOP)
yoff = wp->yoff - 1;
else
yoff = wp->yoff + wp->sy;
- if (spos == 0)
- yoff += 1;
+ xoff = wp->xoff + 2;
+
+ if (xoff + size <= ctx->ox ||
+ xoff >= ctx->ox + ctx->sx ||
+ yoff < ctx->oy ||
+ yoff >= ctx->oy + ctx->sy)
+ continue;
+
+ if (xoff >= ctx->ox && xoff + size <= ctx->ox + ctx->sx) {
+ /* All visible. */
+ i = 0;
+ x = xoff - ctx->ox;
+ width = size;
+ } else if (xoff < ctx->ox && xoff + size > ctx->ox + ctx->sx) {
+ /* Both left and right not visible. */
+ i = ctx->ox;
+ x = 0;
+ width = ctx->sx;
+ } else if (xoff < ctx->ox) {
+ /* Left not visible. */
+ i = ctx->ox - xoff;
+ x = 0;
+ width = size - i;
+ } else {
+ /* Right not visible. */
+ i = 0;
+ x = xoff - ctx->ox;
+ width = size - x;
+ }
- tty_draw_line(tty, NULL, &wp->status_screen, 0, wp->xoff + 2,
- yoff);
+ if (ctx->top)
+ yoff += ctx->lines;
+ tty_draw_line(tty, NULL, s, i, 0, width, x, yoff - ctx->oy);
}
tty_cursor(tty, 0, 0);
}
@@ -385,13 +420,17 @@ screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx)
memset(ctx, 0, sizeof *ctx);
ctx->c = c;
- ctx->lines = tty_status_lines(c);
+ ctx->lines = status_line_size(c);
+ if (c->message_string != NULL || c->prompt_string != NULL)
+ ctx->lines = (ctx->lines == 0) ? 1 : ctx->lines;
if (ctx->lines != 0 && options_get_number(oo, "status-position") == 0)
ctx->top = 1;
ctx->pane_status = options_get_number(wo, "pane-border-status");
- ctx->sx = c->tty.sx;
- ctx->sy = c->tty.sy - ctx->lines;
+ tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy);
+
+ log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name,
+ w->id, ctx->ox, ctx->oy, ctx->sx, ctx->sy, ctx->lines, ctx->top);
}
/* Redraw entire screen. */
@@ -420,33 +459,26 @@ screen_redraw_screen(struct client *c)
tty_reset(&c->tty);
}
-/* Draw a single pane. */
+/* Redraw a single pane. */
void
screen_redraw_pane(struct client *c, struct window_pane *wp)
{
- u_int i, yoff;
+ struct screen_redraw_ctx ctx;
if (!window_pane_visible(wp))
return;
- yoff = wp->yoff;
- if (status_at_line(c) == 0)
- yoff += status_line_size(c->session);
-
- log_debug("%s: redraw pane %%%u (at %u,%u)", c->name, wp->id,
- wp->xoff, yoff);
+ screen_redraw_set_context(c, &ctx);
- for (i = 0; i < wp->sy; i++)
- tty_draw_pane(&c->tty, wp, i, wp->xoff, yoff);
+ screen_redraw_draw_pane(&ctx, wp);
tty_reset(&c->tty);
}
/* Draw a border cell. */
static void
-screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int x, u_int y,
- int small, u_int msgx, u_int msgy, struct grid_cell *m_active_gc,
- struct grid_cell *active_gc, struct grid_cell *m_other_gc,
- struct grid_cell *other_gc)
+screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j,
+ struct grid_cell *m_active_gc, struct grid_cell *active_gc,
+ struct grid_cell *m_other_gc, struct grid_cell *other_gc)
{
struct client *c = ctx->c;
struct session *s = c->session;
@@ -455,14 +487,12 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int x, u_int y,
struct window_pane *wp;
struct window_pane *active = w->active;
struct window_pane *marked = marked_pane.wp;
- u_int type;
+ u_int type, x = ctx->ox + i, y = ctx->oy + j;
int flag, pane_status = ctx->pane_status;
type = screen_redraw_check_cell(c, x, y, pane_status, &wp);
if (type == CELL_INSIDE)
return;
- if (type == CELL_OUTSIDE && small && x > msgx && y == msgy)
- return;
flag = screen_redraw_check_is(x, y, type, pane_status, w, active, wp);
if (server_is_marked(s, s->curw, marked_pane.wp) &&
@@ -476,9 +506,9 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int x, u_int y,
else
tty_attributes(tty, other_gc, NULL);
if (ctx->top)
- tty_cursor(tty, x, ctx->lines + y);
+ tty_cursor(tty, i, ctx->lines + j);
else
- tty_cursor(tty, x, y);
+ tty_cursor(tty, i, j);
tty_putc(tty, CELL_BORDERS[type]);
}
@@ -489,42 +519,12 @@ screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
struct client *c = ctx->c;
struct session *s = c->session;
struct window *w = s->curw->window;
- struct options *oo = w->options;
struct tty *tty = &c->tty;
+ struct options *oo = w->options;
struct grid_cell m_active_gc, active_gc, m_other_gc, other_gc;
- struct grid_cell msg_gc;
- u_int i, j, msgx = 0, msgy = 0;
- int small, flags;
- char msg[256];
- const char *tmp;
- size_t msglen = 0;
-
- small = (ctx->sy + ctx->top > w->sy) || (ctx->sx > w->sx);
- if (small) {
- flags = w->flags & (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT);
- if (flags == (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT))
- tmp = "force-width, force-height";
- else if (flags == WINDOW_FORCEWIDTH)
- tmp = "force-width";
- else if (flags == WINDOW_FORCEHEIGHT)
- tmp = "force-height";
- else if (c->flags & CLIENT_STATUSOFF)
- tmp = "status line";
- else
- tmp = "a smaller client";
- xsnprintf(msg, sizeof msg, "(size %ux%u from %s)",
- w->sx, w->sy, tmp);
- msglen = strlen(msg);
-
- if (ctx->sy - 1 + ctx->top > w->sy && ctx->sx >= msglen) {
- msgx = ctx->sx - msglen;
- msgy = ctx->sy - 1 + ctx->top;
- } else if (ctx->sx - w->sx > msglen) {
- msgx = ctx->sx - msglen;
- msgy = ctx->sy - 1 + ctx->top;
- } else
- small = 0;
- }
+ u_int i, j;
+
+ log_debug("%s: %s @%u", __func__, c->name, w->id);
style_apply(&other_gc, oo, "pane-border-style");
style_apply(&active_gc, oo, "pane-active-border-style");
@@ -535,20 +535,12 @@ screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
memcpy(&m_active_gc, &active_gc, sizeof m_active_gc);
m_active_gc.attr ^= GRID_ATTR_REVERSE;
- for (j = 0; j < ctx->sy; j++) {
- for (i = 0; i < ctx->sx; i++) {
- screen_redraw_draw_borders_cell(ctx, i, j, small,
- msgx, msgy, &m_active_gc, &active_gc, &m_other_gc,
- &other_gc);
+ for (j = 0; j < tty->sy - ctx->lines; j++) {
+ for (i = 0; i < tty->sx; i++) {
+ screen_redraw_draw_borders_cell(ctx, i, j,
+ &m_active_gc, &active_gc, &m_other_gc, &other_gc);
}
}
-
- if (small) {
- memcpy(&msg_gc, &grid_default_cell, sizeof msg_gc);
- tty_attributes(tty, &msg_gc, NULL);
- tty_cursor(tty, msgx, msgy);
- tty_puts(tty, msg);
- }
}
/* Draw the panes. */
@@ -557,19 +549,14 @@ screen_redraw_draw_panes(struct screen_redraw_ctx *ctx)
{
struct client *c = ctx->c;
struct window *w = c->session->curw->window;
- struct tty *tty = &c->tty;
struct window_pane *wp;
- u_int i, y;
- if (ctx->top)
- y = ctx->lines;
- else
- y = 0;
+ log_debug("%s: %s @%u", __func__, c->name, w->id);
+
TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp))
continue;
- for (i = 0; i < wp->sy; i++)
- tty_draw_pane(tty, wp, i, wp->xoff, y + wp->yoff);
+ screen_redraw_draw_pane(ctx, wp);
if (c->flags & CLIENT_IDENTIFY)
screen_redraw_draw_number(ctx, wp);
}
@@ -580,15 +567,74 @@ static void
screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
{
struct client *c = ctx->c;
+ struct window *w = c->session->curw->window;
struct tty *tty = &c->tty;
+ struct screen *s = &c->status.status;
u_int i, y;
+ log_debug("%s: %s @%u", __func__, c->name, w->id);
+
if (ctx->top)
y = 0;
else
- y = ctx->sy;
+ y = c->tty.sy - ctx->lines;
for (i = 0; i < ctx->lines; i++)
- tty_draw_line(tty, NULL, &c->status.status, i, 0, y);
+ tty_draw_line(tty, NULL, s, 0, i, UINT_MAX, 0, y + i);
+}
+
+/* Draw one pane. */
+static void
+screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
+{
+ struct client *c = ctx->c;
+ struct window *w = c->session->curw->window;
+ struct tty *tty = &c->tty;
+ struct screen *s;
+ u_int i, j, top, x, y, width;
+
+ log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
+
+ if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx)
+ return;
+ if (ctx->top)
+ top = ctx->lines;
+ else
+ top = 0;
+
+ s = wp->screen;
+ for (j = 0; j < wp->sy; j++) {
+ if (wp->yoff + j < ctx->oy || wp->yoff + j >= ctx->oy + ctx->sy)
+ continue;
+ y = top + wp->yoff + j - ctx->oy;
+
+ if (wp->xoff >= ctx->ox &&
+ wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
+ /* All visible. */
+ i = 0;
+ x = wp->xoff - ctx->ox;
+ width = wp->sx;
+ } else if (wp->xoff < ctx->ox &&
+ wp->xoff + wp->sx > ctx->ox + ctx->sx) {
+ /* Both left and right not visible. */
+ i = ctx->ox;
+ x = 0;
+ width = ctx->sx;
+ } else if (wp->xoff < ctx->ox) {
+ /* Left not visible. */
+ i = ctx->ox - wp->xoff;
+ x = 0;
+ width = wp->sx - i;
+ } else {
+ /* Right not visible. */
+ i = 0;
+ x = wp->xoff - ctx->ox;
+ width = ctx->sx - x;
+ }
+ log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u",
+ __func__, c->name, wp->id, i, j, x, y, width);
+
+ tty_draw_line(tty, wp, s, i, j, width, x, y);
+ }
}
/* Draw number on a pane. */
@@ -601,27 +647,69 @@ screen_redraw_draw_number(struct screen_redraw_ctx *ctx, struct window_pane *wp)
struct options *oo = s->options;
struct window *w = wp->window;
struct grid_cell gc;
- u_int idx, px, py, i, j, xoff, yoff;
+ u_int idx, px, py, i, j, xoff, yoff, sx, sy;
int colour, active_colour;
char buf[16], *ptr;
size_t len;
+ if (wp->xoff + wp->sx <= ctx->ox ||
+ wp->xoff >= ctx->ox + ctx->sx ||
+ wp->yoff + wp->sy <= ctx->oy ||
+ wp->yoff >= ctx->oy + ctx->sy)
+ return;
+
+ if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
+ /* All visible. */
+ xoff = wp->xoff - ctx->ox;
+ sx = wp->sx;
+ } else if (wp->xoff < ctx->ox &&
+ wp->xoff + wp->sx > ctx->ox + ctx->sx) {
+ /* Both left and right not visible. */
+ xoff = 0;
+ sx = ctx->sx;
+ } else if (wp->xoff < ctx->ox) {
+ /* Left not visible. */
+ xoff = 0;
+ sx = wp->sx - (ctx->ox - wp->xoff);
+ } else {
+ /* Right not visible. */
+ xoff = wp->xoff - ctx->ox;
+ sx = wp->sx - xoff;
+ }
+ if (wp->yoff >= ctx->oy && wp->yoff + wp->sy <= ctx->oy + ctx->sy) {
+ /* All visible. */
+ yoff = wp->yoff - ctx->oy;
+ sy = wp->sy;
+ } else if (wp->yoff < ctx->oy &&
+ wp->yoff + wp->sy > ctx->oy + ctx->sy) {
+ /* Both top and bottom not visible. */
+ yoff = 0;
+ sy = ctx->sy;
+ } else if (wp->yoff < ctx->oy) {
+ /* Top not visible. */
+ yoff = 0;
+ sy = wp->sy - (ctx->oy - wp->yoff);
+ } else {
+ /* Bottom not visible. */
+ yoff = wp->yoff - ctx->oy;
+ sy = wp->sy - yoff;
+ }
+
+ if (ctx->top)
+ yoff += ctx->lines;
+ px = sx / 2;
+ py = sy / 2;
+
if (window_pane_index(wp, &idx) != 0)
fatalx("index not found");
len = xsnprintf(buf, sizeof buf, "%u", idx);
- if (wp->sx < len)
+ if (sx < len)
return;
colour = options_get_number(oo, "display-panes-colour");
active_colour = options_get_number(oo, "display-panes-active-colour");
- px = wp->sx / 2; py = wp->sy / 2;
- xoff = wp->xoff; yoff = wp->yoff;
-
- if (ctx->top)
- yoff += ctx->lines;
-
- if (wp->sx < len * 6 || wp->sy < 5) {
+ if (sx < len * 6 || sy < 5) {
tty_cursor(tty, xoff + px - len / 2, yoff + py);
goto draw_text;
}
@@ -653,9 +741,9 @@ screen_redraw_draw_number(struct screen_redraw_ctx *ctx, struct window_pane *wp)
}
len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
- if (wp->sx < len || wp->sy < 6)
+ if (sx < len || sy < 6)
return;
- tty_cursor(tty, xoff + wp->sx - len, yoff);
+ tty_cursor(tty, xoff + sx - len, yoff);
draw_text:
memcpy(&gc, &grid_default_cell, sizeof gc);
diff --git a/screen-write.c b/screen-write.c
index fac5229e..4f5bee61 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -54,12 +54,47 @@ struct screen_write_collect_line {
TAILQ_HEAD(, screen_write_collect_item) items;
};
+static void
+screen_write_offset_timer(__unused int fd, __unused short events, void *data)
+{
+ struct window *w = data;
+
+ tty_update_window_offset(w);
+}
+
+/* Set cursor position. */
+static void
+screen_write_set_cursor(struct screen_write_ctx *ctx, int cx, int cy)
+{
+ struct window_pane *wp = ctx->wp;
+ struct window *w;
+ struct screen *s = ctx->s;
+ struct timeval tv = { .tv_usec = 10000 };
+
+ if (cx != -1 && (u_int)cx == s->cx && cy != -1 && (u_int)cy == s->cy)
+ return;
+
+ if (cx != -1)
+ s->cx = cx;
+ if (cy != -1)
+ s->cy = cy;
+
+ if (wp == NULL)
+ return;
+ w = wp->window;
+
+ if (!event_initialized(&w->offset_timer))
+ evtimer_set(&w->offset_timer, screen_write_offset_timer, w);
+ if (!evtimer_pending(&w->offset_timer, NULL))
+ evtimer_add(&w->offset_timer, &tv);
+}
+
/* Initialize writing with a window. */
void
screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
struct screen *s)
{
- char tmp[16];
+ char tmp[32];
u_int y;
memset(ctx, 0, sizeof *ctx);
@@ -78,8 +113,10 @@ screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
ctx->scrolled = 0;
ctx->bg = 8;
- if (wp != NULL)
- snprintf(tmp, sizeof tmp, "pane %%%u", wp->id);
+ if (wp != NULL) {
+ snprintf(tmp, sizeof tmp, "pane %%%u (at %u,%u)", wp->id,
+ wp->xoff, wp->yoff);
+ }
log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s),
screen_size_y(ctx->s), wp == NULL ? "no pane" : tmp);
}
@@ -603,25 +640,26 @@ void
screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
{
struct screen *s = ctx->s;
+ u_int cx = s->cx, cy = s->cy;
if (ny == 0)
ny = 1;
- if (s->cy < s->rupper) {
+ if (cy < s->rupper) {
/* Above region. */
- if (ny > s->cy)
- ny = s->cy;
+ if (ny > cy)
+ ny = cy;
} else {
/* Below region. */
- if (ny > s->cy - s->rupper)
- ny = s->cy - s->rupper;
+ if (ny > cy - s->rupper)
+ ny = cy - s->rupper;
}
- if (s->cx == screen_size_x(s))
- s->cx--;
- if (ny == 0)
- return;
+ if (cx == screen_size_x(s))
+ cx--;
- s->cy -= ny;
+ cy -= ny;
+
+ screen_write_set_cursor(ctx, cx, cy);
}
/* Cursor down by ny. */
@@ -629,25 +667,28 @@ void
screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
{
struct screen *s = ctx->s;
+ u_int cx = s->cx, cy = s->cy;
if (ny == 0)
ny = 1;
- if (s->cy > s->rlower) {
+ if (cy > s->rlower) {
/* Below region. */
- if (ny > screen_size_y(s) - 1 - s->cy)
- ny = screen_size_y(s) - 1 - s->cy;
+ if (ny > screen_size_y(s) - 1 - cy)
+ ny = screen_size_y(s) - 1 - cy;
} else {
/* Above region. */
- if (ny > s->rlower - s->cy)
- ny = s->rlower - s->cy;
+ if (ny > s->rlower - cy)
+ ny = s->rlower - cy;
}
- if (s->cx == screen_size_x(s))
- s->cx--;
- if (ny == 0)
+ if (cx == screen_size_x(s))
+ cx--;
+ else if (ny == 0)
return;
- s->cy += ny;
+ cy += ny;
+
+ screen_write_set_cursor(ctx, cx, cy);
}
/* Cursor right by nx. */
@@ -655,16 +696,19 @@ void
screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
{
struct screen *s = ctx->s;
+ u_int cx = s->cx, cy = s->cy;
if (nx == 0)
nx = 1;
- if (nx > screen_size_x(s) - 1 - s->cx)
- nx = screen_size_x(s) - 1 - s->cx;
+ if (nx > screen_size_x(s) - 1 - cx)
+ nx = screen_size_x(s) - 1 - cx;
if (nx == 0)
return;
- s->cx += nx;
+ cx += nx;
+
+ screen_write_set_cursor(ctx, cx, cy);
}
/* Cursor left by nx. */
@@ -672,16 +716,19 @@ void
screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
{
struct screen *s = ctx->s;
+ u_int cx = s->cx, cy = s->cy;
if (nx == 0)
nx = 1;
- if (nx > s->cx)
- nx = s->cx;
+ if (nx > cx)
+ nx = cx;
if (nx == 0)
return;
- s->cx -= nx;
+ cx -= nx;
+
+ screen_write_set_cursor(ctx, cx, cy);
}
/* Backspace; cursor left unless at start of wrapped line when can move up. */
@@ -690,17 +737,20 @@ screen_write_backspace(struct screen_write_ctx *ctx)
{
struct screen *s = ctx->s;
struct grid_line *gl;
+ u_int cx = s->cx, cy = s->cy;
- if (s->cx == 0) {
- if (s->cy == 0)
+ if (cx == 0) {
+ if (cy == 0)
return;
- gl = grid_get_line(s->grid, s->grid->hsize + s->cy - 1);
+ gl = grid_get_line(s->grid, s->grid->hsize + cy - 1);
if (gl->flags & GRID_LINE_WRAPPED) {
- s->cy--;
- s->cx = screen_size_x(s) - 1;
+ cy--;
+ cx = screen_size_x(s) - 1;
}
} else
- s->cx--;
+ cx--;
+
+ screen_write_set_cursor(ctx, cx, cy);
}
/* VT100 alignment test. */
@@ -712,8 +762,6 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
struct grid_cell gc;
u_int xx, yy;
- screen_write_initctx(ctx, &ttyctx);
-
memcpy(&gc, &grid_default_cell, sizeof gc);
utf8_set(&gc.data, 'E');
@@ -722,8 +770,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
grid_view_set_cell(s->grid, xx, yy, &gc);
}
- s->cx = 0;
- s->cy = 0;
+ screen_write_set_cursor(ctx, 0, 0);
s->rupper = 0;
s->rlower = screen_size_y(s) - 1;
@@ -988,8 +1035,7 @@ screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py)
if (py > screen_size_y(s) - 1)
py = screen_size_y(s) - 1;
- s->cx = px;
- s->cy = py;
+ screen_write_set_cursor(ctx, px, py);
}
/* Reverse index (up with scroll). */
@@ -1005,7 +1051,7 @@ screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg)
if (s->cy == s->rupper)
grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg);
else if (s->cy > 0)
- s->cy--;
+ screen_write_set_cursor(ctx, -1, s->cy - 1);
screen_write_collect_flush(ctx, 0);
tty_write(tty_cmd_reverseindex, &ttyctx);
@@ -1028,8 +1074,7 @@ screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper,
screen_write_collect_flush(ctx, 0);
/* Cursor moves to top-left. */
- s->cx = 0;
- s->cy = 0;
+ screen_write_set_cursor(ctx, 0, 0);
s->rupper = rupper;
s->rlower = rlower;
@@ -1062,7 +1107,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
screen_write_collect_scroll(ctx);
ctx->scrolled++;
} else if (s->cy < screen_size_y(s) - 1)
- s->cy++;
+ screen_write_set_cursor(ctx, -1, s->cy + 1);
}
/* Scroll up. */
@@ -1094,9 +1139,7 @@ screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines, u_int bg)
void
screen_write_carriagereturn(struct screen_write_ctx *ctx)
{
- struct screen *s = ctx->s;
-
- s->cx = 0;
+ screen_write_set_cursor(ctx, 0, -1);
}
/* Clear to end of screen from cursor. */
@@ -1300,14 +1343,15 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
grid_view_set_cell(s->grid, xx, s->cy,
&grid_default_cell);
}
- if (gc.data.width > 1)
+ if (gc.data.width > 1) {
grid_view_set_cell(s->grid, xx, s->cy,
&grid_default_cell);
+ }
}
memcpy(&gc, &ci->gc, sizeof gc);
grid_view_set_cells(s->grid, s->cx, s->cy, &gc, ci->data, ci->used);
- s->cx += ci->used;
+ screen_write_set_cursor(ctx, s->cx + ci->used, -1);
for (xx = s->cx; xx < screen_size_x(s); xx++) {
grid_view_get_cell(s->grid, xx, s->cy, &gc);
@@ -1361,7 +1405,7 @@ screen_write_collect_add(struct screen_write_ctx *ctx,
log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy);
ci->wrapped = 1;
screen_write_linefeed(ctx, 1, 8);
- s->cx = 0;
+ screen_write_set_cursor(ctx, 0, -1);
}
if (ci->used == 0)
@@ -1423,7 +1467,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
if ((s->mode & MODE_WRAP) && s->cx > sx - width) {
log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy);
screen_write_linefeed(ctx, 1, 8);
- s->cx = 0;
+ screen_write_set_cursor(ctx, 0, -1);
screen_write_collect_flush(ctx, 1);
}
@@ -1496,9 +1540,9 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
*/
last = !(s->mode & MODE_WRAP);
if (s->cx <= sx - last - width)
- s->cx += width;
+ screen_write_set_cursor(ctx, s->cx + width, -1);
else
- s->cx = sx - last;
+ screen_write_set_cursor(ctx, sx - last, -1);
/* Create space for character in insert mode. */
if (s->mode & MODE_INSERT) {
diff --git a/server-client.c b/server-client.c
index afc390c7..aefe006e 100644
--- a/server-client.c
+++ b/server-client.c
@@ -194,6 +194,7 @@ server_client_create(int fd)
c->session = NULL;
c->last_session = NULL;
+
c->tty.sx = 80;
c->tty.sy = 24;
@@ -412,7 +413,7 @@ server_client_check_mouse(struct client *c)
struct mouse_event *m = &c->tty.mouse;
struct window *w;
struct window_pane *wp;
- u_int x, y, b;
+ u_int x, y, b, sx, sy, px, py;
int flag;
key_code key;
struct timeval tv;
@@ -422,8 +423,8 @@ server_client_check_mouse(struct client *c)
type = NOTYPE;
where = NOWHERE;
- log_debug("mouse %02x at %u,%u (last %u,%u) (%d)", m->b, m->x, m->y,
- m->lx, m->ly, c->tty.mouse_drag_flag);
+ log_debug("%s mouse %02x at %u,%u (last %u,%u) (%d)", c->name, m->b,
+ m->x, m->y, m->lx, m->ly, c->tty.mouse_drag_flag);
/* What type of event is this? */
if ((m->sgr_type != ' ' &&
@@ -442,7 +443,7 @@ server_client_check_mouse(struct client *c)
x = m->x, y = m->y, b = m->b;
log_debug("drag update at %u,%u", x, y);
} else {
- x = m->lx, y = m->ly, b = m->lb;
+ x = m->lx - m->ox, y = m->ly - m->oy, b = m->lb;
log_debug("drag start at %u,%u", x, y);
}
} else if (MOUSE_WHEEL(m->b)) {
@@ -518,20 +519,33 @@ have_event:
/* Not on status line. Adjust position and check for border or pane. */
if (where == NOWHERE) {
+ px = x;
if (m->statusat == 0 && y > 0)
- y--;
+ py = y - 1;
else if (m->statusat > 0 && y >= (u_int)m->statusat)
- y = m->statusat - 1;
+ py = m->statusat - 1;
+ else
+ py = y;
+
+ tty_window_offset(&c->tty, &m->ox, &m->oy, &sx, &sy);
+ log_debug("mouse window @%u at %u,%u (%ux%u)",
+ s->curw->window->id, m->ox, m->oy, sx, sy);
+ if (px > sx || py > sy)
+ return (KEYC_UNKNOWN);
+ px = px + m->ox;
+ py = py + m->oy;
+ m->x = x + m->ox;
+ m->y = y + m->oy;
/* Try the pane borders if not zoomed. */
if (~s->curw->window->flags & WINDOW_ZOOMED) {
TAILQ_FOREACH(wp, &s->curw->window->panes, entry) {
- if ((wp->xoff + wp->sx == x &&
- wp->yoff <= 1 + y &&
- wp->yoff + wp->sy >= y) ||
- (wp->yoff + wp->sy == y &&
- wp->xoff <= 1 + x &&
- wp->xoff + wp->sx >= x))
+ if ((wp->xoff + wp->sx == px &&
+ wp->yoff <= 1 + py &&
+ wp->yoff + wp->sy >= py) ||
+ (wp->yoff + wp->sy == py &&
+ wp->xoff <= 1 + px &&
+ wp->xoff + wp->sx >= px))
break;
}
if (wp != NULL)
@@ -540,7 +554,7 @@ have_event:
/* Otherwise try inside the pane. */
if (where == NOWHERE) {
- wp = window_get_active_at(s->curw->window, x, y);
+ wp = window_get_active_at(s->curw->window, px, py);
if (wp != NULL)
where = PANE;
}
@@ -928,8 +942,6 @@ server_client_handle_key(struct client *c, key_code key)
return;
window_unzoom(w);
wp = window_pane_at_index(w, key - '0');
- if (wp != NULL && !window_pane_visible(wp))
- wp = NULL;
server_client_clear_identify(c, wp);
return;
}
@@ -1304,28 +1316,37 @@ server_client_reset_state(struct client *c)
struct window_pane *wp = w->active, *loop;
struct screen *s = wp->screen;
struct options *oo = c->session->options;
- int lines, mode;
+ int mode, cursor = 0;
+ u_int cx = 0, cy = 0, ox, oy, sx, sy;
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return;
+ mode = s->mode;
tty_region_off(&c->tty);
tty_margin_off(&c->tty);
- if (status_at_line(c) != 0)
- lines = 0;
- else
- lines = status_line_size(c->session);
- if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - lines)
- tty_cursor(&c->tty, 0, 0);
- else
- tty_cursor(&c->tty, wp->xoff + s->cx, lines + wp->yoff + s->cy);
+ /* Move cursor to pane cursor and offset. */
+ cursor = 0;
+ tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
+ if (wp->xoff + s->cx >= ox && wp->xoff + s->cx <= ox + sx &&
+ wp->yoff + s->cy >= oy && wp->yoff + s->cy <= oy + sy) {
+ cursor = 1;
+
+ cx = wp->xoff + s->cx - ox;
+ cy = wp->yoff + s->cy - oy;
+
+ if (status_at_line(c) == 0)
+ cy += status_line_size(c);
+ }
+ if (!cursor)
+ mode &= ~MODE_CURSOR;
+ tty_cursor(&c->tty, cx, cy);
/*
* Set mouse mode if requested. To support dragging, always use button
* mode.
*/
- mode = s->mode;
if (options_get_number(oo, "mouse")) {
mode &= ~ALL_MOUSE_MODES;
TAILQ_FOREACH(loop, &w->panes, entry) {
diff --git a/server-fn.c b/server-fn.c
index c4429033..ae90f0c4 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -409,6 +409,7 @@ server_destroy_session(struct session *s)
c->last_session = NULL;
c->session = s_new;
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_new, NULL);
diff --git a/session.c b/session.c
index 1a109a83..061ff499 100644
--- a/session.c
+++ b/session.c
@@ -113,8 +113,8 @@ session_find_by_id(u_int id)
/* Create a new session. */
struct session *
session_create(const char *prefix, const char *name, int argc, char **argv,
- const char *path, const char *cwd, struct environ *env, struct termios *tio,
- int idx, u_int sx, u_int sy, char **cause)
+ const char *path, const char *cwd, struct environ *env, struct options *oo,
+ struct termios *tio, int idx, char **cause)
{
struct session *s;
struct winlink *wl;
@@ -133,7 +133,7 @@ session_create(const char *prefix, const char *name, int argc, char **argv,
if (env != NULL)
environ_copy(env, s->environ);
- s->options = options_create(global_s_options);
+ s->options = oo;
s->hooks = hooks_create(global_hooks);
status_update_saved(s);
@@ -144,9 +144,6 @@ session_create(const char *prefix, const char *name, int argc, char **argv,
memcpy(s->tio, tio, sizeof *s->tio);
}
- s->sx = sx;
- s->sy = sy;
-
if (name != NULL) {
s->name = xstrdup(name);
s->id = next_session_id++;
@@ -350,7 +347,7 @@ session_new(struct session *s, const char *name, int argc, char **argv,
struct winlink *wl;
struct environ *env;
const char *shell;
- u_int hlimit;
+ u_int hlimit, sx, sy;
if ((wl = winlink_add(&s->windows, idx)) == NULL) {
xasprintf(cause, "index in use: %d", idx);
@@ -362,10 +359,11 @@ session_new(struct session *s, const char *name, int argc, char **argv,
if (*shell == '\0' || areshell(shell))
shell = _PATH_BSHELL;
+ default_window_size(s, NULL, &sx, &sy, -1);
hlimit = options_get_number(s->options, "history-limit");
env = environ_for_session(s, 0);
w = window_create_spawn(name, argc, argv, path, shell, cwd, env, s->tio,
- s->sx, s->sy, hlimit, cause);
+ sx, sy, hlimit, cause);
if (w == NULL) {
winlink_remove(&s->windows, wl);
environ_free(env);
@@ -548,6 +546,7 @@ session_set_current(struct session *s, struct winlink *wl)
s->curw = wl;
winlink_clear_flags(wl);
window_update_activity(wl->window);
+ tty_update_window_offset(wl->window);
notify_session("session-window-changed", s);
return (0);
}
diff --git a/status.c b/status.c
index 10f9f290..211da9fc 100644
--- a/status.c
+++ b/status.c
@@ -214,17 +214,17 @@ status_at_line(struct client *c)
return (-1);
if (s->statusat != 1)
return (s->statusat);
- return (c->tty.sy - status_line_size(s));
+ return (c->tty.sy - status_line_size(c));
}
-/*
- * Get size of status line for session. 0 means off. Note that status line may
- * be forced off for an individual client if it is too small (the
- * CLIENT_STATUSOFF flag is set for this).
- */
+/* Get size of status line for client's session. 0 means off. */
u_int
-status_line_size(struct session *s)
+status_line_size(struct client *c)
{
+ struct session *s = c->session;
+
+ if (c->flags & CLIENT_STATUSOFF)
+ return (0);
if (s->statusat == -1)
return (0);
return (1);
@@ -324,7 +324,7 @@ status_redraw(struct client *c)
}
/* No status line? */
- lines = status_line_size(s);
+ lines = status_line_size(c);
if (c->tty.sy == 0 || lines == 0)
return (1);
left = right = NULL;
@@ -663,7 +663,7 @@ status_message_redraw(struct client *c)
return (0);
memcpy(&old_status, &c->status.status, sizeof old_status);
- lines = status_line_size(c->session);
+ lines = status_line_size(c);
if (lines <= 1) {
lines = 1;
screen_init(&c->status.status, c->tty.sx, 1, 0);
@@ -819,7 +819,7 @@ status_prompt_redraw(struct client *c)
return (0);
memcpy(&old_status, &c->status.status, sizeof old_status);
- lines = status_line_size(c->session);
+ lines = status_line_size(c);
if (lines <= 1) {
lines = 1;
screen_init(&c->status.status, c->tty.sx, 1, 0);
diff --git a/tmux.h b/tmux.h
index 7b451ada..f1727d23 100644
--- a/tmux.h
+++ b/tmux.h
@@ -57,11 +57,17 @@ struct tmuxproc;
#define PROTOCOL_VERSION 8
/* Default global configuration file. */
+#ifndef TMUX_CONF
#define TMUX_CONF "/etc/tmux.conf"
+#endif
/* Minimum layout cell size, NOT including border lines. */
#define PANE_MINIMUM 1
+/* Minimum and maximum window size. */
+#define WINDOW_MINIMUM PANE_MINIMUM
+#define WINDOW_MAXIMUM 10000
+
/* Automatic name refresh interval, in microseconds. Must be < 1 second. */
#define NAME_INTERVAL 500000
@@ -789,6 +795,7 @@ struct window {
struct timeval name_time;
struct event alerts_timer;
+ struct event offset_timer;
struct timeval activity_time;
@@ -809,9 +816,7 @@ struct window {
#define WINDOW_ACTIVITY 0x2
#define WINDOW_SILENCE 0x4
#define WINDOW_ZOOMED 0x8
-#define WINDOW_FORCEWIDTH 0x10
-#define WINDOW_FORCEHEIGHT 0x20
-#define WINDOW_STYLECHANGED 0x40
+#define WINDOW_STYLECHANGED 0x10
#define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE)
int alerts_queued;
@@ -852,6 +857,11 @@ struct winlink {
RB_HEAD(winlinks, winlink);
TAILQ_HEAD(winlink_stack, winlink);
+/* Window size option. */
+#define WINDOW_SIZE_LARGEST 0
+#define WINDOW_SIZE_SMALLEST 1
+#define WINDOW_SIZE_MANUAL 2
+
/* Layout direction. */
enum layout_type {
LAYOUT_LEFTRIGHT,
@@ -910,9 +920,6 @@ struct session {
struct event lock_timer;
- u_int sx;
- u_int sy;
-
struct winlink *curw;
struct winlink_stack lastw;
struct winlinks windows;
@@ -972,6 +979,9 @@ struct mouse_event {
u_int ly;
u_int lb;
+ u_int ox;
+ u_int oy;
+
int s;
int w;
int wp;
@@ -1019,6 +1029,12 @@ struct tty {
u_int cstyle;
char *ccolour;
+ int oflag;
+ u_int oox;
+ u_int ooy;
+ u_int osx;
+ u_int osy;
+
int mode;
u_int rlower;
@@ -1099,11 +1115,19 @@ struct tty_ctx {
u_int orupper;
u_int orlower;
+ /* Pane offset. */
u_int xoff;
u_int yoff;
/* The background colour used for clearing (erasing). */
u_int bg;
+
+ /* Window offset and size. */
+ int bigger;
+ u_int ox;
+ u_int oy;
+ u_int sx;
+ u_int sy;
};
/* Saved message entry. */
@@ -1341,11 +1365,16 @@ struct client {
#define CLIENT_SIZECHANGED 0x400000
#define CLIENT_STATUSOFF 0x800000
#define CLIENT_REDRAWSTATUSALWAYS 0x1000000
-#define CLIENT_ALLREDRAWFLAGS \
- (CLIENT_REDRAWWINDOW| \
- CLIENT_REDRAWSTATUS| \
- CLIENT_REDRAWSTATUSALWAYS| \
+#define CLIENT_ALLREDRAWFLAGS \
+ (CLIENT_REDRAWWINDOW| \
+ CLIENT_REDRAWSTATUS| \
+ CLIENT_REDRAWSTATUSALWAYS| \
CLIENT_REDRAWBORDERS)
+#define CLIENT_NOSIZEFLAGS \
+ (CLIENT_EXIT| \
+ CLIENT_DEAD| \
+ CLIENT_SUSPENDED| \
+ CLIENT_DETACHING)
int flags;
struct key_table *keytable;
@@ -1383,6 +1412,10 @@ struct client {
int references;
+ void *pan_window;
+ u_int pan_ox;
+ u_int pan_oy;
+
TAILQ_ENTRY(client) entry;
};
TAILQ_HEAD(clients, client);
@@ -1443,6 +1476,7 @@ struct options_table_entry {
const char *separator;
const char *style;
+ const char *pattern;
};
/* Common command usages. */
@@ -1643,7 +1677,10 @@ struct environ *environ_for_session(struct session *, int);
/* tty.c */
void tty_create_log(void);
-u_int tty_status_lines(struct client *);
+int tty_window_bigger(struct tty *);
+int tty_window_offset(struct tty *, u_int *, u_int *, u_int *, u_int *);
+void tty_update_window_offset(struct window *);
+void tty_update_client_offset(struct client *);
void tty_raw(struct tty *, const char *);
void tty_attributes(struct tty *, const struct grid_cell *,
const struct window_pane *);
@@ -1668,10 +1705,8 @@ void tty_start_tty(struct tty *);
void tty_stop_tty(struct tty *);
void tty_set_title(struct tty *, const char *);
void tty_update_mode(struct tty *, int, struct screen *);
-void tty_draw_pane(struct tty *, const struct window_pane *, u_int, u_int,
- u_int);
void tty_draw_line(struct tty *, const struct window_pane *, struct screen *,
- u_int, u_int, u_int);
+ u_int, u_int, u_int, u_int, u_int);
int tty_open(struct tty *, char **);
void tty_close(struct tty *);
void tty_free(struct tty *);
@@ -1904,9 +1939,9 @@ void server_unzoom_window(struct window *);
/* status.c */
void status_timer_start(struct client *);
void status_timer_start_all(void);
-void status_update_saved(struct session *s);
+void status_update_saved(struct session *);
int status_at_line(struct client *);
-u_int status_line_size(struct session *);
+u_int status_line_size(struct client *);
struct window *status_get_window_at(struct client *, u_int);
int status_redraw(struct client *);
void printflike(2, 3) status_message_set(struct client *, const char *, ...);
@@ -1922,6 +1957,9 @@ void status_prompt_load_history(void);
void status_prompt_save_history(void);
/* resize.c */
+void resize_window(struct window *, u_int, u_int);
+void default_window_size(struct session *, struct window *, u_int *,
+ u_int *, int);
void recalculate_sizes(void);
/* input.c */
@@ -1989,10 +2027,10 @@ void grid_view_scroll_region_up(struct grid *, u_int, u_int, u_int);
void grid_view_scroll_region_down(struct grid *, u_int, u_int, u_int);
void grid_view_insert_lines(struct grid *, u_int, u_int, u_int);
void grid_view_insert_lines_region(struct grid *, u_int, u_int, u_int,
- u_int);
+ u_int);
void grid_view_delete_lines(struct grid *, u_int, u_int, u_int);
void grid_view_delete_lines_region(struct grid *, u_int, u_int, u_int,
- u_int);
+ u_int);
void grid_view_insert_cells(struct grid *, u_int, u_int, u_int, u_int);
void grid_view_delete_cells(struct grid *, u_int, u_int, u_int, u_int);
char *grid_view_string_cells(struct grid *, u_int, u_int, u_int);
@@ -2180,7 +2218,7 @@ void layout_set_size(struct layout_cell *, u_int, u_int, u_int,
void layout_make_leaf(struct layout_cell *, struct window_pane *);
void layout_make_node(struct layout_cell *, enum layout_type);
void layout_fix_offsets(struct layout_cell *);
-void layout_fix_panes(struct window *, u_int, u_int);
+void layout_fix_panes(struct window *);
void layout_resize_adjust(struct window *, struct layout_cell *,
enum layout_type, int);
void layout_init(struct window *, struct window_pane *);
@@ -2296,7 +2334,7 @@ struct session *session_find_by_id_str(const char *);
struct session *session_find_by_id(u_int);
struct session *session_create(const char *, const char *, int, char **,
const char *, const char *, struct environ *,
- struct termios *, int, u_int, u_int, char **);
+ struct options *, struct termios *, int, char **);
void session_destroy(struct session *, const char *);
void session_add_ref(struct session *, const char *);
void session_remove_ref(struct session *, const char *);
diff --git a/tty.c b/tty.c
index 049ea017..7cc129e5 100644
--- a/tty.c
+++ b/tty.c
@@ -64,6 +64,7 @@ static void tty_redraw_region(struct tty *, const struct tty_ctx *);
static void tty_emulate_repeat(struct tty *, enum tty_code_code,
enum tty_code_code, u_int);
static void tty_repeat_space(struct tty *, u_int);
+static void tty_draw_pane(struct tty *, const struct tty_ctx *, u_int);
static void tty_cell(struct tty *, const struct grid_cell *,
const struct window_pane *);
static void tty_default_colours(struct grid_cell *,
@@ -698,19 +699,127 @@ tty_repeat_space(struct tty *tty, u_int n)
tty_putn(tty, s, n, n);
}
-/* How many lines are taken up by the status line on this client? */
-u_int
-tty_status_lines(struct client *c)
+/* Is this window bigger than the terminal? */
+int
+tty_window_bigger(struct tty *tty)
{
- u_int lines;
+ struct client *c = tty->client;
+ struct window *w = c->session->curw->window;
- if (c->flags & CLIENT_STATUSOFF)
- lines = 0;
- else
- lines = status_line_size(c->session);
- if (c->message_string != NULL || c->prompt_string != NULL)
- lines = (lines == 0) ? 1 : lines;
- return (lines);
+ return (tty->sx < w->sx || tty->sy - status_line_size(c) < w->sy);
+}
+
+/* What offset should this window be drawn at? */
+int
+tty_window_offset(struct tty *tty, u_int *ox, u_int *oy, u_int *sx, u_int *sy)
+{
+ *ox = tty->oox;
+ *oy = tty->ooy;
+ *sx = tty->osx;
+ *sy = tty->osy;
+
+ return (tty->oflag);
+}
+
+/* What offset should this window be drawn at? */
+static int
+tty_window_offset1(struct tty *tty, u_int *ox, u_int *oy, u_int *sx, u_int *sy)
+{
+ struct client *c = tty->client;
+ struct window *w = c->session->curw->window;
+ struct window_pane *wp = w->active;
+ u_int cx, cy, lines;
+
+ lines = status_line_size(c);
+
+ if (tty->sx >= w->sx && tty->sy - lines >= w->sy) {
+ *ox = 0;
+ *oy = 0;
+ *sx = w->sx;
+ *sy = w->sy;
+
+ c->pan_window = NULL;
+ return (0);
+ }
+
+ *sx = tty->sx;
+ *sy = tty->sy - lines;
+
+ if (c->pan_window == w) {
+ if (*sx >= w->sx)
+ c->pan_ox = 0;
+ else if (c->pan_ox + *sx > w->sx)
+ c->pan_ox = w->sx - *sx;
+ *ox = c->pan_ox;
+ if (*sy >= w->sy)
+ c->pan_oy = 0;
+ else if (c->pan_oy + *sy > w->sy)
+ c->pan_oy = w->sy - *sy;
+ *oy = c->pan_oy;
+ return (1);
+ }
+
+ if (~wp->screen->mode & MODE_CURSOR) {
+ *ox = 0;
+ *oy = 0;
+ } else {
+ cx = wp->xoff + wp->screen->cx;
+ cy = wp->yoff + wp->screen->cy;
+
+ if (cx < *sx)
+ *ox = 0;
+ else if (cx > w->sx - *sx)
+ *ox = w->sx - *sx;
+ else
+ *ox = cx - *sx / 2;
+
+ if (cy < *sy)
+ *oy = 0;
+ else if (cy > w->sy - *sy)
+ *oy = w->sy - *sy;
+ else
+ *oy = cy - *sy / 2;
+ }
+
+ c->pan_window = NULL;
+ return (1);
+}
+
+/* Update stored offsets for a window and redraw if necessary. */
+void
+tty_update_window_offset(struct window *w)
+{
+ struct client *c;
+
+ TAILQ_FOREACH(c, &clients, entry) {
+ if (c->session != NULL && c->session->curw->window == w)
+ tty_update_client_offset(c);
+ }
+}
+
+/* Update stored offsets for a client and redraw if necessary. */
+void
+tty_update_client_offset(struct client *c)
+{
+ u_int ox, oy, sx, sy;
+
+ c->tty.oflag = tty_window_offset1(&c->tty, &ox, &oy, &sx, &sy);
+ if (ox == c->tty.oox &&
+ oy == c->tty.ooy &&
+ sx == c->tty.osx &&
+ sy == c->tty.osy)
+ return;
+
+ log_debug ("%s: %s offset has changed (%u,%u %ux%u -> %u,%u %ux%u)",
+ __func__, c->name, c->tty.oox, c->tty.ooy, c->tty.osx, c->tty.osy,
+ ox, oy, sx, sy);
+
+ c->tty.oox = ox;
+ c->tty.ooy = oy;
+ c->tty.osx = sx;
+ c->tty.osy = sy;
+
+ c->flags |= (CLIENT_REDRAWWINDOW|CLIENT_REDRAWSTATUS);
}
/*
@@ -770,18 +879,82 @@ tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx)
if (ctx->ocy < ctx->orupper || ctx->ocy > ctx->orlower) {
for (i = ctx->ocy; i < screen_size_y(s); i++)
- tty_draw_pane(tty, wp, i, ctx->xoff, ctx->yoff);
+ tty_draw_pane(tty, ctx, i);
} else {
for (i = ctx->orupper; i <= ctx->orlower; i++)
- tty_draw_pane(tty, wp, i, ctx->xoff, ctx->yoff);
+ tty_draw_pane(tty, ctx, i);
}
}
+/* Is this position visible in the pane? */
+static int
+tty_is_visible(struct tty *tty, const struct tty_ctx *ctx, u_int px, u_int py,
+ u_int nx, u_int ny)
+{
+ u_int xoff = ctx->xoff + px, yoff = ctx->yoff + py, lines;
+
+ if (!ctx->bigger)
+ return (1);
+
+ if (status_at_line(tty->client) == 0)
+ lines = status_line_size(tty->client);
+ else
+ lines = 0;
+
+ if (xoff + nx <= ctx->ox || xoff >= ctx->ox + ctx->sx ||
+ yoff + ny <= ctx->oy || yoff >= lines + ctx->oy + ctx->sy) {
+ return (0);
+ }
+ return (1);
+}
+
+/* Clamp line position to visible part of pane. */
+static int
+tty_clamp_line(struct tty *tty, const struct tty_ctx *ctx, u_int px, u_int py,
+ u_int nx, u_int *i, u_int *x, u_int *rx, u_int *ry)
+{
+ struct window_pane *wp = ctx->wp;
+ u_int xoff = wp->xoff + px;
+
+ if (!tty_is_visible(tty, ctx, px, py, nx, 1))
+ return (0);
+ *ry = ctx->yoff + py - ctx->oy;
+
+ if (xoff >= ctx->ox && xoff + nx <= ctx->ox + ctx->sx) {
+ /* All visible. */
+ *i = 0;
+ *x = ctx->xoff + px - ctx->ox;
+ *rx = nx;
+ } else if (xoff < ctx->ox && xoff + nx > ctx->ox + ctx->sx) {
+ /* Both left and right not visible. */
+ *i = ctx->ox;
+ *x = 0;
+ *rx = ctx->sx;
+ } else if (xoff < ctx->ox) {
+ /* Left not visible. */
+ *i = ctx->ox - (ctx->xoff + px);
+ *x = 0;
+ *rx = nx - *i;
+ } else {
+ /* Right not visible. */
+ *i = 0;
+ *x = (ctx->xoff + px) - ctx->ox;
+ *rx = ctx->sx - *x;
+ }
+ if (*rx > nx)
+ fatalx("%s: x too big, %u > %u", __func__, *rx, nx);
+
+ return (1);
+}
+
+/* Clear a line. */
static void
tty_clear_line(struct tty *tty, const struct window_pane *wp, u_int py,
u_int px, u_int nx, u_int bg)
{
- log_debug("%s: %u at %u,%u", __func__, nx, px, py);
+ struct client *c = tty->client;
+
+ log_debug("%s: %s, %u at %u,%u", __func__, c->name, nx, px, py);
/* Nothing to clear. */
if (nx == 0)
@@ -816,14 +989,93 @@ tty_clear_line(struct tty *tty, const struct window_pane *wp, u_int py,
tty_repeat_space(tty, nx);
}
+/* Clear a line, adjusting to visible part of pane. */
+static void
+tty_clear_pane_line(struct tty *tty, const struct tty_ctx *ctx, u_int py,
+ u_int px, u_int nx, u_int bg)
+{
+ struct client *c = tty->client;
+ u_int i, x, rx, ry;
+
+ log_debug("%s: %s, %u at %u,%u", __func__, c->name, nx, px, py);
+
+ if (tty_clamp_line(tty, ctx, px, py, nx, &i, &x, &rx, &ry))
+ tty_clear_line(tty, ctx->wp, ry, x, rx, bg);
+}
+
+/* Clamp area position to visible part of pane. */
+static int
+tty_clamp_area(struct tty *tty, const struct tty_ctx *ctx, u_int px, u_int py,
+ u_int nx, u_int ny, u_int *i, u_int *j, u_int *x, u_int *y, u_int *rx,
+ u_int *ry)
+{
+ struct window_pane *wp = ctx->wp;
+ u_int xoff = wp->xoff + px, yoff = wp->yoff + py;
+
+ if (!tty_is_visible(tty, ctx, px, py, nx, ny))
+ return (0);
+
+ if (xoff >= ctx->ox && xoff + nx <= ctx->ox + ctx->sx) {
+ /* All visible. */
+ *i = 0;
+ *x = ctx->xoff + px - ctx->ox;
+ *rx = nx;
+ } else if (xoff < ctx->ox && xoff + nx > ctx->ox + ctx->sx) {
+ /* Both left and right not visible. */
+ *i = ctx->ox;
+ *x = 0;
+ *rx = ctx->sx;
+ } else if (xoff < ctx->ox) {
+ /* Left not visible. */
+ *i = ctx->ox - (ctx->xoff + px);
+ *x = 0;
+ *rx = nx - *i;
+ } else {
+ /* Right not visible. */
+ *i = 0;
+ *x = (ctx->xoff + px) - ctx->ox;
+ *rx = ctx->sx - *x;
+ }
+ if (*rx > nx)
+ fatalx("%s: x too big, %u > %u", __func__, *rx, nx);
+
+ if (yoff >= ctx->oy && yoff + ny <= ctx->oy + ctx->sy) {
+ /* All visible. */
+ *j = 0;
+ *y = ctx->yoff + py - ctx->oy;
+ *ry = ny;
+ } else if (yoff < ctx->oy && yoff + ny > ctx->oy + ctx->sy) {
+ /* Both left and right not visible. */
+ *j = ctx->oy;
+ *y = 0;
+ *ry = ctx->sy;
+ } else if (yoff < ctx->oy) {
+ /* Left not visible. */
+ *j = ctx->oy - (ctx->yoff + py);
+ *y = 0;
+ *ry = ny - *j;
+ } else {
+ /* Right not visible. */
+ *j = 0;
+ *y = (ctx->yoff + py) - ctx->oy;
+ *ry = ctx->sy - *y;
+ }
+ if (*ry > ny)
+ fatalx("%s: y too big, %u > %u", __func__, *ry, ny);
+
+ return (1);
+}
+
+/* Clear an area, adjusting to visible part of pane. */
static void
tty_clear_area(struct tty *tty, const struct window_pane *wp, u_int py,
u_int ny, u_int px, u_int nx, u_int bg)
{
- u_int yy;
- char tmp[64];
+ struct client *c = tty->client;
+ u_int yy;
+ char tmp[64];
- log_debug("%s: %u,%u at %u,%u", __func__, nx, ny, px, py);
+ log_debug("%s: %s, %u,%u at %u,%u", __func__, c->name, nx, ny, px, py);
/* Nothing to clear. */
if (nx == 0 || ny == 0)
@@ -886,11 +1138,32 @@ tty_clear_area(struct tty *tty, const struct window_pane *wp, u_int py,
tty_clear_line(tty, wp, yy, px, nx, bg);
}
-void
-tty_draw_pane(struct tty *tty, const struct window_pane *wp, u_int py, u_int ox,
- u_int oy)
+/* Clear an area in a pane. */
+static void
+tty_clear_pane_area(struct tty *tty, const struct tty_ctx *ctx, u_int py,
+ u_int ny, u_int px, u_int nx, u_int bg)
{
- tty_draw_line(tty, wp, wp->screen, py, ox, oy);
+ u_int i, j, x, y, rx, ry;
+
+ if (tty_clamp_area(tty, ctx, px, py, nx, ny, &i, &j, &x, &y, &rx, &ry))
+ tty_clear_area(tty, ctx->wp, y, ry, x, rx, bg);
+}
+
+static void
+tty_draw_pane(struct tty *tty, const struct tty_ctx *ctx, u_int py)
+{
+ struct window_pane *wp = ctx->wp;
+ struct screen *s = wp->screen;
+ u_int nx = screen_size_x(s), i, x, rx, ry;
+
+ log_debug("%s: %s %u %d", __func__, tty->client->name, py, ctx->bigger);
+
+ if (!ctx->bigger) {
+ tty_draw_line(tty, wp, s, 0, py, nx, ctx->xoff, ctx->yoff + py);
+ return;
+ }
+ if (tty_clamp_line(tty, ctx, 0, py, nx, &i, &x, &rx, &ry))
+ tty_draw_line(tty, wp, s, i, py, rx, x, ry);
}
static const struct grid_cell *
@@ -919,17 +1192,27 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
void
tty_draw_line(struct tty *tty, const struct window_pane *wp,
- struct screen *s, u_int py, u_int ox, u_int oy)
+ struct screen *s, u_int px, u_int py, u_int nx, u_int atx, u_int aty)
{
struct grid *gd = s->grid;
struct grid_cell gc, last;
const struct grid_cell *gcp;
- u_int i, j, ux, sx, nx, width;
+ struct grid_line *gl;
+ u_int i, j, ux, sx, width;
int flags, cleared = 0;
char buf[512];
size_t len, old_len;
u_int cellsize;
+ log_debug("%s: px=%u py=%u nx=%u atx=%u aty=%u", __func__,
+ px, py, nx, atx, aty);
+
+ /*
+ * py is the line in the screen to draw.
+ * px is the start x and nx is the width to draw.
+ * atx,aty is the line on the terminal to draw it.
+ */
+
flags = (tty->flags & TTY_NOCURSOR);
tty->flags |= TTY_NOCURSOR;
tty_update_mode(tty, tty->mode, s);
@@ -942,41 +1225,48 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
* there may be empty background cells after it (from BCE).
*/
sx = screen_size_x(s);
-
+ if (nx > sx)
+ nx = sx;
cellsize = grid_get_line(gd, gd->hsize + py)->cellsize;
if (sx > cellsize)
sx = cellsize;
if (sx > tty->sx)
sx = tty->sx;
+ if (sx > nx)
+ sx = nx;
ux = 0;
+ if (py == 0)
+ gl = NULL;
+ else
+ gl = grid_get_line(gd, gd->hsize + py - 1);
if (wp == NULL ||
- py == 0 ||
- (~grid_get_line(gd, gd->hsize + py - 1)->flags & GRID_LINE_WRAPPED) ||
- ox != 0 ||
+ gl == NULL ||
+ (~gl->flags & GRID_LINE_WRAPPED) ||
+ atx != 0 ||
tty->cx < tty->sx ||
- screen_size_x(s) < tty->sx) {
- if (screen_size_x(s) < tty->sx &&
- ox == 0 &&
- sx != screen_size_x(s) &&
+ nx < tty->sx) {
+ if (nx < tty->sx &&
+ atx == 0 &&
+ px + sx != nx &&
tty_term_has(tty->term, TTYC_EL1) &&
!tty_fake_bce(tty, wp, 8)) {
tty_default_attributes(tty, wp, 8);
- tty_cursor(tty, screen_size_x(s) - 1, oy + py);
+ tty_cursor(tty, nx - 1, aty);
tty_putcode(tty, TTYC_EL1);
cleared = 1;
}
- if (sx != 0)
- tty_cursor(tty, ox, oy + py);
+ if (px + sx != 0)
+ tty_cursor(tty, atx, aty);
} else
- log_debug("%s: wrapped line %u", __func__, oy + py);
+ log_debug("%s: wrapped line %u", __func__, aty);
memcpy(&last, &grid_default_cell, sizeof last);
len = 0;
width = 0;
for (i = 0; i < sx; i++) {
- grid_view_get_cell(gd, i, py, &gc);
+ grid_view_get_cell(gd, px + i, py, &gc);
gcp = tty_check_codeset(tty, &gc);
if (len != 0 &&
((gcp->attr & GRID_ATTR_CHARSET) ||
@@ -984,7 +1274,7 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
gcp->attr != last.attr ||
gcp->fg != last.fg ||
gcp->bg != last.bg ||
- ux + width + gcp->data.width >= screen_size_x(s) ||
+ ux + width + gcp->data.width >= nx ||
(sizeof buf) - len < gcp->data.size)) {
tty_attributes(tty, &last, wp);
tty_putn(tty, buf, len, width);
@@ -998,10 +1288,10 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
screen_select_cell(s, &last, gcp);
else
memcpy(&last, gcp, sizeof last);
- if (ux + gcp->data.width > screen_size_x(s)) {
+ if (ux + gcp->data.width > nx) {
tty_attributes(tty, &last, wp);
for (j = 0; j < gcp->data.width; j++) {
- if (ux + j > screen_size_x(s))
+ if (ux + j > nx)
break;
tty_putc(tty, ' ');
ux++;
@@ -1034,10 +1324,9 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
}
}
- if (!cleared && ux < screen_size_x(s)) {
- nx = screen_size_x(s) - ux;
+ if (!cleared && ux < nx) {
tty_default_attributes(tty, wp, 8);
- tty_clear_line(tty, wp, oy + py, ox + ux, nx, 8);
+ tty_clear_line(tty, wp, aty, atx + ux, nx - ux, 8);
}
tty->flags = (tty->flags & ~TTY_NOCURSOR) | flags;
@@ -1055,6 +1344,8 @@ tty_client_ready(struct client *c, struct window_pane *wp)
return (0);
if (c->session->curw->window != wp->window)
return (0);
+ if (wp->layout_cell == NULL)
+ return (0);
return (1);
}
@@ -1065,21 +1356,23 @@ tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *),
struct window_pane *wp = ctx->wp;
struct client *c;
- /* wp can be NULL if updating the screen but not the terminal. */
if (wp == NULL)
return;
-
- if ((wp->flags & (PANE_REDRAW|PANE_DROP)) || !window_pane_visible(wp))
+ if (wp->flags & (PANE_REDRAW|PANE_DROP))
return;
TAILQ_FOREACH(c, &clients, entry) {
if (!tty_client_ready(c, wp))
continue;
+ ctx->bigger = tty_window_offset(&c->tty, &ctx->ox, &ctx->oy,
+ &ctx->sx, &ctx->sy);
+
ctx->xoff = wp->xoff;
ctx->yoff = wp->yoff;
+
if (status_at_line(c) == 0)
- ctx->yoff += status_line_size(c->session);
+ ctx->yoff += status_line_size(c);
cmdfn(&c->tty, ctx);
}
@@ -1090,11 +1383,12 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx)
{
struct window_pane *wp = ctx->wp;
- if (!tty_pane_full_width(tty, ctx) ||
+ if (ctx->bigger ||
+ !tty_pane_full_width(tty, ctx) ||
tty_fake_bce(tty, wp, ctx->bg) ||
(!tty_term_has(tty->term, TTYC_ICH) &&
!tty_term_has(tty->term, TTYC_ICH1))) {
- tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff);
+ tty_draw_pane(tty, ctx, ctx->ocy);
return;
}
@@ -1110,11 +1404,12 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx)
{
struct window_pane *wp = ctx->wp;
- if (!tty_pane_full_width(tty, ctx) ||
+ if (ctx->bigger ||
+ !tty_pane_full_width(tty, ctx) ||
tty_fake_bce(tty, wp, ctx->bg) ||
(!tty_term_has(tty->term, TTYC_DCH) &&
!tty_term_has(tty->term, TTYC_DCH1))) {
- tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff);
+ tty_draw_pane(tty, ctx, ctx->ocy);
return;
}
@@ -1128,6 +1423,11 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx)
{
+ if (ctx->bigger) {
+ tty_draw_pane(tty, ctx, ctx->ocy);
+ return;
+ }
+
tty_default_attributes(tty, ctx->wp, ctx->bg);
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
@@ -1142,7 +1442,8 @@ tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx)
{
- if (!tty_pane_full_width(tty, ctx) ||
+ if (ctx->bigger ||
+ !tty_pane_full_width(tty, ctx) ||
tty_fake_bce(tty, ctx->wp, ctx->bg) ||
!tty_term_has(tty->term, TTYC_CSR) ||
!tty_term_has(tty->term, TTYC_IL1) ||
@@ -1165,7 +1466,8 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx)
{
- if (!tty_pane_full_width(tty, ctx) ||
+ if (ctx->bigger ||
+ !tty_pane_full_width(tty, ctx) ||
tty_fake_bce(tty, ctx->wp, ctx->bg) ||
!tty_term_has(tty->term, TTYC_CSR) ||
!tty_term_has(tty->term, TTYC_DL1) ||
@@ -1189,35 +1491,34 @@ void
tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx)
{
struct window_pane *wp = ctx->wp;
- u_int nx, py = ctx->yoff + ctx->ocy;
+ u_int nx;
tty_default_attributes(tty, wp, ctx->bg);
nx = screen_size_x(wp->screen);
- tty_clear_line(tty, wp, py, ctx->xoff, nx, ctx->bg);
+ tty_clear_pane_line(tty, ctx, ctx->ocy, 0, nx, ctx->bg);
}
void
tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx)
{
struct window_pane *wp = ctx->wp;
- u_int nx, py = ctx->yoff + ctx->ocy;
+ u_int nx;
tty_default_attributes(tty, wp, ctx->bg);
nx = screen_size_x(wp->screen) - ctx->ocx;
- tty_clear_line(tty, wp, py, ctx->xoff + ctx->ocx, nx, ctx->bg);
+ tty_clear_pane_line(tty, ctx, ctx->ocy, ctx->ocx, nx, ctx->bg);
}
void
tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx)
{
struct window_pane *wp = ctx->wp;
- u_int py = ctx->yoff + ctx->ocy;
tty_default_attributes(tty, wp, ctx->bg);
- tty_clear_line(tty, wp, py, ctx->xoff, ctx->ocx + 1, ctx->bg);
+ tty_clear_pane_line(tty, ctx, ctx->ocy, 0, ctx->ocx + 1, ctx->bg);
}
void
@@ -1228,7 +1529,8 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx)
if (ctx->ocy != ctx->orupper)
return;
- if (!tty_pane_full_width(tty, ctx) ||
+ if (ctx->bigger ||
+ !tty_pane_full_width(tty, ctx) ||
tty_fake_bce(tty, wp, 8) ||
!tty_term_has(tty->term, TTYC_CSR) ||
!tty_term_has(tty->term, TTYC_RI) ||
@@ -1255,7 +1557,8 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
if (ctx->ocy != ctx->orlower)
return;
- if ((!tty_pane_full_width(tty, ctx) && !tty_use_margin(tty)) ||
+ if (ctx->bigger ||
+ (!tty_pane_full_width(tty, ctx) && !tty_use_margin(tty)) ||
tty_fake_bce(tty, wp, 8) ||
!tty_term_has(tty->term, TTYC_CSR) ||
wp->sx == 1 ||
@@ -1293,7 +1596,8 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx)
struct window_pane *wp = ctx->wp;
u_int i;
- if ((!tty_pane_full_width(tty, ctx) && !tty_use_margin(tty)) ||
+ if (ctx->bigger ||
+ (!tty_pane_full_width(tty, ctx) && !tty_use_margin(tty)) ||
tty_fake_bce(tty, wp, 8) ||
!tty_term_has(tty->term, TTYC_CSR) ||
wp->sx == 1 ||
@@ -1331,18 +1635,18 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx)
tty_region_pane(tty, ctx, 0, screen_size_y(wp->screen) - 1);
tty_margin_off(tty);
- px = ctx->xoff;
+ px = 0;
nx = screen_size_x(wp->screen);
- py = ctx->yoff + ctx->ocy + 1;
+ py = ctx->ocy + 1;
ny = screen_size_y(wp->screen) - ctx->ocy - 1;
- tty_clear_area(tty, wp, py, ny, px, nx, ctx->bg);
+ tty_clear_pane_area(tty, ctx, py, ny, px, nx, ctx->bg);
- px = ctx->xoff + ctx->ocx;
+ px = ctx->ocx;
nx = screen_size_x(wp->screen) - ctx->ocx;
- py = ctx->yoff + ctx->ocy;
+ py = ctx->ocy;
- tty_clear_line(tty, wp, py, px, nx, ctx->bg);
+ tty_clear_pane_line(tty, ctx, py, px, nx, ctx->bg);
}
void
@@ -1356,18 +1660,18 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx)
tty_region_pane(tty, ctx, 0, screen_size_y(wp->screen) - 1);
tty_margin_off(tty);
- px = ctx->xoff;
+ px = 0;
nx = screen_size_x(wp->screen);
- py = ctx->yoff;
+ py = 0;
ny = ctx->ocy - 1;
- tty_clear_area(tty, wp, py, ny, px, nx, ctx->bg);
+ tty_clear_pane_area(tty, ctx, py, ny, px, nx, ctx->bg);
- px = ctx->xoff;
+ px = 0;
nx = ctx->ocx + 1;
- py = ctx->yoff + ctx->ocy;
+ py = ctx->ocy;
- tty_clear_line(tty, wp, py, px, nx, ctx->bg);
+ tty_clear_pane_line(tty, ctx, py, px, nx, ctx->bg);
}
void
@@ -1381,12 +1685,12 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx)
tty_region_pane(tty, ctx, 0, screen_size_y(wp->screen) - 1);
tty_margin_off(tty);
- px = ctx->xoff;
+ px = 0;
nx = screen_size_x(wp->screen);
- py = ctx->yoff;
+ py = 0;
ny = screen_size_y(wp->screen);
- tty_clear_area(tty, wp, py, ny, px, nx, ctx->bg);
+ tty_clear_pane_area(tty, ctx, py, ny, px, nx, ctx->bg);
}
void
@@ -1396,6 +1700,11 @@ tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx)
struct screen *s = wp->screen;
u_int i, j;
+ if (ctx->bigger) {
+ wp->flags |= PANE_REDRAW;
+ return;
+ }
+
tty_attributes(tty, &grid_default_cell, wp);
tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1);
@@ -1411,7 +1720,10 @@ tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
{
- if (ctx->xoff + ctx->ocx > tty->sx - 1 &&
+ if (!tty_is_visible(tty, ctx, ctx->ocx, ctx->ocy, 1, 1))
+ return;
+
+ if (ctx->xoff + ctx->ocx - ctx->ox > tty->sx - 1 &&
ctx->ocy == ctx->orlower &&
tty_pane_full_width(tty, ctx))
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
@@ -1425,6 +1737,27 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
{
+ struct window_pane *wp = ctx->wp;
+
+ if (!tty_is_visible(tty, ctx, ctx->ocx, ctx->ocy, ctx->num, 1))
+ return;
+
+ if (ctx->bigger &&
+ (ctx->xoff + ctx->ocx < ctx->ox ||
+ ctx->xoff + ctx->ocx + ctx->num > ctx->ox + ctx->sx)) {
+ if (!ctx->wrapped ||
+ !tty_pane_full_width(tty, ctx) ||
+ (tty->term->flags & TERM_EARLYWRAP) ||
+ ctx->xoff + ctx->ocx != 0 ||
+ ctx->yoff + ctx->ocy != tty->cy + 1 ||
+ tty->cx < tty->sx ||
+ tty->cy == tty->rlower)
+ tty_draw_pane(tty, ctx, ctx->ocy);
+ else
+ wp->flags |= PANE_REDRAW;
+ return;
+ }
+
tty_margin_off(tty);
tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy);
@@ -1543,7 +1876,8 @@ static void
tty_region_pane(struct tty *tty, const struct tty_ctx *ctx, u_int rupper,
u_int rlower)
{
- tty_region(tty, ctx->yoff + rupper, ctx->yoff + rlower);
+ tty_region(tty, ctx->yoff + rupper - ctx->oy,
+ ctx->yoff + rlower - ctx->oy);
}
/* Set region at absolute position. */
@@ -1582,7 +1916,8 @@ tty_margin_off(struct tty *tty)
static void
tty_margin_pane(struct tty *tty, const struct tty_ctx *ctx)
{
- tty_margin(tty, ctx->xoff, ctx->xoff + ctx->wp->sx - 1);
+ tty_margin(tty, ctx->xoff - ctx->ox,
+ ctx->xoff + ctx->wp->sx - 1 - ctx->ox);
}
/* Set margin at absolute position. */
@@ -1633,7 +1968,7 @@ tty_cursor_pane_unless_wrap(struct tty *tty, const struct tty_ctx *ctx,
static void
tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy)
{
- tty_cursor(tty, ctx->xoff + cx, ctx->yoff + cy);
+ tty_cursor(tty, ctx->xoff + cx - ctx->ox, ctx->yoff + cy - ctx->oy);
}
/* Move cursor to absolute position. */
diff --git a/window.c b/window.c
index 019718f2..6e76b480 100644
--- a/window.c
+++ b/window.c
@@ -380,6 +380,8 @@ window_destroy(struct window *w)
if (event_initialized(&w->alerts_timer))
evtimer_del(&w->alerts_timer);
+ if (event_initialized(&w->offset_timer))
+ event_del(&w->offset_timer);
options_free(w->options);
@@ -458,17 +460,9 @@ window_set_active_pane(struct window *w, struct window_pane *wp)
return (0);
w->last = w->active;
w->active = wp;
- while (!window_pane_visible(w->active)) {
- w->active = TAILQ_PREV(w->active, window_panes, entry);
- if (w->active == NULL)
- w->active = TAILQ_LAST(&w->panes, window_panes);
- if (w->active == wp) {
- notify_window("window-pane-changed", w);
- return (1);
- }
- }
w->active->active_point = next_active_point++;
w->active->flags |= PANE_CHANGED;
+ tty_update_window_offset(w);
notify_window("window-pane-changed", w);
return (1);
}
@@ -509,8 +503,8 @@ window_get_active_at(struct window *w, u_int x, u_int y)
struct window_pane *wp;
TAILQ_FOREACH(wp, &w->panes, entry) {
- if (!window_pane_visible(wp))
- continue;
+ if (!window_pane_visible(wp))
+ continue;
if (x < wp->xoff || x > wp->xoff + wp->sx)
continue;
if (y < wp->yoff || y > wp->yoff + wp->sy)
@@ -563,9 +557,6 @@ window_zoom(struct window_pane *wp)
if (w->flags & WINDOW_ZOOMED)
return (-1);
- if (!window_pane_visible(wp))
- return (-1);
-
if (window_count_panes(w) == 1)
return (-1);
@@ -602,7 +593,7 @@ window_unzoom(struct window *w)
wp->layout_cell = wp->saved_layout_cell;
wp->saved_layout_cell = NULL;
}
- layout_fix_panes(w, w->sx, w->sy);
+ layout_fix_panes(w);
notify_window("window-layout-changed", w);
return (0);
@@ -1284,11 +1275,11 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
return;
if (options_get_number(wp->window->options, "synchronize-panes")) {
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
- if (wp2 == wp || wp2->mode != NULL)
- continue;
- if (wp2->fd == -1 || wp2->flags & PANE_INPUTOFF)
- continue;
- if (window_pane_visible(wp2))
+ if (wp2 != wp &&
+ wp2->mode == NULL &&
+ wp2->fd != -1 &&
+ (~wp2->flags & PANE_INPUTOFF) &&
+ window_pane_visible(wp2))
input_key(wp2, key, NULL);
}
}
@@ -1297,16 +1288,9 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
int
window_pane_visible(struct window_pane *wp)
{
- struct window *w = wp->window;
-
- if (wp->layout_cell == NULL)
- return (0);
-
- if (wp->xoff >= w->sx || wp->yoff >= w->sy)
- return (0);
- if (wp->xoff + wp->sx > w->sx || wp->yoff + wp->sy > w->sy)
- return (0);
- return (1);
+ if (~wp->window->flags & WINDOW_ZOOMED)
+ return (1);
+ return (wp == wp->window->active);
}
u_int
@@ -1363,7 +1347,7 @@ window_pane_find_up(struct window_pane *wp)
u_int edge, left, right, end, size;
int status, found;
- if (wp == NULL || !window_pane_visible(wp))
+ if (wp == NULL)
return (NULL);
status = options_get_number(wp->window->options, "pane-border-status");
@@ -1378,7 +1362,7 @@ window_pane_find_up(struct window_pane *wp)
right = wp->xoff + wp->sx;
TAILQ_FOREACH(next, &wp->window->panes, entry) {
- if (next == wp || !window_pane_visible(next))
+ if (next == wp)
continue;
if (next->yoff + next->sy + 1 != edge)
continue;
@@ -1410,7 +1394,7 @@ window_pane_find_down(struct window_pane *wp)
u_int edge, left, right, end, size;
int status, found;
- if (wp == NULL || !window_pane_visible(wp))
+ if (wp == NULL)
return (NULL);
status = options_get_number(wp->window->options, "pane-border-status");
@@ -1425,7 +1409,7 @@ window_pane_find_down(struct window_pane *wp)
right = wp->xoff + wp->sx;
TAILQ_FOREACH(next, &wp->window->panes, entry) {
- if (next == wp || !window_pane_visible(next))
+ if (next == wp)
continue;
if (next->yoff != edge)
continue;
@@ -1457,7 +1441,7 @@ window_pane_find_left(struct window_pane *wp)
u_int edge, top, bottom, end, size;
int found;
- if (wp == NULL || !window_pane_visible(wp))
+ if (wp == NULL)
return (NULL);
list = NULL;
@@ -1471,7 +1455,7 @@ window_pane_find_left(struct window_pane *wp)
bottom = wp->yoff + wp->sy;
TAILQ_FOREACH(next, &wp->window->panes, entry) {
- if (next == wp || !window_pane_visible(next))
+ if (next == wp)
continue;
if (next->xoff + next->sx + 1 != edge)
continue;
@@ -1503,7 +1487,7 @@ window_pane_find_right(struct window_pane *wp)
u_int edge, top, bottom, end, size;
int found;
- if (wp == NULL || !window_pane_visible(wp))
+ if (wp == NULL)
return (NULL);
list = NULL;
@@ -1517,7 +1501,7 @@ window_pane_find_right(struct window_pane *wp)
bottom = wp->yoff + wp->sy;
TAILQ_FOREACH(next, &wp->window->panes, entry) {
- if (next == wp || !window_pane_visible(next))
+ if (next == wp)
continue;
if (next->xoff != edge)
continue;