Update sixdraw.
This commit is contained in:
parent
decdf5738f
commit
1cbe732b6e
|
@ -1,9 +1,13 @@
|
||||||
/**
|
/**
|
||||||
* sixdraw.c - draw lines on your terminal
|
* sixdraw.c - draw lines on your terminal
|
||||||
*
|
*
|
||||||
* Requires sixel graphics and DEC locator support to run on your terminal.
|
* Requires sixel graphics and 1016 mouse mode to run on your terminal.
|
||||||
* These features are not widely supported. To save yourself from trouble,
|
* These features are not widely supported. To save yourself from trouble,
|
||||||
* use a latest version of XTerm or mlterm.
|
* use a latest version of XTerm or mintty.
|
||||||
|
*
|
||||||
|
* Before 1016 mode was introduced in XTerm patch #359, it is also possible
|
||||||
|
* to report mouse position in pixels using DEC locator (which is also rarely
|
||||||
|
* implemented). However, it is not used in this example.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020 CismonX <admin@cismon.net>
|
* Copyright (C) 2020 CismonX <admin@cismon.net>
|
||||||
*
|
*
|
||||||
|
@ -44,9 +48,13 @@
|
||||||
|
|
||||||
#define DECRQM_SET 1
|
#define DECRQM_SET 1
|
||||||
#define DECRQM_RST 2
|
#define DECRQM_RST 2
|
||||||
|
|
||||||
#define DECTCEM 25u
|
#define DECTCEM 25u
|
||||||
|
#define SGR_MOUSE_PIXELMODE 1016u
|
||||||
#define ALT_SCRBUF 1049u
|
#define ALT_SCRBUF 1049u
|
||||||
|
|
||||||
|
#define SIXEL_SEQ_HEAD CTLSEQS_DCS "0;1q\"1;1;"
|
||||||
|
|
||||||
struct sixdraw_ctx {
|
struct sixdraw_ctx {
|
||||||
struct termios termios;
|
struct termios termios;
|
||||||
union ctlseqs_value result[64];
|
union ctlseqs_value result[64];
|
||||||
|
@ -56,13 +64,15 @@ struct sixdraw_ctx {
|
||||||
bool has_termios;
|
bool has_termios;
|
||||||
bool show_cursor;
|
bool show_cursor;
|
||||||
bool normal_scrbuf;
|
bool normal_scrbuf;
|
||||||
|
bool sgr_pixelmode;
|
||||||
int in_fd;
|
int in_fd;
|
||||||
int out_fd;
|
int out_fd;
|
||||||
int timeout;
|
int timeout;
|
||||||
int rows;
|
unsigned rows;
|
||||||
int cols;
|
unsigned cols;
|
||||||
int ch_width;
|
unsigned ch_width;
|
||||||
int ch_height;
|
unsigned ch_height;
|
||||||
|
unsigned line_color;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -117,6 +127,10 @@ terminate(struct sixdraw_ctx *ctx)
|
||||||
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
|
||||||
|
@ -158,6 +172,47 @@ decrqm(struct sixdraw_ctx *ctx, unsigned mode_id, char const *name)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline char *
|
||||||
|
get_sixel_buffer()
|
||||||
|
{
|
||||||
|
static char sixel_seq_buffer[2048] = SIXEL_SEQ_HEAD;
|
||||||
|
return sixel_seq_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_sixel_dot(struct sixdraw_ctx *ctx, unsigned x, unsigned y)
|
||||||
|
{
|
||||||
|
char *sixel_seq = get_sixel_buffer();
|
||||||
|
size_t offset = sizeof(SIXEL_SEQ_HEAD) - 1;
|
||||||
|
offset += sprintf(sixel_seq + offset, "%d;%d", ctx->ch_width, ctx->ch_height);
|
||||||
|
|
||||||
|
// Select color
|
||||||
|
unsigned red, green, blue;
|
||||||
|
get_sixel_color(ctx->line_color, &red, &green, &blue);
|
||||||
|
offset += sprintf(sixel_seq + offset, "#0;2;%d;%d;%d#0", red, green, blue);
|
||||||
|
|
||||||
|
// Move cursor
|
||||||
|
unsigned row = y / ctx->ch_height + 1;
|
||||||
|
unsigned col = x / ctx->ch_width + 1;
|
||||||
|
dprintf(ctx->out_fd, CTLSEQS_CUP("%d", "%d"), row, col);
|
||||||
|
|
||||||
|
// Print dot
|
||||||
|
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);
|
||||||
|
|
||||||
|
write(ctx->out_fd, sixel_seq, offset);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
init(struct sixdraw_ctx *ctx, int argc, char **argv)
|
init(struct sixdraw_ctx *ctx, int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -166,6 +221,7 @@ init(struct sixdraw_ctx *ctx, int argc, char **argv)
|
||||||
.in_fd = STDIN_FILENO,
|
.in_fd = STDIN_FILENO,
|
||||||
.out_fd = STDOUT_FILENO,
|
.out_fd = STDOUT_FILENO,
|
||||||
.timeout = DEFAULT_TIMEOUT_MILLIS,
|
.timeout = DEFAULT_TIMEOUT_MILLIS,
|
||||||
|
.line_color = 0x00FF00
|
||||||
};
|
};
|
||||||
|
|
||||||
// Process command line arguments.
|
// Process command line arguments.
|
||||||
|
@ -175,6 +231,9 @@ init(struct sixdraw_ctx *ctx, int argc, char **argv)
|
||||||
case 't':
|
case 't':
|
||||||
ctx->timeout = atoi(optarg);
|
ctx->timeout = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'c':
|
||||||
|
ctx->line_color = strtoul(optarg, NULL, 16);
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -277,42 +336,40 @@ prepare(struct sixdraw_ctx *ctx)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool has_sixel = false;
|
bool has_sixel = false;
|
||||||
bool has_dec_locator = false;
|
|
||||||
union ctlseqs_value *result = ctx->result;
|
union ctlseqs_value *result = ctx->result;
|
||||||
for (size_t i = 1; i <= result[0].len; ++i) {
|
for (size_t i = 1; i <= result[0].len; ++i) {
|
||||||
if (result[i].num == 4) {
|
if (result[i].num == 4) {
|
||||||
has_sixel = true;
|
has_sixel = true;
|
||||||
} else if (result[i].num == 29) {
|
|
||||||
has_dec_locator = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!has_sixel) {
|
if (!has_sixel) {
|
||||||
print_error(ctx, "terminal does not support sixel graphics");
|
print_error(ctx, "terminal does not support sixel graphics");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!has_dec_locator) {
|
|
||||||
print_error(ctx, "terminal does not support DEC locator mode");
|
// Switch into SGR mouse pixel mode.
|
||||||
|
if (!decrqm(ctx, SGR_MOUSE_PIXELMODE, "SGR mouse pixel mode")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
ctx->sgr_pixelmode = result[1].num == DECRQM_SET;
|
||||||
|
if (!ctx->sgr_pixelmode) {
|
||||||
|
dprintf(ctx->out_fd, CTLSEQS_DECSET("%u"), SGR_MOUSE_PIXELMODE);
|
||||||
|
}
|
||||||
|
|
||||||
// Get current cursor status.
|
// 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->show_cursor = result[1].num == DECRQM_SET;
|
||||||
|
|
||||||
// Hide cursor.
|
|
||||||
if (ctx->show_cursor) {
|
if (ctx->show_cursor) {
|
||||||
dprintf(ctx->out_fd, CTLSEQS_DECRST("%u"), DECTCEM);
|
dprintf(ctx->out_fd, CTLSEQS_DECRST("%u"), DECTCEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current screen buffer status.
|
// 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->normal_scrbuf = result[1].num == DECRQM_RST;
|
||||||
|
|
||||||
// Switch to alternate screen buffer.
|
|
||||||
if (ctx->normal_scrbuf) {
|
if (ctx->normal_scrbuf) {
|
||||||
dprintf(ctx->out_fd, CTLSEQS_DECSET("%u"), ALT_SCRBUF);
|
dprintf(ctx->out_fd, CTLSEQS_DECSET("%u"), ALT_SCRBUF);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue