From fe475bd856ff1f98bf8a4cd9b6aedd5da81a7e3c Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 11 Nov 2022 08:37:55 +0000 Subject: [PATCH] Parse primary device attributes as well as secondary and add a SIXEL flag (not used yet), from Anindya Mukherjee. --- input.c | 4 +- tmux.1 | 4 ++ tmux.h | 5 ++- tty-features.c | 12 ++++++ tty-keys.c | 112 ++++++++++++++++++++++++++++++++++++++++++------- tty-term.c | 1 + tty.c | 10 +++-- 7 files changed, 125 insertions(+), 23 deletions(-) diff --git a/input.c b/input.c index 779b9013..f162b92f 100644 --- a/input.c +++ b/input.c @@ -1345,8 +1345,8 @@ input_csi_dispatch(struct input_ctx *ictx) if (ictx->flags & INPUT_DISCARD) return (0); - log_debug("%s: '%c' \"%s\" \"%s\"", - __func__, ictx->ch, ictx->interm_buf, ictx->param_buf); + log_debug("%s: '%c' \"%s\" \"%s\"", __func__, ictx->ch, + ictx->interm_buf, ictx->param_buf); if (input_split(ictx) != 0) return (0); diff --git a/tmux.1 b/tmux.1 index 52a20266..4f314110 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3687,6 +3687,8 @@ Supports the overline SGR attribute. Supports the DECFRA rectangle fill escape sequence. .It RGB Supports RGB colour with the SGR escape sequences. +.It sixel +Supports SIXEL graphics. .It strikethrough Supports the strikethrough SGR escape sequence. .It sync @@ -6491,6 +6493,8 @@ Set the opening sequence for the working directory notification. The sequence is terminated using the standard .Em fsl capability. +.It Em \&Sxl +Indicates that the terminal supports SIXEL. .It Em \&Sync Start (parameter is 1) or end (parameter is 2) a synchronized update. .It Em \&Tc diff --git a/tmux.h b/tmux.h index 6cb6cc96..8c5e071f 100644 --- a/tmux.h +++ b/tmux.h @@ -543,6 +543,7 @@ enum tty_code_code { TTYC_SMUL, TTYC_SMULX, TTYC_SMXX, + TTYC_SXL, TTYC_SS, TTYC_SWD, TTYC_SYNC, @@ -1349,6 +1350,7 @@ struct tty_term { #define TERM_DECFRA 0x8 #define TERM_RGBCOLOURS 0x10 #define TERM_VT100LIKE 0x20 +#define TERM_SIXEL 0x40 int flags; LIST_ENTRY(tty_term) entry; @@ -1405,9 +1407,10 @@ struct tty { #define TTY_OPENED 0x20 #define TTY_OSC52QUERY 0x40 #define TTY_BLOCK 0x80 -#define TTY_HAVEDA 0x100 +#define TTY_HAVEDA 0x100 /* Primary DA. */ #define TTY_HAVEXDA 0x200 #define TTY_SYNCING 0x400 +#define TTY_HAVEDA2 0x800 /* Seconday DA. */ int flags; struct tty_term *term; diff --git a/tty-features.c b/tty-features.c index 261cb2b8..b1268827 100644 --- a/tty-features.c +++ b/tty-features.c @@ -335,6 +335,17 @@ static const struct tty_feature tty_feature_ignorefkeys = { 0 }; +/* Terminal has sixel capability. */ +static const char *const tty_feature_sixel_capabilities[] = { + "Sxl", + NULL +}; +static const struct tty_feature tty_feature_sixel = { + "sixel", + tty_feature_sixel_capabilities, + 0 +}; + /* Available terminal features. */ static const struct tty_feature *const tty_features[] = { &tty_feature_256, @@ -352,6 +363,7 @@ static const struct tty_feature *const tty_features[] = { &tty_feature_overline, &tty_feature_rectfill, &tty_feature_rgb, + &tty_feature_sixel, &tty_feature_strikethrough, &tty_feature_sync, &tty_feature_title, diff --git a/tty-keys.c b/tty-keys.c index cb8efd49..65294ba8 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -55,6 +55,8 @@ static int tty_keys_clipboard(struct tty *, const char *, size_t, size_t *); static int tty_keys_device_attributes(struct tty *, const char *, size_t, size_t *); +static int tty_keys_device_attributes2(struct tty *, const char *, size_t, + size_t *); static int tty_keys_extended_device_attributes(struct tty *, const char *, size_t, size_t *); @@ -684,7 +686,7 @@ tty_keys_next(struct tty *tty) goto partial_key; } - /* Is this a device attributes response? */ + /* Is this a primary device attributes response? */ switch (tty_keys_device_attributes(tty, buf, len, &size)) { case 0: /* yes */ key = KEYC_UNKNOWN; @@ -695,6 +697,17 @@ tty_keys_next(struct tty *tty) goto partial_key; } + /* Is this a secondary device attributes response? */ + switch (tty_keys_device_attributes2(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 an extended device attributes response? */ switch (tty_keys_extended_device_attributes(tty, buf, len, &size)) { case 0: /* yes */ @@ -1235,7 +1248,7 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) } /* - * Handle secondary device attributes input. Returns 0 for success, -1 for + * Handle primary device attributes input. Returns 0 for success, -1 for * failure, 1 for partial. */ static int @@ -1244,16 +1257,13 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len, { struct client *c = tty->client; u_int i, n = 0; - char tmp[64], *endptr, p[32] = { 0 }, *cp, *next; + char tmp[128], *endptr, p[32] = { 0 }, *cp, *next; *size = 0; if (tty->flags & TTY_HAVEDA) return (-1); - /* - * First three bytes are always \033[>. Some older Terminal.app - * versions respond as for DA (\033[?) so accept and ignore that. - */ + /* First three bytes are always \033[?. */ if (buf[0] != '\033') return (-1); if (len == 1) @@ -1262,35 +1272,105 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len, return (-1); if (len == 2) return (1); - if (buf[2] != '>' && buf[2] != '?') + if (buf[2] != '?') return (-1); if (len == 3) return (1); /* Copy the rest up to a 'c'. */ - for (i = 0; i < (sizeof tmp) - 1; i++) { + for (i = 0; i < (sizeof tmp); i++) { if (3 + i == len) return (1); if (buf[3 + i] == 'c') break; tmp[i] = buf[3 + i]; } - if (i == (sizeof tmp) - 1) + if (i == (sizeof tmp)) return (-1); tmp[i] = '\0'; *size = 4 + i; - /* Ignore DA response. */ - if (buf[2] == '?') - return (0); - /* Convert all arguments to numbers. */ cp = tmp; while ((next = strsep(&cp, ";")) != NULL) { p[n] = strtoul(next, &endptr, 10); if (*endptr != '\0') p[n] = 0; - n++; + if (++n == nitems(p)) + break; + } + + /* Add terminal features. */ + switch (p[0]) { + case 62: /* VT220 */ + case 63: /* VT320 */ + case 64: /* VT420 */ + for (i = 1; i < n; i++) { + log_debug("%s: DA feature: %d", c->name, p[i]); + if (p[i] == 4) + tty->term->flags |= TERM_SIXEL; + } + break; + } + log_debug("%s: received primary DA %.*s", c->name, (int)*size, buf); + + tty_update_features(tty); + tty->flags |= TTY_HAVEDA; + + return (0); +} + +/* + * Handle secondary device attributes input. Returns 0 for success, -1 for + * failure, 1 for partial. + */ +static int +tty_keys_device_attributes2(struct tty *tty, const char *buf, size_t len, + size_t *size) +{ + struct client *c = tty->client; + u_int i, n = 0; + char tmp[128], *endptr, p[32] = { 0 }, *cp, *next; + + *size = 0; + if (tty->flags & TTY_HAVEDA2) + return (-1); + + /* 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); i++) { + if (3 + i == len) + return (1); + if (buf[3 + i] == 'c') + break; + tmp[i] = buf[3 + i]; + } + if (i == (sizeof tmp)) + return (-1); + tmp[i] = '\0'; + *size = 4 + i; + + /* Convert all arguments to numbers. */ + cp = tmp; + while ((next = strsep(&cp, ";")) != NULL) { + p[n] = strtoul(next, &endptr, 10); + if (*endptr != '\0') + p[n] = 0; + if (++n == nitems(p)) + break; } /* Add terminal features. */ @@ -1311,7 +1391,7 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len, log_debug("%s: received secondary DA %.*s", c->name, (int)*size, buf); tty_update_features(tty); - tty->flags |= TTY_HAVEDA; + tty->flags |= TTY_HAVEDA2; return (0); } diff --git a/tty-term.c b/tty-term.c index e3167f19..23abccf5 100644 --- a/tty-term.c +++ b/tty-term.c @@ -265,6 +265,7 @@ static const struct tty_term_code_entry tty_term_codes[] = { [TTYC_SETRGBF] = { TTYCODE_STRING, "setrgbf" }, [TTYC_SETULC] = { TTYCODE_STRING, "Setulc" }, [TTYC_SE] = { TTYCODE_STRING, "Se" }, + [TTYC_SXL] = { TTYCODE_FLAG, "Sxl" }, [TTYC_SGR0] = { TTYCODE_STRING, "sgr0" }, [TTYC_SITM] = { TTYCODE_STRING, "sitm" }, [TTYC_SMACS] = { TTYCODE_STRING, "smacs" }, diff --git a/tty.c b/tty.c index 1394075d..43a2961f 100644 --- a/tty.c +++ b/tty.c @@ -299,9 +299,9 @@ tty_start_timer_callback(__unused int fd, __unused short events, void *data) struct client *c = tty->client; log_debug("%s: start timer fired", c->name); - if ((tty->flags & (TTY_HAVEDA|TTY_HAVEXDA)) == 0) + if ((tty->flags & (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA)) == 0) tty_update_features(tty); - tty->flags |= (TTY_HAVEDA|TTY_HAVEXDA); + tty->flags |= (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA); } void @@ -363,12 +363,14 @@ tty_send_requests(struct tty *tty) return; if (tty->term->flags & TERM_VT100LIKE) { - if (~tty->flags & TTY_HAVEDA) + if (~tty->term->flags & TTY_HAVEDA) + tty_puts(tty, "\033[c"); + if (~tty->flags & TTY_HAVEDA2) tty_puts(tty, "\033[>c"); if (~tty->flags & TTY_HAVEXDA) tty_puts(tty, "\033[>q"); } else - tty->flags |= (TTY_HAVEDA|TTY_HAVEXDA); + tty->flags |= (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA); } void