/*
- * Copyright (C) 1998-2006 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 1998-2009 Andre Noll <maan@systemlinux.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ * Licensed under the GPL v2. For licencing details see COPYING.
*/
-/** \file gui.c ncurses-based interface for paraslash */
+/** \file gui.c Curses-based interface for paraslash. */
+#include <signal.h>
+#include <sys/types.h>
+#include <dirent.h>
#include "gui.cmdline.h"
#include "para.h"
+#include "gui.h"
+#include "string.h"
#include <curses.h>
#include "ringbuffer.h"
-#include "string.h"
#include "fd.h"
#include "error.h"
+#include "list.h"
+#include "sched.h"
+#include "signal.h"
/** define the array of error lists needed by para_gui */
INIT_GUI_ERRLISTS;
-extern const char *status_item_list[NUM_STAT_ITEMS];
static char *stat_content[NUM_STAT_ITEMS];
-#define STANDARD_STATUS_BAR "para_gui " VERSION " (hit ? for help)"
+#define STANDARD_STATUS_BAR "para_gui " PACKAGE_VERSION " (hit ? for help)"
static int signal_pipe;
-static void finish(int sig);
-
static struct win_data {
WINDOW *win;
NCURSES_SIZE_T begx;
size_t len;
int color;
};
-void *bot_win_rb;
+struct ringbuffer *bot_win_rb;
#define NUM_LINES(len) (1 + (len) / bot.cols)
static unsigned scroll_position;
-static int external_cmd_died, curses_active;
-static pid_t external_cmd_pid;
+static int cmd_died, curses_active;
+static pid_t cmd_pid;
static int command_pipe = -1;
static int audiod_pipe = -1;
enum {GETCH_MODE, COMMAND_MODE, EXTERNAL_MODE};
-#define COLOR_STATUSBAR 32
-#define COLOR_COMMAND 33
-#define COLOR_OUTPUT 34
-#define COLOR_MSG 35
-#define COLOR_ERRMSG 36
-#define COLOR_WELCOME 37
-#define COLOR_SEPARATOR 38
-#define COLOR_TOP 39
-#define COLOR_BOT 40
+#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
struct gui_command {
const char *key;
}
};
+static int para_open_audiod_pipe(char *cmd)
+{
+ int fds[3] = {0, 1, 0};
+ pid_t pid;
+ int ret = para_exec_cmdline_pid(&pid, cmd, fds);
+ if (ret < 0)
+ return ret;
+ ret = mark_fd_nonblocking(fds[1]);
+ if (ret > 0)
+ return fds[1];
+ close(fds[1]);
+ return ret;
+}
+
+static int read_audiod_pipe(int fd, line_handler_t *line_handler)
+{
+ static char buf[4096];
+ const ssize_t bufsize = sizeof(buf) - 1;
+ static ssize_t loaded;
+ ssize_t ret;
+
+ if (loaded >= bufsize)
+ loaded = 0;
+ ret = read(fd, buf + loaded, bufsize - loaded);
+ if (ret > 0) {
+ loaded += ret;
+ buf[loaded] = '\0';
+ loaded = for_each_line(buf, loaded, line_handler, NULL);
+ }
+ return ret;
+}
+
static int find_cmd_byname(char *name)
{
int i;
if (!curses_active)
return;
wmove(sb.win, 0, 0);
- align_str(sb.win,STANDARD_STATUS_BAR, sb.cols, CENTER);
+ align_str(sb.win, STANDARD_STATUS_BAR, sb.cols, CENTER);
wrefresh(sb.win);
}
wrefresh(bot.win);
}
-static void add_output_line(char *line)
+static int add_output_line(char *line, __a_unused void *data)
{
if (!curses_active)
- return;
+ return 1;
rb_add_entry(COLOR_OUTPUT, para_strdup(line));
+ return 1;
}
-void para_log(int ll, const char *fmt,...)
+static int loglevel;
+
+__printf_2_3 void para_log(int ll, const char *fmt,...)
{
int color;
char *msg;
- if (ll < conf.loglevel_arg || !curses_active)
+ if (ll < loglevel || !curses_active)
return;
switch (ll) {
- case DEBUG:
- case INFO:
- case NOTICE:
+ case LL_DEBUG:
+ case LL_INFO:
+ case LL_NOTICE:
color = COLOR_MSG;
break;
default:
para_install_sighandler(SIGCHLD);
para_install_sighandler(SIGWINCH);
para_install_sighandler(SIGUSR1);
- signal(SIGPIPE, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
+ para_sigaction(SIGHUP, SIG_IGN);
}
-static void do_exit(int ret)
+__noreturn static void do_exit(int ret)
{
- signal(SIGTERM, SIG_IGN);
+ para_sigaction(SIGTERM, SIG_IGN);
kill(0, SIGTERM);
exit(ret);
}
endwin();
}
-static void finish(int ret)
+__noreturn static void finish(int ret)
{
shutdown_curses();
do_exit(ret);
/*
* exit curses and print given message to stdout/stderr
*/
-__printf_2_3 static void msg_n_exit(int ret, const char* fmt, ...)
+__noreturn __printf_2_3 static void msg_n_exit(int ret, const char* fmt, ...)
{
va_list argp;
FILE *outfd = ret? stderr: stdout;
static void print_welcome(void)
{
- int ll = conf.loglevel_arg;
- if (ll > NOTICE)
+ if (loglevel > LL_NOTICE)
return;
- outputf(COLOR_WELCOME, "Welcome to para_gui " VERSION
+ outputf(COLOR_WELCOME, "Welcome to para_gui " PACKAGE_VERSION
" \"" CODENAME "\". Theme: %s", theme.name);
wclrtoeol(bot.win);
}
if (!curses_active || !d.len || !c)
return;
tmp = make_message("%s%s%s", d.prefix, c, d.postfix);
-// PARA_DEBUG_LOG("%s: read: %s\n", __func__, tmp);
wmove(top.win, d.y * top.lines / 100, d.x * COLS / 100);
wrefresh(top.win);
wattron(top.win, COLOR_PAIR(i + 1));
if (!curses_active)
return;
- for (i = 0; i < NUM_STAT_ITEMS; i++)
+ FOR_EACH_STATUS_ITEM(i)
print_stat_item(i);
}
+
static void clear_all_items(void)
{
int i;
- for (i = 0; i < NUM_STAT_ITEMS; i++) {
+ FOR_EACH_STATUS_ITEM(i) {
free(stat_content[i]);
stat_content[i] = para_strdup("");
}
static void init_colors(void)
{
int i;
+
if (!has_colors())
msg_n_exit(EXIT_FAILURE, "Error: No color term\n");
start_color();
- for (i = 0; i < NUM_STAT_ITEMS; i++)
+ FOR_EACH_STATUS_ITEM(i)
if (theme.data[i].len)
init_pair(i + 1, theme.data[i].fg, theme.data[i].bg);
init_pair(COLOR_STATUSBAR, theme.sb_fg, theme.sb_bg);
static void check_sigchld(void)
{
+ int ret;
pid_t pid;
reap_next_child:
- pid = para_reap_child();
- if (pid <= 0)
+ ret = para_reap_child(&pid);
+ if (ret <= 0)
return;
- if (pid == external_cmd_pid) {
- external_cmd_pid = 0;
- external_cmd_died = 1;
+ if (pid == cmd_pid) {
+ cmd_pid = 0;
+ cmd_died = 1;
}
goto reap_next_child;
}
/*
* print status line if line starts with known command.
*/
-static void check_stat_line(char *line)
+static int check_stat_line(char *line, __a_unused void *data)
{
int i;
i = stat_line_valid(line);
if (i >= 0) {
line += strlen(status_item_list[i]) + 1;
+ if (*line == ' ')
+ line++;
free(stat_content[i]);
stat_content[i] = para_strdup(line);
print_stat_item(i);
}
- return;
+ return 1;
}
/*
}
return;
case SIGINT:
- PARA_WARNING_LOG("%s", "caught SIGINT, reset");
+ PARA_WARNING_LOG("caught SIGINT, reset");
/* Nothing to do. SIGINT killed our child, para_client stat.
* This get noticed by do_select which resets everything
*/
return;
case SIGUSR1:
- PARA_NOTICE_LOG("%s", "got SIGUSR1, rereading configuration");
+ PARA_NOTICE_LOG("got SIGUSR1, rereading configuration");
com_reread_conf();
return;
case SIGCHLD:
* when any key is pressed.
*
* EXTERNAL_MODE: Check only signal pipe. Used when an external command
- * is running. During that thime curses is disabled. Returns when
- * external_cmd_pid == 0.
+ * is running. During that time curses is disabled. Returns when
+ * cmd_pid == 0.
*/
static int do_select(int mode)
{
fd_set rfds;
int ret;
int max_fileno, cp_numread = 1;
- char command_buf[STRINGSIZE] = "";
+ char command_buf[4096] = "";
int cbo = 0; /* command buf offset */
struct timeval tv;
repeat:
/* command pipe only for COMMAND_MODE */
if (command_pipe >= 0 && mode == COMMAND_MODE)
para_fd_set(command_pipe, &rfds, &max_fileno);
- if (curses_active)
- para_fd_set(STDIN_FILENO, &rfds, &max_fileno);
ret = para_select(max_fileno + 1, &rfds, NULL, &tv);
if (ret <= 0)
goto check_return; /* skip fd checks */
if (command_pipe >= 0 && mode == COMMAND_MODE &&
FD_ISSET(command_pipe, &rfds)) {
cp_numread = read(command_pipe, command_buf + cbo,
- STRINGSIZE - 1 - cbo);
+ sizeof(command_buf) - 1 - cbo);
if (cp_numread >= 0)
cbo += cp_numread;
else {
close(audiod_pipe);
audiod_pipe = -1;
clear_all_items();
- free(stat_content[SI_STATUS_BAR]);
- stat_content[SI_STATUS_BAR] =
+ free(stat_content[SI_BASENAME]);
+ stat_content[SI_BASENAME] =
para_strdup("audiod not running!?");
print_all_items();
}
if (cp_numread <= 0 && !cbo) /* command complete */
return 0;
if (cbo)
- cbo = for_each_line(command_buf, cbo, &add_output_line);
+ cbo = for_each_line(command_buf, cbo,
+ &add_output_line, NULL);
if (cp_numread <= 0)
cbo = 0;
wrefresh(bot.win);
+ ret = wgetch(top.win);
+ if (ret != ERR && ret != KEY_RESIZE) {
+ if (command_pipe) {
+ close(command_pipe);
+ command_pipe = -1;
+ }
+ if (cmd_pid)
+ kill(cmd_pid, SIGTERM);
+ return -1;
+ }
break;
case GETCH_MODE:
ret = wgetch(top.win);
return ret;
break;
case EXTERNAL_MODE:
- if (external_cmd_died) {
- external_cmd_died = 0;
+ if (cmd_died) {
+ cmd_died = 0;
return 0;
}
}
*/
static int send_output(void)
{
+ int ret;
+
if (command_pipe < 0)
return 0;
+ ret = mark_fd_nonblocking(command_pipe);
+ if (ret < 0) {
+ close(command_pipe);
+ return ret;
+ }
if (do_select(COMMAND_MODE) >= 0)
- PARA_INFO_LOG("%s", "command complete");
+ PARA_INFO_LOG("command complete");
else
- PARA_NOTICE_LOG("%s", "command aborted");
+ PARA_NOTICE_LOG("command aborted");
print_in_bar(COLOR_MSG, " ");
return 1;
}
static int client_cmd_cmdline(char *cmd)
{
- pid_t pid;
int ret, fds[3] = {0, 1, 0};
- char *c = make_message(BINDIR "/para_client %s", cmd);
+ char *c = make_message(BINDIR "/para_client -- %s", cmd);
outputf(COLOR_COMMAND, "%s", c);
- print_in_bar(COLOR_MSG, "executing client command, hit q to abort\n");
- ret = para_exec_cmdline_pid(&pid, c, fds);
+ print_in_bar(COLOR_MSG, "executing client command, hit any key to abort\n");
+ ret = para_exec_cmdline_pid(&cmd_pid, c, fds);
free(c);
if (ret < 0)
return -1;
*/
static int display_cmd(char *cmd)
{
- pid_t pid;
int fds[3] = {0, 1, 0};
- print_in_bar(COLOR_MSG, "executing display command, hit q to abort");
+ print_in_bar(COLOR_MSG, "executing display command, hit any key to abort");
outputf(COLOR_COMMAND, "%s", cmd);
- if (para_exec_cmdline_pid(&pid, cmd, fds) < 0)
+ if (para_exec_cmdline_pid(&cmd_pid, cmd, fds) < 0)
return -1;
command_pipe = fds[1];
return send_output();
{
int fds[3] = {-1, -1, -1};
- if (external_cmd_pid)
+ if (cmd_pid)
return -1;
shutdown_curses();
- para_exec_cmdline_pid(&external_cmd_pid, cmd, fds);
+ para_exec_cmdline_pid(&cmd_pid, cmd, fds);
+ cmd_died = 0;
do_select(EXTERNAL_MODE);
init_curses();
return 0;
{
unsigned lines;
int fvr = first_visible_rbe(&lines);
+
if (fvr < 0 || fvr + 1 >= ringbuffer_filled(bot_win_rb)) {
print_in_bar(COLOR_ERRMSG, "top of buffer is shown\n");
return;
}
scroll_position = fvr + 1;
for (; scroll_position > 0; scroll_position--) {
- fvr = first_visible_rbe(&lines);
+ first_visible_rbe(&lines);
if (lines == bot.lines)
break;
}
{
struct rb_entry *rbe = NULL;
unsigned lines;
- int i, first_rbe, scroll;
+ int i, first_rbe, num_scroll;
/* the entry that is going to vanish */
rbe = ringbuffer_get(bot_win_rb, scroll_position);
if (!rbe)
goto err_out;
- scroll = NUM_LINES(rbe->len);
+ num_scroll = NUM_LINES(rbe->len);
first_rbe = first_visible_rbe(&lines);
if (first_rbe < 0 || (first_rbe == ringbuffer_filled(bot_win_rb) - 1))
goto err_out;
scroll_position++;
- wscrl(bot.win, -scroll);
+ wscrl(bot.win, -num_scroll);
i = draw_top_rbe(&lines);
if (i < 0)
goto err_out;
- while (i > 0 && lines < scroll) {
+ while (i > 0 && lines < num_scroll) {
int rbe_lines;
rbe = ringbuffer_get(bot_win_rb, --i);
if (!rbe)
static void com_ll_decr(void)
{
- if (conf.loglevel_arg <= DEBUG) {
+ if (loglevel <= LL_DEBUG) {
print_in_bar(COLOR_ERRMSG,
"loglevel already at maximal verbosity\n");
return;
}
- conf.loglevel_arg--;
- print_in_bar(COLOR_MSG, "loglevel set to %d\n", conf.loglevel_arg);
+ loglevel--;
+ print_in_bar(COLOR_MSG, "loglevel set to %d\n", loglevel);
}
static void com_ll_incr(void)
{
- if (conf.loglevel_arg >= EMERG) {
+ if (loglevel >= LL_EMERG) {
print_in_bar(COLOR_ERRMSG,
- "loglevel already at miminal verbosity\n");
+ "loglevel already at minimal verbosity\n");
return;
}
- conf.loglevel_arg++;
- print_in_bar(COLOR_MSG, "loglevel set to %d\n", conf.loglevel_arg);
+ loglevel++;
+ print_in_bar(COLOR_MSG, "loglevel set to %d\n", loglevel);
}
/*
static void com_reread_conf(void)
{
char *cf =configfile_exists();
+ struct gui_cmdline_parser_params params = {
+ .override = 1,
+ .initialize = 1,
+ .check_required = 0,
+ .check_ambiguity = 0
+ };
if (!cf) {
- PARA_WARNING_LOG("%s", "there is no configuration to read");
+ PARA_WARNING_LOG("there is no configuration to read");
return;
}
- PARA_INFO_LOG("%s", "rereading command line options and config file");
+ PARA_INFO_LOG("rereading command line options and config file");
gui_cmdline_parser(_argc, _argv, &conf);
- gui_cmdline_parser_configfile(cf, &conf, 1, 1, 0);
- PARA_NOTICE_LOG("%s", "configuration read");
+ gui_cmdline_parser_config_file(cf, &conf, ¶ms);
+ PARA_NOTICE_LOG("config file reloaded");
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("%s", "can not decrease top window");
+ PARA_WARNING_LOG("can not decrease top window");
return;
}
init_wins(top.lines - 1);
static void com_enlarge_top_win(void)
{
if (bot.lines < 3) {
- PARA_WARNING_LOG("%s", "can not increase top window");
+ PARA_WARNING_LOG("can not increase top window");
return;
}
init_wins(top.lines + 1);
static void com_version(void)
{
- print_in_bar(COLOR_MSG, "para_gui " VERSION " \"" CODENAME "\"");
+ print_in_bar(COLOR_MSG, "para_gui " PACKAGE_VERSION " \""
+ CODENAME "\"");
}
-static void com_quit(void)
+__noreturn static void com_quit(void)
{
finish(0);
}
fprintf(stderr, "parse error while reading command line\n");
exit(EXIT_FAILURE);
}
+ HANDLE_VERSION_FLAG("gui", conf);
init_theme(0, &theme);
top.lines = theme.top_lines_default;
if (check_key_map_args() < 0) {
conf.config_file_arg);
exit(EXIT_FAILURE);
}
- if (cf)
- gui_cmdline_parser_configfile(cf, &conf, 0, 0, 0);
+ if (cf) {
+ struct gui_cmdline_parser_params params = {
+ .override = 0,
+ .initialize = 0,
+ .check_required = 0,
+ .check_ambiguity = 0
+ };
+ gui_cmdline_parser_config_file(cf, &conf, ¶ms);
+ }
+ loglevel = get_loglevel_by_name(conf.loglevel_arg);
if (check_key_map_args() < 0) {
fprintf(stderr, "invalid key map in config file\n");
exit(EXIT_FAILURE);
initscr(); /* needed only once, always successful */
init_curses();
print_welcome();
- ret = mark_fd_nonblock(STDIN_FILENO);
- if (ret < 0) {
- PARA_EMERG_LOG("%s\n", PARA_STRERROR(-ret));
- exit(EXIT_FAILURE);
- }
for (;;) {
print_status_bar();
ret = do_select(GETCH_MODE);