INIT_GUI_ERRLISTS;
static char *stat_content[NUM_STAT_ITEMS];
-#define STANDARD_STATUS_BAR "para_gui " PACKAGE_VERSION " (hit ? for help)"
-
static int signal_pipe;
-static struct win_data {
+static struct gui_window {
WINDOW *win;
- size_t begx;
- size_t begy;
size_t cols;
size_t lines;
} top, bot, sb, in, sep;
static unsigned scroll_position;
-static int curses_active;
+static bool curses_active;
static pid_t cmd_pid;
static int command_fds[2] = {-1, -1};
enum {GETCH_MODE, COMMAND_MODE, EXTERNAL_MODE};
-#define COLOR_STATUSBAR 52
-#define COLOR_COMMAND 53
-#define COLOR_OUTPUT 54
-#define COLOR_MSG 55
-#define COLOR_ERRMSG 56
-#define COLOR_WELCOME 57
-#define COLOR_SEPARATOR 58
-#define COLOR_TOP 59
-#define COLOR_BOT 60
+/**
+ * Codes for various colors.
+ *
+ * Each status item has its own color pair. The ones defined here start at a
+ * higher number so that they do not overlap with these.
+ */
+enum gui_color_pair {
+ COLOR_STATUSBAR = NUM_STAT_ITEMS + 1,
+ COLOR_COMMAND,
+ COLOR_OUTPUT,
+ COLOR_MSG,
+ COLOR_ERRMSG,
+ COLOR_SEPARATOR,
+ COLOR_TOP,
+ COLOR_BOT,
+};
struct gui_command {
const char *key;
void (*handler)(void);
};
-struct stat_item {
- char name[MAXLINE];
- char prefix[MAXLINE];
- char postfix[MAXLINE];
- unsigned y;
- unsigned x;
- unsigned len;
- int fg, bg;
- int align;
- char content[MAXLINE];
-};
-
static struct gui_theme theme;
static int _argc;
wrefresh(in.win);
}
-/*
- * update the status bar
- */
static void print_status_bar(void)
{
char *tmp;
- if (!curses_active)
- return;
- tmp = para_strdup(STANDARD_STATUS_BAR);
+ tmp = para_strdup("para_gui " PACKAGE_VERSION " (hit ? for help)");
wmove(sb.win, 0, 0);
align_str(sb.win, tmp, sb.cols, CENTER);
free(tmp);
- wrefresh(sb.win);
}
/*
* get the number of the oldest rbe that is (partially) visible. On return,
- * lines contains the sum of the number of lines of all visable entries. If the
+ * lines contains the sum of the number of lines of all visible entries. If the
* first one is only partially visible, lines is greater than bot.lines.
*/
static int first_visible_rbe(unsigned *lines)
static int add_output_line(char *line, void *data)
{
int color = *(int *)data? COLOR_ERRMSG : COLOR_OUTPUT;
+
if (!curses_active)
return 1;
rb_add_entry(color, para_strdup(line));
int color;
char *msg;
va_list ap;
+ unsigned bytes;
if (ll < loglevel || !curses_active)
return;
color = COLOR_ERRMSG;
}
va_start(ap, fmt);
- xvasprintf(&msg, fmt, ap);
+ bytes = xvasprintf(&msg, fmt, ap);
va_end(ap);
- chop(msg);
+ if (bytes > 0 && msg[bytes - 1] == '\n')
+ msg[bytes - 1] = '\0'; /* cut trailing newline */
rb_add_entry(color, msg);
wrefresh(bot.win);
}
if (!curses_active)
return;
def_prog_mode();
- curses_active = 0;
+ curses_active = false;
endwin();
}
kill_pg_and_die(ret);
}
-static void print_welcome(void)
-{
- if (loglevel > LL_NOTICE)
- return;
- outputf(COLOR_WELCOME, "Welcome to %s. Theme: %s",
- version_single_line("gui"), theme.name);
- wclrtoeol(bot.win);
-}
-
/*
* init all windows
*/
static void init_wins(int top_lines)
{
- int i;
+ int top_y = 0, bot_y = top_lines + 1, sb_y = LINES - 2,
+ in_y = LINES - 1, sep_y = top_lines;
top.lines = top_lines;
- top.cols = COLS;
- top.begy = 0;
- top.begx = 0;
-
bot.lines = LINES - top.lines - 3;
- bot.cols = COLS;
- bot.begy = top.lines + 1;
- bot.begx = 0;
-
- sb.lines = 1;
- sb.cols = COLS;
- sb.begy = LINES - 2;
- sb.begx = 0;
+ sb.lines = in.lines = sep.lines = 1;
- in.lines = 1;
- in.cols = COLS;
- in.begy = LINES - 1;
- in.begx = 0;
-
- sep.lines = 1;
- sep.cols = COLS;
- sep.begy = top.lines;
- sep.begx = 0;
+ top.cols = bot.cols = sb.cols = in.cols = sep.cols = COLS;
assume_default_colors(theme.default_fg, theme.default_bg);
if (top.win) {
- mvwin(top.win, top.begy, top.begx);
wresize(top.win, top.lines, top.cols);
+ mvwin(top.win, top_y, 0);
- mvwin(sb.win, sb.begy, sb.begx);
wresize(sb.win, sb.lines, sb.cols);
+ mvwin(sb.win, sb_y, 0);
- mvwin(sep.win, sep.begy, sep.begx);
wresize(sep.win, sep.lines, sep.cols);
+ mvwin(sep.win, sep_y, 0);
- mvwin(bot.win, bot.begy, bot.begx);
wresize(bot.win, bot.lines, bot.cols);
+ mvwin(bot.win, bot_y, 0);
- mvwin(in.win, in.begy, in.begx);
wresize(in.win, in.lines, in.cols);
+ mvwin(in.win, in_y, 0);
} else {
- sep.win = newwin(sep.lines, sep.cols, sep.begy, sep.begx);
- top.win = newwin(top.lines, top.cols, top.begy, top.begx);
- bot.win = newwin(bot.lines, bot.cols, bot.begy, bot.begx);
- sb.win = newwin(sb.lines, sb.cols, sb.begy, sb.begx);
- in.win = newwin(in.lines, in.cols, in.begy, in.begx);
+ sep.win = newwin(sep.lines, sep.cols, sep_y, 0);
+ top.win = newwin(top.lines, top.cols, top_y, 0);
+ bot.win = newwin(bot.lines, bot.cols, bot_y, 0);
+ sb.win = newwin(sb.lines, sb.cols, sb_y, 0);
+ in.win = newwin(in.lines, in.cols, in_y, 0);
if (!top.win || !bot.win || !sb.win || !in.win || !sep.win)
msg_n_exit(1, "Error: Cannot create curses windows\n");
wclear(bot.win);
keypad(bot.win, 1);
keypad(sb.win, 1);
keypad(in.win, 1);
- print_status_bar();
}
wmove(sep.win, 0, 0);
- for (i = 1; i <= COLS; i++)
- waddstr(sep.win, theme.sep_str);
+ whline(sep.win, theme.sep_char, COLS);
wclear(top.win);
//wclear(bot.win);
wnoutrefresh(top.win);
wnoutrefresh(bot.win);
- //wnoutrefresh(sb.win);
print_status_bar();
+ wnoutrefresh(sb.win);
wnoutrefresh(in.win);
wnoutrefresh(sep.win);
doupdate();
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_WELCOME, theme.welcome_fg, theme.welcome_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);
/* (Re-)initialize the curses library. */
static void init_curses(void)
{
- curses_active = 1;
- if (top.win && refresh() == ERR) /* refesh is really needed */
+ curses_active = true;
+ if (top.win && refresh() == ERR) /* refresh is really needed */
msg_n_exit(EXIT_FAILURE, "refresh() failed\n");
if (LINES < theme.lines_min || COLS < theme.cols_min)
msg_n_exit(EXIT_FAILURE, "Error: Terminal (%dx%d) too small"
{
int ret;
pid_t pid;
+
reap_next_child:
ret = para_reap_child(&pid);
if (ret <= 0)
for (i = 0; i < conf.key_map_given; ++i) {
s = conf.key_map_arg[i];
if (!(*s))
- goto err_out;
+ goto out;
free(tmp);
tmp = para_strdup(s);
if (!split_key_map(tmp, &handler, &arg))
- goto err_out;
+ goto out;
if (strlen(handler) != 1)
- goto err_out;
+ goto out;
if (*handler != 'x'
&& *handler != 'd'
&& *handler != 'i'
&& *handler != 'p')
- goto err_out;
+ goto out;
if (*handler != 'i')
continue;
if (find_cmd_byname(arg) < 0)
- goto err_out;
+ goto out;
}
ret = 0;
-err_out:
+out:
free(tmp);
return ret;
}
}
return;
case SIGINT:
- PARA_WARNING_LOG("caught SIGINT, reset");
+ PARA_WARNING_LOG("caught SIGINT, reset\n");
/* Nothing to do. SIGINT killed our child which gets noticed
* by do_select and resets everything.
*/
return;
case SIGUSR1:
- PARA_NOTICE_LOG("got SIGUSR1, rereading configuration");
+ PARA_NOTICE_LOG("got SIGUSR1, rereading configuration\n");
com_reread_conf();
return;
case SIGCHLD:
flags[i] = 0;
}
if (ret < 0) {
- PARA_NOTICE_LOG("closing command fd %d: %s",
+ PARA_NOTICE_LOG("closing command fd %d: %s\n",
i, para_strerror(-ret));
close(command_fds[i]);
command_fds[i] = -1;
return 0;
}
if (cbo[i] == COMMAND_BUF_SIZE - 1) {
- PARA_NOTICE_LOG("discarding overlong line");
+ PARA_NOTICE_LOG("discarding overlong line\n");
cbo[i] = 0;
flags[i] = FELF_DISCARD_FIRST;
}
case COMMAND_MODE:
ret = wgetch(top.win);
if (ret != ERR && ret != KEY_RESIZE) {
- if (command_fds[0] >= 0) {
- close(command_fds[0]);
- command_fds[0] = -1;
- }
- if (command_fds[1] >= 0) {
- close(command_fds[1]);
- command_fds[1] = -1;
- }
if (cmd_pid)
kill(cmd_pid, SIGTERM);
return -1;
goto repeat;
}
-/*
- * read from command pipe and print data to bot window
- */
-static void send_output(void)
+/* read from command pipe and print data to bot window */
+static void exec_and_display_cmd(const char *cmd)
{
- int ret;
+ int ret, fds[3] = {0, 1, 1};
- ret = mark_fd_nonblocking(command_fds[0]);
+ outputf(COLOR_COMMAND, "%s", cmd);
+ ret = para_exec_cmdline_pid(&cmd_pid, cmd, fds);
+ if (ret < 0)
+ return;
+ ret = mark_fd_nonblocking(fds[1]);
if (ret < 0)
goto fail;
- ret = mark_fd_nonblocking(command_fds[1]);
+ ret = mark_fd_nonblocking(fds[2]);
if (ret < 0)
goto fail;
+ command_fds[0] = fds[1];
+ command_fds[1] = fds[2];
if (do_select(COMMAND_MODE) >= 0)
- PARA_INFO_LOG("command complete");
+ PARA_INFO_LOG("command complete\n");
else
- PARA_NOTICE_LOG("command aborted");
+ PARA_NOTICE_LOG("command aborted\n");
print_in_bar(COLOR_MSG, " ");
return;
fail:
static void para_cmd(char *cmd)
{
- int ret, fds[3] = {0, 1, 1};
- char *c = make_message(BINDIR "/para_client -- %s", cmd);
+ char *c;
- outputf(COLOR_COMMAND, "%s", c);
print_in_bar(COLOR_MSG, "executing client command, hit any key to abort\n");
- ret = para_exec_cmdline_pid(&cmd_pid, c, fds);
+ c = make_message(BINDIR "/para_client -- %s", cmd);
+ exec_and_display_cmd(c);
free(c);
- if (ret < 0)
- return;
- command_fds[0] = fds[1];
- command_fds[1] = fds[2];
- send_output();
}
-/*
- * exec command and print output to bot win
- */
static void display_cmd(char *cmd)
{
- int fds[3] = {0, 1, 1};
-
print_in_bar(COLOR_MSG, "executing display command, hit any key to abort");
- outputf(COLOR_COMMAND, "%s", cmd);
- if (para_exec_cmdline_pid(&cmd_pid, cmd, fds) < 0)
- return;
- command_fds[0] = fds[1];
- command_fds[1] = fds[2];
- send_output();
+ exec_and_display_cmd(cmd);
}
/*
{
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,
filled - scroll_position, ringbuffer_filled(bot_win_rb));
}
{
unsigned lines = 0;
int i = scroll_position;
+
while (lines < bot.lines && --i > 0) {
struct rb_entry *rbe = ringbuffer_get(bot_win_rb, i);
if (!rbe)
*/
static void com_reread_conf(void)
{
- char *cf =configfile_exists();
+ char *cf = configfile_exists();
struct gui_cmdline_parser_params params = {
.override = 1,
.initialize = 1,
};
if (!cf) {
- PARA_WARNING_LOG("there is no configuration to read");
+ PARA_WARNING_LOG("there is no configuration to read\n");
return;
}
- PARA_INFO_LOG("rereading command line options and config file");
+ PARA_INFO_LOG("rereading command line options and config file\n");
gui_cmdline_parser_ext(_argc, _argv, &conf, ¶ms);
/*
* Despite .print_errors is set to 0, gengetopt will print to stderr
shutdown_curses();
gui_cmdline_parser_config_file(cf, &conf, ¶ms);
init_curses();
- PARA_NOTICE_LOG("config file reloaded");
+ PARA_NOTICE_LOG("config file reloaded\n");
if (check_key_map_args() < 0)
finish(EXIT_FAILURE);
}
static void com_shrink_top_win(void)
{
if (top.lines <= theme.top_lines_min) {
- PARA_WARNING_LOG("can not decrease top window");
+ PARA_WARNING_LOG("can not decrease top window\n");
return;
}
init_wins(top.lines - 1);
static void com_enlarge_top_win(void)
{
if (bot.lines < 3) {
- PARA_WARNING_LOG("can not increase top window");
+ PARA_WARNING_LOG("can not increase top window\n");
return;
}
init_wins(top.lines + 1);
init_curses();
}
-static void change_theme(int next)
-{
- if (next)
- next_theme(&theme);
- else
- prev_theme(&theme);
- /* This seems to be needed twice, why? */
- com_refresh();
- com_refresh();
- PARA_NOTICE_LOG("new theme: %s", theme.name);
-}
-
static void com_next_theme(void)
{
- change_theme(1);
+ theme_next(&theme);
+ com_refresh();
}
static void com_prev_theme(void)
{
- change_theme(0);
+ theme_prev(&theme);
+ com_refresh();
}
-
static void handle_command(int c)
{
int i;
- /* first check user's key bindings */
+ /* first check user-defined key bindings */
for (i = 0; i < conf.key_map_given; ++i) {
char *tmp, *handler, *arg;
fprintf(stderr, "invalid key map\n");
exit(EXIT_FAILURE);
}
- init_theme_or_die(conf.theme_arg, &theme);
- top.lines = theme.top_lines_default;
+ theme_init(conf.theme_arg, &theme);
setup_signal_handling();
bot_win_rb = ringbuffer_new(RINGBUFFER_SIZE);
setlocale(LC_CTYPE, "");
initscr(); /* needed only once, always successful */
init_curses();
- print_welcome();
for (;;) {
print_status_bar();
ret = do_select(GETCH_MODE);