Code

main: use g_unix_signal_add() for SIGTERM, SIGINT and SIGHUP
[ncmpc.git] / src / main.c
index 76fe2354a4c0bc6f0b02c7e3de26948144d8853f..214478e39ded84a53a3ac96591888e7f96c0d19c 100644 (file)
@@ -20,7 +20,7 @@
 #include "config.h"
 #include "ncmpc.h"
 #include "mpdclient.h"
-#include "gidle.h"
+#include "callbacks.h"
 #include "charset.h"
 #include "options.h"
 #include "command.h"
@@ -31,6 +31,8 @@
 #include "strfsong.h"
 #include "i18n.h"
 #include "player_command.h"
+#include "keyboard.h"
+#include "lirc.h"
 
 #ifndef NCMPC_MINI
 #include "conf.h"
 #include "lyrics.h"
 #endif
 
-#ifdef ENABLE_LIRC
-#include "lirc.h"
-#endif
-
 #include <mpd/client.h>
 
+#ifndef WIN32
+#include <glib-unix.h>
+#endif
+
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -74,16 +76,10 @@ static guint check_key_bindings_source_id;
 static void
 update_xterm_title(void)
 {
-       struct mpd_status *status = NULL;
-       const struct mpd_song *song = NULL;
-       if (mpd) {
-               status = mpd->status;
-               song = mpd->song;
-       }
+       const struct mpd_song *song = mpd->song;
 
        char tmp[BUFSIZE];
-       if (options.xterm_title_format && status && song &&
-           mpd_status_get_state(status) == MPD_STATE_PLAY)
+       if (options.xterm_title_format && mpd->playing && song)
                strfsong(tmp, BUFSIZE, options.xterm_title_format, song);
        else
                g_strlcpy(tmp, PACKAGE " version " VERSION, BUFSIZE);
@@ -96,43 +92,12 @@ update_xterm_title(void)
 }
 #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);
-       }
-}
-
 #ifndef WIN32
-static void
-catch_sigint(gcc_unused int sig)
+static gboolean
+handle_quit_signal(gcc_unused gpointer data)
 {
        g_main_loop_quit(main_loop);
-}
-
-
-static void
-catch_sigcont(gcc_unused int sig)
-{
-       char irrelevant = 'a';
-       if (1 != write(sigwinch_pipes[1], &irrelevant, 1))
-               exit(EXIT_FAILURE);
-}
-
-void
-sigstop(void)
-{
-       def_prog_mode();  /* save the tty modes */
-       endwin();         /* end curses mode temporarily */
-       kill(0, SIGSTOP); /* issue SIGSTOP */
+       return false;
 }
 
 static gboolean
@@ -158,12 +123,6 @@ catch_sigwinch(gcc_unused int sig)
 }
 #endif /* WIN32 */
 
-static void
-idle_callback(enum mpd_error error,
-             gcc_unused enum mpd_server_error server_error,
-             const char *message, enum mpd_idle events,
-             gcc_unused void *ctx);
-
 static gboolean
 timer_mpd_update(gpointer data);
 
@@ -190,10 +149,7 @@ disable_update_timer(void)
 static bool
 should_enable_update_timer(void)
 {
-       return (mpdclient_is_connected(mpd) &&
-               (mpd->source == NULL || /* "idle" not supported */
-                (mpd->status != NULL &&
-                 mpd_status_get_state(mpd->status) == MPD_STATE_PLAY)))
+       return mpd->playing
 #ifndef NCMPC_MINI
                || options.display_time
 #endif
@@ -216,9 +172,7 @@ static void
 do_mpd_update(void)
 {
        if (mpdclient_is_connected(mpd) &&
-           (mpd->source == NULL || mpd->events != 0 ||
-            (mpd->status != NULL &&
-             mpd_status_get_state(mpd->status) == MPD_STATE_PLAY)))
+           (mpd->events != 0 || mpd->playing))
                mpdclient_update(mpd);
 
 #ifndef NCMPC_MINI
@@ -272,7 +226,7 @@ default_settings_name(void)
 static gboolean
 timer_reconnect(gcc_unused gpointer data)
 {
-       assert(!mpdclient_is_connected(mpd));
+       assert(mpdclient_is_dead(mpd));
 
        reconnect_source_id = 0;
 
@@ -283,19 +237,30 @@ timer_reconnect(gcc_unused gpointer data)
        doupdate();
 
        mpdclient_disconnect(mpd);
-       if (!mpdclient_connect(mpd, options.host, options.port,
-                              options.timeout_ms,
-                              options.password)) {
-               /* try again in 5 seconds */
-               reconnect_source_id = g_timeout_add(5000,
-                                                   timer_reconnect, NULL);
-               return FALSE;
-       }
+       mpdclient_connect(mpd, options.host, options.port,
+                         options.timeout_ms,
+                         options.password);
 
-       struct mpd_connection *connection = mpdclient_get_connection(mpd);
+       return FALSE;
+}
+
+static void
+check_reconnect(void)
+{
+       if (mpdclient_is_dead(mpd) && reconnect_source_id == 0)
+               /* reconnect when the connection is lost */
+               reconnect_source_id = g_timeout_add(1000, timer_reconnect,
+                                                   NULL);
+}
+
+void
+mpdclient_connected_callback(void)
+{
+       assert(reconnect_source_id == 0);
 
 #ifndef NCMPC_MINI
        /* 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);
@@ -308,13 +273,10 @@ timer_reconnect(gcc_unused gpointer data)
                /* try again after 30 seconds */
                reconnect_source_id = g_timeout_add(30000,
                                                    timer_reconnect, NULL);
-               return FALSE;
+               return;
        }
 #endif
 
-       mpd->source = mpd_glib_new(connection,
-                                  idle_callback, mpd);
-
        screen_status_clear_message();
        doupdate();
 
@@ -324,75 +286,41 @@ timer_reconnect(gcc_unused gpointer data)
        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)
 {
-       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);
+       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).
  */
