Initial attempt to make use of left and right margins if the terminal

supports them (that is, if it advertises itself as a VT420 - probably
just xterm). These are the vertical equivalent of the scroll region and
allow much faster scrolling of panes that do not take up the full width
of the terminal.
pull/654/head
nicm 2016-11-15 14:02:32 +00:00
parent 9fe43d6acb
commit 0ace779cde
4 changed files with 187 additions and 11 deletions

View File

@ -1004,6 +1004,7 @@ server_client_reset_state(struct client *c)
return;
tty_region(&c->tty, 0, c->tty.sy - 1);
tty_margin(&c->tty, 0, c->tty.sx - 1);
status = options_get_number(oo, "status");
if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)

14
tmux.h
View File

@ -1098,6 +1098,9 @@ struct tty {
u_int rlower;
u_int rupper;
u_int rleft;
u_int rright;
char *termname;
struct tty_term *term;
@ -1118,6 +1121,15 @@ struct tty {
int flags;
int term_flags;
enum {
TTY_VT100,
TTY_VT101,
TTY_VT102,
TTY_VT220,
TTY_VT320,
TTY_VT420,
TTY_UNKNOWN
} term_type;
struct mouse_event mouse;
int mouse_drag_flag;
@ -1653,6 +1665,7 @@ void tty_attributes(struct tty *, const struct grid_cell *,
const struct window_pane *);
void tty_reset(struct tty *);
void tty_region(struct tty *, u_int, u_int);
void tty_margin(struct tty *, u_int, u_int);
void tty_cursor(struct tty *, u_int, u_int);
void tty_putcode(struct tty *, enum tty_code_code);
void tty_putcode1(struct tty *, enum tty_code_code, int);
@ -1677,6 +1690,7 @@ void tty_draw_line(struct tty *, const struct window_pane *, struct screen *,
int tty_open(struct tty *, char **);
void tty_close(struct tty *);
void tty_free(struct tty *);
void tty_set_type(struct tty *, int);
void tty_write(void (*)(struct tty *, const struct tty_ctx *),
struct tty_ctx *);
void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *);

View File

@ -44,6 +44,8 @@ static int tty_keys_next1(struct tty *, const char *, size_t, key_code *,
size_t *, int);
static void tty_keys_callback(int, short, void *);
static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *);
static int tty_keys_device_attributes(struct tty *, const char *, size_t,
size_t *);
/* Default raw keys. */
struct tty_default_key_raw {
@ -537,6 +539,17 @@ tty_keys_next(struct tty *tty)
return (0);
log_debug("keys are %zu (%.*s)", len, (int)len, buf);
/* Is this a device attributes response? */
switch (tty_keys_device_attributes(tty, buf, len, &size)) {
case 0: /* yes */
key = KEYC_UNKNOWN;
goto complete_key;
case -1: /* no, or not valid */
break;
case 1: /* partial */
goto partial_key;
}
/* Is this a mouse key press? */
switch (tty_keys_mouse(tty, buf, len, &size)) {
case 0: /* yes */
@ -815,3 +828,84 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
return (0);
}
/*
* Handle device attributes input. Returns 0 for success, -1 for failure, 1 for
* partial.
*/
static int
tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
size_t *size)
{
u_int i, a, b;
char tmp[64], *endptr;
const char *s;
*size = 0;
/* First three bytes are always \033[?. */
if (buf[0] != '\033')
return (-1);
if (len == 1)
return (1);
if (buf[1] != '[')
return (-1);
if (len == 2)
return (1);
if (buf[2] != '?')
return (-1);
if (len == 3)
return (1);
/* Copy the rest up to a 'c'. */
for (i = 0; i < (sizeof tmp) - 1 && buf[3 + i] != 'c'; i++) {
if (3 + i == len)
return (1);
tmp[i] = buf[3 + i];
}
if (i == (sizeof tmp) - 1)
return (-1);
tmp[i] = '\0';
*size = 4 + i;
/* Convert version numbers. */
a = strtoul(tmp, &endptr, 10);
if (*endptr == ';') {
b = strtoul(endptr + 1, &endptr, 10);
if (*endptr != '\0' && *endptr != ';')
b = 0;
} else
a = b = 0;
s = "UNKNOWN";
switch (a) {
case 1:
if (b == 2) {
tty_set_type(tty, TTY_VT100);
s = "VT100";
} else if (b == 0) {
tty_set_type(tty, TTY_VT101);
s = "VT101";
}
break;
case 6:
tty_set_type(tty, TTY_VT102);
s = "VT102";
break;
case 62:
tty_set_type(tty, TTY_VT220);
s = "VT220";
break;
case 63:
tty_set_type(tty, TTY_VT320);
s = "VT320";
break;
case 64:
tty_set_type(tty, TTY_VT420);
s = "VT420";
break;
}
log_debug("received DA %.*s (%s)", (int)*size, buf, s);
return (0);
}

89
tty.c
View File

@ -21,6 +21,7 @@
#include <netinet/in.h>
#include <curses.h>
#include <errno.h>
#include <fcntl.h>
#include <resolv.h>
@ -54,6 +55,7 @@ static void tty_colours_bg(struct tty *, const struct grid_cell *);
static void tty_region_pane(struct tty *, const struct tty_ctx *, u_int,
u_int);
static void tty_margin_pane(struct tty *, const struct tty_ctx *);
static int tty_large_region(struct tty *, const struct tty_ctx *);
static int tty_fake_bce(const struct tty *, const struct window_pane *,
u_int);
@ -70,6 +72,8 @@ static void tty_default_attributes(struct tty *, const struct window_pane *,
#define tty_use_acs(tty) \
(tty_term_has((tty)->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8))
#define tty_use_margin(tty) \
((tty)->term_type == TTY_VT420)
#define tty_pane_full_width(tty, ctx) \
((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx)
@ -110,7 +114,9 @@ tty_init(struct tty *tty, struct client *c, int fd, char *term)
tty->ccolour = xstrdup("");
tty->flags = 0;
tty->term_flags = 0;
tty->term_type = TTY_UNKNOWN;
return (0);
}
@ -138,8 +144,8 @@ tty_resize(struct tty *tty)
tty->cx = UINT_MAX;
tty->cy = UINT_MAX;
tty->rupper = UINT_MAX;
tty->rlower = UINT_MAX;
tty->rupper = tty->rleft = UINT_MAX;
tty->rlower = tty->rright = UINT_MAX;
/*
* If the terminal has been started, reset the actual scroll region and
@ -148,13 +154,15 @@ tty_resize(struct tty *tty)
if (tty->flags & TTY_STARTED) {
tty_cursor(tty, 0, 0);
tty_region(tty, 0, tty->sy - 1);
tty_margin(tty, 0, tty->sx - 1);
}
return (1);
}
int
tty_set_size(struct tty *tty, u_int sx, u_int sy) {
tty_set_size(struct tty *tty, u_int sx, u_int sy)
{
if (sx == tty->sx && sy == tty->sy)
return (0);
tty->sx = sx;
@ -248,13 +256,14 @@ tty_start_tty(struct tty *tty)
tty->flags |= TTY_FOCUS;
tty_puts(tty, "\033[?1004h");
}
tty_puts(tty, "\033[c");
}
tty->cx = UINT_MAX;
tty->cy = UINT_MAX;
tty->rlower = UINT_MAX;
tty->rupper = UINT_MAX;
tty->rupper = tty->rleft = UINT_MAX;
tty->rlower = tty->rright = UINT_MAX;
tty->mode = MODE_CURSOR;
@ -315,6 +324,8 @@ tty_stop_tty(struct tty *tty)
}
}
if (tty_use_margin(tty))
tty_raw(tty, "\033[?69l"); /* DECLRMM */
tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
setblocking(tty->fd, 1);
@ -352,6 +363,15 @@ tty_free(struct tty *tty)
free(tty->termname);
}
void
tty_set_type(struct tty *tty, int type)
{
tty->term_type = type;
if (tty_use_margin(tty))
tty_puts(tty, "\033[?69h"); /* DECLRMM */
}
void
tty_raw(struct tty *tty, const char *s)
{
@ -835,6 +855,7 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx)
tty_default_attributes(tty, ctx->wp, ctx->bg);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_pane(tty, ctx);
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ctx->num);
@ -854,6 +875,7 @@ tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx)
tty_default_attributes(tty, ctx->wp, ctx->bg);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_pane(tty, ctx);
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ctx->num);
@ -930,6 +952,7 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx)
tty_attributes(tty, &grid_default_cell, ctx->wp);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_pane(tty, ctx);
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper);
tty_putcode(tty, TTYC_RI);
@ -943,7 +966,7 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
if (ctx->ocy != ctx->orlower)
return;
if (!tty_pane_full_width(tty, ctx) ||
if ((!tty_pane_full_width(tty, ctx) && !tty_use_margin(tty)) ||
tty_fake_bce(tty, wp, ctx->bg) ||
!tty_term_has(tty->term, TTYC_CSR)) {
if (tty_large_region(tty, ctx))
@ -954,17 +977,30 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
}
/*
* If this line wrapped naturally (ctx->num is nonzero), don't do
* anything - the cursor can just be moved to the last cell and wrap
* naturally.
* If this line wrapped naturally (ctx->num is nonzero) and we are not
* using margins, don't do anything - the cursor can just be moved
* to the last cell and wrap naturally.
*/
if (ctx->num && !(tty->term->flags & TERM_EARLYWRAP))
if (!tty_use_margin(tty) &&
ctx->num != 0 &&
!(tty->term->flags & TERM_EARLYWRAP)) {
return;
}
tty_attributes(tty, &grid_default_cell, wp);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
tty_margin_pane(tty, ctx);
/*
* If we want to wrap a pane, the cursor needs to be exactly on the
* right of the region. But if the pane isn't on the right, it may be
* off the edge - if so, move the cursor back to the right.
*/
if (ctx->xoff + ctx->ocx > tty->rright)
tty_cursor(tty, tty->rright, ctx->yoff + ctx->ocy);
else
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
tty_putc(tty, '\n');
}
@ -979,6 +1015,7 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx)
tty_default_attributes(tty, wp, ctx->bg);
tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1);
tty_margin_pane(tty, ctx);
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
if (tty_pane_full_width(tty, ctx) &&
@ -1014,6 +1051,7 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx)
tty_attributes(tty, &grid_default_cell, wp);
tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1);
tty_margin_pane(tty, ctx);
tty_cursor_pane(tty, ctx, 0, 0);
if (tty_pane_full_width(tty, ctx) &&
@ -1043,6 +1081,7 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx)
tty_default_attributes(tty, wp, ctx->bg);
tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1);
tty_margin_pane(tty, ctx);
tty_cursor_pane(tty, ctx, 0, 0);
if (tty_pane_full_width(tty, ctx) &&
@ -1073,6 +1112,7 @@ tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx)
tty_attributes(tty, &grid_default_cell, wp);
tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1);
tty_margin_pane(tty, ctx);
for (j = 0; j < screen_size_y(s); j++) {
tty_cursor_pane(tty, ctx, 0, j);
@ -1090,6 +1130,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
if (ctx->ocy == ctx->orlower)
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_pane(tty, ctx);
/* Is the cursor in the very last position? */
width = ctx->cell->data.width;
@ -1250,6 +1291,32 @@ tty_region(struct tty *tty, u_int rupper, u_int rlower)
tty_cursor(tty, 0, 0);
}
/* Set margin inside pane. */
static void
tty_margin_pane(struct tty *tty, const struct tty_ctx *ctx)
{
tty_margin(tty, ctx->xoff, ctx->xoff + ctx->wp->sx - 1);
}
/* Set margin at absolute position. */
void
tty_margin(struct tty *tty, u_int rleft, u_int rright)
{
char s[64];
if (!tty_use_margin(tty))
return;
if (tty->rleft == rleft && tty->rright == rright)
return;
tty->rleft = rleft;
tty->rright = rright;
snprintf(s, sizeof s, "\033[%u;%us", rleft + 1, rright + 1);
tty_puts(tty, s);
tty_cursor(tty, 0, 0);
}
/* Move cursor inside pane. */
static void
tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy)