Check and enable sixel scrolling in example.

This commit is contained in:
CismonX 2021-10-30 21:13:38 +08:00
parent 0ebc0054c4
commit b2c5b019cc
Signed by: cismonx
GPG Key ID: 3094873E29A482FB
1 changed files with 69 additions and 10 deletions

View File

@ -29,10 +29,12 @@
# include "config.h"
#endif // HAVE_CONFIG_H
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <getopt.h>
@ -46,17 +48,19 @@
# define DEFAULT_TIMEOUT_MILLIS 500
#endif // !DEFAULT_TIMEOUT_MILLIS
#define DECRQM_SET 1
#define DECRQM_RST 2
#define DECRQM_UNREC 0
#define DECRQM_SET 1
#define DECRQM_RST 2
#define DECTCEM 25
#define DECSDM 80
#define BTN_EVENT_TRACKING 1002
#define SGR_MOUSE_PIXELMODE 1016
#define ALT_SCRBUF 1049
#define SIXEL_SEQ_HEAD CTLSEQS_DCS "0;1q\"1;1;"
static char sixel_seq[2048] = SIXEL_SEQ_HEAD;
static char sixel_seq[4096] = SIXEL_SEQ_HEAD;
struct sixdraw_ctx {
struct termios termios;
@ -70,7 +74,9 @@ struct sixdraw_ctx {
bool hide_cursor;
bool alt_scrbuf;
bool btnev_tracking;
bool legacy_xterm;
bool sgr_pixelmode;
bool sixel_scroll;
int in_fd;
int out_fd;
int timeout;
@ -100,11 +106,6 @@ terminate(struct sixdraw_ctx *ctx)
ctlseqs_matcher_free(ctx->matcher);
ctlseqs_reader_free(ctx->reader);
// Restore cursor status.
if (ctx->hide_cursor) {
fprintf(ctx->out_file, CTLSEQS_DECSET("%d"), DECTCEM);
}
// Restore normal screen buffer.
if (ctx->alt_scrbuf) {
fprintf(ctx->out_file, CTLSEQS_DECRST("%d"), ALT_SCRBUF);
@ -118,6 +119,16 @@ terminate(struct sixdraw_ctx *ctx)
fprintf(ctx->out_file, CTLSEQS_DECRST("%d"), SGR_MOUSE_PIXELMODE);
}
// Restore cursor status.
if (ctx->hide_cursor) {
fprintf(ctx->out_file, CTLSEQS_DECSET("%d"), DECTCEM);
}
// Restore original sixel mode.
if (ctx->sixel_scroll) {
fprintf(ctx->out_file, ctx->legacy_xterm ? CTLSEQS_DECRST("%d") : CTLSEQS_DECSET("%d"), DECSDM);
}
// Restore original terminal modes.
if (ctx->has_termios) {
tcsetattr(ctx->in_fd, TCSANOW, &ctx->termios);
@ -157,13 +168,41 @@ decrqm(struct sixdraw_ctx *ctx, unsigned mode, char const *name)
print_error(ctx, "failed to get %s status", name);
return false;
}
if (result[0].num != mode || (result[1].num != DECRQM_SET && result[1].num != DECRQM_RST)) {
if (result[0].num != mode || result[1].num == DECRQM_UNREC) {
print_error(ctx, "%s status not recognizable", name);
return false;
}
return true;
}
static long
xtversion(struct sixdraw_ctx *ctx) {
ssize_t retval;
union ctlseqs_value *result = ctx->result;
fprintf(ctx->out_file, CTLSEQS_XTVERSION());
do {
retval = ctlseqs_read(ctx->reader, ctx->matcher, ctx->timeout);
} while (retval == CTLSEQS_PARTIAL);
if (retval != 3) {
// Terminal emulator does not recognize XTVERSION;
return -1;
}
char const *xtversion = result[1].str;
if (result[0].len < sizeof("XTerm(")) {
return -2;
}
if (strncmp(xtversion, "XTerm(", sizeof("XTerm(") - 1) != 0) {
// Terminal emulator is not XTerm.
return -2;
}
errno = 0;
long version_num = strtol(xtversion + (sizeof("XTerm(") - 1), NULL, 10);
if (errno) {
return -3;
}
return version_num;
}
static void
print_sixel_dot(struct sixdraw_ctx *ctx, unsigned x, unsigned y)
{
@ -225,7 +264,8 @@ init(struct sixdraw_ctx *ctx, int argc, char **argv)
char const *patterns[] = {
CTLSEQS_RESP_PRIMARY_DA(CTLSEQS_PH_NUMS),
CTLSEQS_RESP_DECRQM(CTLSEQS_PH_NUM, CTLSEQS_PH_NUM),
CTLSEQS_RESP_SGR_MOUSE(CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, "M")
CTLSEQS_RESP_SGR_MOUSE(CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, "M"),
CTLSEQS_RESP_XTVERSION(CTLSEQS_PH_STR),
};
struct ctlseqs_matcher_options matcher_options = {
.patterns = patterns,
@ -330,6 +370,25 @@ prepare(struct sixdraw_ctx *ctx)
fprintf(ctx->out_file, CTLSEQS_DECRST("%d"), DECTCEM);
}
// Check terminal name and version.
long xterm_version = xtversion(ctx);
if (xterm_version >= 0 && xterm_version < 369) {
ctx->legacy_xterm = true;
} else {
ctx->legacy_xterm = false;
}
// Enable sixel scrolling.
if (!decrqm(ctx, DECSDM, "sixel scrolling")) {
return false;
}
// Before patch #369, XTerm implemented DECSDM incorrectly.
// See https://invisible-island.net/xterm/xterm.log.html#xterm_369
ctx->sixel_scroll = result[1].num == (ctx->legacy_xterm ? DECRQM_RST : DECRQM_SET);
if (ctx->sixel_scroll) {
fprintf(ctx->out_file, ctx->legacy_xterm ? CTLSEQS_DECSET("%d") : CTLSEQS_DECRST("%d"), DECSDM);
}
// Enable button event tracking mode.
if (!decrqm(ctx, BTN_EVENT_TRACKING, "button event tracking mode")) {
return false;