-static void
-idle_callback(enum mpd_error error, enum mpd_server_error server_error,
-             const char *message, enum mpd_idle events,
-             void *ctx)
+void
+mpdclient_idle_callback(gcc_unused enum mpd_idle events)
 {
-       struct mpdclient *c = ctx;
-
-       c->idle = false;
-
-       assert(mpdclient_is_connected(c));
-
-       if (error != MPD_ERROR_SUCCESS) {
-               if (error == MPD_ERROR_SERVER &&
-                   server_error == MPD_SERVER_ERROR_UNKNOWN_CMD) {
-                       /* the "idle" command is not supported - fall
-                          back to timer based polling */
-                       mpd_glib_free(c->source);
-                       c->source = NULL;
-                       auto_update_timer();
-                       return;
-               }
-
-               char *allocated;
-               if (error == MPD_ERROR_SERVER)
-                       message = allocated = utf8_to_locale(message);
-               else
-                       allocated = NULL;
-               screen_status_message(message);
-               g_free(allocated);
-               screen_bell();
-               doupdate();
-
-               mpdclient_disconnect(c);
-               screen_update(mpd);
-               reconnect_source_id = g_timeout_add(1000, timer_reconnect,
-                                                   NULL);
-               return;
-       }
-
-       c->events |= events;
-       mpdclient_update(c);
-
 #ifndef NCMPC_MINI
        if (options.enable_xterm_title)
                update_xterm_title();
 #endif
 
        screen_update(mpd);
-       c->events = 0;
-
-       mpdclient_put_connection(c);
-       check_reconnect();
        auto_update_timer();
 }
 
@@ -423,11 +351,12 @@ void end_input_event(void)
        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);
@@ -436,23 +365,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(gcc_unused GIOChannel *source,
-              gcc_unused GIOCondition condition,
-              gcc_unused gpointer data)
-{
-       begin_input_event();
-
-       command_t cmd = get_keyboard_command();
-       if (cmd != CMD_NONE)
-               if (do_input_event(cmd) != 0)
-                       return FALSE;
-
-       end_input_event();
-       return TRUE;
+       return true;
 }
 
 #ifndef NCMPC_MINI
@@ -539,40 +452,23 @@ main(int argc, const char *argv[])
        options_parse(argc, argv);
 
 #ifndef WIN32
-       /* setup signal behavior - SIGINT */
+       /* setup quit signals */
+       g_unix_signal_add(SIGTERM, handle_quit_signal, NULL);
+       g_unix_signal_add(SIGINT, handle_quit_signal, NULL);
+       g_unix_signal_add(SIGHUP, handle_quit_signal, NULL);
+
+       /* setup signal behavior - SIGCONT */
+
        struct sigaction act;
        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;
+       act.sa_handler = catch_sigwinch;
        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;
@@ -607,25 +503,17 @@ main(int argc, const char *argv[])
        main_loop = g_main_loop_new(NULL, FALSE);
 
        /* watch out for keyboard input */
-       GIOChannel *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 */
-       int lirc_socket = ncmpc_lirc_open();
-       GIOChannel *lirc_channel = NULL;
-       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();
 
 #ifndef WIN32
-       GIOChannel *sigwinch_channel = NULL;
        if (!pipe(sigwinch_pipes) &&
                !fcntl(sigwinch_pipes[1], F_SETFL, O_NONBLOCK)) {
-               sigwinch_channel = g_io_channel_unix_new(sigwinch_pipes[0]);
+               GIOChannel *sigwinch_channel = g_io_channel_unix_new(sigwinch_pipes[0]);
                g_io_add_watch(sigwinch_channel, G_IO_IN, sigwinch_event, NULL);
+               g_io_channel_unref(sigwinch_channel);
        }
        else {
                perror("sigwinch pipe creation failed");
@@ -645,6 +533,7 @@ main(int argc, const char *argv[])
        screen_paint(mpd);
 
        g_main_loop_run(main_loop);
+       g_main_loop_unref(main_loop);
 
        /* cleanup */
 
@@ -660,19 +549,18 @@ 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);
-       g_io_channel_unref(sigwinch_channel);
        close(sigwinch_pipes[0]);
        close(sigwinch_pipes[1]);
 
-#ifdef ENABLE_LIRC
-       if (lirc_socket >= 0)
-               g_io_channel_unref(lirc_channel);
-       ncmpc_lirc_close();
+       ncmpc_lirc_deinit();
+
+       screen_exit();
+#ifndef NCMPC_MINI
+       set_xterm_title("");
 #endif
+       printf("\n");
 
-       exit_and_cleanup();
+       mpdclient_free(mpd);
 
 #ifdef ENABLE_LYRICS_SCREEN
        lyrics_deinit();