feat: add refresh_rate option for clock

This commit is contained in:
javalsai 2025-07-04 03:30:29 +02:00
parent 981aa4efc7
commit ba836e5cd4
Signed by: javalsai
SSH Key Fingerprint: SHA256:3G83yKhBUWVABVX/vPWH88xnK4+ptMtHkZGCRXD4Mk8
16 changed files with 133 additions and 95 deletions

View File

@ -98,6 +98,9 @@ Types \fBSTRING_ARRAY\fP. Specify paths to source on login if they exist, simple
.TP .TP
\fBtimefmt\fP \fBtimefmt\fP
Specify the time format string to be displayed. Check \fBstrftime (3)\fP to know the possible formatting variables. Specify the time format string to be displayed. Check \fBstrftime (3)\fP to know the possible formatting variables.
.TP
\fBrefresh_rate\fP
Rate (in milliseconds) at which the UI should refresh, affects clock and resize behavior.
.SH "SEE ALSO" .SH "SEE ALSO"

View File

@ -11,12 +11,14 @@
enum introspection_type { enum introspection_type {
STRING, STRING,
BOOL, BOOL,
NUMBER,
KEY, KEY,
STRING_ARRAY, STRING_ARRAY,
}; };
static const char* NNULLABLE const INTROS_TYS_NAMES[] = { static const char* NNULLABLE const INTROS_TYS_NAMES[] = {
[STRING] = "STRING", [STRING] = "STRING",
[BOOL] = "BOOL", [BOOL] = "BOOL",
[NUMBER] = "NUMBER",
[KEY] = "KEY", [KEY] = "KEY",
[STRING_ARRAY] = "STRING_ARRAY", [STRING_ARRAY] = "STRING_ARRAY",
}; };
@ -116,7 +118,8 @@ BUILD(strings, STRINGS, TABLE_STRINGS);
F(bool, include_defshell, BOOL, true, name) \ F(bool, include_defshell, BOOL, true, name) \
F(struct Vector, source, STRING_ARRAY, NULL_VEC, name) \ F(struct Vector, source, STRING_ARRAY, NULL_VEC, name) \
F(struct Vector, user_source, STRING_ARRAY, NULL_VEC, name) \ F(struct Vector, user_source, STRING_ARRAY, NULL_VEC, name) \
F(char* NNULLABLE, timefmt, STRING, "%X %x", name) F(char* NNULLABLE, timefmt, STRING, "%X %x", name) \
F(long long, refresh_rate, NUMBER, 100, name)
BUILD(behavior, BEHAVIOR, TABLE_BEHAVIOR); BUILD(behavior, BEHAVIOR, TABLE_BEHAVIOR);

View File

@ -13,7 +13,7 @@
int find_keyname(enum keys* at, const char* name); int find_keyname(enum keys* at, const char* name);
enum keys find_ansi(const char* seq); enum keys find_ansi(const char* seq);
void read_press(u_char* length, char* out); void read_press(u_char* length, char* out);
// non blocking, waits up to tv, returns true if actually read // non blocking, waits up to tv or interrupt, returns true if actually read
bool read_press_nb(u_char* length, char* out, struct timeval* tv); bool read_press_nb(u_char* length, char* out, struct timeval* tv);
bool utf8_iscont(char byte); bool utf8_iscont(char byte);

View File

