mirror of https://github.com/fairyglade/ly.git
				
				
				
			Clocks (#461)
* Added a big clock * fixed clock timing when animation is turned off * fix memory leak and segfault * rename clock to bigclock * Added formattable clock * fix clock position on first draw don't rely on box_x and box_y to position the clock, because it might not be initialized in the first frame. * fix memory leak
This commit is contained in:
		
							parent
							
								
									f9848f648b
								
							
						
					
					
						commit
						1124c126f9
					
				|  | @ -6,6 +6,11 @@ | ||||||
| # 1 -> CMatrix  | # 1 -> CMatrix  | ||||||
| #animation = 0 | #animation = 0 | ||||||
| 
 | 
 | ||||||
|  | # format string for clock in top right corner (see strftime specification) | ||||||
|  | #clock = %c | ||||||
|  | 
 | ||||||
|  | # enable/disable big clock | ||||||
|  | #bigclock = true | ||||||
| 
 | 
 | ||||||
| # The character used to mask the password | # The character used to mask the password | ||||||
| #asterisk = * | #asterisk = * | ||||||
|  |  | ||||||
|  | @ -0,0 +1,146 @@ | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | #define CLOCK_W 5 | ||||||
|  | #define CLOCK_H 5 | ||||||
|  | 
 | ||||||
|  | #if defined(__linux__) || defined(__FreeBSD__) | ||||||
|  | 	#define X 0x2593 | ||||||
|  | 	#define _ 0x0000 | ||||||
|  | #else | ||||||
|  | 	#define X '#' | ||||||
|  | 	#define _ 0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if CLOCK_W == 5 && CLOCK_H == 5 | ||||||
|  | 
 | ||||||
|  | uint32_t CLOCK_0[] = { | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	X,X,_,X,X, | ||||||
|  | 	X,X,_,X,X, | ||||||
|  | 	X,X,_,X,X, | ||||||
|  | 	X,X,X,X,X | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uint32_t CLOCK_1[] = { | ||||||
|  | 	_,_,_,X,X, | ||||||
|  | 	_,_,_,X,X, | ||||||
|  | 	_,_,_,X,X, | ||||||
|  | 	_,_,_,X,X, | ||||||
|  | 	_,_,_,X,X | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uint32_t CLOCK_2[] = { | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	_,_,_,X,X, | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	X,X,_,_,_, | ||||||
|  | 	X,X,X,X,X | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uint32_t CLOCK_3[] = { | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	_,_,_,X,X, | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	_,_,_,X,X, | ||||||
|  | 	X,X,X,X,X | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uint32_t CLOCK_4[] = { | ||||||
|  | 	X,X,_,X,X, | ||||||
|  | 	X,X,_,X,X, | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	_,_,_,X,X, | ||||||
|  | 	_,_,_,X,X | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uint32_t CLOCK_5[] = { | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	X,X,_,_,_, | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	_,_,_,X,X, | ||||||
|  | 	X,X,X,X,X | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uint32_t CLOCK_6[] = { | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	X,X,_,_,_, | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	X,X,_,X,X, | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uint32_t CLOCK_7[] = { | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	_,_,_,X,X, | ||||||
|  | 	_,_,_,X,X, | ||||||
|  | 	_,_,_,X,X, | ||||||
|  | 	_,_,_,X,X | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uint32_t CLOCK_8[] = { | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	X,X,_,X,X, | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	X,X,_,X,X, | ||||||
|  | 	X,X,X,X,X | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uint32_t CLOCK_9[] = { | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	X,X,_,X,X, | ||||||
|  | 	X,X,X,X,X, | ||||||
|  | 	_,_,_,X,X, | ||||||
|  | 	X,X,X,X,X | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uint32_t CLOCK_S[] = { | ||||||
|  | 	_,_,_,_,_, | ||||||
|  | 	_,_,X,_,_, | ||||||
|  | 	_,_,_,_,_, | ||||||
|  | 	_,_,X,_,_, | ||||||
|  | 	_,_,_,_,_ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uint32_t CLOCK_E[] = { | ||||||
|  | 	_,_,_,_,_, | ||||||
|  | 	_,_,_,_,_, | ||||||
|  | 	_,_,_,_,_, | ||||||
|  | 	_,_,_,_,_, | ||||||
|  | 	_,_,_,_,_ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #undef X | ||||||
|  | #undef _ | ||||||
|  | 
 | ||||||
|  | static inline uint32_t* CLOCK_N(char c) | ||||||
|  | { | ||||||
|  | 	switch(c) | ||||||
|  | 	{ | ||||||
|  | 		case '0': | ||||||
|  | 			return CLOCK_0; | ||||||
|  | 		case '1': | ||||||
|  | 			return CLOCK_1; | ||||||
|  | 		case '2': | ||||||
|  | 			return CLOCK_2; | ||||||
|  | 		case '3': | ||||||
|  | 			return CLOCK_3; | ||||||
|  | 		case '4': | ||||||
|  | 			return CLOCK_4; | ||||||
|  | 		case '5': | ||||||
|  | 			return CLOCK_5; | ||||||
|  | 		case '6': | ||||||
|  | 			return CLOCK_6; | ||||||
|  | 		case '7': | ||||||
|  | 			return CLOCK_7; | ||||||
|  | 		case '8': | ||||||
|  | 			return CLOCK_8; | ||||||
|  | 		case '9': | ||||||
|  | 			return CLOCK_9; | ||||||
|  | 		case ':': | ||||||
|  | 			return CLOCK_S; | ||||||
|  | 		default: | ||||||
|  | 			return CLOCK_E; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -161,8 +161,10 @@ void config_load(const char *cfg_path) | ||||||
| 		{"animation", &config.animation, config_handle_u8}, | 		{"animation", &config.animation, config_handle_u8}, | ||||||
| 		{"asterisk", &config.asterisk, config_handle_char}, | 		{"asterisk", &config.asterisk, config_handle_char}, | ||||||
| 		{"bg", &config.bg, config_handle_u8}, | 		{"bg", &config.bg, config_handle_u8}, | ||||||
|  | 		{"bigclock", &config.bigclock, config_handle_bool}, | ||||||
| 		{"blank_box", &config.blank_box, config_handle_bool}, | 		{"blank_box", &config.blank_box, config_handle_bool}, | ||||||
| 		{"blank_password", &config.blank_password, config_handle_bool}, | 		{"blank_password", &config.blank_password, config_handle_bool}, | ||||||
|  | 		{"clock", &config.clock, config_handle_str}, | ||||||
| 		{"console_dev", &config.console_dev, config_handle_str}, | 		{"console_dev", &config.console_dev, config_handle_str}, | ||||||
| 		{"default_input", &config.default_input, config_handle_u8}, | 		{"default_input", &config.default_input, config_handle_u8}, | ||||||
| 		{"fg", &config.fg, config_handle_u8}, | 		{"fg", &config.fg, config_handle_u8}, | ||||||
|  | @ -269,8 +271,10 @@ void config_defaults() | ||||||
| 	config.animation = 0; | 	config.animation = 0; | ||||||
| 	config.asterisk = '*'; | 	config.asterisk = '*'; | ||||||
| 	config.bg = 0; | 	config.bg = 0; | ||||||
|  | 	config.bigclock = false; | ||||||
| 	config.blank_box = true; | 	config.blank_box = true; | ||||||
| 	config.blank_password = false; | 	config.blank_password = false; | ||||||
|  | 	config.clock = NULL; | ||||||
| 	config.console_dev = strdup("/dev/console"); | 	config.console_dev = strdup("/dev/console"); | ||||||
| 	config.default_input = LOGIN_INPUT; | 	config.default_input = LOGIN_INPUT; | ||||||
| 	config.fg = 9; | 	config.fg = 9; | ||||||
|  | @ -354,6 +358,7 @@ void lang_free() | ||||||
| 
 | 
 | ||||||
| void config_free() | void config_free() | ||||||
| { | { | ||||||
|  | 	free(config.clock); | ||||||
| 	free(config.console_dev); | 	free(config.console_dev); | ||||||
| 	free(config.lang); | 	free(config.lang); | ||||||
| 	free(config.mcookie_cmd); | 	free(config.mcookie_cmd); | ||||||
|  |  | ||||||
|  | @ -65,8 +65,10 @@ struct config | ||||||
| 	uint8_t animation; | 	uint8_t animation; | ||||||
| 	char asterisk; | 	char asterisk; | ||||||
| 	uint8_t bg; | 	uint8_t bg; | ||||||
|  | 	bool bigclock; | ||||||
| 	bool blank_box; | 	bool blank_box; | ||||||
| 	bool blank_password; | 	bool blank_password; | ||||||
|  | 	char* clock; | ||||||
| 	char* console_dev; | 	char* console_dev; | ||||||
| 	uint8_t default_input; | 	uint8_t default_input; | ||||||
| 	uint8_t fg; | 	uint8_t fg; | ||||||
|  |  | ||||||
							
								
								
									
										92
									
								
								src/draw.c
								
								
								
								
							
							
						
						
									
										92
									
								
								src/draw.c
								
								
								
								
							|  | @ -5,6 +5,7 @@ | ||||||
| #include "utils.h" | #include "utils.h" | ||||||
| #include "config.h" | #include "config.h" | ||||||
| #include "draw.h" | #include "draw.h" | ||||||
|  | #include "bigclock.h" | ||||||
| 
 | 
 | ||||||
| #include <ctype.h> | #include <ctype.h> | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
|  | @ -14,7 +15,9 @@ | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <sys/ioctl.h> | #include <sys/ioctl.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
|  | #include <sys/time.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
|  | #include <time.h> | ||||||
| 
 | 
 | ||||||
| #if defined(__DragonFly__) || defined(__FreeBSD__) | #if defined(__DragonFly__) || defined(__FreeBSD__) | ||||||
| 	#include <sys/kbio.h> | 	#include <sys/kbio.h> | ||||||
|  | @ -176,6 +179,95 @@ void draw_box(struct term_buf* buf) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | char* time_str(char* fmt, int maxlen) | ||||||
|  | { | ||||||
|  | 	time_t timer; | ||||||
|  | 	char* buffer = malloc(maxlen); | ||||||
|  | 	struct tm* tm_info; | ||||||
|  | 
 | ||||||
|  | 	timer = time(NULL); | ||||||
|  | 	tm_info = localtime(&timer); | ||||||
|  | 
 | ||||||
|  | 	if (strftime(buffer, maxlen, fmt, tm_info) == 0) | ||||||
|  | 		buffer[0] = '\0'; | ||||||
|  | 	 | ||||||
|  | 	return buffer; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | extern inline uint32_t* CLOCK_N(char c); | ||||||
|  | 
 | ||||||
|  | struct tb_cell* clock_cell(char c) | ||||||
|  | { | ||||||
|  | 	struct tb_cell* cells = malloc(sizeof(struct tb_cell) * CLOCK_W * CLOCK_H); | ||||||
|  | 
 | ||||||
|  | 	struct timeval tv; | ||||||
|  | 	gettimeofday(&tv, NULL); | ||||||
|  | 	if (config.animate && c == ':' && tv.tv_usec / 500000) | ||||||
|  | 		c = ' '; | ||||||
|  | 	uint32_t* clockchars = CLOCK_N(c); | ||||||
|  | 
 | ||||||
|  | 	for (int i = 0; i < CLOCK_W * CLOCK_H; i++) | ||||||
|  | 	{ | ||||||
|  | 		cells[i].ch = clockchars[i]; | ||||||
|  | 		cells[i].fg = config.fg; | ||||||
|  | 		cells[i].bg = config.bg; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return cells; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void alpha_blit(struct tb_cell* buf, uint16_t x, uint16_t y, uint16_t w, uint16_t h, struct tb_cell* cells) | ||||||
|  | { | ||||||
|  | 	if (x + w >= tb_width() || y + h >= tb_height()) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	for (int i = 0; i < h; i++) | ||||||
|  | 	{ | ||||||
|  | 		for (int j = 0; j < w; j++) | ||||||
|  | 		{ | ||||||
|  | 			struct tb_cell cell = cells[i * w + j]; | ||||||
|  | 			if (cell.ch) | ||||||
|  | 				buf[(y + i) * tb_width() + (x + j)] = cell; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void draw_bigclock(struct term_buf* buf) | ||||||
|  | { | ||||||
|  | 	if (!config.bigclock) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	int xo = buf->width / 2 - (5 * (CLOCK_W + 1)) / 2; | ||||||
|  | 	int yo = (buf->height - buf->box_height) / 2 - CLOCK_H - 2; | ||||||
|  | 
 | ||||||
|  | 	char* clockstr = time_str("%H:%M", 6); | ||||||
|  | 	struct tb_cell* clockcell; | ||||||
|  | 
 | ||||||
|  | 	for (int i = 0; i < 5; i++) | ||||||
|  | 	{ | ||||||
|  | 		clockcell = clock_cell(clockstr[i]); | ||||||
|  | 		alpha_blit(tb_cell_buffer(), xo + i * (CLOCK_W + 1), yo, CLOCK_W, CLOCK_H, clockcell); | ||||||
|  | 		free(clockcell); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	free(clockstr); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void draw_clock(struct term_buf* buf) | ||||||
|  | { | ||||||
|  | 	if (config.clock == NULL || strlen(config.clock) == 0) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	char* clockstr = time_str(config.clock, 32); | ||||||
|  | 	int clockstrlen = strlen(clockstr); | ||||||
|  | 
 | ||||||
|  | 	struct tb_cell* cells = strn_cell(clockstr, clockstrlen); | ||||||
|  | 	tb_blit(buf->width - clockstrlen, 0, clockstrlen, 1, cells); | ||||||
|  | 
 | ||||||
|  | 	free(clockstr); | ||||||
|  | 	free(cells); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| struct tb_cell* strn_cell(char* s, uint16_t len) // throws
 | struct tb_cell* strn_cell(char* s, uint16_t len) // throws
 | ||||||
| { | { | ||||||
| 	struct tb_cell* cells = malloc((sizeof (struct tb_cell)) * len); | 	struct tb_cell* cells = malloc((sizeof (struct tb_cell)) * len); | ||||||
|  |  | ||||||
|  | @ -86,4 +86,7 @@ void animate_init(struct term_buf* buf); | ||||||
| void animate(struct term_buf* buf); | void animate(struct term_buf* buf); | ||||||
| bool cascade(struct term_buf* buf, uint8_t* fails); | bool cascade(struct term_buf* buf, uint8_t* fails); | ||||||
| 
 | 
 | ||||||
|  | void draw_bigclock(struct term_buf *buf); | ||||||
|  | void draw_clock(struct term_buf *buf); | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
							
								
								
									
										26
									
								
								src/main.c
								
								
								
								
							
							
						
						
									
										26
									
								
								src/main.c
								
								
								
								
							|  | @ -14,6 +14,7 @@ | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <stddef.h> | #include <stddef.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  | #include <sys/time.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| 
 | 
 | ||||||
|  | @ -187,7 +188,9 @@ int main(int argc, char** argv) | ||||||
| 				(*input_handles[active_input])(input_structs[active_input], NULL); | 				(*input_handles[active_input])(input_structs[active_input], NULL); | ||||||
| 				tb_clear(); | 				tb_clear(); | ||||||
| 				animate(&buf); | 				animate(&buf); | ||||||
|  | 				draw_bigclock(&buf); | ||||||
| 				draw_box(&buf); | 				draw_box(&buf); | ||||||
|  | 				draw_clock(&buf); | ||||||
| 				draw_labels(&buf); | 				draw_labels(&buf); | ||||||
| 				if(!config.hide_f1_commands) | 				if(!config.hide_f1_commands) | ||||||
| 					draw_f_commands(); | 					draw_f_commands(); | ||||||
|  | @ -207,11 +210,26 @@ int main(int argc, char** argv) | ||||||
| 			tb_present(); | 			tb_present(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (config.animate) { | 		int timeout = -1; | ||||||
| 			error = tb_peek_event(&event, config.min_refresh_delta); | 
 | ||||||
| 		} else { | 		if (config.animate) | ||||||
| 			error = tb_poll_event(&event); | 		{ | ||||||
|  | 			timeout = config.min_refresh_delta; | ||||||
| 		} | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			struct timeval tv; | ||||||
|  | 			gettimeofday(&tv, NULL); | ||||||
|  | 			if (config.bigclock) | ||||||
|  | 				timeout = (60 - tv.tv_sec % 60) * 1000 - tv.tv_usec / 1000 + 1; | ||||||
|  | 			if (config.clock) | ||||||
|  | 				timeout = 1000 - tv.tv_usec / 1000 + 1; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (timeout == -1) | ||||||
|  | 			error = tb_poll_event(&event); | ||||||
|  | 		else | ||||||
|  | 			error = tb_peek_event(&event, timeout); | ||||||
| 
 | 
 | ||||||
| 		if (error < 0) | 		if (error < 0) | ||||||
| 		{ | 		{ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue