aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server-client.c1
-rw-r--r--tmux.h14
-rw-r--r--tty-keys.c94
-rw-r--r--tty.c89
4 files changed, 187 insertions, 11 deletions
diff --git a/server-client.c b/server-client.c
index b92bada5..29f3e08b 100644
--- a/server-client.c
+++ b/server-client.c
@@ -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)
diff --git a/tmux.h b/tmux.h
index 50527c10..e2d49962 100644
--- a/tmux.h
+++ b/tmux.h
@@ -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 *);
diff --git a/tty-keys.c b/tty-keys.c
index 174b008e..802bbbdc 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -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);
+}
diff --git a/tty.c b/tty.c
index 34270625..fb7b6f8c 100644
--- a/tty.c
+++ b/tty.c
@@ -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);
@@ -353,6 +364,15 @@ tty_free(struct tty *tty)
}
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)
{
ssize_t n, slen;
@@ -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)