include(header.m4)
define(CURRENT_PROGRAM,para_gui)
+define(DEFAULT_CONFIG_FILE,~/.paraslash/gui.conf)
<qu>
#########################
-section "general options"
+section "General options"
#########################
</qu>
option "timeout" t
#~~~~~~~~~~~~~~~~~
"set timeout"
+int typestr = "milliseconds"
+default = "30"
+optional
- int typestr="milliseconds"
- default="30"
- optional
+option "theme" T
+#~~~~~~~~~~~~~~~
+"select startup theme"
+string typestr = "name"
+optional
+details = "
+ If this option is not given the default theme is used.
+ If the given name is not a valid theme name, the list of
+ available themes is printed and the program terminates.
+"
option "stat_cmd" s
#~~~~~~~~~~~~~~~~~~
-"command to read server and audiod status
-data from"
+"command to read status items from"
+string typestr = "command"
+default = "para_audioc -- stat -p"
+optional
+details = "
+ In order to run para_gui on a host on which no para_audiod
+ is running (hence the default command does not work), the
+ command
- string typestr="command"
- default="para_audioc -- stat -p"
- optional
+ para_client -- stat -p
+
+ may be used. This command prints less information though.
+ In particular, no timing information about the current audio
+ file is printed.
+"
#---------------------------------
-section "mapping keys to commands"
+section "Mapping keys to commands"
#---------------------------------
option "key_map" k
#~~~~~~~~~~~~~~~~~
+"Map key k to command c using mode m."
-"Map key k to command c using mode m. Mode
-may be d, x or p for display, external and
-paraslash commands, respectively. Of course,
-this option may be given multiple times, one
-for each key mapping."
-
- string typestr="k:m:c"
- optional
- multiple
+string typestr = "k:m:c"
+optional
+multiple
+details = "
+ Mode may be d, x or p for display, external and paraslash
+ commands, respectively. Of course, this option may be given
+ multiple times, one for each key mapping.
+"
</qu>
static void com_scroll_down(void);
static void com_page_up(void);
static void com_page_down(void);
+static void com_cancel_scrolling(void);
+static void com_scroll_top(void);
static struct gui_command command_list[] = {
{
.name = "page_down",
.description = "scroll down one page",
.handler = com_page_down
+ }, {
+ .key = "<home>",
+ .name = "scroll_top",
+ .description = "scroll to top of buffer",
+ .handler = com_scroll_top
+ }, {
+ .key = "<end>",
+ .name = "cancel_scroll",
+ .description = "deactivate scroll mode",
+ .handler = com_cancel_scrolling
}, {
.handler = NULL
}
sprintf(buf, "<ppage>");
return buf;
}
+ if (c == KEY_HOME) {
+ sprintf(buf, "<home>");
+ return buf;
+ }
+ if (c == KEY_END) {
+ sprintf(buf, "<end>");
+ return buf;
+ }
if (c < 256 && c > -128 && iscntrl((unsigned char) c)) {
if (c < 0)
c += 256;
doupdate();
}
-static void check_geometry(void)
-{
- if (LINES < theme.lines_min || COLS < theme.cols_min)
- msg_n_exit(EXIT_FAILURE, "Error: Terminal (%dx%d) too small"
- " (need at least %dx%d)\n", COLS, LINES,
- theme.cols_min, theme.lines_min);
-}
-
/*
* Print stat item #i to curses window
*/
}
}
-static void init_colors(void)
+static void init_pair_or_die(short pair, short f, short b)
+{
+ if (init_pair(pair, f, b) == ERR)
+ msg_n_exit(EXIT_FAILURE, "fatal: init_pair() failed\n");
+}
+
+static void init_colors_or_die(void)
{
int i;
if (!has_colors())
- msg_n_exit(EXIT_FAILURE, "Error: No color term\n");
- start_color();
+ msg_n_exit(EXIT_FAILURE, "fatal: No color term\n");
+ if (start_color() == ERR)
+ msg_n_exit(EXIT_FAILURE, "fatal: failed to start colors\n");
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);
- init_pair(COLOR_COMMAND, theme.cmd_fg, theme.cmd_bg);
- init_pair(COLOR_OUTPUT, theme.output_fg, theme.output_bg);
- init_pair(COLOR_MSG, theme.msg_fg, theme.msg_bg);
- init_pair(COLOR_ERRMSG, theme.err_msg_fg, theme.err_msg_bg);
- init_pair(COLOR_WELCOME, theme.welcome_fg, theme.welcome_bg);
- init_pair(COLOR_SEPARATOR, theme.sep_fg, theme.sep_bg);
- init_pair(COLOR_TOP, theme.default_fg, theme.default_bg);
- init_pair(COLOR_BOT, theme.default_fg, theme.default_bg);
+ 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_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 FIXME: Error checking
- */
+/* (Re-)initialize the curses library. */
static void init_curses(void)
{
curses_active = 1;
- if (top.win && refresh() == ERR) { /* refesh is really needed */
+ if (top.win && refresh() == ERR) /* refesh is really needed */
msg_n_exit(EXIT_FAILURE, "refresh() failed\n");
- }
- check_geometry();
+ if (LINES < theme.lines_min || COLS < theme.cols_min)
+ msg_n_exit(EXIT_FAILURE, "Error: Terminal (%dx%d) too small"
+ " (need at least %dx%d)\n", COLS, LINES,
+ theme.cols_min, theme.lines_min);
curs_set(0); /* make cursor invisible, ignore errors */
-// if (noraw() == ERR);
-// msg_n_exit(EXIT_FAILURE, "can not place terminal out of "
-// "raw mode\n");
- nonl(); /* tell curses not to do NL->CR/NL on output */
- noecho(); /* don't echo input */
- cbreak(); /* take input chars one at a time, no wait for \n */
- //reset_prog_mode();
- init_colors();
- clear();
+ nonl(); /* do not NL->CR/NL on output, always returns OK */
+ /* don't echo input */
+ if (noecho() == ERR)
+ msg_n_exit(EXIT_FAILURE, "fatal: noecho() failed\n");
+ /* take input chars one at a time, no wait for \n */
+ if (cbreak() == ERR)
+ msg_n_exit(EXIT_FAILURE, "fatal: cbreak() failed\n");
+ init_colors_or_die();
+ clear(); /* ignore non-fatal errors */
init_wins(theme.top_lines_default);
print_all_items();
- noecho(); /* don't echo input */
+ // noecho(); /* don't echo input */
}
-
static void check_sigchld(void)
{
int ret;
filled - scroll_position, ringbuffer_filled(bot_win_rb));
}
+static void com_scroll_top(void)
+{
+ int i = RINGBUFFER_SIZE - 1;
+ unsigned lines = 0;
+
+ while (i > 0 && !ringbuffer_get(bot_win_rb, i))
+ i--;
+ /* i is oldest entry */
+ for (; lines < bot.lines && i >= 0; i--) {
+ struct rb_entry *rbe = ringbuffer_get(bot_win_rb, i);
+ if (!rbe)
+ break;
+ lines += NUM_LINES(strlen(rbe->msg));
+ }
+ i++;
+ if (lines > 0 && scroll_position != i) {
+ scroll_position = i;
+ redraw_bot_win();
+ print_scroll_msg();
+ return;
+ }
+ print_in_bar(COLOR_ERRMSG, "top of buffer is shown\n");
+}
+
+static void com_cancel_scrolling(void)
+{
+
+ if (scroll_position == 0) {
+ print_in_bar(COLOR_ERRMSG, "bottom of buffer is shown\n");
+ return;
+ }
+ scroll_position = 0;
+ redraw_bot_win();
+}
+
static void com_page_down(void)
{
unsigned lines = 0;
.override = 1,
.initialize = 1,
.check_required = 0,
- .check_ambiguity = 0
+ .check_ambiguity = 0,
+ .print_errors = 0,
};
if (!cf) {
return;
}
PARA_INFO_LOG("rereading command line options and config file");
- gui_cmdline_parser(_argc, _argv, &conf);
- gui_cmdline_parser_config_file(cf, &conf, ¶ms);
+ gui_cmdline_parser_ext(_argc, _argv, &conf, ¶ms);
+ if (gui_cmdline_parser_config_file(cf, &conf, ¶ms) != 0) {
+ PARA_EMERG_LOG("errors in config file");
+ finish(EXIT_FAILURE);
+ }
PARA_NOTICE_LOG("config file reloaded");
if (check_key_map_args() < 0)
finish(EXIT_FAILURE);
_argc = argc;
_argv = argv;
- if (gui_cmdline_parser(argc, argv, &conf)) {
- fprintf(stderr, "parse error while reading command line\n");
+ if (gui_cmdline_parser(argc, argv, &conf) != 0)
exit(EXIT_FAILURE);
- }
HANDLE_VERSION_FLAG("gui", conf);
- init_theme(0, &theme);
- top.lines = theme.top_lines_default;
- if (check_key_map_args() < 0) {
- fprintf(stderr, "invalid key map\n");
- exit(EXIT_FAILURE);
- }
cf = configfile_exists();
if (!cf && conf.config_file_given) {
fprintf(stderr, "can not read config file %s\n",
.override = 0,
.initialize = 0,
.check_required = 0,
- .check_ambiguity = 0
+ .check_ambiguity = 0,
+ .print_errors = 1,
};
- gui_cmdline_parser_config_file(cf, &conf, ¶ms);
+ if (gui_cmdline_parser_config_file(cf, &conf, ¶ms) != 0)
+ exit(EXIT_FAILURE);
}
loglevel = get_loglevel_by_name(conf.loglevel_arg);
if (check_key_map_args() < 0) {
- fprintf(stderr, "invalid key map in config file\n");
+ fprintf(stderr, "invalid key map\n");
exit(EXIT_FAILURE);
}
+ init_theme_or_die(conf.theme_arg, &theme);
+ top.lines = theme.top_lines_default;
setup_signal_handling();
bot_win_rb = ringbuffer_new(RINGBUFFER_SIZE);
initscr(); /* needed only once, always successful */
* Licensed under the GPL v2. For licencing details see COPYING.
*/
+#include <stdbool.h>
#include "para.h"
#include "gui.h"
#include <curses.h>
-#define NUM_THEMES 2
-
-
-static int current_theme_num;
-
static void init_theme_simple(struct gui_theme *t)
{
struct stat_item_data *d = t->data;
- t->name = "simple";
t->author = "Andre Noll";
t->lines_min = 5;
t->top_lines_min = 2;
static void init_theme_colorful_blackness(struct gui_theme *t)
{
struct stat_item_data *d = t->data;
- t->name = "colorful blackness";
t->author = "Andre Noll";
/* minimal number of lines that is needed to display all
* information provided by this theme
d[SI_DIRECTORY].len = 100;
}
-void init_theme(int num, struct gui_theme *t)
+struct theme_description {
+ const char *name;
+ void (*init)(struct gui_theme *t);
+};
+
+struct theme_description themes[] = {
+ {
+ .name = "colorful blackness",
+ .init = init_theme_colorful_blackness,
+ },
+ {
+ .name = "simple",
+ .init = init_theme_simple,
+ },
+};
+
+#define NUM_THEMES (ARRAY_SIZE(themes))
+
+static int current_theme_num;
+
+void set_theme(int num, struct gui_theme *t)
{
int i;
FOR_EACH_STATUS_ITEM(i)
t->data[i].len = 0;
+ num %= NUM_THEMES;
+ t->name = themes[num].name;
+ themes[num].init(t);
current_theme_num = num;
+}
+
+void init_theme_or_die(const char *name, struct gui_theme *t)
+{
+ int i;
- return (num % NUM_THEMES)?
- init_theme_simple(t) : init_theme_colorful_blackness(t);
+ if (!name)
+ return set_theme(0, t);
+ for (i = 0; i < NUM_THEMES; i++)
+ if (strcmp(name, themes[i].name) == 0)
+ return set_theme(i, t);
+ fprintf(stderr, "Available themes:\n");
+ for (i = 0; i < NUM_THEMES; i++)
+ fprintf(stderr, "\t%s\n", themes[i].name);
+ exit(EXIT_FAILURE);
}
void prev_theme(struct gui_theme *t)
{
- return init_theme(++current_theme_num, t);
+ return set_theme(++current_theme_num, t);
}
void next_theme(struct gui_theme *t)
{
- return init_theme(--current_theme_num, t);
+ return set_theme(--current_theme_num, t);
}