diff options
author | Max Kellermann <max@duempel.org> | 2008-09-18 01:49:53 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2008-09-18 01:49:53 +0200 |
commit | f0aa88e5c18de0b1e4f5d85dd5c3ae5d9be76bc3 (patch) | |
tree | ead2fd90d2a19b39c5e1a7a0942df9be77c02831 | |
parent | e54533bd1fad95b149e87918dffca06b0afb5074 (diff) | |
download | mpd-f0aa88e5c18de0b1e4f5d85dd5c3ae5d9be76bc3.tar.gz mpd-f0aa88e5c18de0b1e4f5d85dd5c3ae5d9be76bc3.tar.xz mpd-f0aa88e5c18de0b1e4f5d85dd5c3ae5d9be76bc3.zip |
use the glib main event loop
This big patch replaces our custom main loop with the event based glib
main loop. This has several advantages: we can make all the tiny code
bits in the main loop independent from each others, we can add
additional file descriptors for polling (e.g. the mpdclient socket).
We don't need the ncurses timeout() anymore, because glib will poll
stdin for us.
-rw-r--r-- | src/command.c | 16 | ||||
-rw-r--r-- | src/command.h | 1 | ||||
-rw-r--r-- | src/main.c | 226 | ||||
-rw-r--r-- | src/screen.c | 2 | ||||
-rw-r--r-- | src/screen_utils.c | 2 |
5 files changed, 157 insertions, 90 deletions
diff --git a/src/command.c b/src/command.c index 881df278a..151d46535 100644 --- a/src/command.c +++ b/src/command.c @@ -30,6 +30,7 @@ #include <ctype.h> #include <glib.h> #include <signal.h> +#include <unistd.h> #undef DEBUG_KEYS @@ -420,23 +421,18 @@ my_wgetch(WINDOW *w) sigstop(); /* handle SIGINT (Ctrl-C) */ if (c == 3) - exit(EXIT_SUCCESS); + kill(getpid(), SIGTERM); #endif return c; } command_t -get_keyboard_command_with_timeout(int ms) +get_keyboard_command(void) { int key; - if (ms != SCREEN_TIMEOUT) - timeout(ms); key = my_wgetch(stdscr); - if (ms != SCREEN_TIMEOUT) - timeout(SCREEN_TIMEOUT); - if (key == ERR) return CMD_NONE; @@ -448,12 +444,6 @@ get_keyboard_command_with_timeout(int ms) return get_key_command(key); } -command_t -get_keyboard_command(void) -{ - return get_keyboard_command_with_timeout(SCREEN_TIMEOUT); -} - int assign_keys(command_t command, int keys[MAX_COMMAND_KEYS]) { diff --git a/src/command.h b/src/command.h index 9e3b8394b..4b20a592c 100644 --- a/src/command.h +++ b/src/command.h @@ -100,6 +100,5 @@ int assign_keys(command_t command, int keys[MAX_COMMAND_KEYS]); int my_wgetch(WINDOW *w); command_t get_keyboard_command(void); -command_t get_keyboard_command_with_timeout(int milliseconds); #endif diff --git a/src/main.c b/src/main.c index cbb4735b9..f29ce67fd 100644 --- a/src/main.c +++ b/src/main.c @@ -38,9 +38,12 @@ #define BUFSIZE 1024 +static const guint idle_interval = 500; + static mpdclient_t *mpd = NULL; static gboolean connected = FALSE; -static GTimer *timer = NULL; +static GMainLoop *main_loop; +static guint reconnect_source_id, idle_source_id, update_source_id; static const gchar * error_msg(const gchar *msg) @@ -119,16 +122,12 @@ exit_and_cleanup(void) g_free(options.list_format); g_free(options.status_format); g_free(options.scroll_sep); - - if (timer) - g_timer_destroy(timer); } static void catch_sigint(mpd_unused int sig) { - printf("\n%s\n", _("Exiting...")); - exit(EXIT_SUCCESS); + g_main_loop_quit(main_loop); } @@ -169,12 +168,144 @@ D(const char *format, ...) } #endif +static gboolean +timer_mpd_update(gpointer data); + +/** + * This timer is installed when the connection to the MPD server is + * broken. It tries to recover by reconnecting periodically. + */ +static gboolean +timer_reconnect(mpd_unused gpointer data) +{ + int ret; + + if (connected) + return FALSE; + + screen_status_printf(_("Connecting to %s... [Press %s to abort]"), + options.host, get_key_names(CMD_QUIT,0) ); + doupdate(); + + mpdclient_disconnect(mpd); + ret = mpdclient_connect(mpd, + options.host, options.port, + 1.5, + options.password); + if (ret != 0) { + /* try again in 5 seconds */ + g_timeout_add(5000, timer_reconnect, NULL); + return FALSE; + } + + /* quit if mpd is pre 0.11.0 - song id not supported by mpd */ + if (MPD_VERSION_LT(mpd, 0, 11, 0)) { + screen_status_printf(_("Error: MPD version %d.%d.%d is to old (0.11.0 needed).\n"), + mpd->connection->version[0], + mpd->connection->version[1], + mpd->connection->version[2]); + mpdclient_disconnect(mpd); + doupdate(); + + /* try again after 30 seconds */ + g_timeout_add(30000, timer_reconnect, NULL); + return FALSE; + } + + screen_status_printf(_("Connected to %s!"), options.host); + doupdate(); + + connected = TRUE; + + /* update immediately */ + g_timeout_add(1, timer_mpd_update, GINT_TO_POINTER(FALSE)); + + reconnect_source_id = 0; + return FALSE; + +} + +static gboolean +timer_mpd_update(gpointer data) +{ + if (connected) + mpdclient_update(mpd); + else if (reconnect_source_id == 0) + reconnect_source_id = g_timeout_add(1000, timer_reconnect, + NULL); + + if (options.enable_xterm_title) + update_xterm_title(); + + screen_update(mpd); + + return GPOINTER_TO_INT(data); +} + +/** + * This idle timer is invoked when the user hasn't typed a key for + * 500ms. It is used for delayed seeking. + */ +static gboolean +timer_idle(mpd_unused gpointer data) +{ + screen_idle(mpd); + return TRUE; +} + +static gboolean +keyboard_event(mpd_unused GIOChannel *source, + mpd_unused GIOCondition condition, mpd_unused gpointer data) +{ + command_t cmd; + + /* remove the idle timeout; add it later with fresh interval */ + g_source_remove(idle_source_id); + + if ((cmd=get_keyboard_command()) != CMD_NONE) { + screen_cmd(mpd, cmd); + + if (cmd == CMD_VOLUME_UP || cmd == CMD_VOLUME_DOWN) { + /* make sure we dont update the volume yet */ + g_source_remove(update_source_id); + update_source_id = g_timeout_add((guint)(MPD_UPDATE_TIME * 1000), + timer_mpd_update, + GINT_TO_POINTER(TRUE)); + } + } + + screen_update(mpd); + + idle_source_id = g_timeout_add(idle_interval, timer_idle, NULL); + return TRUE; +} + +/** + * Check the configured key bindings for errors, and display a status + * message every 10 seconds. + */ +static gboolean +timer_check_key_bindings(mpd_unused gpointer data) +{ + char buf[256]; + gboolean key_error; + + key_error = check_key_bindings(NULL, buf, sizeof(buf)); + if (!key_error) + /* no error: disable this timer for the rest of this + process */ + return FALSE; + + screen_status_printf("%s", buf); + doupdate(); + return TRUE; +} + int main(int argc, const char *argv[]) { struct sigaction act; const char *charset = NULL; - gboolean key_error; #ifdef HAVE_LOCALE_H /* time and date formatting */ @@ -206,7 +337,7 @@ main(int argc, const char *argv[]) read_configuration(&options); /* check key bindings */ - key_error = check_key_bindings(NULL, NULL, 0); + check_key_bindings(NULL, NULL, 0); /* parse command line options - 2 pass */ options_parse(argc, argv); @@ -261,73 +392,24 @@ main(int argc, const char *argv[]) /* initialize curses */ screen_init(mpd); - /* initialize timer */ - timer = g_timer_new(); + /* the main loop */ + main_loop = g_main_loop_new(NULL, FALSE); - while (1) { - static gdouble t = G_MAXDOUBLE; + /* watch out for keyboard input */ + g_io_add_watch(g_io_channel_unix_new(STDIN_FILENO), G_IO_IN, + keyboard_event, NULL); - if (key_error) { - char buf[BUFSIZE]; + /* attempt to connect */ + reconnect_source_id = g_timeout_add(1, timer_reconnect, NULL); - key_error=check_key_bindings(NULL, buf, BUFSIZE); - screen_status_printf("%s", buf); - } - - if (connected && (t >= MPD_UPDATE_TIME || mpd->need_update)) { - mpdclient_update(mpd); - g_timer_start(timer); - } + update_source_id = g_timeout_add((guint)(MPD_UPDATE_TIME * 1000), + timer_mpd_update, + GINT_TO_POINTER(TRUE)); + g_timeout_add(10000, timer_check_key_bindings, NULL); + idle_source_id = g_timeout_add(idle_interval, timer_idle, NULL); - if (connected) { - command_t cmd; - - screen_update(mpd); - if ((cmd=get_keyboard_command()) != CMD_NONE) { - screen_cmd(mpd, cmd); - if (cmd == CMD_VOLUME_UP || cmd == CMD_VOLUME_DOWN) - /* make shure we dont update the volume yet */ - g_timer_start(timer); - } else - screen_idle(mpd); - } else { - screen_status_printf(_("Connecting to %s... [Press %s to abort]"), - options.host, get_key_names(CMD_QUIT,0) ); - - /* - if (get_keyboard_command_with_timeout(MPD_RECONNECT_TIME) == CMD_QUIT) - exit(EXIT_SUCCESS); - */ - - if (mpdclient_connect(mpd, - options.host, options.port, - 1.5, - options.password) == 0) { - screen_status_printf(_("Connected to %s!"), options.host); - - /* quit if mpd is pre 0.11.0 - song id not supported by mpd */ - if (MPD_VERSION_LT(mpd, 0, 11, 0)) { - screen_status_printf(_("Error: MPD version %d.%d.%d is to old (0.11.0 needed).\n"), - mpd->connection->version[0], - mpd->connection->version[1], - mpd->connection->version[2]); - mpdclient_disconnect(mpd); - } else { - mpdclient_update(mpd); - if (!mpd->status) - screen_auth(mpd); - - connected = TRUE; - } - } - - doupdate(); - } - - if (options.enable_xterm_title) - update_xterm_title(); + g_main_loop_run(main_loop); + g_main_loop_unref(main_loop); - t = g_timer_elapsed(timer, NULL); - } - exit(EXIT_FAILURE); + exit_and_cleanup(); } diff --git a/src/screen.c b/src/screen.c index beddb95b8..479b1de5d 100644 --- a/src/screen.c +++ b/src/screen.c @@ -547,8 +547,6 @@ ncurses_init(void) curs_set(0); /* enable extra keys */ keypad(stdscr, TRUE); - /* return from getch() without blocking */ - timeout(SCREEN_TIMEOUT); /* initialize mouse support */ #ifdef HAVE_GETMOUSE if (options.enable_mouse) diff --git a/src/screen_utils.c b/src/screen_utils.c index 311c744af..21da92e1a 100644 --- a/src/screen_utils.c +++ b/src/screen_utils.c @@ -58,7 +58,6 @@ screen_getch(WINDOW *w, const char *prompt) echo(); curs_set(1); - timeout(-1); while( (key=my_wgetch(w)) == ERR ) ; @@ -71,7 +70,6 @@ screen_getch(WINDOW *w, const char *prompt) noecho(); curs_set(0); - timeout(SCREEN_TIMEOUT); return key; } |