diff --git a/include/util.h b/include/util.h index 126533c..9dce5fd 100644 --- a/include/util.h +++ b/include/util.h @@ -1,6 +1,7 @@ #ifndef UTILH_ #define UTILH_ +#include #include #include #include @@ -12,6 +13,8 @@ int find_keyname(enum keys* at, const char* name); enum keys find_ansi(const char* seq); void read_press(u_char* length, char* out); +// non blocking, waits up to tv, returns true if actually read +bool read_press_nb(u_char* length, char* out, struct timeval* tv); bool utf8_iscont(char byte); size_t utf8len(const char* str); diff --git a/src/ui.c b/src/ui.c index 85ab74c..0d6a271 100644 --- a/src/ui.c +++ b/src/ui.c @@ -46,6 +46,7 @@ static void print_session(struct uint_point origin, struct session session, static void print_user(struct uint_point origin, struct user user, bool multiple); static void print_passwd(struct uint_point origin, uint length, bool err); +static void scratch_print_ui(); // ansi resource: https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 static struct termios orig_term; @@ -54,18 +55,15 @@ static struct winsize window; #define INNER_BOX_OUT_MARGIN 2 struct config* g_config = NULL; + +static volatile sig_atomic_t need_resize = 0; + +static void process_sigwinch(int signal) { + need_resize = 1; +} + void setup(struct config* config) { g_config = config; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &window); - - // at least - // 2 padding top and bottom for footer and vertical compensation - // 2 padding left & right to not overflow footer width - if (window.ws_row < BOX_HEIGHT + INNER_BOX_OUT_MARGIN * 2 || - window.ws_col < BOX_WIDTH + INNER_BOX_OUT_MARGIN * 2) { - (void)fprintf(stderr, "\x1b[1;31mScreen too small\x1b[0m\n"); - exit(1); - } tcgetattr(STDOUT_FILENO, &orig_term); term = orig_term; // save term @@ -78,9 +76,9 @@ void setup(struct config* config) { printf("\x1b[s\x1b[?47h\x1b[%s;%sm\x1b[2J", g_config->colors.bg, g_config->colors.fg); - print_footer(); (void)atexit(restore_all); (void)signal(SIGINT, signal_handler); + (void)signal(SIGWINCH, process_sigwinch); } static struct uint_point box_start() { @@ -173,11 +171,18 @@ void ui_update_ofield(struct opts_field* NNULLABLE self) { } static char* unknown_str = "unknown"; -// NOLINTNEXTLINE(readability-function-cognitive-complexity) -int load(struct Vector* users, struct Vector* sessions) { - /// SETUP - gusers = users; - gsessions = sessions; +void scratch_print_ui() { + ioctl(STDOUT_FILENO, TIOCGWINSZ, &window); + + if (window.ws_row < BOX_HEIGHT + INNER_BOX_OUT_MARGIN * 2 || + window.ws_col < BOX_WIDTH + INNER_BOX_OUT_MARGIN * 2) { + printf("\033[2J\033[H"); // Clear screen + printf("\x1b[1;31mScreen too small\x1b[0m\n"); + printf("\x1b[%s;%sm\x1b[2J", g_config->colors.bg, g_config->colors.fg); + return; + } + + printf("\033[2J\033[H"); // Clear screen // hostnames larger won't render properly const u_char HOSTNAME_SIZE = VALUES_COL - VALUES_SEPR - BOX_HMARGIN; @@ -194,6 +199,42 @@ int load(struct Vector* users, struct Vector* sessions) { // 1]); // *hidx = '\0'; } + /// PRINTING + const struct uint_point BOXSTART = box_start(); + + // printf box + print_box(); + + // put hostname + printf("\x1b[%d;%dH\x1b[%sm%s\x1b[%sm", BOXSTART.y + HEAD_ROW, + BOXSTART.x + VALUES_COL - VALUES_SEPR - (uint)utf8len(hostname), + g_config->colors.e_hostname, hostname, g_config->colors.fg); + + // put date + char* fmtd_time = fmt_time(g_config->behavior.timefmt); + printf("\x1b[%d;%dH\x1b[%sm%s\x1b[%sm", BOXSTART.y + HEAD_ROW, + BOXSTART.x + BOX_WIDTH - 1 - BOX_HMARGIN - (uint)utf8len(fmtd_time), + g_config->colors.e_date, fmtd_time, g_config->colors.fg); + free(fmtd_time); + + print_footer(); + + ui_update_field(SESSION); + ui_update_field(USER); + ui_update_field(PASSWD); + ui_update_cursor_focus(); +} + +#define READ_NONBLOCK_DELAY 100000 +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +int load(struct Vector* users, struct Vector* sessions) { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = READ_NONBLOCK_DELAY; // timeout = 100ms + + /// SETUP + gusers = users; + gsessions = sessions; of_session = ofield_new(sessions->length + g_config->behavior.include_defshell); @@ -228,35 +269,19 @@ int load(struct Vector* users, struct Vector* sessions) { free(initial_state.session_opt); } - /// PRINTING - const struct uint_point BOXSTART = box_start(); - - // printf box - print_box(); - - // put hostname - printf("\x1b[%d;%dH\x1b[%sm%s\x1b[%sm", BOXSTART.y + HEAD_ROW, - BOXSTART.x + VALUES_COL - VALUES_SEPR - (uint)utf8len(hostname), - g_config->colors.e_hostname, hostname, g_config->colors.fg); - - // put date - char* fmtd_time = fmt_time(g_config->behavior.timefmt); - printf("\x1b[%d;%dH\x1b[%sm%s\x1b[%sm", BOXSTART.y + HEAD_ROW, - BOXSTART.x + BOX_WIDTH - 1 - BOX_HMARGIN - (uint)utf8len(fmtd_time), - g_config->colors.e_date, fmtd_time, g_config->colors.fg); - free(fmtd_time); - - ui_update_field(SESSION); - ui_update_field(USER); - ui_update_field(PASSWD); - ui_update_cursor_focus(); + scratch_print_ui(); /// INTERACTIVE u_char len; char seq[0xff]; uint esc = 0; while (true) { - read_press(&len, seq); + if (need_resize) { + need_resize = 0; + scratch_print_ui(); + } + + if (!read_press_nb(&len, seq, &tv)) continue; if (*seq == '\x1b') { enum keys ansi_code = find_ansi(seq); if (ansi_code != -1) { diff --git a/src/util.c b/src/util.c index 7701f9f..12864d4 100644 --- a/src/util.c +++ b/src/util.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -53,6 +55,17 @@ void read_press(u_char* length, char* out) { } } +bool read_press_nb(u_char* length, char* out, struct timeval* tv) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + int ret = select(STDIN_FILENO + 1, &fds, NULL, NULL, tv); + if ((ret < 0 && errno == EINTR) || ret == 0) return false; + + read_press(length, out); + return true; +} + // https://stackoverflow.com/a/48040042 static int selret_magic() { fd_set set;