Update sixdraw.
This commit is contained in:
parent
1758837c47
commit
1a9cbf9302
|
@ -49,9 +49,10 @@
|
||||||
#define DECRQM_SET 1
|
#define DECRQM_SET 1
|
||||||
#define DECRQM_RST 2
|
#define DECRQM_RST 2
|
||||||
|
|
||||||
#define DECTCEM 25u
|
#define DECTCEM 25
|
||||||
#define SGR_MOUSE_PIXELMODE 1016u
|
#define BTN_EVENT_TRACKING 1002
|
||||||
#define ALT_SCRBUF 1049u
|
#define SGR_MOUSE_PIXELMODE 1016
|
||||||
|
#define ALT_SCRBUF 1049
|
||||||
|
|
||||||
#define SIXEL_SEQ_HEAD CTLSEQS_DCS "0;1q\"1;1;"
|
#define SIXEL_SEQ_HEAD CTLSEQS_DCS "0;1q\"1;1;"
|
||||||
|
|
||||||
|
@ -62,14 +63,13 @@ struct sixdraw_ctx {
|
||||||
struct ctlseqs_matcher *matcher;
|
struct ctlseqs_matcher *matcher;
|
||||||
struct ctlseqs_reader *reader;
|
struct ctlseqs_reader *reader;
|
||||||
bool has_termios;
|
bool has_termios;
|
||||||
bool show_cursor;
|
bool hide_cursor;
|
||||||
bool normal_scrbuf;
|
bool alt_scrbuf;
|
||||||
|
bool btnev_tracking;
|
||||||
bool sgr_pixelmode;
|
bool sgr_pixelmode;
|
||||||
int in_fd;
|
int in_fd;
|
||||||
int out_fd;
|
int out_fd;
|
||||||
int timeout;
|
int timeout;
|
||||||
unsigned rows;
|
|
||||||
unsigned cols;
|
|
||||||
unsigned ch_width;
|
unsigned ch_width;
|
||||||
unsigned ch_height;
|
unsigned ch_height;
|
||||||
unsigned line_color;
|
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);
|
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
|
static void
|
||||||
terminate(struct sixdraw_ctx *ctx)
|
terminate(struct sixdraw_ctx *ctx)
|
||||||
{
|
{
|
||||||
|
@ -114,23 +93,27 @@ terminate(struct sixdraw_ctx *ctx)
|
||||||
ctlseqs_reader_free(ctx->reader);
|
ctlseqs_reader_free(ctx->reader);
|
||||||
|
|
||||||
// Restore cursor status.
|
// Restore cursor status.
|
||||||
if (ctx->show_cursor) {
|
if (ctx->hide_cursor) {
|
||||||
dprintf(ctx->out_fd, CTLSEQS_DECSET("%u"), DECTCEM);
|
dprintf(ctx->out_fd, CTLSEQS_DECSET("%d"), DECTCEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore normal screen buffer.
|
// Restore normal screen buffer.
|
||||||
if (ctx->normal_scrbuf) {
|
if (ctx->alt_scrbuf) {
|
||||||
dprintf(ctx->out_fd, CTLSEQS_DECRST("%u"), 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.
|
// Restore original terminal modes.
|
||||||
if (ctx->has_termios) {
|
if (ctx->has_termios) {
|
||||||
tcsetattr(ctx->in_fd, TCSANOW, &ctx->termios);
|
tcsetattr(ctx->in_fd, TCSANOW, &ctx->termios);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx->sgr_pixelmode) {
|
|
||||||
dprintf(ctx->out_fd, CTLSEQS_DECRST("%u"), SGR_MOUSE_PIXELMODE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -145,19 +128,17 @@ get_winsize(struct sixdraw_ctx *ctx)
|
||||||
print_error(ctx, "failed to get terminal window size (in pixels)");
|
print_error(ctx, "failed to get terminal window size (in pixels)");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ctx->rows = ws.ws_row;
|
|
||||||
ctx->cols = ws.ws_col;
|
|
||||||
ctx->ch_width = ws.ws_xpixel / ws.ws_col;
|
ctx->ch_width = ws.ws_xpixel / ws.ws_col;
|
||||||
ctx->ch_height = ws.ws_ypixel / ws.ws_row;
|
ctx->ch_height = ws.ws_ypixel / ws.ws_row;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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;
|
ssize_t retval;
|
||||||
union ctlseqs_value *result = ctx->result;
|
union ctlseqs_value *result = ctx->result;
|
||||||
dprintf(ctx->out_fd, CTLSEQS_DECRQM("%u"), mode_id);
|
dprintf(ctx->out_fd, CTLSEQS_DECRQM("%d"), mode);
|
||||||
do {
|
do {
|
||||||
retval = ctlseqs_read(ctx->reader, ctx->matcher, ctx->timeout);
|
retval = ctlseqs_read(ctx->reader, ctx->matcher, ctx->timeout);
|
||||||
} while (retval == CTLSEQS_PARTIAL);
|
} 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);
|
print_error(ctx, "failed to get %s status", name);
|
||||||
return false;
|
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);
|
print_error(ctx, "%s status not recognizable", name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -175,9 +156,9 @@ decrqm(struct sixdraw_ctx *ctx, unsigned mode_id, char const *name)
|
||||||
static inline void
|
static inline void
|
||||||
get_sixel_color(unsigned rgb888, unsigned *red, unsigned *green, unsigned *blue)
|
get_sixel_color(unsigned rgb888, unsigned *red, unsigned *green, unsigned *blue)
|
||||||
{
|
{
|
||||||
*red = ((rgb888 >> 16) & 0xFF) * 100 / 255;
|
*red = ((rgb888 >> 16) & 0xFF) * 100 / 0xFF;
|
||||||
*green = ((rgb888 >> 8) & 0xFF) * 100 / 255;
|
*green = ((rgb888 >> 8) & 0xFF) * 100 / 0xFF;
|
||||||
*blue = ((rgb888 >> 0) & 0xFF) * 100 / 255;
|
*blue = ((rgb888 >> 0) & 0xFF) * 100 / 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline char *
|
static inline char *
|
||||||
|
@ -208,7 +189,7 @@ print_sixel_dot(struct sixdraw_ctx *ctx, unsigned x, unsigned y)
|
||||||
row = y % ctx->ch_height;
|
row = y % ctx->ch_height;
|
||||||
col = x % ctx->ch_width;
|
col = x % ctx->ch_width;
|
||||||
offset += sprintf(sixel_seq + offset, "%.*s", row / 6, "----------------");
|
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);
|
write(ctx->out_fd, sixel_seq, offset);
|
||||||
}
|
}
|
||||||
|
@ -226,7 +207,7 @@ init(struct sixdraw_ctx *ctx, int argc, char **argv)
|
||||||
|
|
||||||
// Process command line arguments.
|
// Process command line arguments.
|
||||||
int opt;
|
int opt;
|
||||||
while (-1 != (opt = getopt(argc, argv, "t:"))) {
|
while (-1 != (opt = getopt(argc, argv, "t:c:"))) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 't':
|
case 't':
|
||||||
ctx->timeout = atoi(optarg);
|
ctx->timeout = atoi(optarg);
|
||||||
|
@ -248,7 +229,8 @@ init(struct sixdraw_ctx *ctx, int argc, char **argv)
|
||||||
}
|
}
|
||||||
char const *patterns[] = {
|
char const *patterns[] = {
|
||||||
CTLSEQS_RESP_PRIMARY_DA(CTLSEQS_PH_NUMS),
|
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 = {
|
struct ctlseqs_matcher_options matcher_options = {
|
||||||
.patterns = patterns,
|
.patterns = patterns,
|
||||||
|
@ -275,13 +257,6 @@ init(struct sixdraw_ctx *ctx, int argc, char **argv)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block SIGWINCH.
|
|
||||||
sigset_t sigset;
|
|
||||||
sigemptyset(&sigset);
|
|
||||||
sigaddset(&sigset, SIGWINCH);
|
|
||||||
sigprocmask(SIG_BLOCK, &sigset, NULL);
|
|
||||||
signal(SIGWINCH, SIG_DFL);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,48 +322,78 @@ prepare(struct sixdraw_ctx *ctx)
|
||||||
return false;
|
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.
|
// Hide cursor.
|
||||||
if (!decrqm(ctx, DECTCEM, "cursor")) {
|
if (!decrqm(ctx, DECTCEM, "cursor")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ctx->show_cursor = result[1].num == DECRQM_SET;
|
ctx->hide_cursor = result[1].num == DECRQM_SET;
|
||||||
if (ctx->show_cursor) {
|
if (ctx->hide_cursor) {
|
||||||
dprintf(ctx->out_fd, CTLSEQS_DECRST("%u"), DECTCEM);
|
dprintf(ctx->out_fd, CTLSEQS_DECRST("%d"), DECTCEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Switch to alternate screen buffer.
|
// Switch to alternate screen buffer.
|
||||||
if (!decrqm(ctx, ALT_SCRBUF, "screen buffer")) {
|
if (!decrqm(ctx, ALT_SCRBUF, "screen buffer")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ctx->normal_scrbuf = result[1].num == DECRQM_RST;
|
ctx->alt_scrbuf = result[1].num == DECRQM_RST;
|
||||||
if (ctx->normal_scrbuf) {
|
if (ctx->alt_scrbuf) {
|
||||||
dprintf(ctx->out_fd, CTLSEQS_DECSET("%u"), 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;
|
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
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int status = 0;
|
int status;
|
||||||
|
|
||||||
struct sixdraw_ctx ctx;
|
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;
|
status = -1;
|
||||||
goto terminate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
terminate:
|
|
||||||
terminate(&ctx);
|
terminate(&ctx);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue