Support for windows larger than visible on the attached client. This has

been a limitation for a long time.

There are two new options, window-size and default-size, and a new
command, resize-window. The force-width and force-height options and the
session_width and session_height formats have been removed.

The new window-size option tells tmux how to work out the size of
windows: largest means it picks the size of the largest session,
smallest the smallest session (similar to the old behaviour) and manual
means that it does not automatically resize windows. The default is
currently largest but this may change. aggressive-resize modifies the
choice of session for largest and smallest as it did before.

If a window is in a session attached to a client that is too small, only
part of the window is shown. tmux attempts to keep the cursor visible,
so the part of the window displayed is changed as the cursor moves (with
a small delay, to try and avoid excess redrawing when applications
redraw status lines or similar that are not currently visible). The
offset of the visible portion of the window is shown in status-right.

Drawing windows which are larger than the client is not as efficient as
those which fit, particularly when the cursor moves, so it is
recommended to avoid using this on slow machines or networks (set
window-size to smallest or manual).

The resize-window command can be used to resize a window manually. If it
is used, the window-size option is automatically set to manual for the
window (undo this with "setw -u window-size"). resize-window works in a
similar way to resize-pane (-U -D -L -R -x -y flags) but also has -a and
-A flags. -a sets the window to the size of the smallest client (what it
would be if window-size was smallest) and -A the largest.

For the same behaviour as force-width or force-height, use resize-window
-x or -y, and "setw -u window-size" to revert to automatic sizing..

If the global window-size option is set to manual, the default-size
option is used for new windows. If -x or -y is used with new-session,
that sets the default-size option for the new session.

The maximum size of a window is 10000x10000. But expect applications to
complain and much higher memory use if making a window excessively
big. The minimum size is the size required for the current layout
including borders.

The refresh-client command can be used to pan around a window, -U -D -L
-R moves up, down, left or right and -c returns to automatic cursor
tracking. The position is reset when the current window is changed.
pull/1545/head
nicm 2018-10-18 08:38:01 +00:00
parent a51668ca06
commit 646995384d
31 changed files with 1389 additions and 605 deletions

View File

@ -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 \

View File

@ -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);

View File

@ -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;

View File

@ -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),}"

View File

@ -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,8 +190,36 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
}
}
/* Get default session size. */
if (args_has(args, 'x')) {
tmp = args_get(args, 'x');
if (strcmp(tmp, "-") == 0) {
if (c != NULL)
dsx = c->tty.sx;
} else {
dsx = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
goto error;
}
}
}
if (args_has(args, 'y')) {
tmp = args_get(args, 'y');
if (strcmp(tmp, "-") == 0) {
if (c != NULL)
dsy = c->tty.sy;
} else {
dsy = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
goto error;
}
}
}
/* Find new session size. */
if (!detached) {
if (!detached && !is_control) {
sx = c->tty.sx;
sy = c->tty.sy;
if (!is_control &&
@ -198,34 +227,15 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
options_get_number(global_s_options, "status"))
sy--;
} else {
sx = 80;
sy = 24;
}
if ((is_control || detached) && args_has(args, 'x')) {
tmp = args_get(args, 'x');
if (strcmp(tmp, "-") == 0) {
if (c != NULL)
sx = c->tty.sx;
} else {
sx = 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')) {
tmp = args_get(args, 'y');
if (strcmp(tmp, "-") == 0) {
if (c != NULL)
sy = c->tty.sy;
} else {
sy = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
goto error;
}
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;
@ -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);

View File

@ -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);
}

109
cmd-resize-window.c Normal file
View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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')) {

View File

@ -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 {

View File

@ -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);

2
cmd.c
View File

@ -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,

View File

@ -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)

View File

@ -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) &&

View File

@ -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",

View File

@ -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 },

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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,

326
resize.c
View File

@ -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
default_window_size(struct session *s, struct window *w, u_int *sx, u_int *sy,
int type)
{
struct client *c;
u_int cx, cy;
const char *value;
if (type == -1)
type = options_get_number(global_w_options, "window-size");
if (type == WINDOW_SIZE_MANUAL)
goto manual;
if (type == WINDOW_SIZE_LARGEST) {
*sx = *sy = 0;
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;
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)
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;
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)
goto manual;
}
goto done;
manual:
value = options_get_string(s->options, "default-size");
if (sscanf(value, "%ux%u", sx, sy) != 2) {
*sx = 80;
*sy = 24;
}
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;
struct window_pane *wp;
u_int ssx, ssy, has, limit, lines;
int flag, is_zoomed, forced;
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) {
lines = status_line_size(s);
s->attached = 0;
ssx = ssy = UINT_MAX;
TAILQ_FOREACH(c, &clients, entry) {
if (c->flags & CLIENT_SUSPENDED)
continue;
if ((c->flags & (CLIENT_CONTROL|CLIENT_SIZECHANGED)) ==
CLIENT_CONTROL)
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 (ssx == UINT_MAX || ssy == UINT_MAX)
continue;
if (lines != 0 && ssy == 0)
ssy = lines;
if (s->sx == ssx && s->sy == ssy)
continue;
log_debug("session $%u size %u,%u (was %u,%u)", s->id, ssx, ssy,
s->sx, s->sy);
s->sx = ssx;
s->sy = ssy;
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;
type = options_get_number(w->options, "window-size");
if (type == WINDOW_SIZE_MANUAL)
continue;
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 (ssx == UINT_MAX || ssy == UINT_MAX)
if (w->sx == sx && w->sy == sy)
changed = 0;
if (!changed) {
tty_update_window_offset(w);
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;
}
if (w->sx == ssx && w->sy == ssy)
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);
}
}

View File

@ -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;
tty_draw_line(tty, NULL, &wp->status_screen, 0, wp->xoff + 2,
yoff);
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;
}
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);
screen_redraw_set_context(c, &ctx);
log_debug("%s: redraw pane %%%u (at %u,%u)", c->name, wp->id,
wp->xoff, yoff);
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;
u_int i, j;
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;
}
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);

View File

@ -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) {

View File

@ -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) {

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

78
tmux.h
View File

@ -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 *);

495
tty.c
View File

@ -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. */

View File

@ -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;