X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=gui.c;h=8e83cc53c6d55f53ccdb0a9dfbb4c89f0bb7525a;hp=1a89681d196bce31b863e390bd60fc62f441a886;hb=ce9e297eb91a932a11f81890c800d0380b5bc9c9;hpb=642445e95fea1c548c79f80ad3b5d6f30ba572f3 diff --git a/gui.c b/gui.c index 1a89681d..8e83cc53 100644 --- a/gui.c +++ b/gui.c @@ -26,8 +26,9 @@ #include "ggo.h" #include "version.h" -/** define the array of error lists needed by para_gui */ -INIT_GUI_ERRLISTS; +/** Array of error strings. */ +DEFINE_PARA_ERRLIST; + static char *stat_content[NUM_STAT_ITEMS]; static struct gui_window { @@ -146,7 +147,7 @@ struct exec_task { unsigned flags[2]; /* passed to for_each_line() */ }; -static int find_cmd_byname(char *name) +static int find_cmd_byname(const char *name) { int i; @@ -246,8 +247,8 @@ static char *km_keyname(int c) /* Print given number of spaces to curses window. */ static void add_spaces(WINDOW* win, unsigned int num) { - char space[] = " "; - unsigned sz = sizeof(space) - 1; /* number of spaces */ + const char space[] = " "; + const unsigned sz = sizeof(space) - 1; /* number of spaces */ while (num >= sz) { waddstr(win, space); @@ -255,8 +256,7 @@ static void add_spaces(WINDOW* win, unsigned int num) } if (num > 0) { assert(num < sz); - space[num] = '\0'; - waddstr(win, space); + waddstr(win, space + sz - num); } } @@ -264,41 +264,35 @@ static void add_spaces(WINDOW* win, unsigned int num) * print aligned string to curses window. This function always prints * exactly len chars. */ -static int align_str(WINDOW* win, char *str, unsigned int len, +static int align_str(WINDOW* win, const char *str, unsigned int len, unsigned int align) { - int ret, i, num; /* of spaces */ + int ret, num; /* of spaces */ size_t width; + char *sstr; /* sanitized string */ if (!win || !str) return 0; - ret = strwidth(str, &width); + ret = sanitize_str(str, len, &sstr, &width); if (ret < 0) { PARA_ERROR_LOG("%s\n", para_strerror(-ret)); width = 0; - str[0] = '\0'; + sstr = para_strdup(NULL); } + assert(width <= len); num = len - width; - if (num < 0) { - str[len] = '\0'; - num = 0; - } - /* replace control characters by spaces */ - for (i = 0; i < len && str[i]; i++) { - if (str[i] == '\n' || str[i] == '\r' || str[i] == '\f') - str[i] = ' '; - } if (align == LEFT) { - waddstr(win, str); + waddstr(win, sstr); add_spaces(win, num); } else if (align == RIGHT) { add_spaces(win, num); - waddstr(win, str); + waddstr(win, sstr); } else { add_spaces(win, num / 2); - waddstr(win, str[0]? str: ""); + waddstr(win, sstr); add_spaces(win, num - num / 2); } + free(sstr); return 1; } @@ -505,9 +499,18 @@ static __printf_2_3 void curses_log(int ll, const char *fmt,...) /** The log function of para_gui, always set to curses_log(). */ __printf_2_3 void (*para_log)(int, const char*, ...) = curses_log; +/* Call endwin() to reset the terminal into non-visual mode. */ static void shutdown_curses(void) { - def_prog_mode(); + /* + * If para_gui received a terminating signal in external mode, the + * terminal can be in an unusable state at this point because the child + * process might not have caught the signal. In this case endwin() has + * already been called and must not be called again. So we first return + * to program mode, then call endwin(). + */ + if (!curses_active()) + reset_prog_mode(); endwin(); } @@ -516,13 +519,22 @@ __noreturn __printf_2_3 static void die(int exit_code, const char* fmt, ...) { va_list argp; + /* Kill every process in our process group. */ + para_sigaction(SIGTERM, SIG_IGN); + kill(0, SIGTERM); + /* Wait up to two seconds for child processes to die. */ + alarm(2); + while (waitpid(0, NULL, 0) >= 0) + ; /* nothing */ + alarm(0); + /* mousemask() exists only in ncurses */ +#ifdef NCURSES_MOUSE_VERSION + mousemask(~(mmask_t)0, NULL); /* Avoid bad terminal state with xterm. */ +#endif shutdown_curses(); va_start(argp, fmt); vfprintf(stderr, fmt, argp); va_end(argp); - /* kill every process in the process group and exit */ - para_sigaction(SIGTERM, SIG_IGN); - kill(0, SIGTERM); exit(exit_code); } @@ -776,7 +788,7 @@ static void init_curses(void) { if (curses_active()) return; - if (top.win && refresh() == ERR) /* refresh is really needed */ + if (refresh() == ERR) /* refresh is really needed */ die(EXIT_FAILURE, "refresh() failed\n"); if (LINES < theme.lines_min || COLS < theme.cols_min) die(EXIT_FAILURE, "Terminal (%dx%d) too small" @@ -924,12 +936,7 @@ static int signal_post_select(struct sched *s, __a_unused void *context) switch (ret) { case SIGTERM: die(EXIT_FAILURE, "only the good die young (caught SIGTERM)\n"); - return 1; case SIGINT: - PARA_WARNING_LOG("caught SIGINT, reset\n"); - /* Nothing to do. SIGINT killed our child which gets noticed - * by do_select and resets everything. - */ return 1; case SIGUSR1: PARA_NOTICE_LOG("got SIGUSR1, rereading configuration\n"); @@ -1154,7 +1161,7 @@ static void print_scroll_msg(void) unsigned lines_total, filled = ringbuffer_filled(bot_win_rb); int first_rbe = first_visible_rbe(&lines_total); - print_in_bar(COLOR_MSG, "scrolled view: %d-%d/%d\n", filled - first_rbe, + print_in_bar(COLOR_MSG, "scrolled view: %u-%u/%u\n", filled - first_rbe, filled - scroll_position, ringbuffer_filled(bot_win_rb)); } @@ -1485,9 +1492,9 @@ static int setup_tasks_and_schedule(void) * The exec task is responsible for printing the output of the currently * running executable to the bottom window. * - * The signal task performs suitable actions according to any signals received. - * For example it refreshes all windows on terminal size changes and resets the - * terminal on \p SIGTERM. + * The signal task performs various actions according to signals received. For + * example, it reloads the configuration file on SIGUSR1, and it shuts down the + * curses system on SIGTERM to restore the terminal settings before exit. * * The input task reads single key strokes from stdin. For each key pressed, it * executes the command handler associated with this key.