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"
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+
77147static void
78148sigint_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
84177static void
@@ -903,13 +996,7 @@ static void
903996proc_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