[pacman-dev] Hide cursor while pacman is running

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

Commit Message

Anatol Pomozov March 4, 2020, 8:56 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/common/util-common.c | 15 +++++++++++++++
 src/common/util-common.h |  3 +++
 src/pacman/pacman.c      |  2 ++
 src/pacman/sighandler.c  |  5 +++++
 4 files changed, 25 insertions(+)

Comments

Allan McRae March 5, 2020, 6:07 a.m. UTC | #1
On 5/3/20 6:56 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.
> 

Some issues:

> sudo ./src/pacman/pacman -Suw
:: Starting full system upgrade...
:: Replace bzr with extra/breezy? [Y/n]
resolving dependencies...
warning: dependency cycle detected:
warning: libglvnd will be installed before its mesa dependency
?25l
Packages (204) alsa-lib-1.2.2-1  alsa-plugins-1.2.2-1

A rogue "?25l" there.  I also get a lot of flickering of the cursor at
"resolving dependencies" after this patch (which is not present before).

Also,

util-common.c: In function ‘console_hide_cursor’:
util-common.c:110:10: warning: non-ISO-standard escape sequence, '\e'
  110 |   printf("\e[?25l");
      |          ^~~~~~~~~

(and two other places)

\e is a GNU shortcut.  Use \x1B instead.

Patch

diff --git a/src/common/util-common.c b/src/common/util-common.c
index 7d43ac0d..ad2a8ad1 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("\e[?25l");
+	}
+}
+
+void console_show_cursor(void) {
+	if(isatty(fileno(stdout))) {
+		printf("\e[?25h");
+	}
+}
+
 /** Wrapper around fgets() which properly handles EINTR
  * @param s string to read into
  * @param size maximum length to read
@@ -114,6 +127,7 @@  char *safe_fgets(char *s, int size, FILE *stream)
 {
 	char *ret;
 	int errno_save = errno, ferror_save = ferror(stream);
+	console_show_cursor();
 	while((ret = fgets(s, size, stream)) == NULL && !feof(stream)) {
 		if(errno == EINTR) {
 			/* clear any errors we set and try again */
@@ -125,6 +139,7 @@  char *safe_fgets(char *s, int size, FILE *stream)
 			break;
 		}
 	}
+	console_hide_cursor();
 	return ret;
 }
 
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..adad411a 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 "\e[?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);