Skip to content

Commit e6cc49e

Browse files
committed
chafa: Implement fast exit with terminal cleanup
We will now emit CAN, ST and re-enable the cursor in a signal handler if the user interrupts us and we can't exit cleanly. Fixes #309 (GitHub).
1 parent e12fe69 commit e6cc49e

File tree

2 files changed

+97
-9
lines changed

2 files changed

+97
-9
lines changed

configure.ac

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,8 @@ AS_IF([ test "$enable_man" != no ], [
320320

321321
dnl --- Specific checks ---
322322

323-
AC_CHECK_FUNCS(ctermid getrandom mmap sigaction)
324-
AC_CHECK_HEADERS(sys/ioctl.h termios.h windows.h)
323+
AC_CHECK_FUNCS(ctermid getrandom mmap sigaction setitimer)
324+
AC_CHECK_HEADERS(sys/time.h sys/ioctl.h termios.h windows.h)
325325

326326
dnl
327327
dnl Define IS_WIN32_BUILD if we're building for Microsoft Windows. In order to

tools/chafa/chafa.c

Lines changed: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
#ifdef HAVE_TERMIOS_H
3636
# include <termios.h> /* tcgetattr, tcsetattr */
3737
#endif
38+
#if defined(HAVE_SYS_TIME_H) && defined(HAVE_SETITIMER)
39+
# include <sys/time.h> /* setitimer */
40+
#endif
3841

3942
#include <chafa.h>
4043
#include "chicle-font-loader.h"
@@ -57,6 +60,10 @@
5760
/* Maximum size of stack-allocated read/write buffer */
5861
#define BUFFER_MAX 4096
5962

63+
/* If the user issues a SIGINT and we can't exit immediately, wait
64+
* this long for processing to finish before forcing an exit. */
65+
#define EXIT_GRACE_USEC (500 * 1000)
66+
6067
#ifdef G_OS_WIN32
6168
/* Enable command line globbing on Windows.
6269
*
@@ -74,11 +81,97 @@ static struct termios saved_termios;
7481
#endif
7582

7683
#ifdef HAVE_SIGACTION
84+
85+
static gchar fast_exit_seq [CHAFA_TERM_SEQ_LENGTH_MAX + 4];
86+
87+
static void
88+
prepare_fast_exit (ChafaTermInfo *term_info)
89+
{
90+
gchar *p0;
91+
92+
/* CAN, ST */
93+
strcpy (fast_exit_seq, "\x18\x1b\x5c");
94+
95+
p0 = chafa_term_info_emit_enable_cursor (term_info, fast_exit_seq + strlen (fast_exit_seq));
96+
*p0 = '\0';
97+
}
98+
99+
static void
100+
fast_exit (void)
101+
{
102+
/* Fast exit */
103+
104+
if (!options.polite)
105+
{
106+
#ifdef HAVE_TERMIOS_H
107+
if (options.is_interactive)
108+
{
109+
tcsetattr (STDIN_FILENO, TCSANOW, &saved_termios);
110+
}
111+
#endif
112+
113+
write (STDOUT_FILENO, fast_exit_seq, strlen (fast_exit_seq));
114+
}
115+
116+
exit (0);
117+
}
118+
119+
static void
120+
sigalarm_handler (G_GNUC_UNUSED int sig)
121+
{
122+
fast_exit ();
123+
}
124+
125+
static void
126+
install_fast_exit_alarm (void)
127+
{
128+
#ifdef HAVE_SETITIMER
129+
struct sigaction sa;
130+
struct itimerval itv;
131+
132+
memset (&sa, 0, sizeof (sa));
133+
memset (&itv, 0, sizeof (itv));
134+
135+
sa.sa_handler = sigalarm_handler;
136+
sa.sa_flags = SA_RESETHAND;
137+
sigaction (SIGALRM, &sa, NULL);
138+
139+
itv.it_value.tv_usec = EXIT_GRACE_USEC;
140+
141+
setitimer (ITIMER_REAL, &itv, NULL);
142+
#endif
143+
}
144+
145+
static void install_interrupt_handler (void);
146+
77147
static void
78148
sigint_handler (G_GNUC_UNUSED int sig)
79149
{
150+
if (interrupted_by_user)
151+
{
152+
fast_exit ();
153+
}
154+
else
155+
{
156+
install_interrupt_handler ();
157+
install_fast_exit_alarm ();
158+
}
159+
80160
interrupted_by_user = TRUE;
81161
}
162+
163+
static void
164+
install_interrupt_handler (void)
165+
{
166+
struct sigaction sa;
167+
168+
memset (&sa, 0, sizeof (sa));
169+
sa.sa_handler = sigint_handler;
170+
sa.sa_flags = 0;
171+
172+
sigaction (SIGINT, &sa, NULL);
173+
}
174+
82175
#endif
83176

84177
static void
@@ -903,13 +996,7 @@ static void
903996
proc_init (void)
904997
{
905998
#ifdef HAVE_SIGACTION
906-
struct sigaction sa;
907-
908-
memset (&sa, 0, sizeof (sa));
909-
sa.sa_handler = sigint_handler;
910-
sa.sa_flags = SA_RESETHAND;
911-
912-
sigaction (SIGINT, &sa, NULL);
999+
install_interrupt_handler ();
9131000
#endif
9141001

9151002
#ifdef G_OS_WIN32
@@ -953,6 +1040,7 @@ main (int argc, char *argv [])
9531040
|| chicle_path_queue_get_length (global_path_queue) == 0)
9541041
goto out;
9551042

1043+
prepare_fast_exit (options.term_info);
9561044
tty_options_init ();
9571045

9581046
if (options.grid_width > 0 || options.grid_height > 0)

0 commit comments

Comments
 (0)