@ -1,10 +1,13 @@
#include <errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h>
#include "config.h" #include "config.h"
#include "desktop.h" #include "desktop.h"
@ -111,6 +114,7 @@ unfinished:
#define NOFAIL return (struct parser_error){NULL, 0} #define NOFAIL return (struct parser_error){NULL, 0}
union typ_ptr { union typ_ptr {
char** string; char** string;
long long* number;
bool* boolean; bool* boolean;
enum keys* key; enum keys* key;
struct Vector* vec; struct Vector* vec;
@ -147,6 +151,13 @@ struct parser_error parse_key(enum introspection_type typ, union typ_ptr at,
FAIL("Invalid key value, wasn't 'true' nor 'false'"); FAIL("Invalid key value, wasn't 'true' nor 'false'");
} }
break; break;
case NUMBER:
errno = 0;
*at.number = strtol(key, NULL, 10);
if (errno) {
FAIL("strtol failed");
}
break;
case KEY: case KEY:
// NOLINTNEXTLINE(performance-no-int-to-ptr) // NOLINTNEXTLINE(performance-no-int-to-ptr)
if (find_keyname(at.key, key) != 0) { if (find_keyname(at.key, key) != 0) {
@ -205,6 +216,8 @@ struct status config_line_handler(void* _config, char* table, char* k,
size_t offset = this_intros_table->offset + this_intros_key->offset; size_t offset = this_intros_table->offset + this_intros_key->offset;
union typ_ptr k_addr = {.ptr = (uintptr_t)config + offset}; union typ_ptr k_addr = {.ptr = (uintptr_t)config + offset};
log_printf("[I] parsing [%s.%s] as %s\n", table, k,
INTROS_TYS_NAMES[this_intros_key->typ]);
struct parser_error err = parse_key(this_intros_key->typ, k_addr, v, offset); struct parser_error err = parse_key(this_intros_key->typ, k_addr, v, offset);
if (err.msg != NULL) { if (err.msg != NULL) {
log_printf("[E] cfg parser, failed to parse [%s.%s] (%s): %s\n", table, k, log_printf("[E] cfg parser, failed to parse [%s.%s] (%s): %s\n", table, k,
@ -213,7 +226,9 @@ struct status config_line_handler(void* _config, char* table, char* k,
return ret; return ret;
} }
if (this_intros_key->typ == STRING) if (this_intros_key->typ == NUMBER)
log_printf("[I] cfg parsed [%s.%s] (%lld)\n", table, k, *k_addr.number);
else if (this_intros_key->typ == STRING)
log_printf("[I] cfg parsed [%s.%s] (%s)\n", table, k, *k_addr.string); log_printf("[I] cfg parsed [%s.%s] (%s)\n", table, k, *k_addr.string);
else else
log_printf("[I] cfg parsed [%s.%s]\n", table, k); log_printf("[I] cfg parsed [%s.%s]\n", table, k);

188
src/ui.c
View File

@ -6,6 +6,7 @@
#include <signal.h> #include <signal.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -31,21 +32,20 @@
const u_char INPUTS_N = 3; const u_char INPUTS_N = 3;
static void print_box();
static void print_footer();
static void restore_all();
static void signal_handler(int code);
struct uint_point { struct uint_point {
uint x; uint x;
uint y; uint y;
}; };
static void print_session(struct uint_point origin, struct session session, static void print_box();
bool multiple); static void print_head();
static void print_user(struct uint_point origin, struct user user, static void print_footer();
bool multiple); static void restore_all();
static void print_passwd(struct uint_point origin, uint length, bool err); static void signal_handler(int code);
static void print_session(struct session session, bool multiple);
static void print_user(struct user user, bool multiple);
static void print_passwd(uint length, bool err);
static void scratch_print_ui(); static void scratch_print_ui();
// ansi resource: https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 // ansi resource: https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
@ -79,14 +79,10 @@ void setup(struct config* config) {
(void)atexit(restore_all); (void)atexit(restore_all);
(void)signal(SIGINT, signal_handler); (void)signal(SIGINT, signal_handler);
(void)signal(SIGWINCH, process_sigwinch); (void)signal(SIGWINCH, process_sigwinch);
(void)fflush(stdout);
} }
static struct uint_point box_start() { static struct uint_point box_start = {.x = 0, .y = 0};
return (struct uint_point){
.x = ((window.ws_col - BOX_WIDTH) / 2) + 1, // looks better
.y = ((window.ws_row - BOX_HEIGHT) / 2), // leave more space under
};
}
#define STRFTIME_PREALLOC 64 #define STRFTIME_PREALLOC 64
#define TM_YEAR_EPOCH 1900 #define TM_YEAR_EPOCH 1900
@ -98,7 +94,8 @@ static char* fmt_time(const char* fmt) {
char* buf = malloc(alloc_size); char* buf = malloc(alloc_size);
if (!buf) return NULL; if (!buf) return NULL;
while (true) { while (true) {
if (strftime(buf, alloc_size, fmt, &tm) != 0) return buf; if (strftime(buf, alloc_size, fmt, &tm) != 0 && strlen(fmt) != 0)
return buf;
alloc_size *= 2; alloc_size *= 2;
char* nbuf = realloc(buf, alloc_size); char* nbuf = realloc(buf, alloc_size);
@ -111,9 +108,8 @@ static char* fmt_time(const char* fmt) {
} }
void ui_update_cursor_focus() { void ui_update_cursor_focus() {
struct uint_point bstart = box_start(); u_char line = box_start.y;
u_char line = bstart.y; u_char col = box_start.x + VALUES_COL;
u_char col = bstart.x + VALUES_COL;
struct opts_field* ofield = get_opts_ffield(); struct opts_field* ofield = get_opts_ffield();
u_char maxlen = VALUE_MAXLEN; u_char maxlen = VALUE_MAXLEN;
@ -133,19 +129,16 @@ void ui_update_cursor_focus() {
line += PASSWD_ROW; line += PASSWD_ROW;
(void)printf("\x1b[%d;%dH", line, col); (void)printf("\x1b[%d;%dH", line, col);
(void)fflush(stdout);
} }
void ui_update_field(enum input focused_input) { void ui_update_field(enum input focused_input) {
struct uint_point origin = box_start();
if (focused_input == PASSWD) { if (focused_input == PASSWD) {
print_passwd(origin, utf8len(of_passwd.efield.content), false); print_passwd(utf8len(of_passwd.efield.content), false);
} else if (focused_input == SESSION) { } else if (focused_input == SESSION) {
print_session(origin, st_session(g_config->behavior.include_defshell), print_session(st_session(g_config->behavior.include_defshell),
of_session.opts > 1); of_session.opts > 1);
} else if (focused_input == USER) { } else if (focused_input == USER) {
print_user(origin, st_user(), of_user.opts > 1); print_user(st_user(), of_user.opts > 1);
ui_update_field(SESSION); ui_update_field(SESSION);
} }
@ -173,6 +166,10 @@ void ui_update_ofield(struct opts_field* NNULLABLE self) {
static char* unknown_str = "unknown"; static char* unknown_str = "unknown";
void scratch_print_ui() { void scratch_print_ui() {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &window); ioctl(STDOUT_FILENO, TIOCGWINSZ, &window);
box_start = (struct uint_point){
.x = ((window.ws_col - BOX_WIDTH) / 2) + 1, // looks better
.y = ((window.ws_row - BOX_HEIGHT) / 2), // leave more space under
};
if (window.ws_row < BOX_HEIGHT + INNER_BOX_OUT_MARGIN * 2 || if (window.ws_row < BOX_HEIGHT + INNER_BOX_OUT_MARGIN * 2 ||
window.ws_col < BOX_WIDTH + INNER_BOX_OUT_MARGIN * 2) { window.ws_col < BOX_WIDTH + INNER_BOX_OUT_MARGIN * 2) {
@ -184,39 +181,11 @@ void scratch_print_ui() {
printf("\033[2J\033[H"); // Clear screen printf("\033[2J\033[H"); // Clear screen
// hostnames larger won't render properly
const u_char HOSTNAME_SIZE = VALUES_COL - VALUES_SEPR - BOX_HMARGIN;
char hostname_buf[HOSTNAME_SIZE];
char* hostname = hostname_buf;
if (gethostname(hostname_buf, HOSTNAME_SIZE) != 0) {
hostname = unknown_str;
} else {
// Ig "successful completion" doesn't contemplate truncation case, so need
// to append the unspecified nullbyte
// char* hidx =
// (char*)utf8back(&hostname[VALUES_COL - VALUES_SEPR - BOX_HMARGIN -
// 1]);
// *hidx = '\0';
}
/// PRINTING /// PRINTING
const struct uint_point BOXSTART = box_start();
// printf box // printf box
print_box(); print_box();
// put hostname print_head();
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(); print_footer();
ui_update_field(SESSION); ui_update_field(SESSION);
@ -225,12 +194,12 @@ void scratch_print_ui() {
ui_update_cursor_focus(); ui_update_cursor_focus();
} }
#define READ_NONBLOCK_DELAY 100000 #define MS_PER_S 1000
#define US_PER_MS 1000
// NOLINTNEXTLINE(readability-function-cognitive-complexity) // NOLINTNEXTLINE(readability-function-cognitive-complexity)
int load(struct Vector* users, struct Vector* sessions) { int load(struct Vector* users, struct Vector* sessions) {
struct timeval tv; long long ms_time = g_config->behavior.refresh_rate;
tv.tv_sec = 0; ms_time = ms_time < 0 ? 0 : ms_time;
tv.tv_usec = READ_NONBLOCK_DELAY; // timeout = 100ms
/// SETUP /// SETUP
gusers = users; gusers = users;
@ -279,8 +248,17 @@ int load(struct Vector* users, struct Vector* sessions) {
if (need_resize) { if (need_resize) {
need_resize = 0; need_resize = 0;
scratch_print_ui(); scratch_print_ui();
} else {
// partial refresh
print_head();
ui_update_cursor_focus();
} }
struct timeval tv;
tv.tv_usec = (ms_time % MS_PER_S) * US_PER_MS;
tv.tv_sec = ms_time / MS_PER_S;
(void)fflush(stdout);
if (!read_press_nb(&len, seq, &tv)) continue; if (!read_press_nb(&len, seq, &tv)) continue;
if (*seq == '\x1b') { if (*seq == '\x1b') {
enum keys ansi_code = find_ansi(seq); enum keys ansi_code = find_ansi(seq);
@ -318,7 +296,7 @@ int load(struct Vector* users, struct Vector* sessions) {
if (!launch(st_user().username, of_passwd.efield.content, if (!launch(st_user().username, of_passwd.efield.content,
st_session(g_config->behavior.include_defshell), st_session(g_config->behavior.include_defshell),
&restore_all, g_config)) { &restore_all, g_config)) {
print_passwd(box_start(), utf8len(of_passwd.efield.content), true); print_passwd(utf8len(of_passwd.efield.content), true);
ui_update_cursor_focus(); ui_update_cursor_focus();
} }
} else } else
@ -344,9 +322,43 @@ u_char get_render_pos_offset(struct opts_field* self, u_char maxlen) {
return pos - ofield_display_cursor_col(self, maxlen); return pos - ofield_display_cursor_col(self, maxlen);
} }
void print_session(struct uint_point origin, struct session session, #define HOSTNAME_SIZE (VALUES_COL - VALUES_SEPR - BOX_HMARGIN)
bool multiple) { void print_head() {
clean_line(origin, SESSION_ROW); // hostname doesn't just change on runtime
static char* hostname = NULL;
static char hostname_buf[HOSTNAME_SIZE + 1];
if (!hostname) {
// hostnames larger won't render properly
hostname = hostname_buf;
if (gethostname(hostname_buf, HOSTNAME_SIZE) != 0) {
hostname = unknown_str;
} else {
// Ig "successful completion" doesn't contemplate truncation case, so need
// to append the unspecified nullbyte
// char* hidx =
// (char*)utf8back(&hostname[VALUES_COL - VALUES_SEPR - BOX_HMARGIN -
// 1]);
// *hidx = '\0';
}
}
clean_line(box_start, HEAD_ROW);
// put hostname
printf("\x1b[%dG\x1b[%sm%s\x1b[%sm",
box_start.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[%dG\x1b[%sm%s\x1b[%sm",
box_start.x + BOX_WIDTH - 1 - BOX_HMARGIN - (uint)utf8len(fmtd_time),
g_config->colors.e_date, fmtd_time, g_config->colors.fg);
free(fmtd_time);
}
void print_session(struct session session, bool multiple) {
clean_line(box_start, SESSION_ROW);
const char* NNULLABLE session_type; const char* NNULLABLE session_type;
if (session.type == XORG) { if (session.type == XORG) {
@ -361,10 +373,10 @@ void print_session(struct uint_point origin, struct session session,
// already in the box, - 1 bcs no need to step over margin, same reasoning in // already in the box, - 1 bcs no need to step over margin, same reasoning in
// other places // other places
printf( printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm",
"\r\x1b[%luC\x1b[%sm%s\x1b[%sm", (ulong)(box_start.x + VALUES_COL - VALUES_SEPR -
(ulong)(origin.x + VALUES_COL - VALUES_SEPR - utf8len(session_type) - 1), utf8len(session_type) - 1),
g_config->colors.e_header, session_type, g_config->colors.fg); g_config->colors.e_header, session_type, g_config->colors.fg);
char* session_color; char* session_color;
if (session.type == XORG) { if (session.type == XORG) {
@ -382,21 +394,21 @@ void print_session(struct uint_point origin, struct session session,
toprint += get_render_pos_offset(&of_session, maxlen); toprint += get_render_pos_offset(&of_session, maxlen);
size_t printlen = utf8seekn(toprint, maxlen) - toprint; size_t printlen = utf8seekn(toprint, maxlen) - toprint;
printf("\r\x1b[%dC%s\x1b[%sm%.*s\x1b[%sm%s", origin.x + VALUES_COL - 1, printf("\r\x1b[%dC%s\x1b[%sm%.*s\x1b[%sm%s", box_start.x + VALUES_COL - 1,
g_config->strings.opts_pre, session_color, (int)printlen, toprint, g_config->strings.opts_pre, session_color, (int)printlen, toprint,
g_config->colors.fg, g_config->strings.opts_post); g_config->colors.fg, g_config->strings.opts_post);
} else { } else {
toprint += get_render_pos_offset(&of_session, VALUE_MAXLEN); toprint += get_render_pos_offset(&of_session, VALUE_MAXLEN);
size_t printlen = utf8seekn(toprint, VALUE_MAXLEN) - toprint; size_t printlen = utf8seekn(toprint, VALUE_MAXLEN) - toprint;
printf("\r\x1b[%dC\x1b[%sm%.*s\x1b[%sm", origin.x + VALUES_COL - 1, printf("\r\x1b[%dC\x1b[%sm%.*s\x1b[%sm", box_start.x + VALUES_COL - 1,
session_color, (int)printlen, toprint, g_config->colors.fg); session_color, (int)printlen, toprint, g_config->colors.fg);
} }
} }
void print_user(struct uint_point origin, struct user user, bool multiple) { void print_user(struct user user, bool multiple) {
clean_line(origin, USER_ROW); clean_line(box_start, USER_ROW);
printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm", printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm",
(ulong)(origin.x + VALUES_COL - VALUES_SEPR - (ulong)(box_start.x + VALUES_COL - VALUES_SEPR -
utf8len(g_config->strings.e_user) - 1), utf8len(g_config->strings.e_user) - 1),
g_config->colors.e_header, g_config->strings.e_user, g_config->colors.e_header, g_config->strings.e_user,
g_config->colors.fg); g_config->colors.fg);
@ -410,21 +422,21 @@ void print_user(struct uint_point origin, struct user user, bool multiple) {
toprint += get_render_pos_offset(&of_session, maxlen); toprint += get_render_pos_offset(&of_session, maxlen);
size_t printlen = utf8seekn(toprint, maxlen) - toprint; size_t printlen = utf8seekn(toprint, maxlen) - toprint;
printf("\r\x1b[%dC< \x1b[%sm%.*s\x1b[%sm >", origin.x + VALUES_COL - 1, printf("\r\x1b[%dC< \x1b[%sm%.*s\x1b[%sm >", box_start.x + VALUES_COL - 1,
user_color, (int)printlen, toprint, g_config->colors.fg); user_color, (int)printlen, toprint, g_config->colors.fg);
} else { } else {
toprint += get_render_pos_offset(&of_user, VALUE_MAXLEN); toprint += get_render_pos_offset(&of_user, VALUE_MAXLEN);
size_t printlen = utf8seekn(toprint, VALUE_MAXLEN) - toprint; size_t printlen = utf8seekn(toprint, VALUE_MAXLEN) - toprint;
printf("\r\x1b[%dC\x1b[%sm%.*s\x1b[%sm", origin.x + VALUES_COL - 1, printf("\r\x1b[%dC\x1b[%sm%.*s\x1b[%sm", box_start.x + VALUES_COL - 1,
user_color, (int)printlen, toprint, g_config->colors.fg); user_color, (int)printlen, toprint, g_config->colors.fg);
} }
} }
void print_passwd(struct uint_point origin, uint length, bool err) { void print_passwd(uint length, bool err) {
char passwd_prompt[VALUE_MAXLEN + 1]; char passwd_prompt[VALUE_MAXLEN + 1];
clean_line(origin, PASSWD_ROW); clean_line(box_start, PASSWD_ROW);
printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm", printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm",
(ulong)(origin.x + VALUES_COL - VALUES_SEPR - (ulong)(box_start.x + VALUES_COL - VALUES_SEPR -
utf8len(g_config->strings.e_passwd) - 1), utf8len(g_config->strings.e_passwd) - 1),
g_config->colors.e_header, g_config->strings.e_passwd, g_config->colors.e_header, g_config->strings.e_passwd,
g_config->colors.fg); g_config->colors.fg);
@ -440,7 +452,7 @@ void print_passwd(struct uint_point origin, uint length, bool err) {
memset(passwd_prompt, '*', actual_len); memset(passwd_prompt, '*', actual_len);
passwd_prompt[VALUE_MAXLEN] = '\0'; passwd_prompt[VALUE_MAXLEN] = '\0';
printf("\r\x1b[%dC\x1b[%sm", origin.x + VALUES_COL - 1, pass_color); printf("\r\x1b[%dC\x1b[%sm", box_start.x + VALUES_COL - 1, pass_color);
printf("%s", passwd_prompt); printf("%s", passwd_prompt);
printf("\x1b[%sm", g_config->colors.fg); printf("\x1b[%sm", g_config->colors.fg);
@ -464,9 +476,8 @@ static void print_row(uint wid, uint n, char* edge1, char* edge2,
} }
static void print_box() { static void print_box() {
const struct uint_point BSTART = box_start(); printf("\x1b[%d;%dH\x1b[%sm", box_start.y, box_start.x,
g_config->colors.e_box);
printf("\x1b[%d;%dH\x1b[%sm", BSTART.y, BSTART.x, g_config->colors.e_box);
print_row(BOX_WIDTH - 2, 1, g_config->chars.ctl, g_config->chars.ctr, print_row(BOX_WIDTH - 2, 1, g_config->chars.ctl, g_config->chars.ctr,
g_config->chars.hb); g_config->chars.hb);
print_empty_row(BOX_WIDTH - 2, BOX_HEIGHT - 2, g_config->chars.vb, print_empty_row(BOX_WIDTH - 2, BOX_HEIGHT - 2, g_config->chars.vb,
@ -474,7 +485,6 @@ static void print_box() {
print_row(BOX_WIDTH - 2, 1, g_config->chars.cbl, g_config->chars.cbr, print_row(BOX_WIDTH - 2, 1, g_config->chars.cbl, g_config->chars.cbr,
g_config->chars.hb); g_config->chars.hb);
printf("\x1b[%sm", g_config->colors.fg); printf("\x1b[%sm", g_config->colors.fg);
(void)fflush(stdout);
} }
static void print_footer() { static void print_footer() {
@ -498,24 +508,21 @@ static void print_footer() {
KEY_NAMES[g_config->functions.reboot], KEY_NAMES[g_config->functions.reboot],
KEY_NAMES[g_config->functions.refresh], g_config->strings.f_poweroff, KEY_NAMES[g_config->functions.refresh], g_config->strings.f_poweroff,
g_config->strings.f_reboot, g_config->strings.f_refresh); g_config->strings.f_reboot, g_config->strings.f_refresh);
(void)fflush(stdout);
} }
void print_err(const char* msg) { void print_err(const char* msg) {
struct uint_point origin = box_start(); (void)fprintf(stderr, "\x1b[%d;%dH%s(%d): %s", box_start.y - 1, box_start.x,
(void)fprintf(stderr, "\x1b[%d;%dH%s(%d): %s", origin.y - 1, origin.x, msg, msg, errno, strerror(errno));
errno, strerror(errno));
} }
void print_errno(const char* descr) { void print_errno(const char* descr) {
struct uint_point origin = box_start();
if (descr == NULL) if (descr == NULL)
(void)fprintf(stderr, "\x1b[%d;%dH\x1b[%smunknown error(%d): %s", (void)fprintf(stderr, "\x1b[%d;%dH\x1b[%smunknown error(%d): %s",
origin.y - 1, origin.x, g_config->colors.err, errno, box_start.y - 1, box_start.x, g_config->colors.err, errno,
strerror(errno)); strerror(errno));
else { else {
(void)fprintf(stderr, "\x1b[%d;%dH\x1b[%sm%s(%d): %s", origin.y - 1, (void)fprintf(stderr, "\x1b[%d;%dH\x1b[%sm%s(%d): %s", box_start.y - 1,
origin.x, g_config->colors.err, descr, errno, box_start.x, g_config->colors.err, descr, errno,
strerror(errno)); strerror(errno));
} }
} }
@ -523,7 +530,6 @@ void print_errno(const char* descr) {
void restore_all() { void restore_all() {
// restore cursor pos, restore screen and show cursor // restore cursor pos, restore screen and show cursor
(void)printf("\x1b[u\x1b[?47l\x1b[?25h"); (void)printf("\x1b[u\x1b[?47l\x1b[?25h");
(void)fflush(stdout);
tcsetattr(STDOUT_FILENO, TCSANOW, &orig_term); tcsetattr(STDOUT_FILENO, TCSANOW, &orig_term);
} }

View File

@ -59,8 +59,9 @@ bool read_press_nb(u_char* length, char* out, struct timeval* tv) {
fd_set fds; fd_set fds;
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds); FD_SET(STDIN_FILENO, &fds);
errno = 0;
int ret = select(STDIN_FILENO + 1, &fds, NULL, NULL, tv); int ret = select(STDIN_FILENO + 1, &fds, NULL, NULL, tv);
if ((ret < 0 && errno == EINTR) || ret == 0) return false; if (errno || ret <= 0) return false;
read_press(length, out); read_press(length, out);
return true; return true;

View File

@ -42,6 +42,7 @@ e_key = "1;23;38;5;197"
[behavior] [behavior]
# include_defshell = true # include_defshell = true
# timefmt = "%X %x" # timefmt = "%X %x"
# refresh_rate = 100
source = "/etc/lidm.env" source = "/etc/lidm.env"
source = "/etc/locale.conf" source = "/etc/locale.conf"
user_source = ".lidm.env" user_source = ".lidm.env"

View File

@ -42,6 +42,7 @@
[behavior] [behavior]
# include_defshell = true # include_defshell = true
# timefmt = "%X %x" # timefmt = "%X %x"
refresh_rate = 2000
source = "/etc/lidm.env" source = "/etc/lidm.env"
source = "/etc/locale.conf" source = "/etc/locale.conf"
user_source = ".lidm.env" user_source = ".lidm.env"

View File

@ -42,6 +42,7 @@ e_user = "38;2;148;89;84"
[behavior] [behavior]
# include_defshell = true # include_defshell = true
timefmt = "%Y-%m-%d %H:%M:%S" timefmt = "%Y-%m-%d %H:%M:%S"
# refresh_rate = 100
source = "/etc/lidm.env" source = "/etc/lidm.env"
source = "/etc/locale.conf" source = "/etc/locale.conf"
user_source = ".lidm.env" user_source = ".lidm.env"

View File

@ -42,6 +42,7 @@ e_user = "38;2;211;137;88"
[behavior] [behavior]
# include_defshell = true # include_defshell = true
timefmt = "%Y-%m-%d %H:%M:%S" timefmt = "%Y-%m-%d %H:%M:%S"
# refresh_rate = 100
source = "/etc/lidm.env" source = "/etc/lidm.env"
source = "/etc/locale.conf" source = "/etc/locale.conf"
user_source = ".lidm.env" user_source = ".lidm.env"

View File

@ -43,6 +43,7 @@ s_shell = "$"
[behavior] [behavior]
# include_defshell = true # include_defshell = true
timefmt = "\xef\x80\x97 %X \xef\x84\xb3 %x" timefmt = "\xef\x80\x97 %X \xef\x84\xb3 %x"
# refresh_rate = 100
source = "/etc/lidm.env" source = "/etc/lidm.env"
source = "/etc/locale.conf" source = "/etc/locale.conf"
user_source = ".lidm.env" user_source = ".lidm.env"

View File

@ -42,6 +42,7 @@ e_key = "32"
[behavior] [behavior]
# include_defshell = true # include_defshell = true
timefmt = "%Y-%m-%d %H:%M:%S" timefmt = "%Y-%m-%d %H:%M:%S"
# refresh_rate = 100
source = "/etc/lidm.env" source = "/etc/lidm.env"
source = "/etc/locale.conf" source = "/etc/locale.conf"
user_source = ".lidm.env" user_source = ".lidm.env"

View File

@ -42,6 +42,7 @@ e_key = "34"
[behavior] [behavior]
# include_defshell = true # include_defshell = true
timefmt = "%Y-%m-%d %H:%M:%S" timefmt = "%Y-%m-%d %H:%M:%S"
# refresh_rate = 100
source = "/etc/lidm.env" source = "/etc/lidm.env"
source = "/etc/locale.conf" source = "/etc/locale.conf"
user_source = ".lidm.env" user_source = ".lidm.env"

View File

@ -44,6 +44,7 @@ s_shell = ""
[behavior] [behavior]
# include_defshell = true # include_defshell = true
timefmt = " " timefmt = " "
# refresh_rate = 100
source = "/etc/lidm.env" source = "/etc/lidm.env"
source = "/etc/locale.conf" source = "/etc/locale.conf"
user_source = ".lidm.env" user_source = ".lidm.env"

View File

@ -42,6 +42,7 @@ s_shell = "swell"
[behavior] [behavior]
# include_defshell = true # include_defshell = true
timefmt = "%Y-%m-%d %H:%M:%S" timefmt = "%Y-%m-%d %H:%M:%S"
# refresh_rate = 100
source = "/etc/lidm.env" source = "/etc/lidm.env"
source = "/etc/locale.conf" source = "/etc/locale.conf"
user_source = ".lidm.env" user_source = ".lidm.env"

View File

@ -43,6 +43,7 @@ opts_post = " "
[behavior] [behavior]
# include_defshell = true # include_defshell = true
timefmt = "%Y-%m-%d %H:%M:%S" timefmt = "%Y-%m-%d %H:%M:%S"
# refresh_rate = 100
source = "/etc/lidm.env" source = "/etc/lidm.env"
source = "/etc/locale.conf" source = "/etc/locale.conf"
user_source = ".lidm.env" user_source = ".lidm.env"