[pacman-dev] [PATCH v2] Hide cursor while pacman is running

Anatol Pomozov anatol.pomozov at gmail.com
Sun Mar 8 20:22:53 UTC 2020


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 at gmail.com>
---
 src/common/util-common.c | 13 +++++++++++++
 src/common/util-common.h |  3 +++
 src/pacman/pacman.c      |  2 ++
 src/pacman/sighandler.c  |  5 +++++
 src/pacman/util.c        | 19 ++++++++++++++-----
 src/pacman/util.h        |  1 +
 6 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/src/common/util-common.c b/src/common/util-common.c
index 7d43ac0d..3850cffb 100644
--- a/src/common/util-common.c
+++ b/src/common/util-common.c
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "util-common.h"
 
@@ -104,6 +105,18 @@ int llstat(char *path, struct stat *buf)
 	return ret;
 }
 
+void console_hide_cursor(void) {
+	if(isatty(fileno(stdout))) {
+		printf("\x1B[?25l");
+	}
+}
+
+void console_show_cursor(void) {
+	if(isatty(fileno(stdout))) {
+		printf("\x1B[?25h");
+	}
+}
+
 /** Wrapper around fgets() which properly handles EINTR
  * @param s string to read into
  * @param size maximum length to read
diff --git a/src/common/util-common.h b/src/common/util-common.h
index 483d5da4..8eacde7e 100644
--- a/src/common/util-common.h
+++ b/src/common/util-common.h
@@ -28,6 +28,9 @@ char *mdirname(const char *path);
 
 int llstat(char *path, struct stat *buf);
 
+void console_hide_cursor(void);
+void console_show_cursor(void);
+
 char *safe_fgets(char *s, int size, FILE *stream);
 
 void wordsplit_free(char **ws);
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index d58c428a..aafd9e63 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_show_cursor();
 	exit(ret);
 }
 
@@ -1084,6 +1085,7 @@ int main(int argc, char *argv[])
 	int ret = 0;
 	uid_t myuid = getuid();
 
+	console_hide_cursor();
 	install_segv_handler();
 
 	/* i18n init */
diff --git a/src/pacman/sighandler.c b/src/pacman/sighandler.c
index 46e6481f..59aaa61f 100644
--- a/src/pacman/sighandler.c
+++ b/src/pacman/sighandler.c
@@ -27,6 +27,9 @@
 #include "sighandler.h"
 #include "util.h"
 
+/* the same ANSI sequence as used in console_show_cursor */
+#define SHOW_CURSOR_ANSI "\x1B[?25h"
+
 /** Write function that correctly handles EINTR.
  */
 static ssize_t xwrite(int fd, const void *buf, size_t count)
@@ -60,6 +63,7 @@ static void soft_interrupt_handler(int signum)
 		const char msg[] = "\nHangup signal received\n";
 		xwrite(STDERR_FILENO, msg, ARRAYSIZE(msg) - 1);
 	}
+	xwrite(STDOUT_FILENO, SHOW_CURSOR_ANSI, sizeof(SHOW_CURSOR_ANSI) - 1);
 	if(alpm_trans_interrupt(config->handle) == 0) {
 		/* a transaction is being interrupted, don't exit pacman yet. */
 		return;
@@ -95,6 +99,7 @@ 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, SHOW_CURSOR_ANSI, sizeof(SHOW_CURSOR_ANSI) - 1);
 
 	/* restore the default handler */
 	_reset_handler(signum);
diff --git a/src/pacman/util.c b/src/pacman/util.c
index a640ffb4..7dfbdbca 100644
--- a/src/pacman/util.c
+++ b/src/pacman/util.c
@@ -1391,6 +1391,15 @@ static int multiselect_parse(char *array, int count, char *response)
 	return 0;
 }
 
+char *safe_fgets_stdin(char *s, int size)
+{
+	char *result;
+	console_show_cursor();
+	result = safe_fgets(s, size, stdin);
+	console_hide_cursor();
+	return result;
+}
+
 int multiselect_question(char *array, int count)
 {
 	char *response, *lastchar;
@@ -1427,7 +1436,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 +1452,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 +1503,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 +1591,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..fbc5f33c 100644
--- a/src/pacman/util.h
+++ b/src/pacman/util.h
@@ -77,6 +77,7 @@ 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);
 
 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)));
-- 
2.25.1


More information about the pacman-dev mailing list