manual: Bump required gcc version to 4.1.
[paraslash.git] / gui.c
diff --git a/gui.c b/gui.c
index 57ee8be5e9e9f2867f8c85ecdcce7aca2b4656a0..9d96e70f6949362b39b50fa1dc23e85327a9316a 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1998-2014 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 1998 Andre Noll <maan@tuebingen.mpg.de>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
@@ -124,11 +124,11 @@ GUI_COMMANDS
 static struct gui_command command_list[] = {GUI_COMMANDS {.name = NULL}};
 
 struct input_task {
-       struct task task;
+       struct task *task;
 };
 
 struct status_task {
-       struct task task;
+       struct task *task;
        pid_t pid;
        char *buf;
        int bufsize, loaded;
@@ -140,7 +140,7 @@ struct status_task {
 #define COMMAND_BUF_SIZE 32768
 
 struct exec_task {
-       struct task task;
+       struct task *task;
        char command_buf[2][COMMAND_BUF_SIZE]; /* stdout/stderr of command */
        int cbo[2]; /* command buf offsets */
        unsigned flags[2]; /* passed to for_each_line() */
@@ -296,7 +296,7 @@ static int align_str(WINDOW* win, char *str, unsigned int len,
                waddstr(win, str);
        } else {
                add_spaces(win, num / 2);
-               waddstr(win, str[0]? str: "");
+               waddstr(win, str);
                add_spaces(win, num - num / 2);
        }
        return 1;
@@ -597,25 +597,25 @@ static void clear_all_items(void)
        }
 }
 
-static void status_pre_select(struct sched *s, struct task *t)
+static void status_pre_select(struct sched *s, void *context)
 {
-       struct status_task *st = container_of(t, struct status_task, task);
+       struct status_task *st = context;
 
        if (st->fd >= 0)
                para_fd_set(st->fd, &s->rfds, &s->max_fileno);
-       if (task_get_notification(t) < 0)
+       if (task_get_notification(st->task) < 0)
                return sched_min_delay(s);
        if (st->fd < 0)
                sched_request_barrier_or_min_delay(&st->next_exec, s);
 }
 
-static int status_post_select(struct sched *s, struct task *t)
+static int status_post_select(struct sched *s, void *context)
 {
-       struct status_task *st = container_of(t, struct status_task, task);
+       struct status_task *st = context;
        size_t sz;
        int ret, ret2;
 
-       ret = task_get_notification(t);
+       ret = task_get_notification(st->task);
        if (ret == -E_GUI_SIGCHLD && st->pid > 0) {
                int exit_status;
                if (waitpid(st->pid, &exit_status, WNOHANG) == st->pid) {
@@ -659,7 +659,8 @@ static int status_post_select(struct sched *s, struct task *t)
        ret2 = for_each_stat_item(st->buf, st->loaded, update_item);
        if (ret < 0 || ret2 < 0) {
                st->loaded = 0;
-               PARA_NOTICE_LOG("closing stat pipe: %s\n", para_strerror(-ret));
+               PARA_NOTICE_LOG("closing stat pipe: %s\n",
+                       para_strerror(ret < 0? -ret : -ret2));
                close(st->fd);
                st->fd = -1;
                clear_all_items();
@@ -686,7 +687,7 @@ static void init_wins(int top_lines)
        int bot_lines = LINES - top_lines - 3, sb_lines = 1, in_lines = 1,
                sep_lines = 1;
 
-       assume_default_colors(theme.default_fg, theme.default_bg);
+       assume_default_colors(theme.dflt.fg, theme.dflt.bg);
        if (top.win) {
                wresize(top.win, top_lines, COLS);
                mvwin(top.win, top_y, 0);
@@ -758,16 +759,16 @@ static void init_colors_or_die(void)
                die(EXIT_FAILURE, "fatal: failed to start colors\n");
        FOR_EACH_STATUS_ITEM(i)
                if (theme.data[i].len)
-                       init_pair_or_die(i + 1, theme.data[i].fg,
-                               theme.data[i].bg);
-       init_pair_or_die(COLOR_STATUSBAR, theme.sb_fg, theme.sb_bg);
-       init_pair_or_die(COLOR_COMMAND, theme.cmd_fg, theme.cmd_bg);
-       init_pair_or_die(COLOR_OUTPUT, theme.output_fg, theme.output_bg);
-       init_pair_or_die(COLOR_MSG, theme.msg_fg, theme.msg_bg);
-       init_pair_or_die(COLOR_ERRMSG, theme.err_msg_fg, theme.err_msg_bg);
-       init_pair_or_die(COLOR_SEPARATOR, theme.sep_fg, theme.sep_bg);
-       init_pair_or_die(COLOR_TOP, theme.default_fg, theme.default_bg);
-       init_pair_or_die(COLOR_BOT, theme.default_fg, theme.default_bg);
+                       init_pair_or_die(i + 1, theme.data[i].color.fg,
+                               theme.data[i].color.bg);
+       init_pair_or_die(COLOR_STATUSBAR, theme.sb.fg, theme.sb.bg);
+       init_pair_or_die(COLOR_COMMAND, theme.cmd.fg, theme.cmd.bg);
+       init_pair_or_die(COLOR_OUTPUT, theme.output.fg, theme.output.bg);
+       init_pair_or_die(COLOR_MSG, theme.msg.fg, theme.msg.bg);
+       init_pair_or_die(COLOR_ERRMSG, theme.err_msg.fg, theme.err_msg.bg);
+       init_pair_or_die(COLOR_SEPARATOR, theme.sep.fg, theme.sep.bg);
+       init_pair_or_die(COLOR_TOP, theme.dflt.fg, theme.dflt.bg);
+       init_pair_or_die(COLOR_BOT, theme.dflt.fg, theme.dflt.bg);
 }
 
 /* (Re-)initialize the curses library. */
@@ -775,7 +776,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"
@@ -870,15 +871,32 @@ static void parse_config_file_or_die(bool override)
                }
                goto out;
        }
+       /*
+        * When the gengetopt config file parser is called more than once, any
+        * key map arguments found in the config file are _appended_ to the old
+        * values, even though we turn on ->override. We want the new arguments
+        * to replace the old ones, so we must empty the key_map_arg array
+        * first. Unfortunately, this also clears any key map arguments given
+        * at the command line.
+        */
+       if (override) {
+               int i;
+               for (i = 0; i < conf.key_map_given; i++) {
+                       free(conf.key_map_arg[i]);
+                       conf.key_map_arg[i] = NULL;
+               }
+               conf.key_map_given = 0;
+       }
+
        gui_cmdline_parser_config_file(config_file, &conf, &params);
        loglevel = get_loglevel_by_name(conf.loglevel_arg);
        check_key_map_args_or_die();
-       theme_init(conf.theme_arg, &theme);
        err = false;
 out:
        free(config_file);
        if (err)
                exit(EXIT_FAILURE);
+       theme_init(conf.theme_arg, &theme);
 }
 
 /* reread configuration, terminate on errors */
@@ -897,7 +915,7 @@ static void reread_conf(void)
 /*
  * React to various signal-related events
  */
-static int signal_post_select(struct sched *s, __a_unused struct task *t)
+static int signal_post_select(struct sched *s, __a_unused void *context)
 {
        int ret = para_next_signal(&s->rfds);
 
@@ -933,22 +951,23 @@ static enum exec_status exec_status(void)
        return EXEC_IDLE;
 }
 
-static void exec_pre_select(struct sched *s, struct task *t)
+static void exec_pre_select(struct sched *s, void *context)
 {
+       struct exec_task *et = context;
        if (exec_fds[0] >= 0)
                para_fd_set(exec_fds[0], &s->rfds, &s->max_fileno);
        if (exec_fds[1] >= 0)
                para_fd_set(exec_fds[1], &s->rfds, &s->max_fileno);
-       if (task_get_notification(t) < 0)
+       if (task_get_notification(et->task) < 0)
                sched_min_delay(s);
 }
 
-static int exec_post_select(struct sched *s, struct task *t)
+static int exec_post_select(struct sched *s, void *context)
 {
-       struct exec_task *ct = container_of(t, struct exec_task, task);
+       struct exec_task *ct = context;
        int i, ret;
 
-       ret = task_get_notification(t);
+       ret = task_get_notification(ct->task);
        if (ret == -E_GUI_SIGCHLD && exec_pid > 0) {
                int exit_status;
                if (waitpid(exec_pid, &exit_status, WNOHANG) == exec_pid) {
@@ -993,7 +1012,7 @@ static int exec_post_select(struct sched *s, struct task *t)
        return 0;
 }
 
-static void input_pre_select(struct sched *s, __a_unused struct task *t)
+static void input_pre_select(struct sched *s, __a_unused void *context)
 {
        if (exec_status() != EXEC_XCMD)
                para_fd_set(STDIN_FILENO, &s->rfds, &s->max_fileno);
@@ -1090,7 +1109,7 @@ static void handle_command(int c)
                km_keyname(c));
 }
 
-static int input_post_select(__a_unused struct sched *s, __a_unused struct task *t)
+static int input_post_select(__a_unused struct sched *s, __a_unused void *context)
 {
        int ret;
        enum exec_status exs = exec_status();
@@ -1130,12 +1149,6 @@ static int input_post_select(__a_unused struct sched *s, __a_unused struct task
        return 0;
 }
 
-static void signal_pre_select(struct sched *s, struct task *t)
-{
-       struct signal_task *st = container_of(t, struct signal_task, task);
-       para_fd_set(st->fd, &s->rfds, &s->max_fileno);
-}
-
 static void print_scroll_msg(void)
 {
        unsigned lines_total, filled = ringbuffer_filled(bot_win_rb);
@@ -1406,52 +1419,54 @@ __noreturn static void print_help_and_die(void)
 
 static int setup_tasks_and_schedule(void)
 {
+       int ret;
+       struct exec_task exec_task = {.task = NULL};
+       struct status_task status_task = {.fd = -1};
+       struct input_task input_task = {.task = NULL};
+       struct signal_task *signal_task;
        struct sched sched = {
                .default_timeout = {
                        .tv_sec = conf.timeout_arg  / 1000,
                        .tv_usec = (conf.timeout_arg % 1000) * 1000,
                },
        };
-       struct exec_task exec_task = {
-               .task = {
-                       .status = "exec",
-                       .pre_select = exec_pre_select,
-                       .post_select = exec_post_select,
-               },
-       };
-       struct status_task status_task = {
-               .task = {
-                       .status = "status",
-                       .pre_select = status_pre_select,
-                       .post_select = status_post_select,
-               },
-               .fd = -1
-       };
-       struct input_task input_task = {
-               .task = {
-                       .status = "input",
-                       .pre_select = input_pre_select,
-                       .post_select = input_post_select,
-               },
-       };
-       struct signal_task signal_task = {
-               .task = {
-                       .status = "signal",
-                       .pre_select = signal_pre_select,
-                       .post_select = signal_post_select,
-               },
-       };
-       signal_task.fd = para_signal_init();
+
+       exec_task.task = task_register(&(struct task_info) {
+               .name = "exec",
+               .pre_select = exec_pre_select,
+               .post_select = exec_post_select,
+               .context = &exec_task,
+       }, &sched);
+
+       status_task.task = task_register(&(struct task_info) {
+               .name = "status",
+               .pre_select = status_pre_select,
+               .post_select = status_post_select,
+               .context = &status_task,
+       }, &sched);
+
+       input_task.task = task_register(&(struct task_info) {
+               .name = "input",
+               .pre_select = input_pre_select,
+               .post_select = input_post_select,
+               .context = &input_task,
+       }, &sched);
+
+       signal_task = signal_init_or_die();
        para_install_sighandler(SIGINT);
        para_install_sighandler(SIGTERM);
        para_install_sighandler(SIGCHLD);
        para_install_sighandler(SIGUSR1);
-
-       register_task(&sched, &exec_task.task);
-       register_task(&sched, &status_task.task);
-       register_task(&sched, &input_task.task);
-       register_task(&sched, &signal_task.task);
-       return schedule(&sched);
+       signal_task->task = task_register(&(struct task_info) {
+               .name = "signal",
+               .pre_select = signal_pre_select,
+               .post_select = signal_post_select,
+               .context = signal_task,
+       }, &sched);
+       ret = schedule(&sched);
+       sched_shutdown(&sched);
+       signal_shutdown(signal_task);
+       return ret;
 }
 
 /**