From: Andre Noll Date: Sun, 20 Feb 2011 12:12:32 +0000 (+0100) Subject: Merge branch 't/gui_improvements' X-Git-Tag: v0.4.6~39 X-Git-Url: http://git.tuebingen.mpg.de/?a=commitdiff_plain;h=b4a05b0b792d1890be868b9763feb119064ff863;hp=540e19319a41ee5ed74565d40f9bf49867747b2c;p=paraslash.git Merge branch 't/gui_improvements' --- diff --git a/ggo/gui.m4 b/ggo/gui.m4 index 3f31dc1a..895229b2 100644 --- a/ggo/gui.m4 +++ b/ggo/gui.m4 @@ -1,9 +1,10 @@ include(header.m4) define(CURRENT_PROGRAM,para_gui) +define(DEFAULT_CONFIG_FILE,~/.paraslash/gui.conf) ######################### -section "general options" +section "General options" ######################### @@ -14,34 +15,53 @@ include(loglevel.m4) 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. +" diff --git a/ggo/makefile b/ggo/makefile index d4f3a8cd..d5a1d645 100644 --- a/ggo/makefile +++ b/ggo/makefile @@ -29,6 +29,7 @@ $(cmdline_dir)/%_write.cmdline.h $(cmdline_dir)/%_write.cmdline.c: $(ggo_dir)/%_ --func-name $(subst _write.ggo,,$("); return buf; } + if (c == KEY_HOME) { + sprintf(buf, ""); + return buf; + } + if (c == KEY_END) { + sprintf(buf, ""); + return buf; + } if (c < 256 && c > -128 && iscntrl((unsigned char) c)) { if (c < 0) c += 256; @@ -635,14 +655,6 @@ static void init_wins(int top_lines) 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 */ @@ -747,53 +759,60 @@ static void clear_all_items(void) } } -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; @@ -1097,6 +1116,41 @@ static void print_scroll_msg(void) 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; @@ -1228,7 +1282,8 @@ static void com_reread_conf(void) .override = 1, .initialize = 1, .check_required = 0, - .check_ambiguity = 0 + .check_ambiguity = 0, + .print_errors = 0, }; if (!cf) { @@ -1236,8 +1291,11 @@ static void com_reread_conf(void) 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); @@ -1394,17 +1452,9 @@ int main(int argc, char *argv[]) _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", @@ -1416,15 +1466,19 @@ int main(int argc, char *argv[]) .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 */ diff --git a/gui.h b/gui.h index f8c6712b..aad20488 100644 --- a/gui.h +++ b/gui.h @@ -30,7 +30,7 @@ struct gui_theme { 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 diff --git a/gui_theme.c b/gui_theme.c index ffb47d43..5976a0e7 100644 --- a/gui_theme.c +++ b/gui_theme.c @@ -4,19 +4,14 @@ * Licensed under the GPL v2. For licencing details see COPYING. */ +#include #include "para.h" #include "gui.h" #include -#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; @@ -72,7 +67,6 @@ static void init_theme_simple(struct gui_theme *t) 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 @@ -363,24 +357,59 @@ static void init_theme_colorful_blackness(struct gui_theme *t) 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); }