[pacman-dev,v3] Hide cursor while pacman is running

Message ID 20200309185417.126005-1-anatol.pomozov@gmail.com
State Accepted, archived
Headers show
Series [pacman-dev,v3] Hide cursor while pacman is running | expand

Commit Message

Anatol Pomozov March 9, 2020, 6:54 p.m. UTC
Use ASCII control codes to hide cursor at the pacman start and then
show the cursor when pacman finishes.

It helps to avoid annoying blinking when progress bars are re-drawn.

Cursor is reenabled if pacman expects user's input.

Signed-off-by: Anatol Pomozov <anatol.pomozov@gmail.com>
---
 src/pacman/pacman.c     |  2 ++
 src/pacman/sighandler.c |  4 ++++
 src/pacman/util.c       | 31 ++++++++++++++++++++++++++-----
 src/pacman/util.h       |  6 ++++++
 4 files changed, 38 insertions(+), 5 deletions(-)

Comments

Allan McRae March 9, 2020, 10:05 p.m. UTC | #1
On 10/3/20 4:54 am, Anatol Pomozov wrote:
> Use ASCII control codes to hide cursor at the pacman start and then
> show the cursor when pacman finishes.
> 
> It helps to avoid annoying blinking when progress bars are re-drawn.
> 
> Cursor is reenabled if pacman expects user's input.
> 
> Signed-off-by: Anatol Pomozov <anatol.pomozov@gmail.com>
> ---

Ack.

A

Patch

diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index d58c428a..fefd3fa4 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -300,6 +300,7 @@  static void cleanup(int ret)
 
 	/* free memory */
 	FREELIST(pm_targets);
+	console_cursor_show();
 	exit(ret);
 }
 
@@ -1084,6 +1085,7 @@  int main(int argc, char *argv[])
 	int ret = 0;
 	uid_t myuid = getuid();
 
+	console_cursor_hide();
 	install_segv_handler();
 
 	/* i18n init */
diff --git a/src/pacman/sighandler.c b/src/pacman/sighandler.c
index 46e6481f..fc4ea766 100644
--- a/src/pacman/sighandler.c
+++ b/src/pacman/sighandler.c
@@ -60,6 +60,8 @@  static void soft_interrupt_handler(int signum)
 		const char msg[] = "\nHangup signal received\n";
 		xwrite(STDERR_FILENO, msg, ARRAYSIZE(msg) - 1);
 	}
+	xwrite(STDOUT_FILENO, CURSOR_SHOW_ANSICODE,
+		sizeof(CURSOR_SHOW_ANSICODE) - 1);
 	if(alpm_trans_interrupt(config->handle) == 0) {
 		/* a transaction is being interrupted, don't exit pacman yet. */
 		return;
@@ -95,6 +97,8 @@  static void segv_handler(int signum)
 	const char msg[] = "\nerror: segmentation fault\n"
 		"Please submit a full bug report with --debug if appropriate.\n";
 	xwrite(STDERR_FILENO, msg, sizeof(msg) - 1);
+	xwrite(STDOUT_FILENO, CURSOR_SHOW_ANSICODE,
+		sizeof(CURSOR_SHOW_ANSICODE) - 1);
 
 	/* restore the default handler */
 	_reset_handler(signum);
diff --git a/src/pacman/util.c b/src/pacman/util.c
index a640ffb4..a3a85bb9 100644
--- a/src/pacman/util.c
+++ b/src/pacman/util.c
@@ -1391,6 +1391,27 @@  static int multiselect_parse(char *array, int count, char *response)
 	return 0;
 }
 
+void console_cursor_hide(void) {
+	if(isatty(fileno(stdout))) {
+		printf(CURSOR_HIDE_ANSICODE);
+	}
+}
+
+void console_cursor_show(void) {
+	if(isatty(fileno(stdout))) {
+		printf(CURSOR_SHOW_ANSICODE);
+	}
+}
+
+char *safe_fgets_stdin(char *s, int size)
+{
+	char *result;
+	console_cursor_show();
+	result = safe_fgets(s, size, stdin);
+	console_cursor_hide();
+	return result;
+}
+
 int multiselect_question(char *array, int count)
 {
 	char *response, *lastchar;
@@ -1427,7 +1448,7 @@  int multiselect_question(char *array, int count)
 
 		flush_term_input(fileno(stdin));
 
-		if(safe_fgets(response, response_len, stdin)) {
+		if(safe_fgets_stdin(response, response_len)) {
 			const size_t response_incr = 64;
 			size_t len;
 			/* handle buffer not being large enough to read full line case */
@@ -1443,8 +1464,8 @@  int multiselect_question(char *array, int count)
 				lastchar = response + response_len - 1;
 				/* sentinel byte */
 				*lastchar = 1;
-				if(safe_fgets(response + response_len - response_incr - 1,
-							response_incr + 1, stdin) == 0) {
+				if(safe_fgets_stdin(response + response_len - response_incr - 1,
+							response_incr + 1) == 0) {
 					free(response);
 					return -1;
 				}
@@ -1494,7 +1515,7 @@  int select_question(int count)
 
 		flush_term_input(fileno(stdin));
 
-		if(safe_fgets(response, sizeof(response), stdin)) {
+		if(safe_fgets_stdin(response, sizeof(response))) {
 			size_t len = strtrim(response);
 			if(len > 0) {
 				int n;
@@ -1582,7 +1603,7 @@  static int question(short preset, const char *format, va_list args)
 
 	flush_term_input(fd_in);
 
-	if(safe_fgets(response, sizeof(response), stdin)) {
+	if(safe_fgets_stdin(response, sizeof(response))) {
 		size_t len = strtrim(response);
 		if(len == 0) {
 			return preset;
diff --git a/src/pacman/util.h b/src/pacman/util.h
index 2cee479f..2b21f3d5 100644
--- a/src/pacman/util.h
+++ b/src/pacman/util.h
@@ -28,6 +28,9 @@ 
 
 #include "util-common.h"
 
+#define CURSOR_HIDE_ANSICODE "\x1B[?25l"
+#define CURSOR_SHOW_ANSICODE "\x1B[?25h"
+
 #ifdef ENABLE_NLS
 #include <libintl.h> /* here so it doesn't need to be included elsewhere */
 /* define _() as shortcut for gettext() */
@@ -77,6 +80,9 @@  int colon_printf(const char *format, ...) __attribute__((format(printf, 1, 2)));
 int yesno(const char *format, ...) __attribute__((format(printf, 1, 2)));
 int noyes(const char *format, ...) __attribute__((format(printf, 1, 2)));
 char *arg_to_string(int argc, char *argv[]);
+char *safe_fgets_stdin(char *s, int size);
+void console_cursor_hide(void);
+void console_cursor_show(void);
 
 int pm_printf(alpm_loglevel_t level, const char *format, ...) __attribute__((format(printf,2,3)));
 int pm_asprintf(char **string, const char *format, ...) __attribute__((format(printf,2,3)));