Update sixdraw.
This commit is contained in:
parent
1758837c47
commit
1a9cbf9302
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue