Update sixdraw.

This commit is contained in:
CismonX 2021-01-08 08:00:49 +08:00
parent 1758837c47
commit 1a9cbf9302
Signed by: cismonx
GPG Key ID: 3094873E29A482FB
1 changed files with 80 additions and 75 deletions

View File

@ -49,9 +49,10 @@
#define DECRQM_SET 1
#define DECRQM_RST 2
#define DECTCEM 25u
#define SGR_MOUSE_PIXELMODE 1016u
#define ALT_SCRBUF 1049u
#define DECTCEM 25
#define BTN_EVENT_TRACKING 1002
#define SGR_MOUSE_PIXELMODE 1016
#define ALT_SCRBUF 1049
#define SIXEL_SEQ_HEAD CTLSEQS_DCS "0;1q\"1;1;"
@ -62,14 +63,13 @@ struct sixdraw_ctx {
struct ctlseqs_matcher *matcher;
struct ctlseqs_reader *reader;
bool has_termios;
bool show_cursor;
bool normal_scrbuf;
bool hide_cursor;
bool alt_scrbuf;
bool btnev_tracking;
bool sgr_pixelmode;
int in_fd;
int out_fd;
int timeout;
unsigned rows;
unsigned cols;
unsigned ch_width;
unsigned ch_height;
unsigned line_color;
@ -86,27 +86,6 @@ print_error(struct sixdraw_ctx const *ctx, char const *format, ...)
dprintf(ctx->out_fd, "%s: [error] %s.\n", ctx->prog_name, msg);
}
static inline void
clear_signal(int signum)
{
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, signum);
sigwait(&sigset, &signum);
}
static bool
handle_signals(struct sixdraw_ctx *ctx)
{
sigset_t sigset;
sigpending(&sigset);
if (!sigismember(&sigset, SIGWINCH)) {
return false;
}
clear_signal(SIGWINCH);
return true;
}
static void
terminate(struct sixdraw_ctx *ctx)
{
@ -114,23 +93,27 @@ terminate(struct sixdraw_ctx *ctx)
ctlseqs_reader_free(ctx->reader);
// Restore cursor status.
if (ctx->show_cursor) {
dprintf(ctx->out_fd, CTLSEQS_DECSET("%u"), DECTCEM);
if (ctx->hide_cursor) {
dprintf(ctx->out_fd, CTLSEQS_DECSET("%d"), DECTCEM);
}
// Restore normal screen buffer.
if (ctx->normal_scrbuf) {
dprintf(ctx->out_fd, CTLSEQS_DECRST("%u"), ALT_SCRBUF);
if (ctx->alt_scrbuf) {
dprintf(ctx->out_fd, CTLSEQS_DECRST("%d"), ALT_SCRBUF);
}
// Restore original mouse modes.
if (ctx->btnev_tracking) {
dprintf(ctx->out_fd, CTLSEQS_DECRST("%d"), BTN_EVENT_TRACKING);
}
if (ctx->sgr_pixelmode) {
dprintf(ctx->out_fd, CTLSEQS_DECRST("%d"), SGR_MOUSE_PIXELMODE);
}
// Restore original terminal modes.
if (ctx->has_termios) {
tcsetattr(ctx->in_fd, TCSANOW, &ctx->termios);
}
if (!ctx->sgr_pixelmode) {
dprintf(ctx->out_fd, CTLSEQS_DECRST("%u"), SGR_MOUSE_PIXELMODE);
}
}
static bool
@ -145,19 +128,17 @@ get_winsize(struct sixdraw_ctx *ctx)
print_error(ctx, "failed to get terminal window size (in pixels)");
return false;
}
ctx->rows = ws.ws_row;
ctx->cols = ws.ws_col;
ctx->ch_width = ws.ws_xpixel / ws.ws_col;
ctx->ch_height = ws.ws_ypixel / ws.ws_row;
return true;
}
static bool
decrqm(struct sixdraw_ctx *ctx, unsigned mode_id, char const *name)
decrqm(struct sixdraw_ctx *ctx, unsigned mode, char const *name)
{
ssize_t retval;
union ctlseqs_value *result = ctx->result;
dprintf(ctx->out_fd, CTLSEQS_DECRQM("%u"), mode_id);
dprintf(ctx->out_fd, CTLSEQS_DECRQM("%d"), mode);
do {
retval = ctlseqs_read(ctx->reader, ctx->matcher, ctx->timeout);
} while (retval == CTLSEQS_PARTIAL);
@ -165,7 +146,7 @@ decrqm(struct sixdraw_ctx *ctx, unsigned mode_id, char const *name)
print_error(ctx, "failed to get %s status", name);
return false;
}
if (result[0].num != mode_id || (result[1].num != DECRQM_SET && result[1].num != DECRQM_RST)) {
if (result[0].num != mode || (result[1].num != DECRQM_SET && result[1].num != DECRQM_RST)) {
print_error(ctx, "%s status not recognizable", name);
return false;
}
@ -175,9 +156,9 @@ decrqm(struct sixdraw_ctx *ctx, unsigned mode_id, char const *name)
static inline void
get_sixel_color(unsigned rgb888, unsigned *red, unsigned *green, unsigned *blue)
{
*red = ((rgb888 >> 16) & 0xFF) * 100 / 255;
*green = ((rgb888 >> 8) & 0xFF) * 100 / 255;
*blue = ((rgb888 >> 0) & 0xFF) * 100 / 255;
*red = ((rgb888 >> 16) & 0xFF) * 100 / 0xFF;
*green = ((rgb888 >> 8) & 0xFF) * 100 / 0xFF;
*blue = ((rgb888 >> 0) & 0xFF) * 100 / 0xFF;
}
static inline char *
@ -208,7 +189,7 @@ print_sixel_dot(struct sixdraw_ctx *ctx, unsigned x, unsigned y)
row = y % ctx->ch_height;
col = x % ctx->ch_width;
offset += sprintf(sixel_seq + offset, "%.*s", row / 6, "----------------");
offset += sprintf(sixel_seq + offset, "!%u?%u", col, (1 << row % 6) + 0x3F);
offset += sprintf(sixel_seq + offset, "!%u?%c" CTLSEQS_ST, col, (1 << row % 6) + 0x3F);
write(ctx->out_fd, sixel_seq, offset);
}
@ -226,7 +207,7 @@ init(struct sixdraw_ctx *ctx, int argc, char **argv)
// Process command line arguments.
int opt;
while (-1 != (opt = getopt(argc, argv, "t:"))) {
while (-1 != (opt = getopt(argc, argv, "t:c:"))) {
switch (opt) {
case 't':
ctx->timeout = atoi(optarg);
@ -248,7 +229,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_DECRQM(CTLSEQS_PH_NUM, CTLSEQS_PH_NUM),
CTLSEQS_RESP_SGR_MOUSE(CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, "M")
};
struct ctlseqs_matcher_options matcher_options = {
.patterns = patterns,
@ -275,13 +257,6 @@ init(struct sixdraw_ctx *ctx, int argc, char **argv)
return false;
}
// Block SIGWINCH.
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGWINCH);
sigprocmask(SIG_BLOCK, &sigset, NULL);
signal(SIGWINCH, SIG_DFL);
return true;
}
@ -347,48 +322,78 @@ prepare(struct sixdraw_ctx *ctx)
return false;
}
// Switch into SGR mouse pixel mode.
if (!decrqm(ctx, SGR_MOUSE_PIXELMODE, "SGR mouse pixel mode")) {
return false;
}
ctx->sgr_pixelmode = result[1].num == DECRQM_SET;
if (!ctx->sgr_pixelmode) {
dprintf(ctx->out_fd, CTLSEQS_DECSET("%u"), SGR_MOUSE_PIXELMODE);
}
// Hide cursor.
if (!decrqm(ctx, DECTCEM, "cursor")) {
return false;
}
ctx->show_cursor = result[1].num == DECRQM_SET;
if (ctx->show_cursor) {
dprintf(ctx->out_fd, CTLSEQS_DECRST("%u"), DECTCEM);
ctx->hide_cursor = result[1].num == DECRQM_SET;
if (ctx->hide_cursor) {
dprintf(ctx->out_fd, CTLSEQS_DECRST("%d"), DECTCEM);
}
// Switch to alternate screen buffer.
if (!decrqm(ctx, ALT_SCRBUF, "screen buffer")) {
return false;
}
ctx->normal_scrbuf = result[1].num == DECRQM_RST;
if (ctx->normal_scrbuf) {
dprintf(ctx->out_fd, CTLSEQS_DECSET("%u"), ALT_SCRBUF);
ctx->alt_scrbuf = result[1].num == DECRQM_RST;
if (ctx->alt_scrbuf) {
dprintf(ctx->out_fd, CTLSEQS_DECSET("%d"), ALT_SCRBUF);
}
// Enable button event tracking mode.
if (!decrqm(ctx, BTN_EVENT_TRACKING, "button event tracking mode")) {
return false;
}
ctx->btnev_tracking = result[1].num == DECRQM_RST;
if (ctx->btnev_tracking) {
dprintf(ctx->out_fd, CTLSEQS_DECSET("%d"), BTN_EVENT_TRACKING);
}
// Enable SGR mouse pixel mode.
if (!decrqm(ctx, SGR_MOUSE_PIXELMODE, "SGR mouse pixel mode")) {
return false;
}
ctx->sgr_pixelmode = result[1].num == DECRQM_RST;
if (ctx->sgr_pixelmode) {
dprintf(ctx->out_fd, CTLSEQS_DECSET("%d"), SGR_MOUSE_PIXELMODE);
}
return true;
}
static bool
draw(struct sixdraw_ctx *ctx)
{
union ctlseqs_value *result = ctx->result;
while (true) {
switch (ctlseqs_read(ctx->reader, ctx->matcher, -1)) {
case 2: // CTLSEQS_RESP_SGR_MOUSE
print_sixel_dot(ctx, result[1].num, result[2].num);
break;
case CTLSEQS_NOSEQ:
// Press Ctrl+C to exit.
if (result[1].str[0] == 0x03) {
return true;
}
break;
case CTLSEQS_ERROR:
case CTLSEQS_NOMEM:
case CTLSEQS_EOF:
return false;
}
}
}
int
main(int argc, char **argv)
{
int status = 0;
int status;
struct sixdraw_ctx ctx;
if (!init(&ctx, argc, argv) || !prepare(&ctx)) {
if (init(&ctx, argc, argv) && prepare(&ctx)) {
status = draw(&ctx) ? 0 : -1;
} else {
status = -1;
goto terminate;
}
terminate:
terminate(&ctx);
return status;
}