Update sixdraw.

This commit is contained in:
CismonX 2020-12-22 21:51:01 +08:00
parent c7730bf220
commit b19ef960a0
Signed by: cismonx
GPG Key ID: 3094873E29A482FB
1 changed files with 62 additions and 12 deletions

View File

@ -26,6 +26,7 @@
#endif // HAVE_CONFIG_H
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@ -41,6 +42,11 @@
# define SIXDRAW_DEFAULT_TIMEOUT_MILLIS 500
#endif // !SIXDRAW_DEFAULT_TIMEOUT_MILLIS
#define SIXDRAW_DECRQM_SET 1
#define SIXDRAW_DECRQM_RST 2
#define SIXDRAW_DECTCEM 25u
#define SIXDRAW_ALT_SCRBUF 1049u
struct sixdraw_ctx {
struct termios termios;
union ctlseqs_value buffer[64];
@ -49,6 +55,7 @@ struct sixdraw_ctx {
struct ctlseqs_reader *reader;
bool has_termios;
bool show_cursor;
bool normal_scrbuf;
int in_fd;
int out_fd;
int timeout;
@ -59,8 +66,13 @@ struct sixdraw_ctx {
};
static inline void
sixdraw_print_error(struct sixdraw_ctx const *ctx, char const *msg)
sixdraw_print_error(struct sixdraw_ctx const *ctx, char const *format, ...)
{
char msg[1024];
va_list args;
va_start(args, format);
vsnprintf(msg, 1024, format, args);
va_end(args);
dprintf(ctx->out_fd, "%s: [error] %s.\n", ctx->prog_name, msg);
}
@ -91,7 +103,17 @@ sixdraw_terminate(struct sixdraw_ctx *ctx)
ctlseqs_matcher_free(ctx->matcher);
ctlseqs_reader_free(ctx->reader);
// Restore original terminal modes
// Restore cursor status.
if (ctx->show_cursor) {
dprintf(ctx->out_fd, CTLSEQS_DECSET("%u"), SIXDRAW_DECTCEM);
}
// Restore normal screen buffer.
if (ctx->normal_scrbuf) {
dprintf(ctx->out_fd, CTLSEQS_DECRST("%u"), SIXDRAW_ALT_SCRBUF);
}
// Restore original terminal modes.
if (ctx->has_termios) {
tcsetattr(ctx->in_fd, TCSANOW, &ctx->termios);
}
@ -102,9 +124,11 @@ sixdraw_get_winsize(struct sixdraw_ctx *ctx)
{
struct winsize ws = { 0 };
if (ioctl(ctx->in_fd, TIOCGWINSZ, &ws) != 0) {
sixdraw_print_error(ctx, "failed to get terminal window size");
return false;
}
if (ws.ws_xpixel == 0 || ws.ws_ypixel == 0) {
sixdraw_print_error(ctx, "failed to get terminal window size (in pixels)");
return false;
}
ctx->rows = ws.ws_row;
@ -114,6 +138,26 @@ sixdraw_get_winsize(struct sixdraw_ctx *ctx)
return true;
}
static bool
sixdraw_decrqm(struct sixdraw_ctx *ctx, unsigned mode_id, char const *name)
{
ssize_t result;
union ctlseqs_value *buffer = ctx->buffer;
dprintf(ctx->out_fd, CTLSEQS_DECRQM("%u"), mode_id);
do {
result = ctlseqs_read(ctx->reader, ctx->matcher, ctx->timeout);
} while (result == CTLSEQS_PARTIAL);
if (result != 1) {
sixdraw_print_error(ctx, "failed to get %s status", name);
return false;
}
if (buffer[0].num != mode_id || (buffer[1].num != SIXDRAW_DECRQM_SET && buffer[1].num != SIXDRAW_DECRQM_RST)) {
sixdraw_print_error(ctx, "%s status not recognizable", name);
return false;
}
return true;
}
static bool
sixdraw_init(struct sixdraw_ctx *ctx, int argc, char **argv)
{
@ -219,7 +263,6 @@ sixdraw_prepare(struct sixdraw_ctx *ctx)
// Get initial terminal window size.
if (!sixdraw_get_winsize(ctx)) {
sixdraw_print_error(ctx, "failed to get terminal window size");
return false;
}
@ -253,19 +296,26 @@ sixdraw_prepare(struct sixdraw_ctx *ctx)
}
// Get current cursor status.
dprintf(ctx->out_fd, CTLSEQS_DECRQM("25"));
do {
result = ctlseqs_read(ctx->reader, ctx->matcher, ctx->timeout);
} while (result == CTLSEQS_PARTIAL);
if (result != 1) {
sixdraw_print_error(ctx, "failed to get cursor status");
if (!sixdraw_decrqm(ctx, SIXDRAW_DECTCEM, "cursor")) {
return false;
}
if (buffer[0].num != 25 || (buffer[1].num != 1 && buffer[1].num != 2)) {
sixdraw_print_error(ctx, "cursor status not recognizable");
ctx->show_cursor = buffer[1].num == SIXDRAW_DECRQM_SET;
// Hide cursor.
if (ctx->show_cursor) {
dprintf(ctx->out_fd, CTLSEQS_DECRST("%u"), SIXDRAW_DECTCEM);
}
// Get current screen buffer status.
if (!sixdraw_decrqm(ctx, SIXDRAW_ALT_SCRBUF, "screen buffer")) {
return false;
}
ctx->show_cursor = buffer[1].num == 1;
ctx->normal_scrbuf = buffer[1].num == SIXDRAW_DECRQM_RST;
// Switch to alternate screen buffer.
if (ctx->normal_scrbuf) {
dprintf(ctx->out_fd, CTLSEQS_DECSET("%u"), SIXDRAW_ALT_SCRBUF);
}
return true;
}