FEC group size.
- aacdec error message cleanups
- simplified color error handling
+ - para_gui: New option --theme to select a startup theme. Several
+ other improvements and fixes.
--------------------------------------------
0.4.5 (2010-12-17) "symmetric randomization"
return -E_STSZ;
}
-static int atom_cmp(unsigned char *buf1, char *buf2)
+static int atom_cmp(const unsigned char *buf1, const char *buf2)
{
- unsigned char *b2 = (unsigned char *)buf2;
+ const unsigned char *b2 = (unsigned char *)buf2;
if (buf1[0] != b2[0])
return 1;
if (!pad) {
int32_t val;
- pad = para_calloc(sizeof(*pad));
- wn->private_data = pad;
if (bytes == 0) /* no data available */
return;
+ pad = para_calloc(sizeof(*pad));
get_btr_sample_rate(btrn, &val);
pad->sample_rate = val;
get_btr_channels(btrn, &val);
PARA_INFO_LOG("%d channel(s), %dHz\n", pad->channels,
pad->sample_rate);
ret = alsa_init(pad, wn->conf);
- if (ret < 0)
+ if (ret < 0) {
+ free(pad);
goto err;
+ }
+ wn->private_data = pad;
wn->min_iqs = pad->bytes_per_frame;
goto again;
}
ret = get_audio_format_num(arg);
if (ret < 0)
goto out;
+ /*
+ * If multiple receivers are given for this audio format, the
+ * last one wins and we have to free the previous receiver
+ * config here. Since we are iterating backwards, the winning
+ * receiver arg is in fact the first one given.
+ */
+ if (afi[ret].receiver_conf)
+ afi[ret].receiver->free_config(afi[ret].receiver_conf);
afi[ret].receiver_conf = check_receiver_arg(recv_arg, &receiver_num);
if (!afi[ret].receiver_conf) {
ret = -E_RECV_SYNTAX;
}
afi[ret].receiver = &receivers[receiver_num];
}
- /* use the first available receiver with no arguments
- * for those audio formats for which no receiver
- * was specified
+ /*
+ * Use the first available receiver with no arguments for those audio
+ * formats for which no receiver was specified.
*/
cmd = para_strdup(receivers[0].name);
FOR_EACH_AUDIO_FORMAT(i) {
AC_HEADER_DIRENT
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
+AC_HEADER_STDBOOL
AC_CHECK_HEADERS([arpa/inet.h ctype.h fcntl.h limits.h netdb.h netinet/in.h \
stdlib.h string.h sys/socket.h sys/time.h sys/timeb.h sys/un.h \
sys/ipc.h unistd.h utime.h stddef.h],
[], [AC_MSG_ERROR([$ac_header not found])])
-
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_INLINE
AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_STRUCT_TM
+AC_TYPE_INT8_T
AC_TYPE_INT16_T
AC_TYPE_INT32_T
AC_TYPE_INT64_T
AC_CHECK_FUNCS([atexit dup2 memchr memmove memset \
regcomp select strchr strdup strerror strstr strtol uname \
fchdir gettimeofday localtime_r munmap strcasecmp strcspn \
- strncasecmp strrchr strspn alarm mkdir rmdir], [],
+ strncasecmp strrchr strspn alarm mkdir inet_ntoa socket], [],
[AC_MSG_ERROR([function not found, cannot live without it])])
cmdline_dir="cmdline"
AC_DEFINE_UNQUOTED(SERVER_AUDIO_FORMATS, "$server_audio_formats",
[formats supported by para_server and para_afh])
-
AC_SUBST(executables, add_para($executables))
recv_objs="$recv_cmdline_objs $recv_errlist_objs"
LC_ALL=C gcc -MM -MG "$@" \
| sed -e "s@^\(.*\)\.o:@$object_dir/\1.d $object_dir/\1.o:@" \
- -e "s@[ ^]\([a-zA-Z0-9_]\+\.cmdline.h\)@ $cmdline_dir/\1@g"
+ -e "s@[ ^]\([a-zA-Z0-9_]\{1,\}\.cmdline.h\)@ $cmdline_dir/\1@g"
* \sa getcwd(3).
*
*/
-int para_opendir(const char *dirname, DIR **dir, int *cwd)
+static int para_opendir(const char *dirname, DIR **dir, int *cwd)
{
int ret;
*
* \return Standard.
*/
-int para_fchdir(int fd)
+static int para_fchdir(int fd)
{
if (fchdir(fd) < 0)
return -ERRNO_TO_PARA_ERROR(errno);
int para_mmap(size_t length, int prot, int flags, int fd, off_t offset,
void *map);
int para_open(const char *path, int flags, mode_t mode);
-int para_opendir(const char *dirname, DIR **dir, int *cwd);
int para_mkdir(const char *path, mode_t mode);
-int para_fchdir(int fd);
int para_chdir(const char *path);
int mmap_full_file(const char *filename, int open_mode, void **map,
size_t *size, int *fd_ptr);
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>
--func-name $(subst _write.ggo,,$(<F))_cmdline_parser < $<
define ggo-opts
+$(if $(filter gui,$(*F)), --no-handle-error) \
$(if $(filter recv filter write audiod,$(*F)), --no-handle-help) \
$(if $(filter afh,$(*F)), --unamed-opts=audio_file) \
$(if $(filter client audioc,$(*F)), --unamed-opts=command) \
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 */
struct stat_item_data data[NUM_STAT_ITEMS];
};
-void init_theme(int i, struct gui_theme *);
+void init_theme_or_die(const char *name, struct gui_theme *t);
void next_theme(struct gui_theme *);
void prev_theme(struct gui_theme *);
#define LEFT 1
* 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;
+
+static 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;
+}
- return (num % NUM_THEMES)?
- init_theme_simple(t) : init_theme_colorful_blackness(t);
+void init_theme_or_die(const char *name, struct gui_theme *t)
+{
+ int i;
+
+ 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);
}
-
struct oss_write_args_info *conf = wn->conf;
struct private_oss_write_data *powd = para_calloc(sizeof(*powd));
- wn->private_data = powd;
PARA_INFO_LOG("opening %s\n", conf->device_arg);
ret = para_open(conf->device_arg, O_WRONLY, 0);
if (ret < 0)
sample_rate);
}
wn->min_iqs = powd->bytes_per_frame;
+ wn->private_data = powd;
return 1;
err:
close(powd->fd);
<tr>
<td>
<a title="paraslash homepage" href="/">
- <img src="@web_root@/paraslash.png" alt="paraslash"
- border="0">
- </img>
+ <img src="@web_root@/paraslash.png" alt="paraslash"/>
</a>
</td>
<td>
</td>
</tr>
<tr>
- <td valign="TOP">
+ <td valign="top">
<a href="@web_root@/index.html">Home</a><br></br>
<a href="@web_root@/NEWS.html">News</a><br></br>
<a href="@web_root@/FEATURES.html">Features</a><br></br>
<a href="@web_root@/download.html">Download</a><br></br>
<a href="@web_root@/screenshots.html">Screenshots</a><br></br>
- <a href="/gitweb/gitweb.cgi?p=.git;a=shortlog">Changes</a><br></br>
+ <a href="/gitweb/gitweb.cgi?p=.git;a=summary">Changes</a><br></br>
<a href="@web_root@/documentation.html">Documentation</a><br></br>
<a href="@web_root@/license.html">License</a><br></br>
<a href="@web_root@/contact.html">Contact</a><br></br>
<a href="@web_root@/CREDITS.html">Credits</a><br></br>
</td>
- <td Valign="TOP">
+ <td valign="top">
<br><a href="FEATURES.html">Features</a>
<br><a href="download.html">Download</a>
<br><a href="screenshots.html">Screenshots</a>
- <br><a href="/gitweb/gitweb.cgi?p=.git;a=shortlog">Changes</a>
+ <br><a href="/gitweb/gitweb.cgi?p=.git;a=summary">Changes</a>
<br><a href="documentation.html">Documentation</a>
<br><a href="license.html">License</a>
<br><a href="contact.html">Contact</a>
<br><a href="../../FEATURES.html">Features</a>
<br><a href="../../download.html">Download</a>
<br><a href="../../screenshots.html">Screenshots</a>
- <br><a href="../../gitweb/gitweb.cgi?p=.git;a=shortlog">Changes</a>
+ <br><a href="../../gitweb/gitweb.cgi?p=.git;a=summary">Changes</a>
<br><a href="../../documentation.html">Documentation</a>
<br><a href="../../license.html">License</a>
<br><a href="../../contact.html">Contact</a>
w->close(wn);
btr_free_node(wn->btrn);
+ w->free_config(wn->conf);
free(wn->conf);
}
free(wns);