X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fmain.c;h=a8fb3b36f654a93e4157c46baa594108dbf03153;hb=2fb89f607219e3893d76007e9920337f7676eb25;hp=e5afa359728fafaf8d3a3667ab7d56b8ff6c8b2f;hpb=ba6e36186aa8c6bd13d4162d6e16125b6616ace3;p=ncmpc.git diff --git a/src/main.c b/src/main.c index e5afa35..a8fb3b3 100644 --- a/src/main.c +++ b/src/main.c @@ -1,35 +1,39 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2009 The Music Player Daemon Project + * (c) 2004-2017 The Music Player Daemon Project * Project homepage: http://musicpd.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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ + */ #include "config.h" #include "ncmpc.h" #include "mpdclient.h" +#include "callbacks.h" #include "charset.h" #include "options.h" #include "command.h" #include "ncu.h" #include "screen.h" -#include "screen_utils.h" -#include "screen_message.h" +#include "screen_status.h" +#include "xterm_title.h" #include "strfsong.h" #include "i18n.h" #include "player_command.h" +#include "keyboard.h" +#include "lirc.h" +#include "signals.h" #ifndef NCMPC_MINI #include "conf.h" @@ -39,14 +43,11 @@ #include "lyrics.h" #endif -#ifdef ENABLE_LIRC -#include "lirc.h" -#endif - #include #include #include +#include #include #include @@ -54,7 +55,7 @@ #include #endif -/* time between mpd updates [s] */ +/* time between mpd updates [ms] */ static const guint update_interval = 500; #define BUFSIZE 1024 @@ -71,90 +72,26 @@ static guint check_key_bindings_source_id; static void update_xterm_title(void) { - static char title[BUFSIZE]; - char tmp[BUFSIZE]; - struct mpd_status *status = NULL; - const struct mpd_song *song = NULL; + const struct mpd_song *song = mpd->song; - if (mpd) { - status = mpd->status; - song = mpd->song; - } + char tmp[BUFSIZE]; + const char *new_title = NULL; + if (options.xterm_title_format && mpd->playing && song) + new_title = strfsong(tmp, BUFSIZE, options.xterm_title_format, song) > 0 + ? tmp + : NULL; - if (options.xterm_title_format && status && song && - mpd_status_get_state(status) == MPD_STATE_PLAY) - strfsong(tmp, BUFSIZE, options.xterm_title_format, song); - else - g_strlcpy(tmp, PACKAGE " version " VERSION, BUFSIZE); + if (new_title == NULL) + new_title = PACKAGE " version " VERSION; - if (strncmp(title, tmp, BUFSIZE)) { - g_strlcpy(title, tmp, BUFSIZE); - set_xterm_title("%s", title); + static char title[BUFSIZE]; + if (strncmp(title, new_title, BUFSIZE)) { + g_strlcpy(title, new_title, BUFSIZE); + set_xterm_title(title); } } #endif -static void -exit_and_cleanup(void) -{ - screen_exit(); -#ifndef NCMPC_MINI - set_xterm_title(""); -#endif - printf("\n"); - - if (mpd) { - mpdclient_disconnect(mpd); - mpdclient_free(mpd); - } -} - -static void -catch_sigint(G_GNUC_UNUSED int sig) -{ - g_main_loop_quit(main_loop); -} - - -static void -catch_sigcont(G_GNUC_UNUSED int sig) -{ - screen_resize(mpd); -} - -void -sigstop(void) -{ - def_prog_mode(); /* save the tty modes */ - endwin(); /* end curses mode temporarily */ - kill(0, SIGSTOP); /* issue SIGSTOP */ -} - -static guint timer_sigwinch_id; - -static gboolean -timer_sigwinch(G_GNUC_UNUSED gpointer data) -{ - /* the following causes the screen to flicker. There might be - better solutions, but I believe it isn't all that - important. */ - - endwin(); - refresh(); - screen_resize(mpd); - - return FALSE; -} - -static void -catch_sigwinch(G_GNUC_UNUSED int sig) -{ - if (timer_sigwinch_id != 0) - g_source_remove(timer_sigwinch_id); - - timer_sigwinch_id = g_timeout_add(100, timer_sigwinch, NULL); -} - static gboolean timer_mpd_update(gpointer data); @@ -181,11 +118,7 @@ disable_update_timer(void) static bool should_enable_update_timer(void) { - return mpdclient_is_connected(mpd) -#ifndef NCMPC_MINI - || options.display_time -#endif - ; + return mpd->playing; } static void @@ -197,13 +130,11 @@ auto_update_timer(void) disable_update_timer(); } -static void -check_reconnect(void); - static void do_mpd_update(void) { - if (mpdclient_is_connected(mpd)) + if (mpdclient_is_connected(mpd) && + (mpd->events != 0 || mpd->playing)) mpdclient_update(mpd); #ifndef NCMPC_MINI @@ -213,9 +144,38 @@ do_mpd_update(void) screen_update(mpd); mpd->events = 0; +} + +static char * +settings_name(const struct mpd_settings *settings) +{ + const char *host = mpd_settings_get_host(settings); + if (host == NULL) + host = _("unknown"); + + if (host[0] == '/') + return g_strdup(host); + + unsigned port = mpd_settings_get_port(settings); + if (port == 0 || port == 6600) + return g_strdup(host); + + return g_strdup_printf("%s:%u", host, port); +} + +static char * +default_settings_name(void) +{ + struct mpd_settings *settings = + mpd_settings_new(options.host, options.port, 0, + NULL, options.password); + if (settings == NULL) + return g_strdup(_("unknown")); + + char *name = settings_name(settings); + mpd_settings_free(settings); - mpdclient_put_connection(mpd); - check_reconnect(); + return name; } /** @@ -223,79 +183,96 @@ do_mpd_update(void) * broken. It tries to recover by reconnecting periodically. */ static gboolean -timer_reconnect(G_GNUC_UNUSED gpointer data) +timer_reconnect(gcc_unused gpointer data) { - bool success; - struct mpd_connection *connection; - - assert(!mpdclient_is_connected(mpd)); + assert(mpdclient_is_dead(mpd)); reconnect_source_id = 0; + char *name = default_settings_name(); screen_status_printf(_("Connecting to %s... [Press %s to abort]"), - options.host, get_key_names(CMD_QUIT,0) ); + name, get_key_names(CMD_QUIT, false)); + g_free(name); doupdate(); - mpdclient_disconnect(mpd); - success = mpdclient_connect(mpd, - options.host, options.port, - 1.5, - options.password); - if (!success) { - /* try again in 5 seconds */ - reconnect_source_id = g_timeout_add(5000, - timer_reconnect, NULL); - return FALSE; - } + mpdclient_connect(mpd); + + return FALSE; +} - connection = mpdclient_get_connection(mpd); +void +mpdclient_connected_callback(void) +{ + assert(reconnect_source_id == 0); #ifndef NCMPC_MINI - /* quit if mpd is pre 0.11.0 - song id not supported by mpd */ - if (mpd_connection_cmp_server_version(connection, 0, 12, 0) < 0) { + /* quit if mpd is pre 0.14 - song id not supported by mpd */ + struct mpd_connection *connection = mpdclient_get_connection(mpd); + if (mpd_connection_cmp_server_version(connection, 0, 16, 0) < 0) { const unsigned *version = mpd_connection_get_server_version(connection); - screen_status_printf(_("Error: MPD version %d.%d.%d is to old (%s needed)"), + screen_status_printf(_("Error: MPD version %d.%d.%d is too old (%s needed)"), version[0], version[1], version[2], - "0.12.0"); + "0.16.0"); mpdclient_disconnect(mpd); doupdate(); /* try again after 30 seconds */ reconnect_source_id = g_timeout_add(30000, timer_reconnect, NULL); - return FALSE; + return; } #endif - screen_status_printf(_("Connected to %s"), - options.host != NULL - ? options.host : "localhost"); + screen_status_clear_message(); doupdate(); /* update immediately */ - mpd->events = MPD_IDLE_DATABASE|MPD_IDLE_STORED_PLAYLIST| - MPD_IDLE_QUEUE|MPD_IDLE_PLAYER|MPD_IDLE_MIXER|MPD_IDLE_OUTPUT| - MPD_IDLE_OPTIONS|MPD_IDLE_UPDATE; + mpd->events = MPD_IDLE_ALL; do_mpd_update(); auto_update_timer(); +} - return FALSE; +void +mpdclient_failed_callback(void) +{ + assert(reconnect_source_id == 0); + + /* try again in 5 seconds */ + reconnect_source_id = g_timeout_add(5000, + timer_reconnect, NULL); } -static void -check_reconnect(void) +void +mpdclient_lost_callback(void) +{ + assert(reconnect_source_id == 0); + + screen_update(mpd); + + reconnect_source_id = g_timeout_add(1000, timer_reconnect, NULL); +} + +/** + * This function is called by the gidle.c library when MPD sends us an + * idle event (or when the connection dies). + */ +void +mpdclient_idle_callback(gcc_unused enum mpd_idle events) { - if (!mpdclient_is_connected(mpd) && reconnect_source_id == 0) - /* reconnect when the connection is lost */ - reconnect_source_id = g_timeout_add(1000, timer_reconnect, - NULL); +#ifndef NCMPC_MINI + if (options.enable_xterm_title) + update_xterm_title(); +#endif + + screen_update(mpd); + auto_update_timer(); } static gboolean -timer_mpd_update(G_GNUC_UNUSED gpointer data) +timer_mpd_update(gcc_unused gpointer data) { do_mpd_update(); @@ -316,16 +293,15 @@ void end_input_event(void) screen_update(mpd); mpd->events = 0; - mpdclient_put_connection(mpd); - check_reconnect(); auto_update_timer(); } -int do_input_event(command_t cmd) +bool +do_input_event(command_t cmd) { if (cmd == CMD_QUIT) { g_main_loop_quit(main_loop); - return -1; + return false; } screen_cmd(mpd, cmd); @@ -334,24 +310,7 @@ int do_input_event(command_t cmd) /* make sure we don't update the volume yet */ disable_update_timer(); - return 0; -} - -static gboolean -keyboard_event(G_GNUC_UNUSED GIOChannel *source, - G_GNUC_UNUSED GIOCondition condition, - G_GNUC_UNUSED gpointer data) -{ - command_t cmd; - - begin_input_event(); - - if ((cmd=get_keyboard_command()) != CMD_NONE) - if (do_input_event(cmd) != 0) - return FALSE; - - end_input_event(); - return TRUE; + return true; } #ifndef NCMPC_MINI @@ -360,16 +319,11 @@ keyboard_event(G_GNUC_UNUSED GIOChannel *source, * message every 10 seconds. */ static gboolean -timer_check_key_bindings(G_GNUC_UNUSED gpointer data) +timer_check_key_bindings(gcc_unused gpointer data) { char buf[256]; -#ifdef ENABLE_KEYDEF_SCREEN - char comment[64]; -#endif - gboolean key_error; - key_error = check_key_bindings(NULL, buf, sizeof(buf)); - if (!key_error) { + if (check_key_bindings(NULL, buf, sizeof(buf))) { /* no error: disable this timer for the rest of this process */ check_key_bindings_source_id = 0; @@ -382,8 +336,9 @@ timer_check_key_bindings(G_GNUC_UNUSED gpointer data) /* to translators: a key was bound twice in the key editor, and this is a hint for the user what to press to correct that */ + char comment[64]; g_snprintf(comment, sizeof(comment), _("press %s for the key editor"), - get_key_names(CMD_SCREEN_KEYDEF, 0)); + get_key_names(CMD_SCREEN_KEYDEF, false)); g_strlcat(buf, comment, sizeof(buf)); g_strlcat(buf, ")", sizeof(buf)); #endif @@ -398,17 +353,11 @@ timer_check_key_bindings(G_GNUC_UNUSED gpointer data) int main(int argc, const char *argv[]) { - struct sigaction act; #ifdef ENABLE_LOCALE - const char *charset = NULL; -#endif - GIOChannel *keyboard_channel; -#ifdef ENABLE_LIRC - int lirc_socket; - GIOChannel *lirc_channel = NULL; +#ifndef ENABLE_NLS + gcc_unused #endif - -#ifdef ENABLE_LOCALE + const char *charset = NULL; /* time and date formatting */ setlocale(LC_TIME,""); /* care about sorting order etc */ @@ -447,56 +396,6 @@ main(int argc, const char *argv[]) /* parse command line options - 2 pass */ options_parse(argc, argv); - /* setup signal behavior - SIGINT */ - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = catch_sigint; - if (sigaction(SIGINT, &act, NULL) < 0) { - perror("signal"); - exit(EXIT_FAILURE); - } - - /* setup signal behavior - SIGTERM */ - - act.sa_handler = catch_sigint; - if (sigaction(SIGTERM, &act, NULL) < 0) { - perror("sigaction()"); - exit(EXIT_FAILURE); - } - - /* setup signal behavior - SIGCONT */ - - act.sa_handler = catch_sigcont; - if (sigaction(SIGCONT, &act, NULL) < 0) { - perror("sigaction(SIGCONT)"); - exit(EXIT_FAILURE); - } - - /* setup signal behaviour - SIGHUP*/ - - act.sa_handler = catch_sigint; - if (sigaction(SIGHUP, &act, NULL) < 0) { - perror("sigaction(SIGHUP)"); - exit(EXIT_FAILURE); - } - - /* setup SIGWINCH */ - - act.sa_flags = SA_RESTART; - act.sa_handler = catch_sigwinch; - if (sigaction(SIGWINCH, &act, NULL) < 0) { - perror("sigaction(SIGWINCH)"); - exit(EXIT_FAILURE); - } - - /* ignore SIGPIPE */ - - act.sa_handler = SIG_IGN; - if (sigaction(SIGPIPE, &act, NULL) < 0) { - perror("sigaction(SIGPIPE)"); - exit(EXIT_FAILURE); - } - ncu_init(); #ifdef ENABLE_LYRICS_SCREEN @@ -504,7 +403,9 @@ main(int argc, const char *argv[]) #endif /* create mpdclient instance */ - mpd = mpdclient_new(); + mpd = mpdclient_new(options.host, options.port, + options.timeout_ms, + options.password); /* initialize curses */ screen_init(mpd); @@ -513,20 +414,15 @@ main(int argc, const char *argv[]) main_loop = g_main_loop_new(NULL, FALSE); /* watch out for keyboard input */ - keyboard_channel = g_io_channel_unix_new(STDIN_FILENO); - g_io_add_watch(keyboard_channel, G_IO_IN, keyboard_event, NULL); + keyboard_init(); -#ifdef ENABLE_LIRC /* watch out for lirc input */ - lirc_socket = ncmpc_lirc_open(); - if (lirc_socket >= 0) { - lirc_channel = g_io_channel_unix_new(lirc_socket); - g_io_add_watch(lirc_channel, G_IO_IN, lirc_event, NULL); - } -#endif + ncmpc_lirc_init(); + + signals_init(main_loop, mpd); /* attempt to connect */ - reconnect_source_id = g_timeout_add(1, timer_reconnect, NULL); + reconnect_source_id = g_idle_add(timer_reconnect, NULL); auto_update_timer(); @@ -537,6 +433,7 @@ main(int argc, const char *argv[]) screen_paint(mpd); g_main_loop_run(main_loop); + g_main_loop_unref(main_loop); /* cleanup */ @@ -552,16 +449,16 @@ main(int argc, const char *argv[]) g_source_remove(check_key_bindings_source_id); #endif - g_main_loop_unref(main_loop); - g_io_channel_unref(keyboard_channel); + signals_deinit(); + ncmpc_lirc_deinit(); -#ifdef ENABLE_LIRC - if (lirc_socket >= 0) - g_io_channel_unref(lirc_channel); - ncmpc_lirc_close(); + screen_exit(); +#ifndef NCMPC_MINI + set_xterm_title(""); #endif + printf("\n"); - exit_and_cleanup(); + mpdclient_free(mpd); #ifdef ENABLE_LYRICS_SCREEN lyrics_deinit();