Code

cbb4735b9c1e4d9c29e0a7b2a85b106d3d36caf5
[ncmpc.git] / src / main.c
1 /* 
2  * $Id$
3  *
4  * (c) 2004 by Kalle Wallin <kaw@linux.se>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
21 #include "config.h"
22 #include "ncmpc.h"
23 #include "mpdclient.h"
24 #include "support.h"
25 #include "options.h"
26 #include "conf.h"
27 #include "command.h"
28 #include "lyrics.h"
29 #include "screen.h"
30 #include "screen_utils.h"
31 #include "strfsong.h"
32 #include "gcc.h"
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <signal.h>
37 #include <string.h>
39 #define BUFSIZE 1024
41 static mpdclient_t *mpd = NULL;
42 static gboolean connected = FALSE;
43 static GTimer *timer = NULL;
45 static const gchar *
46 error_msg(const gchar *msg)
47 {
48         gchar *p;
50         if ((p = strchr(msg, '}')) == NULL)
51                 return msg;
53         while (p && *p && (*p=='}' || *p==' '))
54                 p++;
56         return p;
57 }
59 static void
60 error_callback(mpd_unused mpdclient_t *c, gint error, const gchar *msg)
61 {
62         error = error & 0xFF;
63         D("Error [%d:%d]> \"%s\"\n", error, GET_ACK_ERROR_CODE(error), msg);
64         switch (error) {
65         case MPD_ERROR_CONNPORT:
66         case MPD_ERROR_NORESPONSE:
67                 break;
68         case MPD_ERROR_ACK:
69                 screen_status_printf("%s", error_msg(msg));
70                 screen_bell();
71                 break;
72         default:
73                 screen_status_printf("%s", msg);
74                 screen_bell();
75                 doupdate();
76                 connected = FALSE;
77         }
78 }
80 static void
81 update_xterm_title(void)
82 {
83         static char title[BUFSIZE];
84         char tmp[BUFSIZE];
85         mpd_Status *status = NULL;
86         mpd_Song *song = NULL;
88         if (mpd) {
89                 status = mpd->status;
90                 song = mpd->song;
91         }
93         if (options.xterm_title_format && status && song &&
94             IS_PLAYING(status->state))
95                 strfsong(tmp, BUFSIZE, options.xterm_title_format, song);
96         else
97                 g_strlcpy(tmp, PACKAGE " version " VERSION, BUFSIZE);
99         if (strncmp(title, tmp, BUFSIZE)) {
100                 g_strlcpy(title, tmp, BUFSIZE);
101                 set_xterm_title("%s", title);
102         }
105 static void
106 exit_and_cleanup(void)
108         screen_exit();
109         set_xterm_title("");
110         printf("\n");
112         if (mpd) {
113                 mpdclient_disconnect(mpd);
114                 mpdclient_free(mpd);
115         }
117         g_free(options.host);
118         g_free(options.password);
119         g_free(options.list_format);
120         g_free(options.status_format);
121         g_free(options.scroll_sep);
123         if (timer)
124                 g_timer_destroy(timer);
127 static void
128 catch_sigint(mpd_unused int sig)
130         printf("\n%s\n", _("Exiting..."));
131         exit(EXIT_SUCCESS);
135 static void
136 catch_sigcont(mpd_unused int sig)
138         D("catch_sigcont()\n");
139 #ifdef ENABLE_RAW_MODE
140         reset_prog_mode(); /* restore tty modes */
141         refresh();
142 #endif
143         screen_resize();
146 void
147 sigstop(void)
149   def_prog_mode();  /* save the tty modes */
150   endwin();         /* end curses mode temporarily */
151   kill(0, SIGSTOP); /* issue SIGSTOP */
154 #ifndef NDEBUG
155 void 
156 D(const char *format, ...)
158   if( options.debug )
159     {
160       gchar *msg;
161       va_list ap;
162   
163       va_start(ap,format);
164       msg = g_strdup_vprintf(format,ap);
165       va_end(ap);
166       fprintf(stderr, "%s", msg);
167       g_free(msg);
168     }
170 #endif
172 int
173 main(int argc, const char *argv[])
175         struct sigaction act;
176         const char *charset = NULL;
177         gboolean key_error;
179 #ifdef HAVE_LOCALE_H
180         /* time and date formatting */
181         setlocale(LC_TIME,"");
182         /* care about sorting order etc */
183         setlocale(LC_COLLATE,"");
184         /* charset */
185         setlocale(LC_CTYPE,"");
186         /* initialize charset conversions */
187         charset_init(g_get_charset(&charset));
188         D("charset: %s\n", charset);
189 #endif
191         /* initialize i18n support */
192 #ifdef ENABLE_NLS
193         setlocale(LC_MESSAGES, "");
194         bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR);
195         bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
196         textdomain(GETTEXT_PACKAGE);
197 #endif
199         /* initialize options */
200         options_init();
202         /* parse command line options - 1 pass get configuration files */
203         options_parse(argc, argv);
205         /* read configuration */
206         read_configuration(&options);
208         /* check key bindings */
209         key_error = check_key_bindings(NULL, NULL, 0);
211         /* parse command line options - 2 pass */
212         options_parse(argc, argv);
214         /* setup signal behavior - SIGINT */
215         sigemptyset(&act.sa_mask);
216         act.sa_flags = 0;
217         act.sa_handler = catch_sigint;
218         if (sigaction(SIGINT, &act, NULL) < 0) {
219                 perror("signal");
220                 exit(EXIT_FAILURE);
221         }
223         /* setup signal behavior - SIGTERM */
224         sigemptyset(&act.sa_mask);
225         act.sa_flags = 0;
226         act.sa_handler = catch_sigint;
227         if (sigaction(SIGTERM, &act, NULL) < 0) {
228                 perror("sigaction()");
229                 exit(EXIT_FAILURE);
230         }
232         /* setup signal behavior - SIGCONT */
233         sigemptyset(&act.sa_mask);
234         act.sa_flags = 0;
235         act.sa_handler = catch_sigcont;
236         if (sigaction(SIGCONT, &act, NULL) < 0) {
237                 perror("sigaction(SIGCONT)");
238                 exit(EXIT_FAILURE);
239         }
241         /* setup signal behaviour - SIGHUP*/
242         sigemptyset(&act.sa_mask);
243         act.sa_flags = 0;
244         act.sa_handler = catch_sigint;
245         if (sigaction(SIGHUP, &act, NULL) < 0) {
246                 perror("sigaction(SIGHUP)");
247                 exit(EXIT_FAILURE);
248         }
250         /* install exit function */
251         atexit(exit_and_cleanup);
253         ncurses_init();
255         lyrics_init();
257         /* create mpdclient instance */
258         mpd = mpdclient_new();
259         mpdclient_install_error_callback(mpd, error_callback);
261         /* initialize curses */
262         screen_init(mpd);
264         /* initialize timer */
265         timer = g_timer_new();
267         while (1) {
268                 static gdouble t = G_MAXDOUBLE;
270                 if (key_error) {
271                         char buf[BUFSIZE];
273                         key_error=check_key_bindings(NULL, buf, BUFSIZE);
274                         screen_status_printf("%s", buf);
275                 }
277                 if (connected && (t >= MPD_UPDATE_TIME || mpd->need_update)) {
278                         mpdclient_update(mpd);
279                         g_timer_start(timer);
280                 }
282                 if (connected) {
283                         command_t cmd;
285                         screen_update(mpd);
286                         if ((cmd=get_keyboard_command()) != CMD_NONE) {
287                                 screen_cmd(mpd, cmd);
288                                 if (cmd == CMD_VOLUME_UP || cmd == CMD_VOLUME_DOWN)
289                                         /* make shure we dont update the volume yet */
290                                         g_timer_start(timer);
291                         } else
292                                 screen_idle(mpd);
293                 } else {
294                         screen_status_printf(_("Connecting to %s...  [Press %s to abort]"),
295                                              options.host, get_key_names(CMD_QUIT,0) );
297                         /*
298                         if (get_keyboard_command_with_timeout(MPD_RECONNECT_TIME) == CMD_QUIT)
299                                 exit(EXIT_SUCCESS);
300                         */
302                         if (mpdclient_connect(mpd,
303                                               options.host, options.port,
304                                               1.5,
305                                               options.password) == 0) {
306                                 screen_status_printf(_("Connected to %s!"), options.host);
308                                 /* quit if mpd is pre 0.11.0 - song id not supported by mpd */
309                                 if (MPD_VERSION_LT(mpd, 0, 11, 0)) {
310                                         screen_status_printf(_("Error: MPD version %d.%d.%d is to old (0.11.0 needed).\n"),
311                                                              mpd->connection->version[0],
312                                                              mpd->connection->version[1],
313                                                              mpd->connection->version[2]);
314                                         mpdclient_disconnect(mpd);
315                                 } else {
316                                         mpdclient_update(mpd);
317                                         if (!mpd->status)
318                                                 screen_auth(mpd);
320                                         connected = TRUE;
321                                 }
322                         }
324                         doupdate();
325                 }
327                 if (options.enable_xterm_title)
328                         update_xterm_title();
330                 t = g_timer_elapsed(timer, NULL);
331         }
332         exit(EXIT_FAILURE);