X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=gui.c;h=894fc2f87298962b7f4a8de7729f74f853b7c49c;hp=ae585b8b3434d6253cc382cf310a3b2560de5ef4;hb=405a66cac091943206ea466455638b876942fe1d;hpb=f127354753a643a070958f577f31251a3f58115f diff --git a/gui.c b/gui.c index ae585b8b..894fc2f8 100644 --- a/gui.c +++ b/gui.c @@ -53,8 +53,11 @@ static int stat_pipe = -1; static struct gui_args_info conf; static int loglevel; -enum {GETCH_MODE, COMMAND_MODE, EXTERNAL_MODE}; - +enum cmd_status { + CMDS_IDLE, /* no command running */ + CMDS_DCMD, /* para or display command running */ + CMDS_XCMD, /* external command running */ +}; /** * Codes for various colors. @@ -641,15 +644,50 @@ static void clear_all_items(void) } } +static struct timeval next_exec; + +static void status_pre_select(fd_set *rfds, int *max_fileno, struct timeval *tv) +{ + struct timeval atm, diff; + + if (stat_pipe >= 0) + return para_fd_set(stat_pipe, rfds, max_fileno); + gettimeofday(&atm, NULL); + if (tv_diff(&next_exec, &atm, &diff) > 0) { + *tv = diff; + return; + } + tv->tv_sec = tv->tv_usec = 0; /* min delay */ +} + static void status_post_select(fd_set *rfds) { static char *buf; static int bufsize, loaded; - int ret, ret2; size_t sz; + pid_t pid; + int ret, ret2; - if (stat_pipe < 0) + if (stat_pipe < 0) { + struct timeval atm; + int fds[3] = {0, 1, 0}; + /* Avoid busy loop */ + gettimeofday(&atm, NULL); + if (tv_diff(&next_exec, &atm, NULL) > 0) + return; + next_exec.tv_sec = atm.tv_sec + 2; + ret = para_exec_cmdline_pid(&pid, conf.stat_cmd_arg, fds); + if (ret < 0) + return; + ret = mark_fd_nonblocking(fds[1]); + if (ret < 0) { + close(fds[1]); + return; + } + stat_pipe = fds[1]; return; + } + if (loaded >= bufsize) { if (bufsize > 1000 * 1000) { loaded = 0; @@ -809,8 +847,11 @@ reap_next_child: ret = para_reap_child(&pid); if (ret <= 0) return; - if (pid == cmd_pid) + if (pid == cmd_pid) { cmd_pid = 0; + init_curses(); + print_in_bar(COLOR_MSG, " "); + } goto reap_next_child; } @@ -916,9 +957,12 @@ static void reread_conf(void) /* * React to various signal-related events */ -static void handle_signal(int sig) +static void signal_post_select(fd_set *rfds) { - switch (sig) { + int ret = para_next_signal(rfds); + if (ret <= 0) + return; + switch (ret) { case SIGTERM: die(EXIT_FAILURE, "only the good die young (caught SIGTERM)\n"); return; @@ -945,41 +989,22 @@ static void handle_signal(int sig) } } -static void status_pre_select(fd_set *rfds, int *max_fileno, struct timeval *tv) -{ - static struct timeval next_exec, atm, diff; - int ret, fds[3] = {0, 1, 0}; - pid_t pid; +#define COMMAND_BUF_SIZE 32768 - if (stat_pipe >= 0) - goto success; - /* Avoid busy loop */ - gettimeofday(&atm, NULL); - if (tv_diff(&next_exec, &atm, &diff) > 0) { - if (tv_diff(&diff, tv, NULL) < 0) - *tv = diff; - return; - } - next_exec.tv_sec = atm.tv_sec + 2; - ret = para_exec_cmdline_pid(&pid, conf.stat_cmd_arg, fds); - if (ret < 0) - return; - ret = mark_fd_nonblocking(fds[1]); - if (ret < 0) { - close(fds[1]); - return; - } - stat_pipe = fds[1]; -success: - para_fd_set(stat_pipe, rfds, max_fileno); +static enum cmd_status cmd_status(void) +{ + if (command_fds[0] >= 0 || command_fds[1] >= 0) + return CMDS_DCMD; + if (cmd_pid > 0) + return CMDS_XCMD; + return CMDS_IDLE; } -#define COMMAND_BUF_SIZE 32768 - -static void command_pre_select(int mode, fd_set *rfds, int *max_fileno) +static void command_pre_select(fd_set *rfds, int *max_fileno) { - /* check command pipe only in COMMAND_MODE */ - if (mode != COMMAND_MODE) + enum cmd_status cmds = cmd_status(); + + if (cmds != CMDS_DCMD) return; if (command_fds[0] >= 0) para_fd_set(command_fds[0], rfds, max_fileno); @@ -987,15 +1012,16 @@ static void command_pre_select(int mode, fd_set *rfds, int *max_fileno) para_fd_set(command_fds[1], rfds, max_fileno); } -static int command_post_select(int mode, fd_set *rfds) +static void command_post_select(fd_set *rfds) { int i, ret; static char command_buf[2][COMMAND_BUF_SIZE]; static int cbo[2]; /* command buf offsets */ static unsigned flags[2]; /* for for_each_line() */ + enum cmd_status cmds = cmd_status(); - if (mode != COMMAND_MODE) - return 0; + if (cmds != CMDS_DCMD) + return; for (i = 0; i < 2; i++) { size_t sz; if (command_fds[i] < 0) @@ -1011,15 +1037,16 @@ static int command_post_select(int mode, fd_set *rfds) wrefresh(bot.win); flags[i] = 0; } - if (ret < 0) { - PARA_NOTICE_LOG("closing command fd %d: %s", - i, para_strerror(-ret)); + if (ret < 0 || cmd_pid == 0) { + if (ret < 0) + PARA_NOTICE_LOG("closing command fd %d: %s", + i, para_strerror(-ret)); close(command_fds[i]); command_fds[i] = -1; flags[i] = 0; cbo[i] = 0; if (command_fds[!i] < 0) /* both fds closed */ - return -1; + return; } if (cbo[i] == COMMAND_BUF_SIZE - 1) { PARA_NOTICE_LOG("discarding overlong line"); @@ -1027,89 +1054,14 @@ static int command_post_select(int mode, fd_set *rfds) flags[i] = FELF_DISCARD_FIRST; } } - return 1; } -static void input_pre_select(int mode, fd_set *rfds, int *max_fileno) +static void input_pre_select(fd_set *rfds, int *max_fileno) { - if (mode == GETCH_MODE || mode == COMMAND_MODE) - para_fd_set(STDIN_FILENO, rfds, max_fileno); -} + enum cmd_status cmds = cmd_status(); -static int input_post_select(int mode) -{ - int ret; - - switch (mode) { - case COMMAND_MODE: - ret = wgetch(top.win); - if (ret != ERR && ret != KEY_RESIZE) { - if (cmd_pid) - kill(cmd_pid, SIGTERM); - return -1; - } - return 0; - case GETCH_MODE: - ret = wgetch(top.win); - if (ret != ERR && ret != KEY_RESIZE) - return ret; - return 0; - case EXTERNAL_MODE: - if (cmd_pid == 0) - return -1; - return 0; - default: - assert(false); /* bug */ - } -} - -/* - * This is the core select loop. Besides the (internal) signal - * pipe, the following other fds are checked according to the mode: - * - * GETCH_MODE: check stdin, return when key is pressed - * - * COMMAND_MODE: check command fds and stdin. Return when peer has closed both - * stdout and stderr or when any key is pressed. - * - * EXTERNAL_MODE: Check only signal pipe. Used when an external command - * is running. During that time curses is disabled. Returns when - * cmd_pid == 0. - */ -static int do_select(int mode) -{ - fd_set rfds; - int ret, max_fileno; - struct timeval tv; - -repeat: - tv.tv_sec = conf.timeout_arg / 1000; - tv.tv_usec = (conf.timeout_arg % 1000) * 1000; -// ret = refresh_status(); - FD_ZERO(&rfds); - max_fileno = 0; - status_pre_select(&rfds, &max_fileno, &tv); - /* signal pipe */ - para_fd_set(signal_pipe, &rfds, &max_fileno); - command_pre_select(mode, &rfds, &max_fileno); - input_pre_select(mode, &rfds, &max_fileno); - ret = para_select(max_fileno + 1, &rfds, NULL, &tv); - if (ret <= 0) - goto check_return; /* skip fd checks */ - /* signals */ - ret = para_next_signal(&rfds); - if (ret > 0) - handle_signal(ret); - /* read command pipe if ready */ - ret = command_post_select(mode, &rfds); - if (ret < 0) - return 0; - status_post_select(&rfds); -check_return: - ret = input_post_select(mode); - if (ret != 0) - return ret; - goto repeat; + if (cmds != CMDS_XCMD) + para_fd_set(STDIN_FILENO, rfds, max_fileno); } /* read from command pipe and print data to bot window */ @@ -1129,11 +1081,6 @@ static void exec_and_display_cmd(const char *cmd) goto fail; command_fds[0] = fds[1]; command_fds[1] = fds[2]; - if (do_select(COMMAND_MODE) >= 0) - PARA_INFO_LOG("command complete\n"); - else - PARA_NOTICE_LOG("command aborted\n"); - print_in_bar(COLOR_MSG, " "); return; fail: PARA_ERROR_LOG("%s\n", para_strerror(-ret)); @@ -1167,10 +1114,102 @@ static void external_cmd(char *cmd) if (cmd_pid) return; shutdown_curses(); - if (para_exec_cmdline_pid(&cmd_pid, cmd, fds) < 0) + para_exec_cmdline_pid(&cmd_pid, cmd, fds); +} + +static void handle_command(int c) +{ + int i; + + /* first check user-defined key bindings */ + for (i = 0; i < conf.key_map_given; ++i) { + char *tmp, *handler, *arg; + + tmp = para_strdup(conf.key_map_arg[i]); + if (!split_key_map(tmp, &handler, &arg)) { + free(tmp); + return; + } + if (strcmp(tmp, km_keyname(c))) { + free(tmp); + continue; + } + if (*handler == 'd') + display_cmd(arg); + else if (*handler == 'x') + external_cmd(arg); + else if (*handler == 'p') + para_cmd(arg); + else if (*handler == 'i') { + int num = find_cmd_byname(arg); + if (num >= 0) + command_list[num].handler(); + } + free(tmp); return; - do_select(EXTERNAL_MODE); - init_curses(); + } + /* not found, check internal key bindings */ + for (i = 0; command_list[i].handler; i++) { + if (!strcmp(km_keyname(c), command_list[i].key)) { + command_list[i].handler(); + return; + } + } + print_in_bar(COLOR_ERRMSG, "key '%s' is not bound, press ? for help", + km_keyname(c)); +} + +static void input_post_select(void) +{ + int ret; + enum cmd_status cmds = cmd_status(); + + if (cmds == CMDS_XCMD) + return; + ret = wgetch(top.win); + if (ret == ERR || ret == KEY_RESIZE) + return; + if (cmds == CMDS_IDLE) + return handle_command(ret); + if (cmd_pid != 0) + kill(cmd_pid, SIGTERM); +} + +static void signal_pre_select(fd_set *rfds, int *max_fileno) +{ + para_fd_set(signal_pipe, rfds, max_fileno); +} + +/* + * This is the core select loop. It checks the following fds: + * + * - signal pipe + * - stdin + * - stdout/stderr of display or internal commands + */ +__noreturn static void do_select(void) +{ + fd_set rfds; + int ret, max_fileno; + struct timeval tv; + +repeat: + tv.tv_sec = conf.timeout_arg / 1000; + tv.tv_usec = (conf.timeout_arg % 1000) * 1000; + FD_ZERO(&rfds); + max_fileno = 0; + status_pre_select(&rfds, &max_fileno, &tv); + signal_pre_select(&rfds, &max_fileno); + command_pre_select(&rfds, &max_fileno); + input_pre_select(&rfds, &max_fileno); + ret = para_select(max_fileno + 1, &rfds, NULL, &tv); + if (ret <= 0) + goto repeat; /* skip fd checks */ + signal_post_select(&rfds); + command_post_select(&rfds); + status_post_select(&rfds); + input_post_select(); + goto repeat; } static void print_scroll_msg(void) @@ -1432,48 +1471,6 @@ static void com_prev_theme(void) com_refresh(); } -static void handle_command(int c) -{ - int i; - - /* first check user-defined key bindings */ - for (i = 0; i < conf.key_map_given; ++i) { - char *tmp, *handler, *arg; - - tmp = para_strdup(conf.key_map_arg[i]); - if (!split_key_map(tmp, &handler, &arg)) { - free(tmp); - return; - } - if (strcmp(tmp, km_keyname(c))) { - free(tmp); - continue; - } - if (*handler == 'd') - display_cmd(arg); - else if (*handler == 'x') - external_cmd(arg); - else if (*handler == 'p') - para_cmd(arg); - else if (*handler == 'i') { - int num = find_cmd_byname(arg); - if (num >= 0) - command_list[num].handler(); - } - free(tmp); - return; - } - /* not found, check internal key bindings */ - for (i = 0; command_list[i].handler; i++) { - if (!strcmp(km_keyname(c), command_list[i].key)) { - command_list[i].handler(); - return; - } - } - print_in_bar(COLOR_ERRMSG, "key '%s' is not bound, press ? for help", - km_keyname(c)); -} - __noreturn static void print_help_and_die(void) { struct ggo_help h = DEFINE_GGO_HELP(gui); @@ -1485,8 +1482,6 @@ __noreturn static void print_help_and_die(void) int main(int argc, char *argv[]) { - int ret; - gui_cmdline_parser(argc, argv, &conf); /* exits on errors */ loglevel = get_loglevel_by_name(conf.loglevel_arg); version_handle_flag("gui", conf.version_given); @@ -1498,12 +1493,5 @@ int main(int argc, char *argv[]) setlocale(LC_CTYPE, ""); initscr(); /* needed only once, always successful */ init_curses(); - for (;;) { - print_status_bar(); - ret = do_select(GETCH_MODE); - if (!ret) - continue; - print_in_bar(COLOR_MSG, " "); - handle_command(ret); - } + do_select(); }