aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am12
-rw-r--r--src/colors.c10
-rw-r--r--src/conf.c8
-rw-r--r--src/libmpdclient.c270
-rw-r--r--src/libmpdclient.h35
-rw-r--r--src/main.c109
-rw-r--r--src/mpc.c559
-rw-r--r--src/mpc.h51
-rw-r--r--src/mpdclient.c868
-rw-r--r--src/mpdclient.h173
-rw-r--r--src/ncmpc.h9
-rw-r--r--src/screen.c188
-rw-r--r--src/screen.h18
-rw-r--r--src/screen_clock.c13
-rw-r--r--src/screen_file.c396
-rw-r--r--src/screen_file.h7
-rw-r--r--src/screen_help.c10
-rw-r--r--src/screen_help.h2
-rw-r--r--src/screen_keydef.c11
-rw-r--r--src/screen_play.c255
-rw-r--r--src/screen_play.h9
-rw-r--r--src/screen_search.c4
-rw-r--r--src/screen_search.h0
-rw-r--r--src/screen_utils.c9
-rw-r--r--src/screen_utils.h2
-rw-r--r--src/strfsong.c214
-rw-r--r--src/strfsong.h3
-rw-r--r--src/support.c7
28 files changed, 2002 insertions, 1250 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 0554098b9..2d99bc103 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,15 +9,15 @@ ncmpc_LDADD = $(GLIB_LIBS)
AM_CPPFLAGS = $(GLIB_CFLAGS) -DLOCALE_DIR=\""$(datadir)/locale"\" -DSYSCONFDIR=\""$(sysconfdir)"\"
-ncmpc_headers = libmpdclient.h mpc.h options.h conf.h command.h screen.h \
- screen_utils.h screen_play.h screen_file.h screen_search.h \
- screen_help.h list_window.h colors.h support.h \
- wreadln.h ncmpc.h
+ncmpc_headers = libmpdclient.h mpdclient.h options.h conf.h command.h \
+ screen.h screen_utils.h list_window.h colors.h support.h \
+ wreadln.h strfsong.h ncmpc.h
-ncmpc_SOURCES = libmpdclient.c main.c mpc.c options.c conf.c command.c \
+ncmpc_SOURCES = libmpdclient.c main.c mpdclient.c options.c conf.c command.c \
screen.c screen_utils.c screen_play.c screen_file.c \
screen_search.c screen_help.c screen_keydef.c screen_clock.c \
- list_window.c colors.c support.c wreadln.c $(ncmpc_headers)
+ list_window.c colors.c support.c wreadln.c strfsong.c \
+ $(ncmpc_headers)
diff --git a/src/colors.c b/src/colors.c
index bfb4c316c..2a1c04c03 100644
--- a/src/colors.c
+++ b/src/colors.c
@@ -1,5 +1,7 @@
/*
- * (c) 2004 by Kalle Wallin (kaw@linux.se)
+ * $Id$
+ *
+ * (c) 2004 by Kalle Wallin <kaw@linux.se>
*
* 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
@@ -28,12 +30,6 @@
#include "support.h"
#include "colors.h"
-#ifdef DEBUG
-#define D(x) x
-#else
-#define D(x)
-#endif
-
#define COLOR_BRIGHT_MASK (1<<7)
#define COLOR_BRIGHT_BLACK (COLOR_BLACK | COLOR_BRIGHT_MASK)
diff --git a/src/conf.c b/src/conf.c
index cb8ba0eb2..0d6d96834 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -1,5 +1,7 @@
/*
- * (c) 2004 by Kalle Wallin (kaw@linux.se)
+ * $Id$
+ *
+ * (c) 2004 by Kalle Wallin <kaw@linux.se>
*
* 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
@@ -308,7 +310,7 @@ read_rc_file(char *filename, options_t *options)
if( filename==NULL )
return -1;
- D(printf("Reading configuration file %s\n", filename));
+ D("Reading configuration file %s\n", filename);
if( (fd=open(filename,O_RDONLY)) <0 )
{
perror(filename);
@@ -480,7 +482,7 @@ read_rc_file(char *filename, options_t *options)
}
}
- D(printf( "--\n\n" ));
+ D("--\n\n");
if( free_filename )
g_free(filename);
diff --git a/src/libmpdclient.c b/src/libmpdclient.c
index b61e2d1e9..089e7201f 100644
--- a/src/libmpdclient.c
+++ b/src/libmpdclient.c
@@ -30,13 +30,7 @@
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#ifndef HAVE_SOCKLEN_T
-typedef SOCKLEN_T socklen_t;
-#endif
-#endif
+#include <fcntl.h>
#ifndef MPD_NO_IPV6
#ifdef AF_INET6
@@ -44,6 +38,9 @@ typedef SOCKLEN_T socklen_t;
#endif
#endif
+#define COMMAND_LIST 1
+#define COMMAND_LIST_OK 2
+
#ifdef MPD_HAVE_IPV6
int mpd_ipv6Supported() {
int s;
@@ -104,7 +101,11 @@ mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
int err;
struct hostent * he;
struct sockaddr * dest;
+#ifdef MPD_HAVE_SOCKLEN_T
socklen_t destlen;
+#else
+ int destlen;
+#endif
struct sockaddr_in sin;
char * rt;
char * output;
@@ -121,6 +122,8 @@ mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
connection->error = 0;
connection->doneProcessing = 0;
connection->commandList = 0;
+ connection->listOks = 0;
+ connection->doneListOk = 0;
connection->returnElement = NULL;
if(!(he=gethostbyname(host))) {
@@ -174,60 +177,22 @@ mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
return connection;
}
+ mpd_setConnectionTimeout(connection,timeout);
+
/* connect stuff */
{
-#ifdef SO_RCVTIMEO
- struct timeval rcvoldto;
- struct timeval sndoldto;
- socklen_t oldlen = sizeof(struct timeval);
+ int flags = fcntl(connection->sock, F_GETFL, 0);
+ fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
- mpd_setConnectionTimeout(connection,timeout);
-
- tv.tv_sec = connection->timeout.tv_sec;
- tv.tv_usec = connection->timeout.tv_usec;
-
- if(getsockopt(connection->sock,SOL_SOCKET,SO_RCVTIMEO,&rcvoldto,
- &oldlen)<0 ||
- getsockopt(connection->sock,SOL_SOCKET,
- SO_SNDTIMEO,&sndoldto,&oldlen)<0)
+ if(connect(connection->sock,dest,destlen)<0 &&
+ errno!=EINPROGRESS)
{
- strcpy(connection->errorStr,"problems getting socket "
- "timeout\n");
- connection->error = MPD_ERROR_SYSTEM;
- return connection;
- }
- if(setsockopt(connection->sock,SOL_SOCKET,SO_RCVTIMEO,&tv,
- sizeof(struct timeval))<0 ||
- setsockopt(connection->sock,SOL_SOCKET,
- SO_SNDTIMEO,&tv,
- sizeof(struct timeval))<0)
- {
- strcpy(connection->errorStr,"problems setting socket "
- "timeout\n");
- connection->error = MPD_ERROR_SYSTEM;
- return connection;
- }
-#endif
- if(connect(connection->sock,dest,destlen)<0) {
snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
"problems connecting to \"%s\" on port"
" %i",host,port);
connection->error = MPD_ERROR_CONNPORT;
return connection;
}
-#ifdef SO_RCVTIMEO
- if(setsockopt(connection->sock,SOL_SOCKET,SO_SNDTIMEO,&rcvoldto,
- sizeof(struct timeval))<0 ||
- setsockopt(connection->sock,SOL_SOCKET,
- SO_SNDTIMEO,&sndoldto,
- sizeof(struct timeval))<0)
- {
- strcpy(connection->errorStr,"problems setting socket "
- "timeout\n");
- connection->error = MPD_ERROR_SYSTEM;
- return connection;
- }
-#endif
}
while(!(rt = strstr(connection->buffer,"\n"))) {
@@ -253,7 +218,19 @@ mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
tv.tv_sec = connection->timeout.tv_sec;
tv.tv_usec = connection->timeout.tv_usec;
}
- else if(err<0 && errno==EINTR) continue;
+ else if(err<0) {
+ switch(errno) {
+ case EINTR:
+ continue;
+ default:
+ snprintf(connection->errorStr,
+ MPD_BUFFER_MAX_LENGTH,
+ "problems connecting to \"%s\" on port"
+ " %i",host,port);
+ connection->error = MPD_ERROR_CONNPORT;
+ return connection;
+ }
+ }
else {
snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
"timeout in attempting to get a response from"
@@ -380,6 +357,9 @@ void mpd_executeCommand(mpd_Connection * connection, char * command) {
}
if(!connection->commandList) connection->doneProcessing = 0;
+ else if(connection->commandList == COMMAND_LIST_OK) {
+ connection->listOks++;
+ }
}
void mpd_getNextReturnElement(mpd_Connection * connection) {
@@ -397,7 +377,9 @@ void mpd_getNextReturnElement(mpd_Connection * connection) {
if(connection->returnElement) mpd_freeReturnElement(connection->returnElement);
connection->returnElement = NULL;
- if(connection->doneProcessing) {
+ if(connection->doneProcessing || (connection->listOks &&
+ connection->doneListOk))
+ {
strcpy(connection->errorStr,"already done processing current command");
connection->error = 1;
return;
@@ -459,9 +441,28 @@ void mpd_getNextReturnElement(mpd_Connection * connection) {
connection->bufstart = rt - connection->buffer + 1;
if(strcmp(output,"OK")==0) {
+ if(connection->listOks > 0) {
+ strcpy(connection->errorStr, "expected more list_OK's");
+ connection->error = 1;
+ }
+ connection->listOks = 0;
connection->doneProcessing = 1;
return;
}
+
+ if(strcmp(output, "list_OK") == 0) {
+ if(!connection->listOks) {
+ strcpy(connection->errorStr,
+ "got an unexpected list_OK");
+ connection->error = 1;
+ }
+ else {
+ connection->doneListOk = 1;
+ connection->listOks--;
+ }
+ return;
+ }
+
if(strncmp(output,"ACK",strlen("ACK"))==0) {
char * test;
char * needle;
@@ -503,15 +504,45 @@ void mpd_getNextReturnElement(mpd_Connection * connection) {
}
void mpd_finishCommand(mpd_Connection * connection) {
- while(!connection->doneProcessing) mpd_getNextReturnElement(connection);
+ while(!connection->doneProcessing) {
+ if(connection->doneListOk) connection->doneListOk = 0;
+ mpd_getNextReturnElement(connection);
+ }
+}
+
+void mpd_finishListOkCommand(mpd_Connection * connection) {
+ while(!connection->doneProcessing && connection->listOks &&
+ !connection->doneListOk )
+ {
+ mpd_getNextReturnElement(connection);
+ }
+}
+
+int mpd_nextListOkCommand(mpd_Connection * connection) {
+ mpd_finishListOkCommand(connection);
+ if(!connection->doneProcessing) connection->doneListOk = 0;
+ if(connection->listOks == 0 || connection->doneProcessing) return -1;
+ return 0;
+}
+
+void mpd_sendStatusCommand(mpd_Connection * connection) {
+ mpd_executeCommand(connection,"status\n");
}
mpd_Status * mpd_getStatus(mpd_Connection * connection) {
mpd_Status * status;
- mpd_executeCommand(connection,"status\n");
+ /*mpd_executeCommand(connection,"status\n");
- if(connection->error) return NULL;
+ if(connection->error) return NULL;*/
+
+ if(connection->doneProcessing || (connection->listOks &&
+ connection->doneListOk))
+ {
+ return NULL;
+ }
+
+ if(!connection->returnElement) mpd_getNextReturnElement(connection);
status = malloc(sizeof(mpd_Status));
status->volume = -1;
@@ -531,7 +562,6 @@ mpd_Status * mpd_getStatus(mpd_Connection * connection) {
status->error = NULL;
status->updatingDb = 0;
- mpd_getNextReturnElement(connection);
if(connection->error) {
free(status);
return NULL;
@@ -573,6 +603,9 @@ mpd_Status * mpd_getStatus(mpd_Connection * connection) {
else if(strcmp(re->name,"song")==0) {
status->song = atoi(re->value);
}
+ else if(strcmp(re->name,"songid")==0) {
+ status->songid = atoi(re->value);
+ }
else if(strcmp(re->name,"time")==0) {
char * tok;
char * copy;
@@ -639,12 +672,24 @@ void mpd_freeStatus(mpd_Status * status) {
free(status);
}
+void mpd_sendStatsCommand(mpd_Connection * connection) {
+ mpd_executeCommand(connection,"stats\n");
+}
+
mpd_Stats * mpd_getStats(mpd_Connection * connection) {
mpd_Stats * stats;
- mpd_executeCommand(connection,"stats\n");
+ /*mpd_executeCommand(connection,"stats\n");
- if(connection->error) return NULL;
+ if(connection->error) return NULL;*/
+
+ if(connection->doneProcessing || (connection->listOks &&
+ connection->doneListOk))
+ {
+ return NULL;
+ }
+
+ if(!connection->returnElement) mpd_getNextReturnElement(connection);
stats = malloc(sizeof(mpd_Stats));
stats->numberOfArtists = 0;
@@ -655,7 +700,6 @@ mpd_Stats * mpd_getStats(mpd_Connection * connection) {
stats->playTime = 0;
stats->dbPlayTime = 0;
- mpd_getNextReturnElement(connection);
if(connection->error) {
free(stats);
return NULL;
@@ -711,7 +755,8 @@ void mpd_initSong(mpd_Song * song) {
song->title = NULL;
song->name = NULL;
song->time = MPD_SONG_NO_TIME;
- song->num = MPD_SONG_NO_NUM;
+ song->pos = MPD_SONG_NO_NUM;
+ song->id = MPD_SONG_NO_ID;
}
void mpd_finishSong(mpd_Song * song) {
@@ -746,7 +791,8 @@ mpd_Song * mpd_songDup(mpd_Song * song) {
if(song->track) ret->track = strdup(song->track);
if(song->name) ret->name = strdup(song->name);
ret->time = song->time;
- ret->num = song->num;
+ ret->pos = song->pos;
+ ret->id = song->id;
return ret;
}
@@ -848,7 +894,11 @@ void mpd_sendInfoCommand(mpd_Connection * connection, char * command) {
mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection) {
mpd_InfoEntity * entity = NULL;
- if(connection->doneProcessing) return NULL;
+ if(connection->doneProcessing || (connection->listOks &&
+ connection->doneListOk))
+ {
+ return NULL;
+ }
if(!connection->returnElement) mpd_getNextReturnElement(connection);
@@ -917,9 +967,13 @@ mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection) {
strcmp(re->name,"Time")==0) {
entity->info.song->time = atoi(re->value);
}
- else if(entity->info.song->num==MPD_SONG_NO_NUM &&
- strcmp(re->name,"Num")==0) {
- entity->info.song->num = atoi(re->value);
+ else if(entity->info.song->pos==MPD_SONG_NO_NUM &&
+ strcmp(re->name,"Pos")==0) {
+ entity->info.song->pos = atoi(re->value);
+ }
+ else if(entity->info.song->id==MPD_SONG_NO_ID &&
+ strcmp(re->name,"Id")==0) {
+ entity->info.song->id = atoi(re->value);
}
}
else if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
@@ -936,7 +990,11 @@ mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection) {
char * mpd_getNextReturnElementNamed(mpd_Connection * connection,
const char * name)
{
- if(connection->doneProcessing) return NULL;
+ if(connection->doneProcessing || (connection->listOks &&
+ connection->doneListOk))
+ {
+ return NULL;
+ }
mpd_getNextReturnElement(connection);
while(connection->returnElement) {
@@ -957,13 +1015,20 @@ char * mpd_getNextAlbum(mpd_Connection * connection) {
return mpd_getNextReturnElementNamed(connection,"Album");
}
-void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songNum) {
+void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songPos) {
char * string = malloc(strlen("playlistinfo")+25);
- sprintf(string,"playlistinfo \"%i\"\n",songNum);
+ sprintf(string,"playlistinfo \"%i\"\n",songPos);
mpd_sendInfoCommand(connection,string);
free(string);
}
+void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int id) {
+ char * string = malloc(strlen("playlistid")+25);
+ sprintf(string, "playlistid \"%i\"\n", id);
+ mpd_sendInfoCommand(connection, string);
+ free(string);
+}
+
void mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist) {
char * string = malloc(strlen("plchanges")+25);
sprintf(string,"plchanges \"%lld\"\n",playlist);
@@ -998,6 +1063,10 @@ void mpd_sendLsInfoCommand(mpd_Connection * connection, const char * dir) {
free(sDir);
}
+void mpd_sendCurrentSongCommand(mpd_Connection * connection) {
+ mpd_executeCommand(connection,"currentsong\n");
+}
+
void mpd_sendSearchCommand(mpd_Connection * connection, int table,
const char * str)
{
@@ -1076,9 +1145,16 @@ void mpd_sendAddCommand(mpd_Connection * connection, const char * file) {
free(sFile);
}
-void mpd_sendDeleteCommand(mpd_Connection * connection, int songNum) {
+void mpd_sendDeleteCommand(mpd_Connection * connection, int songPos) {
char * string = malloc(strlen("delete")+25);
- sprintf(string,"delete \"%i\"\n",songNum);
+ sprintf(string,"delete \"%i\"\n",songPos);
+ mpd_sendInfoCommand(connection,string);
+ free(string);
+}
+
+void mpd_sendDeleteIdCommand(mpd_Connection * connection, int id) {
+ char * string = malloc(strlen("deleteid")+25);
+ sprintf(string, "deleteid \"%i\"\n", id);
mpd_sendInfoCommand(connection,string);
free(string);
}
@@ -1118,9 +1194,16 @@ void mpd_sendClearCommand(mpd_Connection * connection) {
mpd_executeCommand(connection,"clear\n");
}
-void mpd_sendPlayCommand(mpd_Connection * connection, int songNum) {
+void mpd_sendPlayCommand(mpd_Connection * connection, int songPos) {
char * string = malloc(strlen("play")+25);
- sprintf(string,"play \"%i\"\n",songNum);
+ sprintf(string,"play \"%i\"\n",songPos);
+ mpd_sendInfoCommand(connection,string);
+ free(string);
+}
+
+void mpd_sendPlayIdCommand(mpd_Connection * connection, int id) {
+ char * string = malloc(strlen("playid")+25);
+ sprintf(string,"playid \"%i\"\n",id);
mpd_sendInfoCommand(connection,string);
free(string);
}
@@ -1129,8 +1212,11 @@ void mpd_sendStopCommand(mpd_Connection * connection) {
mpd_executeCommand(connection,"stop\n");
}
-void mpd_sendPauseCommand(mpd_Connection * connection) {
- mpd_executeCommand(connection,"pause\n");
+void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode) {
+ char * string = malloc(strlen("pause")+25);
+ sprintf(string,"pause \"%i\"\n",pauseMode);
+ mpd_executeCommand(connection,string);
+ free(string);
}
void mpd_sendNextCommand(mpd_Connection * connection) {
@@ -1144,6 +1230,13 @@ void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to) {
free(string);
}
+void mpd_sendMoveIdCommand(mpd_Connection * connection, int id, int to) {
+ char * string = malloc(strlen("moveid")+25);
+ sprintf(string, "moveid \"%i\" \"%i\"\n", id, to);
+ mpd_sendInfoCommand(connection,string);
+ free(string);
+}
+
void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2) {
char * string = malloc(strlen("swap")+25);
sprintf(string,"swap \"%i\" \"%i\"\n",song1,song2);
@@ -1151,6 +1244,13 @@ void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2) {
free(string);
}
+void mpd_sendSwapIdCommand(mpd_Connection * connection, int id1, int id2) {
+ char * string = malloc(strlen("swapid")+25);
+ sprintf(string, "swapid \"%i\" \"%i\"\n", id1, id2);
+ mpd_sendInfoCommand(connection,string);
+ free(string);
+}
+
void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time) {
char * string = malloc(strlen("seek")+25);
sprintf(string,"seek \"%i\" \"%i\"\n",song,time);
@@ -1158,6 +1258,13 @@ void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time) {
free(string);
}
+void mpd_sendSeekIdCommand(mpd_Connection * connection, int id, int time) {
+ char * string = malloc(strlen("seekid")+25);
+ sprintf(string,"seekid \"%i\" \"%i\"\n",id,time);
+ mpd_sendInfoCommand(connection,string);
+ free(string);
+}
+
void mpd_sendUpdateCommand(mpd_Connection * connection) {
mpd_executeCommand(connection,"update\n");
}
@@ -1229,10 +1336,21 @@ void mpd_sendCommandListBegin(mpd_Connection * connection) {
connection->error = 1;
return;
}
- connection->commandList = 1;
+ connection->commandList = COMMAND_LIST;
mpd_executeCommand(connection,"command_list_begin\n");
}
+void mpd_sendCommandListOkBegin(mpd_Connection * connection) {
+ if(connection->commandList) {
+ strcpy(connection->errorStr,"already in command list mode");
+ connection->error = 1;
+ return;
+ }
+ connection->commandList = COMMAND_LIST_OK;
+ mpd_executeCommand(connection,"command_list_ok_begin\n");
+ connection->listOks = 0;
+}
+
void mpd_sendCommandListEnd(mpd_Connection * connection) {
if(!connection->commandList) {
strcpy(connection->errorStr,"not in command list mode");
diff --git a/src/libmpdclient.h b/src/libmpdclient.h
index c4b022cd9..1b5f02dfe 100644
--- a/src/libmpdclient.h
+++ b/src/libmpdclient.h
@@ -43,7 +43,7 @@
#define MPD_ACK_ERROR_ARG 2
#define MPD_ACK_ERROR_PASSWORD 3
#define MPD_ACK_ERROR_PERMISSION 4
-#define MPD_ACK_ERROR_UNKNOWN 5
+#define MPD_ACK_ERROR_UNKNOWN_CMD 5
#define MPD_ACK_ERROR_NO_EXIST 6
#define MPD_ACK_ERROR_PLAYLIST_MAX 7
#define MPD_ACK_ERROR_SYSTEM 8
@@ -80,6 +80,8 @@ typedef struct _mpd_Connection {
int buflen;
int bufstart;
int doneProcessing;
+ int listOks;
+ int doneListOk;
int commandList;
mpd_ReturnElement * returnElement;
struct timeval timeout;
@@ -134,10 +136,11 @@ typedef struct mpd_Status {
int state;
/* crossfade setting in seconds */
int crossfade;
- /* if in PLAY or PAUSE state, this is the number of the currently
+ /* if in PLAY or PAUSE state, this is the position of the currently
* playing song in the playlist, beginning with 0
*/
int song;
+ int songid;
/* time in seconds that have elapsed in the currently playing/paused
* song
*/
@@ -158,6 +161,8 @@ typedef struct mpd_Status {
char * error;
} mpd_Status;
+void mpd_sendStatusCommand(mpd_Connection * connection);
+
/* mpd_getStatus
* returns status info, be sure to free it with mpd_freeStatus()
*/
@@ -178,6 +183,8 @@ typedef struct _mpd_Stats {
unsigned long dbPlayTime;
} mpd_Stats;
+void mpd_sendStatsCommand(mpd_Connection * connection);
+
mpd_Stats * mpd_getStats(mpd_Connection * connection);
void mpd_freeStats(mpd_Stats * stats);
@@ -186,6 +193,7 @@ void mpd_freeStats(mpd_Stats * stats);
#define MPD_SONG_NO_TIME -1
#define MPD_SONG_NO_NUM -1
+#define MPD_SONG_NO_ID -1
/* mpd_Song
* for storing song info returned by mpd
@@ -206,9 +214,10 @@ typedef struct _mpd_Song {
char * name;
/* length of song in seconds, check that it is not MPD_SONG_NO_TIME */
int time;
- /* if plchanges or playlistinfo used, is the number of the song in
+ /* if plchanges or playlistinfo used, is the position of the song in
* the playlist */
- int num;
+ int pos;
+ int id;
} mpd_Song;
/* mpd_newSong
@@ -318,6 +327,8 @@ void mpd_freeInfoEntity(mpd_InfoEntity * entity);
/* use this function to loop over after calling Info/Listall functions */
mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection);
+void mpd_sendCurrentSongCommand(mpd_Connection * connection);
+
/* songNum of -1, means to display the whole list */
void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songNum);
@@ -362,6 +373,8 @@ void mpd_sendAddCommand(mpd_Connection * connection, const char * file);
void mpd_sendDeleteCommand(mpd_Connection * connection, int songNum);
+void mpd_sendDeleteIdCommand(mpd_Connection * connection, int songNum);
+
void mpd_sendSaveCommand(mpd_Connection * connection, const char * name);
void mpd_sendLoadCommand(mpd_Connection * connection, const char * name);
@@ -377,9 +390,11 @@ void mpd_sendClearCommand(mpd_Connection * connection);
void mpd_sendPlayCommand(mpd_Connection * connection, int songNum);
+void mpd_sendPlayIdCommand(mpd_Connection * connection, int songNum);
+
void mpd_sendStopCommand(mpd_Connection * connection);
-void mpd_sendPauseCommand(mpd_Connection * connection);
+void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode);
void mpd_sendNextCommand(mpd_Connection * connection);
@@ -387,10 +402,16 @@ void mpd_sendPrevCommand(mpd_Connection * connection);
void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to);
+void mpd_sendMoveIdCommand(mpd_Connection * connection, int from, int to);
+
void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2);
+void mpd_sendSwapIdCommand(mpd_Connection * connection, int song1, int song2);
+
void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time);
+void mpd_sendSeekIdCommand(mpd_Connection * connection, int song, int time);
+
void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode);
void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode);
@@ -417,8 +438,12 @@ void mpd_finishCommand(mpd_Connection * connection);
/* command list stuff, use this to do things like add files very quickly */
void mpd_sendCommandListBegin(mpd_Connection * connection);
+void mpd_sendCommandListOkBegin(mpd_Connection * connection);
+
void mpd_sendCommandListEnd(mpd_Connection * connection);
+int mpd_nextListOkCommand(mpd_Connection * connection);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/main.c b/src/main.c
index 7a44f0985..8d3a82fd2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -26,27 +26,44 @@
#include "config.h"
#include "ncmpc.h"
-#include "libmpdclient.h"
+#include "mpdclient.h"
#include "support.h"
-#include "mpc.h"
#include "options.h"
#include "command.h"
#include "screen.h"
#include "conf.h"
-static mpd_client_t *mpc = NULL;
-static GTimer *timer = NULL;
+static mpdclient_t *mpd = NULL;
+static gboolean connected = FALSE;
+static GTimer *timer = NULL;
+
+static void
+error_callback(mpdclient_t *c, int error, char *msg)
+{
+ D("error_callback> error=%d errorCode=%d errorAt=%d\n",
+ error, c->connection->errorCode, c->connection->errorAt);
+ D("error_callback> \"%s\"\n", msg);
+ switch(error)
+ {
+ case MPD_ERROR_ACK:
+ screen_status_printf("%s", msg);
+ break;
+ default:
+ screen_status_printf(_("Lost connection to %s"), options.host);
+ connected = FALSE;
+ }
+ doupdate();
+}
void
exit_and_cleanup(void)
{
screen_exit();
printf("\n");
- if( mpc )
+ if( mpd )
{
- if( mpc_error(mpc) )
- fprintf(stderr,"Error: %s\n", mpc_error_str(mpc));
- mpc_close(mpc);
+ mpdclient_disconnect(mpd);
+ mpd = mpdclient_free(mpd);
}
g_free(options.host);
g_free(options.password);
@@ -57,7 +74,7 @@ exit_and_cleanup(void)
void
catch_sigint( int sig )
{
- printf( _("\nExiting...\n"));
+ printf("\n%s\n", _("Exiting..."));
exit(EXIT_SUCCESS);
}
@@ -66,7 +83,6 @@ main(int argc, const char *argv[])
{
options_t *options;
struct sigaction act;
- gboolean connected;
const char *charset = NULL;
#ifdef HAVE_LOCALE_H
@@ -76,7 +92,7 @@ main(int argc, const char *argv[])
setlocale(LC_CTYPE,"");
/* initialize charset conversions */
charset_init(g_get_charset(&charset));
- D(printf("charset: %s\n", charset));
+ D("charset: %s\n", charset);
#endif
/* initialize i18n support */
@@ -133,12 +149,26 @@ main(int argc, const char *argv[])
atexit(exit_and_cleanup);
/* connect to our music player daemon */
- mpc = mpc_connect(options->host, options->port, options->password);
- if( mpc_error(mpc) )
- exit(EXIT_FAILURE);
+ mpd = mpdclient_new();
+ if( mpdclient_connect(mpd,
+ options->host,
+ options->port,
+ 10.0,
+ options->password) )
+ {
+ exit(EXIT_FAILURE);
+ }
+ connected = TRUE;
+ D("Connected to MPD version %d.%d.%d\n",
+ mpd->connection->version[0],
+ mpd->connection->version[1],
+ mpd->connection->version[2]);
/* initialize curses */
- screen_init();
+ screen_init(mpd);
+
+ /* install error callback function */
+ mpdclient_install_error_callback(mpd, error_callback);
/* initialize timer */
timer = g_timer_new();
@@ -148,27 +178,9 @@ main(int argc, const char *argv[])
{
static gdouble t = G_MAXDOUBLE;
- if( connected && t>=MPD_UPDATE_TIME )
+ if( connected && (t>=MPD_UPDATE_TIME || mpd->need_update) )
{
- mpc_update(mpc);
- if( mpc_error(mpc) == MPD_ERROR_ACK )
- {
- screen_status_printf("%s", mpc_error_str(mpc));
- mpd_clearError(mpc->connection);
- mpd_finishCommand(mpc->connection);
- }
- else if( mpc_error(mpc) )
- {
- screen_status_printf(_("Lost connection to %s"), options->host);
- connected = FALSE;
- doupdate();
- mpd_clearError(mpc->connection);
- mpd_closeConnection(mpc->connection);
- mpc->connection = NULL;
- }
- else
- mpd_finishCommand(mpc->connection);
-
+ mpdclient_update(mpd);
g_timer_start(timer);
}
@@ -176,36 +188,39 @@ main(int argc, const char *argv[])
{
command_t cmd;
- screen_update(mpc);
+ screen_update(mpd);
if( (cmd=get_keyboard_command()) != CMD_NONE )
{
- screen_cmd(mpc, cmd);
+ 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(mpc);
+ screen_idle(mpd);
}
else if( options->reconnect )
{
- if( get_keyboard_command_with_timeout(MPD_RECONNECT_TIME)==CMD_QUIT)
- exit(EXIT_SUCCESS);
screen_status_printf(_("Connecting to %s... [Press %s to abort]"),
options->host, get_key_names(CMD_QUIT,0) );
- if( mpc_reconnect(mpc,
- options->host,
- options->port,
- options->password) == 0 )
+ doupdate();
+
+ if( get_keyboard_command_with_timeout(MPD_RECONNECT_TIME)==CMD_QUIT)
+ exit(EXIT_SUCCESS);
+
+ if( mpdclient_connect(mpd,
+ options->host,
+ options->port,
+ 1.0,
+ options->password) == 0 )
{
screen_status_printf(_("Connected to %s!"), options->host);
+ doupdate();
connected = TRUE;
- }
- doupdate();
+ }
}
t = g_timer_elapsed(timer, NULL);
}
-
exit(EXIT_FAILURE);
}
diff --git a/src/mpc.c b/src/mpc.c
deleted file mode 100644
index e5b6a2e8b..000000000
--- a/src/mpc.c
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * $Id$
- *
- * (c) 2004 by Kalle Wallin <kaw@linux.se>
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <time.h>
-#include <string.h>
-#include <glib.h>
-
-#include "config.h"
-#include "ncmpc.h"
-#include "support.h"
-#include "libmpdclient.h"
-#include "mpc.h"
-#include "options.h"
-
-#define MAX_SONG_LENGTH 1024
-
-int
-mpc_close(mpd_client_t *c)
-{
- if( c->connection )
- mpd_closeConnection(c->connection);
- if( c->cwd )
- g_free( c->cwd );
-
- return 0;
-}
-
-mpd_client_t *
-mpc_connect(char *host, int port, char *password)
-{
- mpd_Connection *connection;
- mpd_client_t *c;
-
- connection = mpd_newConnection(host, port, 10);
- if( connection==NULL )
- {
- fprintf(stderr, "mpd_newConnection to %s:%d failed!\n", host, port);
- exit(EXIT_FAILURE);
- }
-
- c = g_malloc(sizeof(mpd_client_t));
- memset(c, 0, sizeof(mpd_client_t));
- c->connection = connection;
- c->cwd = g_strdup("");
-
- if( password )
- {
- mpd_sendPasswordCommand(connection, password);
- mpd_finishCommand(connection);
- }
-
- return c;
-}
-
-int
-mpc_reconnect(mpd_client_t *c, char *host, int port, char *password)
-{
- mpd_Connection *connection;
-
- connection = mpd_newConnection(host, port, 1);
- if( connection==NULL )
- return -1;
- if( connection->error )
- {
- mpd_closeConnection(connection);
- return -1;
- }
-
- c->connection = connection;
-
- if( password )
- {
- mpd_sendPasswordCommand(connection, password);
- mpd_finishCommand(connection);
- }
-
- return 0;
-}
-
-
-int
-mpc_error(mpd_client_t *c)
-{
- if( c == NULL || c->connection == NULL )
- return 1;
-
- if( c->connection->error )
- return c->connection->error;
-
- return 0;
-}
-
-char *
-mpc_error_str(mpd_client_t *c)
-{
- if( c == NULL || c->connection == NULL )
- return "Not connected";
-
- if( c->connection && c->connection->errorStr )
- return c->connection->errorStr;
-
- return NULL;
-}
-
-
-
-int
-mpc_free_playlist(mpd_client_t *c)
-{
- GList *list;
-
- if( c==NULL || c->playlist==NULL )
- return -1;
-
- list=g_list_first(c->playlist);
-
- while( list!=NULL )
- {
- mpd_Song *song = (mpd_Song *) list->data;
-
- mpd_freeSong(song);
- list=list->next;
- }
- g_list_free(c->playlist);
- c->playlist=NULL;
- c->playlist_length=0;
-
- c->song_id = -1;
- c->song = NULL;
-
- return 0;
-}
-
-int
-mpc_get_playlist(mpd_client_t *c)
-{
- mpd_InfoEntity *entity;
-
- D(fprintf(stderr, "mpc_get_playlist() [%lld]\n", c->status->playlist));
-
- if( mpc_error(c) )
- return -1;
-
- if( c->playlist )
- mpc_free_playlist(c);
-
- c->playlist_length=0;
- mpd_sendPlaylistInfoCommand(c->connection,-1);
- if( mpc_error(c) )
- return -1;
- while( (entity=mpd_getNextInfoEntity(c->connection)) )
- {
- if(entity->type==MPD_INFO_ENTITY_TYPE_SONG)
- {
- mpd_Song *song = mpd_songDup(entity->info.song);
-
- c->playlist = g_list_append(c->playlist, (gpointer) song);
- c->playlist_length++;
- }
- mpd_freeInfoEntity(entity);
- }
- mpd_finishCommand(c->connection);
- c->playlist_id = c->status->playlist;
- c->playlist_updated = 1;
- c->song_id = -1;
- c->song = NULL;
-
- mpc_filelist_set_selected(c);
-
- return 0;
-}
-
-int
-mpc_update_playlist(mpd_client_t *c)
-{
- mpd_InfoEntity *entity;
-
- D(fprintf(stderr, "mpc_update_playlist() [%lld -> %lld]\n",
- c->status->playlist, c->playlist_id));
-
- if( mpc_error(c) )
- return -1;
-
- mpd_sendPlChangesCommand(c->connection, c->playlist_id);
- if( mpc_error(c) )
- return -1;
-
- while( (entity=mpd_getNextInfoEntity(c->connection)) != NULL )
- {
- if(entity->type==MPD_INFO_ENTITY_TYPE_SONG)
- {
- mpd_Song *song;
- GList *item;
-
- if( (song=mpd_songDup(entity->info.song)) == NULL )
- {
- D(fprintf(stderr, "song==NULL\n"));
- return mpc_get_playlist(c);
- }
-
- item = g_list_nth(c->playlist, song->num);
- if( item && item->data)
- {
- /* Update playlist entry */
- mpd_freeSong((mpd_Song *) item->data);
- item->data = song;
- if( c->song_id == song->num )
- c->song = song;
- D(fprintf(stderr, "Changing num %d to %s\n",
- song->num, mpc_get_song_name(song)));
- }
- else
- {
- /* Add a new playlist entry */
- D(fprintf(stderr, "Adding num %d - %s\n",
- song->num, mpc_get_song_name(song)));
- c->playlist = g_list_append(c->playlist,
- (gpointer) song);
- c->playlist_length++;
- }
- }
- mpd_freeInfoEntity(entity);
- }
- mpd_finishCommand(c->connection);
-
- while( g_list_length(c->playlist) > c->status->playlistLength )
- {
- GList *item = g_list_last(c->playlist);
-
- /* Remove the last playlist entry */
- mpd_freeSong((mpd_Song *) item->data);
- c->playlist = g_list_delete_link(c->playlist, item);
- c->playlist_length--;
- D(fprintf(stderr, "Removed the last playlist entryn\n"));
- }
-
- c->playlist_id = c->status->playlist;
- c->playlist_updated = 1;
- mpc_filelist_set_selected(c);
-
- return 0;
-}
-
-int
-mpc_playlist_get_song_index(mpd_client_t *c, char *filename)
-{
- GList *list = c->playlist;
- int i=0;
-
- while( list )
- {
- mpd_Song *song = (mpd_Song *) list->data;
- if( strcmp(song->file, filename ) == 0 )
- return i;
- list=list->next;
- i++;
- }
- return -1;
-}
-
-mpd_Song *
-mpc_playlist_get_song(mpd_client_t *c, int n)
-{
- return (mpd_Song *) g_list_nth_data(c->playlist, n);
-}
-
-
-char *
-mpc_get_song_name(mpd_Song *song)
-{
- static char buf[MAX_SONG_LENGTH];
- char *name;
-
- if( song->title )
- {
- if( song->artist )
- {
- snprintf(buf, MAX_SONG_LENGTH, "%s - %s", song->artist, song->title);
- name = utf8_to_locale(buf);
- strncpy(buf, name, MAX_SONG_LENGTH);
- g_free(name);
- return buf;
- }
- else
- {
- name = utf8_to_locale(song->title);
- strncpy(buf, name, MAX_SONG_LENGTH);
- g_free(name);
- return buf;
- }
- }
- name = utf8_to_locale(basename(song->file));
- strncpy(buf, name, MAX_SONG_LENGTH);
- g_free(name);
- return buf;
-}
-
-char *
-mpc_get_song_name2(mpd_Song *song)
-{
- static char buf[MAX_SONG_LENGTH];
- char *name;
-
- /* streams */
- if( song->name )
- {
- name = utf8_to_locale(song->name);
- strncpy(buf, name, MAX_SONG_LENGTH);
- g_free(name);
- return buf;
- }
- else if( strstr(song->file, "://") )
- {
- name = utf8_to_locale(song->file);
- strncpy(buf, name, MAX_SONG_LENGTH);
- g_free(name);
-
- return buf;
- }
-
- /* regular songs */
- if( song->title )
- {
- if( song->artist )
- {
- snprintf(buf, MAX_SONG_LENGTH, "%s - %s", song->artist, song->title);
- name = utf8_to_locale(buf);
- strncpy(buf, name, MAX_SONG_LENGTH);
- g_free(name);
- return buf;
- }
- else
- {
- name = utf8_to_locale(song->title);
- strncpy(buf, name, MAX_SONG_LENGTH);
- g_free(name);
- return buf;
- }
- }
- name = utf8_to_locale(basename(song->file));
- strncpy(buf, name, MAX_SONG_LENGTH);
- g_free(name);
- return buf;
-}
-
-#if 0
-size_t
-strfsong(char *s, size_t max, const char *format, mpd_Song *song)
-{
- size_t i, len, format_len;
- char prev;
-
- void sappend(char *utfstr) {
- char *tmp = utf8_to_locale(utfstr);
- size_t tmplen = strlen(tmp);
- if( i+tmplen < max )
- strcat(s, tmp);
- else
- strncat(s, tmp, max-i);
- i = strlen(s);
- g_free(tmp);
- }
-
- i = 0;
- len = 0;
- format_len = strlen(format);
- memset(s, 0, max);
- while(i<format_len && len<max)
- {
- if( i>0 && format[i-1]=='%' )
- {
- char *tmp;
- size_t tmplen;
-
- switch(format[i])
- {
- case '%':
- s[len++] = format[i];
- break;
- case 'a':
- sappend(song->artist);
- break;
- case 't':
- sappend(song->title);
- break;
- case 'n':
- sappend(song->name);
- break;
- case 'f':
- sappend(song->file);
- break;
- }
- }
- else if( format[i]!='%' )
- {
- s[len] = format[i++];
- }
- len++;
- }
-
- return len;
-}
-#endif
-
-
-int
-mpc_update(mpd_client_t *c)
-{
- if( mpc_error(c) )
- return -1;
-
- if( c->status )
- {
- mpd_freeStatus(c->status);
- }
-
- c->status = mpd_getStatus(c->connection);
- if( mpc_error(c) )
- return -1;
-
- if( c->playlist_id!=c->status->playlist )
- {
- if( c->playlist_length<2 )
- mpc_get_playlist(c);
- else
- mpc_update_playlist(c);
- }
-
- if( !c->song || c->status->song != c->song_id )
- {
- c->song = mpc_playlist_get_song(c, c->status->song);
- c->song_id = c->status->song;
- c->song_updated = 1;
- }
-
- return 0;
-}
-
-
-
-
-
-
-int
-mpc_free_filelist(mpd_client_t *c)
-{
- GList *list;
-
- if( c==NULL || c->filelist==NULL )
- return -1;
-
- list=g_list_first(c->filelist);
-
- while( list!=NULL )
- {
- filelist_entry_t *entry = list->data;
-
- if( entry->entity )
- mpd_freeInfoEntity(entry->entity);
- g_free(entry);
- list=list->next;
- }
- g_list_free(c->filelist);
- c->filelist=NULL;
- c->filelist_length=0;
-
- return 0;
-}
-
-
-
-int
-mpc_update_filelist(mpd_client_t *c)
-{
- mpd_InfoEntity *entity;
-
- if( mpc_error(c) )
- return -1;
-
- if( c->filelist )
- mpc_free_filelist(c);
-
- c->filelist_length=0;
-
- mpd_sendLsInfoCommand(c->connection, c->cwd);
-
- if( c->cwd && c->cwd[0] )
- {
- /* add a dummy entry for ./.. */
- filelist_entry_t *entry = g_malloc(sizeof(filelist_entry_t));
- memset(entry, 0, sizeof(filelist_entry_t));
- entry->entity = NULL;
- c->filelist = g_list_append(c->filelist, (gpointer) entry);
- c->filelist_length++;
- }
-
- while( (entity=mpd_getNextInfoEntity(c->connection)) )
- {
- filelist_entry_t *entry = g_malloc(sizeof(filelist_entry_t));
-
- memset(entry, 0, sizeof(filelist_entry_t));
- entry->entity = entity;
- c->filelist = g_list_append(c->filelist, (gpointer) entry);
- c->filelist_length++;
- }
-
- c->filelist_updated = 1;
-
- mpd_finishCommand(c->connection);
-
- mpc_filelist_set_selected(c);
-
- return 0;
-}
-
-int
-mpc_filelist_set_selected(mpd_client_t *c)
-{
- GList *list = c->filelist;
-
- while( list )
- {
- filelist_entry_t *entry = list->data;
- mpd_InfoEntity *entity = entry->entity ;
-
- if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
- {
- mpd_Song *song = entity->info.song;
-
- if( mpc_playlist_get_song_index(c, song->file) >= 0 )
- entry->selected = 1;
- else
- entry->selected = 0;
- }
-
- list=list->next;
- }
- return 0;
-}
diff --git a/src/mpc.h b/src/mpc.h
deleted file mode 100644
index 152f1532b..000000000
--- a/src/mpc.h
+++ /dev/null
@@ -1,51 +0,0 @@
-
-typedef struct
-{
- char selected;
- mpd_InfoEntity *entity;
-} filelist_entry_t;
-
-typedef struct
-{
- mpd_Connection *connection;
- mpd_Status *status;
-
- mpd_Song *song;
- int song_id;
- int song_updated;
-
- int seek_song_id;
- int seek_target_time;
-
- GList *playlist;
- int playlist_length;
- long long playlist_id;
- int playlist_updated;
-
- char *cwd;
- GList *filelist;
- int filelist_length;
- int filelist_updated;
-
-} mpd_client_t;
-
-
-int mpc_close(mpd_client_t *c);
-
-mpd_client_t *mpc_connect(char *host, int port, char *passwd);
-int mpc_reconnect(mpd_client_t *c, char *host, int port, char *passwd);
-
-int mpc_update(mpd_client_t *c);
-int mpc_update_playlist(mpd_client_t *c);
-
-int mpc_update_filelist(mpd_client_t *c);
-int mpc_filelist_set_selected(mpd_client_t *c);
-int mpc_set_cwd(mpd_client_t *c, char *dir);
-
-mpd_Song *mpc_playlist_get_song(mpd_client_t *c, int n);
-char *mpc_get_song_name(mpd_Song *song);
-char *mpc_get_song_name2(mpd_Song *song);
-int mpc_playlist_get_song_index(mpd_client_t *c, char *filename);
-
-int mpc_error(mpd_client_t *c);
-char *mpc_error_str(mpd_client_t *c);
diff --git a/src/mpdclient.c b/src/mpdclient.c
new file mode 100644
index 000000000..af6476fdb
--- /dev/null
+++ b/src/mpdclient.c
@@ -0,0 +1,868 @@
+/*
+ * $Id$
+ *
+ * (c) 2004 by Kalle Wallin <kaw@linux.se>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <glib.h>
+
+#include "config.h"
+#include "ncmpc.h"
+#include "support.h"
+#include "mpdclient.h"
+#include "options.h"
+
+#undef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_ADD /* broken with song id's */
+#define ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_DELETE
+#define ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_MOVE
+#undef ENABLE_SONG_ID
+
+#define MPD_ERROR(c) (c==NULL || c->connection==NULL || c->connection->error)
+
+
+/* Error callbacks */
+static gint
+error_cb(mpdclient_t *c, gint error, gchar *msg)
+{
+ GList *list = c->error_callbacks;
+
+ if( list==NULL )
+ fprintf(stderr, "error [%d]: %s\n", error, msg);
+
+ while(list)
+ {
+ mpdc_error_cb_t cb = list->data;
+ if( cb )
+ cb(c, error, msg);
+ list=list->next;
+ }
+ mpd_clearError(c->connection);
+ return error;
+}
+
+#ifdef DEBUG
+#include "strfsong.h"
+
+static gchar *
+get_song_name(mpd_Song *song)
+{
+ static gchar name[256];
+
+ strfsong(name, 256, "[%artist% - ]%title%|%file%", song);
+ return name;
+}
+
+#endif
+
+/****************************************************************************/
+/*** mpdclient functions ****************************************************/
+/****************************************************************************/
+
+gint
+mpdclient_finish_command(mpdclient_t *c)
+{
+ mpd_finishCommand(c->connection);
+
+ if( c->connection->error )
+ {
+ gchar *msg = locale_to_utf8(c->connection->errorStr);
+ gint retval = c->connection->error;
+
+ error_cb(c, c->connection->error, msg);
+ g_free(msg);
+ return retval;
+ }
+
+ return 0;
+}
+
+mpdclient_t *
+mpdclient_new(void)
+{
+ mpdclient_t *c;
+
+ c = g_malloc0(sizeof(mpdclient_t));
+
+ return c;
+}
+
+mpdclient_t *
+mpdclient_free(mpdclient_t *c)
+{
+ mpdclient_disconnect(c);
+ g_list_free(c->error_callbacks);
+ g_list_free(c->playlist_callbacks);
+ g_list_free(c->browse_callbacks);
+ g_free(c);
+
+ return NULL;
+}
+
+gint
+mpdclient_disconnect(mpdclient_t *c)
+{
+ D("mpdclient_disconnect()...\n");
+ if( c->connection )
+ mpd_closeConnection(c->connection);
+ c->connection = NULL;
+
+ if( c->status )
+ mpd_freeStatus(c->status);
+ c->status = NULL;
+
+ if( c->playlist.list )
+ mpdclient_playlist_free(&c->playlist);
+
+ if( c->song )
+ c->song = NULL;
+
+ return 0;
+}
+
+gint
+mpdclient_connect(mpdclient_t *c,
+ gchar *host,
+ gint port,
+ gfloat timeout,
+ gchar *password)
+{
+ gint retval = 0;
+
+ /* close any open connection */
+ if( c->connection )
+ mpdclient_disconnect(c);
+
+ /* connect to MPD */
+ D("mpdclient_connect(%s, %d)...\n", host, port);
+ c->connection = mpd_newConnection(host, port, timeout);
+ if( c->connection->error )
+ return error_cb(c, c->connection->error, c->connection->errorStr);
+
+ /* send password */
+ if( password )
+ {
+ mpd_sendPasswordCommand(c->connection, password);
+ retval = mpdclient_finish_command(c);
+ }
+
+ return retval;
+}
+
+gint
+mpdclient_update(mpdclient_t *c)
+{
+ gint retval = 0;
+
+ if( MPD_ERROR(c) )
+ return -1;
+
+ /* free the old status */
+ if( c->status )
+ mpd_freeStatus(c->status);
+
+ /* retreive new status */
+ mpd_sendStatusCommand(c->connection);
+ c->status = mpd_getStatus(c->connection);
+ if( (retval=mpdclient_finish_command(c)) )
+ return retval;
+#ifdef DEBUG
+ if( c->status->error )
+ D("status> %s\n", c->status->error);
+#endif
+
+ /* check if the playlist needs an update */
+ if( c->playlist.id != c->status->playlist )
+ {
+ if( c->playlist.list )
+ retval = mpdclient_playlist_update_changes(c);
+ else
+ retval = mpdclient_playlist_update(c);
+ }
+
+ /* update the current song */
+ if( !c->song || c->status->songid != c->song->id )
+ {
+ c->song = playlist_get_song(c, c->status->song);
+ }
+
+ c->need_update = FALSE;
+
+ return retval;
+}
+
+
+/****************************************************************************/
+/*** MPD Commands **********************************************************/
+/****************************************************************************/
+
+gint
+mpdclient_cmd_play(mpdclient_t *c, gint index)
+{
+#ifdef ENABLE_SONG_ID
+ mpd_Song *song = playlist_get_song(c, index);
+
+ if( song )
+ mpd_sendPlayIdCommand(c->connection, song->id);
+ else
+ mpd_sendPlayIdCommand(c->connection, MPD_PLAY_AT_BEGINNING);
+#else
+ mpd_sendPlayCommand(c->connection, index);
+#endif
+ c->need_update = TRUE;
+ return mpdclient_finish_command(c);
+}
+
+gint
+mpdclient_cmd_pause(mpdclient_t *c, gint value)
+{
+ mpd_sendPauseCommand(c->connection, value);
+ return mpdclient_finish_command(c);
+}
+
+gint
+mpdclient_cmd_stop(mpdclient_t *c)
+{
+ mpd_sendStopCommand(c->connection);
+ return mpdclient_finish_command(c);
+}
+
+gint
+mpdclient_cmd_next(mpdclient_t *c)
+{
+ mpd_sendNextCommand(c->connection);
+ c->need_update = TRUE;
+ return mpdclient_finish_command(c);
+}
+
+gint
+mpdclient_cmd_prev(mpdclient_t *c)
+{
+ mpd_sendPrevCommand(c->connection);
+ c->need_update = TRUE;
+ return mpdclient_finish_command(c);
+}
+
+gint
+mpdclient_cmd_seek(mpdclient_t *c, gint id, gint pos)
+{
+ mpd_sendSeekIdCommand(c->connection, id, pos);
+ return mpdclient_finish_command(c);
+}
+
+gint
+mpdclient_cmd_shuffle(mpdclient_t *c)
+{
+ mpd_sendShuffleCommand(c->connection);
+ c->need_update = TRUE;
+ return mpdclient_finish_command(c);
+}
+
+gint
+mpdclient_cmd_clear(mpdclient_t *c)
+{
+ gint retval = 0;
+
+ mpd_sendClearCommand(c->connection);
+ retval = mpdclient_finish_command(c);
+ /* call playlist updated callback */
+ mpdclient_playlist_callback(c, PLAYLIST_EVENT_CLEAR, NULL);
+ c->need_update = TRUE;
+ return retval;
+}
+
+gint
+mpdclient_cmd_repeat(mpdclient_t *c, gint value)
+{
+ mpd_sendRepeatCommand(c->connection, value);
+ return mpdclient_finish_command(c);
+}
+
+gint
+mpdclient_cmd_random(mpdclient_t *c, gint value)
+{
+ mpd_sendRandomCommand(c->connection, value);
+ return mpdclient_finish_command(c);
+}
+
+gint
+mpdclient_cmd_crossfade(mpdclient_t *c, gint value)
+{
+ mpd_sendCrossfadeCommand(c->connection, value);
+ return mpdclient_finish_command(c);
+}
+
+gint
+mpdclient_cmd_db_update(mpdclient_t *c)
+{
+ mpd_sendUpdateCommand(c->connection);
+ return mpdclient_finish_command(c);
+}
+
+gint
+mpdclient_cmd_volume(mpdclient_t *c, gint value)
+{
+ mpd_sendSetvolCommand(c->connection, value);
+ return mpdclient_finish_command(c);
+}
+
+gint
+mpdclient_cmd_add(mpdclient_t *c, mpd_Song *song)
+{
+ gint retval = 0;
+
+ if( !song || !song->file )
+ return -1;
+
+ /* send the add command to mpd */
+ mpd_sendAddCommand(c->connection, song->file);
+ if( (retval=mpdclient_finish_command(c)) )
+ return retval;
+
+#ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_ADD
+ /* add the song to playlist */
+ c->playlist.list = g_list_append(c->playlist.list, mpd_songDup(song));
+ c->playlist.length++;
+
+ /* increment the playlist id, so we dont retrives a new playlist */
+ c->playlist.id++;
+
+ /* call playlist updated callback */
+ mpdclient_playlist_callback(c, PLAYLIST_EVENT_ADD, (gpointer) song);
+#else
+ c->need_update = TRUE;
+#endif
+
+ return 0;
+}
+
+gint
+mpdclient_cmd_delete(mpdclient_t *c, gint index)
+{
+ gint retval = 0;
+ mpd_Song *song = playlist_get_song(c, index);
+
+ if( !song )
+ return -1;
+
+ /* send the delete command to mpd */
+#ifdef ENABLE_SONG_ID
+ mpd_sendDeleteIdCommand(c->connection, song->id);
+#else
+ mpd_sendDeleteCommand(c->connection, index);
+#endif
+ if( (retval=mpdclient_finish_command(c)) )
+ return retval;
+
+#ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_DELETE
+ /* increment the playlist id, so we dont retrive a new playlist */
+ c->playlist.id++;
+
+ /* remove the song from the playlist */
+ c->playlist.list = g_list_remove(c->playlist.list, (gpointer) song);
+ c->playlist.length = g_list_length(c->playlist.list);
+
+ /* call playlist updated callback */
+ mpdclient_playlist_callback(c, PLAYLIST_EVENT_DELETE, (gpointer) song);
+
+ /* remove references to the song */
+ if( c->song == song )
+ {
+ c->song = NULL;
+ c->need_update = TRUE;
+ }
+
+ /* free song */
+ mpd_freeSong(song);
+
+#else
+ c->need_update = TRUE;
+#endif
+
+ return 0;
+}
+
+gint
+mpdclient_cmd_move(mpdclient_t *c, gint old_index, gint new_index)
+{
+ gint retval, index1, index2;
+ GList *item1, *item2;
+ gpointer data1, data2;
+ mpd_Song *song1, *song2;
+
+ if( old_index==new_index || new_index<0 || new_index>=c->playlist.length )
+ return -1;
+
+ song1 = playlist_get_song(c, old_index);
+ song2 = playlist_get_song(c, new_index);
+
+ /* send the move command to mpd */
+#ifdef ENABLE_SONG_ID
+ mpd_sendMoveIdCommand(c->connection, song1->id, song2->id);
+#else
+ mpd_sendMoveCommand(c->connection, old_index, new_index);
+#endif
+ if( (retval=mpdclient_finish_command(c)) )
+ return retval;
+
+#ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_MOVE
+ index1 = MIN(old_index, new_index);
+ index2 = MAX(old_index, new_index);
+ item1 = g_list_nth(c->playlist.list, index1);
+ item2 = g_list_nth(c->playlist.list, index2);
+ data1 = item1->data;
+ data2 = item2->data;
+
+ /* move the second item */
+ c->playlist.list = g_list_remove(c->playlist.list, data2);
+ c->playlist.list = g_list_insert_before(c->playlist.list, item1, data2);
+
+ /* move the first item */
+ if( index2-index1 >1 )
+ {
+ item2 = g_list_nth(c->playlist.list, index2);
+ c->playlist.list = g_list_remove(c->playlist.list, data1);
+ c->playlist.list = g_list_insert_before(c->playlist.list, item2, data1);
+ }
+
+ /* increment the playlist id, so we dont retrives a new playlist */
+ c->playlist.id++;
+
+ /* call playlist updated callback */
+ mpdclient_playlist_callback(c, PLAYLIST_EVENT_MOVE, (gpointer) &new_index);
+#else
+ c->need_update = TRUE;
+#endif
+
+ return 0;
+}
+
+gint
+mpdclient_cmd_save_playlist(mpdclient_t *c, gchar *filename)
+{
+ gint retval = 0;
+ gchar *filename_utf8 = locale_to_utf8(filename);
+
+ mpd_sendSaveCommand(c->connection, filename_utf8);
+ if( (retval=mpdclient_finish_command(c)) == 0 )
+ mpdclient_browse_callback(c, BROWSE_PLAYLIST_SAVED, NULL);
+ g_free(filename_utf8);
+ return retval;
+}
+
+gint
+mpdclient_cmd_load_playlist(mpdclient_t *c, gchar *filename_utf8)
+{
+ mpd_sendLoadCommand(c->connection, filename_utf8);
+ c->need_update = TRUE;
+ return mpdclient_finish_command(c);
+}
+
+gint
+mpdclient_cmd_delete_playlist(mpdclient_t *c, gchar *filename_utf8)
+{
+ gint retval = 0;
+
+ mpd_sendRmCommand(c->connection, filename_utf8);
+ if( (retval=mpdclient_finish_command(c)) == 0 )
+ mpdclient_browse_callback(c, BROWSE_PLAYLIST_DELETED, NULL);
+ return retval;
+}
+
+
+/****************************************************************************/
+/*** Callback managment functions *******************************************/
+/****************************************************************************/
+static void
+do_list_callbacks(mpdclient_t *c, GList *list, gint event, gpointer data)
+{
+ while(list)
+ {
+ mpdc_list_cb_t fn = list->data;
+
+ fn(c, event, data);
+ list=list->next;
+ }
+}
+
+void
+mpdclient_playlist_callback(mpdclient_t *c, int event, gpointer data)
+{
+ do_list_callbacks(c, c->playlist_callbacks, event, data);
+}
+
+void
+mpdclient_install_playlist_callback(mpdclient_t *c,mpdc_list_cb_t cb)
+{
+ c->playlist_callbacks = g_list_append(c->playlist_callbacks, cb);
+}
+
+void
+mpdclient_remove_playlist_callback(mpdclient_t *c, mpdc_list_cb_t cb)
+{
+ c->playlist_callbacks = g_list_remove(c->playlist_callbacks, cb);
+}
+
+void
+mpdclient_browse_callback(mpdclient_t *c, int event, gpointer data)
+{
+ do_list_callbacks(c, c->browse_callbacks, event, data);
+}
+
+
+void
+mpdclient_install_browse_callback(mpdclient_t *c,mpdc_list_cb_t cb)
+{
+ c->browse_callbacks = g_list_append(c->browse_callbacks, cb);
+}
+
+void
+mpdclient_remove_browse_callback(mpdclient_t *c, mpdc_list_cb_t cb)
+{
+ c->browse_callbacks = g_list_remove(c->browse_callbacks, cb);
+}
+
+void
+mpdclient_install_error_callback(mpdclient_t *c, mpdc_error_cb_t cb)
+{
+ c->error_callbacks = g_list_append(c->error_callbacks, cb);
+}
+
+void
+mpdclient_remove_error_callback(mpdclient_t *c, mpdc_error_cb_t cb)
+{
+ c->error_callbacks = g_list_remove(c->error_callbacks, cb);
+}
+
+/****************************************************************************/
+/*** Playlist managment functions *******************************************/
+/****************************************************************************/
+
+gint
+mpdclient_playlist_free(mpdclient_playlist_t *playlist)
+{
+ GList *list = g_list_first(playlist->list);
+
+ while(list)
+ {
+ mpd_Song *song = (mpd_Song *) list->data;
+ mpd_freeSong(song);
+ list=list->next;
+ }
+ g_list_free(playlist->list);
+ playlist->list = NULL;
+ playlist->length = 0;
+ return 0;
+}
+
+/* update playlist */
+gint
+mpdclient_playlist_update(mpdclient_t *c)
+{
+ mpd_InfoEntity *entity;
+
+ D("mpdclient_playlist_update() [%lld]\n", c->status->playlist);
+
+ if( MPD_ERROR(c) )
+ return -1;
+
+ if( c->playlist.list )
+ mpdclient_playlist_free(&c->playlist);
+
+ c->song = NULL;
+ c->playlist.updated = TRUE;
+
+ mpd_sendPlaylistInfoCommand(c->connection,-1);
+ while( (entity=mpd_getNextInfoEntity(c->connection)) )
+ {
+ if(entity->type==MPD_INFO_ENTITY_TYPE_SONG)
+ {
+ mpd_Song *song = mpd_songDup(entity->info.song);
+
+ c->playlist.list = g_list_append(c->playlist.list, (gpointer) song);
+ c->playlist.length++;
+ }
+ mpd_freeInfoEntity(entity);
+ }
+ c->playlist.id = c->status->playlist;
+ c->song = NULL;
+
+ /* call playlist updated callbacks */
+ mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
+
+ return mpdclient_finish_command(c);
+}
+
+/* update playlist (plchanges) */
+gint
+mpdclient_playlist_update_changes(mpdclient_t *c)
+{
+ mpd_InfoEntity *entity;
+
+ D("mpdclient_playlist_update_changes() [%lld -> %lld]\n",
+ c->status->playlist, c->playlist.id);
+
+ if( MPD_ERROR(c) )
+ return -1;
+
+ mpd_sendPlChangesCommand(c->connection, c->playlist.id);
+
+ while( (entity=mpd_getNextInfoEntity(c->connection)) != NULL )
+ {
+ if(entity->type==MPD_INFO_ENTITY_TYPE_SONG)
+ {
+ mpd_Song *song;
+ GList *item;
+
+ if( (song=mpd_songDup(entity->info.song)) == NULL )
+ {
+ D("song==NULL => calling mpdclient_playlist_update()\n");
+ return mpdclient_playlist_update(c);
+ }
+
+ item = playlist_lookup(c, song->id);
+
+ if( item && item->data)
+ {
+ /* Update playlist entry */
+ mpd_freeSong((mpd_Song *) item->data);
+ item->data = song;
+ if( c->song && c->song->id == song->id )
+ c->song = song;
+ D("Changing num %d [%d] to %s\n",
+ song->pos, song->id, get_song_name(song));
+ }
+ else
+ {
+ /* Add a new playlist entry */
+ D("Adding pos:%d, id;%d - %s\n",
+ song->pos, song->id, get_song_name(song));
+ c->playlist.list = g_list_append(c->playlist.list,
+ (gpointer) song);
+ c->playlist.length++;
+ }
+ }
+ mpd_freeInfoEntity(entity);
+ }
+ mpd_finishCommand(c->connection);
+
+ while( g_list_length(c->playlist.list) > c->status->playlistLength )
+ {
+ GList *item = g_list_last(c->playlist.list);
+
+ /* Remove the last playlist entry */
+ mpd_freeSong((mpd_Song *) item->data);
+ c->playlist.list = g_list_delete_link(c->playlist.list, item);
+ c->playlist.length--;
+ D("Removed the last playlist entry\n");
+ }
+
+ c->playlist.id = c->status->playlist;
+ c->playlist.updated = TRUE;
+
+ mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
+
+ return 0;
+}
+
+mpd_Song *
+playlist_get_song(mpdclient_t *c, gint index)
+{
+ return (mpd_Song *) g_list_nth_data(c->playlist.list, index);
+}
+
+GList *
+playlist_lookup(mpdclient_t *c, gint id)
+{
+ GList *list = c->playlist.list;
+
+ while( list )
+ {
+ mpd_Song *song = (mpd_Song *) list->data;
+ if( song->id == id )
+ return list;
+ list=list->next;
+ }
+ return NULL;
+}
+
+mpd_Song *
+playlist_lookup_song(mpdclient_t *c, gint id)
+{
+ GList *list = c->playlist.list;
+
+ while( list )
+ {
+ mpd_Song *song = (mpd_Song *) list->data;
+ if( song->id == id )
+ return song;
+ list=list->next;
+ }
+ return NULL;
+}
+
+gint
+playlist_get_index(mpdclient_t *c, mpd_Song *song)
+{
+ return g_list_index(c->playlist.list, song);
+}
+
+gint
+playlist_get_index_from_id(mpdclient_t *c, gint id)
+{
+ return g_list_index(c->playlist.list, playlist_lookup_song(c, id));
+}
+
+gint
+playlist_get_index_from_file(mpdclient_t *c, gchar *filename)
+{
+ GList *list = c->playlist.list;
+ gint i=0;
+
+ while( list )
+ {
+ mpd_Song *song = (mpd_Song *) list->data;
+ if( strcmp(song->file, filename ) == 0 )
+ return i;
+ list=list->next;
+ i++;
+ }
+ return -1;
+}
+
+
+/****************************************************************************/
+/*** Filelist functions *****************************************************/
+/****************************************************************************/
+
+mpdclient_filelist_t *
+mpdclient_filelist_free(mpdclient_filelist_t *filelist)
+{
+ GList *list = g_list_first(filelist->list);
+
+ while( list!=NULL )
+ {
+ filelist_entry_t *entry = list->data;
+
+ if( entry->entity )
+ mpd_freeInfoEntity(entry->entity);
+ g_free(entry);
+ list=list->next;
+ }
+ g_list_free(filelist->list);
+ g_free(filelist->path);
+ filelist->path = NULL;
+ filelist->list = NULL;
+ filelist->length = 0;
+ g_free(filelist);
+
+ return NULL;
+}
+
+
+mpdclient_filelist_t *
+mpdclient_filelist_get(mpdclient_t *c, gchar *path)
+{
+ mpdclient_filelist_t *filelist;
+ mpd_InfoEntity *entity;
+ gchar *path_utf8 = locale_to_utf8(path);
+
+ mpd_sendLsInfoCommand(c->connection, path_utf8);
+ filelist = g_malloc0(sizeof(mpdclient_filelist_t));
+ if( path && path[0] && strcmp(path, "/") )
+ {
+ /* add a dummy entry for ./.. */
+ filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t));
+ entry->entity = NULL;
+ filelist->list = g_list_append(filelist->list, (gpointer) entry);
+ filelist->length++;
+ }
+
+ while( (entity=mpd_getNextInfoEntity(c->connection)) )
+ {
+ filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t));
+
+ entry->entity = entity;
+ filelist->list = g_list_append(filelist->list, (gpointer) entry);
+ filelist->length++;
+ }
+
+ if( mpdclient_finish_command(c) )
+ {
+ g_free(path_utf8);
+ return mpdclient_filelist_free(filelist);
+ }
+
+ g_free(path_utf8);
+ filelist->path = g_strdup(path);
+ filelist->updated = TRUE;
+
+ return filelist;
+}
+
+mpdclient_filelist_t *
+mpdclient_filelist_update(mpdclient_t *c, mpdclient_filelist_t *filelist)
+{
+ if( filelist == NULL )
+ {
+ gchar *path = g_strdup(filelist->path);
+
+ filelist = mpdclient_filelist_free(filelist);
+ filelist = mpdclient_filelist_get(c, path);
+ g_free(path);
+ return filelist;
+ }
+ return NULL;
+}
+
+filelist_entry_t *
+mpdclient_filelist_find_song(mpdclient_filelist_t *fl, mpd_Song *song)
+{
+ GList *list = g_list_first(fl->list);
+
+ while( list && song)
+ {
+ filelist_entry_t *entry = list->data;
+ mpd_InfoEntity *entity = entry->entity;
+
+ if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
+ {
+ mpd_Song *song2 = entity->info.song;
+
+ if( strcmp(song->file, song2->file) == 0 )
+ {
+ return entry;
+ }
+ }
+ list = list->next;
+ }
+ return NULL;
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mpdclient.h b/src/mpdclient.h
new file mode 100644
index 000000000..86f1b0ce8
--- /dev/null
+++ b/src/mpdclient.h
@@ -0,0 +1,173 @@
+#ifndef MPDCLIENT_H
+#define MPDCLIENT_H
+#include "libmpdclient.h"
+
+/****************************************************************************/
+/* Playlist */
+/****************************************************************************/
+
+typedef struct
+{
+ /* playlist id */
+ long long id;
+ /* list length */
+ guint length;
+ /* true if the list is updated */
+ gboolean updated;
+ /* the list */
+ GList *list;
+
+} mpdclient_playlist_t;
+
+
+typedef struct
+{
+ guint flags;
+ mpd_InfoEntity *entity;
+} filelist_entry_t;
+
+typedef struct
+{
+ /* path */
+ gchar *path;
+ /* list length */
+ guint length;
+ /* true if the list is updated */
+ gboolean updated;
+ /* the list */
+ GList *list;
+
+} mpdclient_filelist_t;
+
+typedef struct
+{
+ /* playlist */
+ mpdclient_playlist_t playlist;
+
+ /* Callbacks */
+ GList *error_callbacks;
+ GList *playlist_callbacks;
+ GList *browse_callbacks;
+
+ mpd_Connection *connection;
+ mpd_Status *status;
+ mpd_Song *song;
+
+ gboolean need_update;
+
+} mpdclient_t;
+
+/** functions ***************************************************************/
+mpdclient_t *mpdclient_new(void);
+mpdclient_t *mpdclient_free(mpdclient_t *c);
+gint mpdclient_connect(mpdclient_t *c, gchar *host, gint port,
+ gfloat timeout, gchar *password);
+gint mpdclient_disconnect(mpdclient_t *c);
+gint mpdclient_update(mpdclient_t *c);
+
+
+/*** MPD Commands **********************************************************/
+gint mpdclient_cmd_play(mpdclient_t *c, gint index);
+gint mpdclient_cmd_pause(mpdclient_t *c, gint value);
+gint mpdclient_cmd_stop(mpdclient_t *c);
+gint mpdclient_cmd_next(mpdclient_t *c);
+gint mpdclient_cmd_prev(mpdclient_t *c);
+gint mpdclient_cmd_seek(mpdclient_t *c, gint id, gint pos);
+gint mpdclient_cmd_shuffle(mpdclient_t *c);
+gint mpdclient_cmd_clear(mpdclient_t *c);
+gint mpdclient_cmd_repeat(mpdclient_t *c, gint value);
+gint mpdclient_cmd_random(mpdclient_t *c, gint value);
+gint mpdclient_cmd_crossfade(mpdclient_t *c, gint value);
+gint mpdclient_cmd_db_update(mpdclient_t *c);
+gint mpdclient_cmd_volume(mpdclient_t *c, gint value);
+
+gint mpdclient_cmd_add(mpdclient_t *c, mpd_Song *song);
+gint mpdclient_cmd_delete(mpdclient_t *c, gint index);
+gint mpdclient_cmd_move(mpdclient_t *c, gint old_index, gint new_index);
+
+gint mpdclient_cmd_save_playlist(mpdclient_t *c, gchar *filename);
+gint mpdclient_cmd_load_playlist(mpdclient_t *c, gchar *filename_utf8);
+gint mpdclient_cmd_delete_playlist(mpdclient_t *c, gchar *filename_utf8);
+
+
+/*** error callbacks *****************************************************/
+typedef void (*mpdc_error_cb_t) (mpdclient_t *c, gint error, gchar *msg);
+
+void mpdclient_install_error_callback(mpdclient_t *c, mpdc_error_cb_t cb);
+void mpdclient_remove_error_callback(mpdclient_t *c, mpdc_error_cb_t cb);
+
+/*** playlist functions **************************************************/
+
+/* free a playlist */
+gint mpdclient_playlist_free(mpdclient_playlist_t *playlist);
+/* update the complete playlist */
+gint mpdclient_playlist_update(mpdclient_t *c);
+/* get playlist changes */
+gint mpdclient_playlist_update_changes(mpdclient_t *c);
+
+GList *playlist_lookup(mpdclient_t *c, gint id);
+mpd_Song *playlist_lookup_song(mpdclient_t *c, gint id);
+mpd_Song *playlist_get_song(mpdclient_t *c, gint index);
+gint playlist_get_index(mpdclient_t *c, mpd_Song *song);
+gint playlist_get_index_from_id(mpdclient_t *c, gint id);
+gint playlist_get_index_from_file(mpdclient_t *c, gchar *filename);
+
+
+
+/*** mpdclient playlist callbacks *****************************************/
+
+#define PLAYLIST_EVENT_UPDATED 0x01
+#define PLAYLIST_EVENT_CLEAR 0x02
+#define PLAYLIST_EVENT_DELETE 0x03
+#define PLAYLIST_EVENT_ADD 0x04
+#define PLAYLIST_EVENT_MOVE 0x05
+
+
+typedef void (*mpdc_list_cb_t) (mpdclient_t *c, int event, gpointer data);
+
+/* install a playlist callback function */
+void mpdclient_install_playlist_callback(mpdclient_t *c, mpdc_list_cb_t cb);
+
+/* remove a playlist callback function */
+void mpdclient_remove_playlist_callback(mpdclient_t *c, mpdc_list_cb_t cb);
+
+
+/* issue a playlist callback */
+void mpdclient_playlist_callback(mpdclient_t *c, int event, gpointer data);
+
+
+/*** filelist functions ***************************************************/
+mpdclient_filelist_t *mpdclient_filelist_free(mpdclient_filelist_t *filelist);
+mpdclient_filelist_t *mpdclient_filelist_get(mpdclient_t *c, gchar *path);
+mpdclient_filelist_t *mpdclient_filelist_update(mpdclient_t *c,
+ mpdclient_filelist_t *flist);
+
+#define HIGHLIGHT (0x01)
+void mpdclient_filelist_set_flags(mpdclient_filelist_t *flist,
+ mpd_Song *song,
+ guint flags);
+
+void mpdclient_filelist_clear_flags(mpdclient_filelist_t *flist);
+void mpdclient_filelist_clear_flags(mpdclient_filelist_t *flist);
+filelist_entry_t *mpdclient_filelist_find_song(mpdclient_filelist_t *flist,
+ mpd_Song *song);
+
+/*** mpdclient browse callbacks ********************************************/
+
+#define BROWSE_DB_UPDATED 0x01
+#define BROWSE_PLAYLIST_SAVED 0x02
+#define BROWSE_PLAYLIST_DELETED 0x03
+
+
+/* install a playlist callback function */
+void mpdclient_install_browse_callback(mpdclient_t *c, mpdc_list_cb_t cb);
+
+/* remove a playlist callback function */
+void mpdclient_remove_browse_callback(mpdclient_t *c, mpdc_list_cb_t cb);
+
+
+/* issue a playlist callback */
+void mpdclient_browse_callback(mpdclient_t *c, int event, gpointer data);
+
+
+#endif
diff --git a/src/ncmpc.h b/src/ncmpc.h
index 93e48d541..6bbb745fb 100644
--- a/src/ncmpc.h
+++ b/src/ncmpc.h
@@ -6,9 +6,9 @@
#endif
#ifdef DEBUG
-#define D(x) x
+#define D(x, args...) fprintf(stderr, x, ##args)
#else
-#define D(x)
+#define D(x,...)
#endif
/* i18n */
@@ -35,5 +35,10 @@
/* time in milliseconds before trying to reconnect (int) */
#define MPD_RECONNECT_TIME 1000
+/* song format - list window */
+#define LIST_FORMAT "%name%|[%artist% - ]%title%|%file%"
+
+/* song format - status window */
+#define STATUS_FORMAT "[%artist% - ]%title%|%basename%"
#endif /* NCMPC_H */
diff --git a/src/screen.c b/src/screen.c
index d50e5925f..76d04fa22 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -30,27 +30,28 @@
#include "config.h"
#include "ncmpc.h"
#include "support.h"
-#include "libmpdclient.h"
-#include "mpc.h"
+#include "mpdclient.h"
#include "command.h"
#include "options.h"
#include "colors.h"
+#include "strfsong.h"
#include "wreadln.h"
#include "screen.h"
-#include "screen_play.h"
-#include "screen_file.h"
-#include "screen_help.h"
-#include "screen_search.h"
#include "screen_utils.h"
#define ENABLE_STATUS_LINE_CLOCK
#define ENABLE_SCROLLING
-#define DEFAULT_CROSSFADE_TIME 10
+#define CROSSFADE_TIME 10
#define STATUS_MESSAGE_TIMEOUT 3
#define STATUS_LINE_MAX_SIZE 512
+/* screens */
+extern screen_functions_t *get_screen_playlist(void);
+extern screen_functions_t *get_screen_browse(void);
+extern screen_functions_t *get_screen_help(void);
+
#ifdef ENABLE_KEYDEF_SCREEN
extern screen_functions_t *get_screen_keydef(void);
#endif
@@ -58,13 +59,15 @@ extern screen_functions_t *get_screen_keydef(void);
extern screen_functions_t *get_screen_clock(void);
#endif
-
static gboolean welcome = TRUE;
static screen_t *screen = NULL;
static screen_functions_t *mode_fn = NULL;
+static int seek_id = -1;
+static int seek_target_time = 0;
+
static void
-switch_screen_mode(screen_mode_t new_mode, mpd_client_t *c)
+switch_screen_mode(screen_mode_t new_mode, mpdclient_t *c)
{
if( new_mode == screen->mode )
return;
@@ -80,7 +83,7 @@ switch_screen_mode(screen_mode_t new_mode, mpd_client_t *c)
mode_fn = get_screen_playlist();
break;
case SCREEN_FILE_WINDOW:
- mode_fn = get_screen_file();
+ mode_fn = get_screen_browse();
break;
case SCREEN_HELP_WINDOW:
mode_fn = get_screen_help();
@@ -110,7 +113,7 @@ switch_screen_mode(screen_mode_t new_mode, mpd_client_t *c)
}
static void
-paint_top_window(char *header, mpd_client_t *c, int clear)
+paint_top_window(char *header, mpdclient_t *c, int clear)
{
char flags[4];
static int prev_volume = -1;
@@ -189,7 +192,7 @@ paint_top_window(char *header, mpd_client_t *c, int clear)
}
static void
-paint_progress_window(mpd_client_t *c)
+paint_progress_window(mpdclient_t *c)
{
double p;
int width;
@@ -203,8 +206,8 @@ paint_progress_window(mpd_client_t *c)
return;
}
- if( c->seek_song_id == c->song_id )
- elapsedTime = c->seek_target_time;
+ if( c->song && seek_id == c->song->id )
+ elapsedTime = seek_target_time;
p = ((double) elapsedTime) / ((double) c->status->totalTime);
@@ -219,12 +222,13 @@ paint_progress_window(mpd_client_t *c)
}
static void
-paint_status_window(mpd_client_t *c)
+paint_status_window(mpdclient_t *c)
{
WINDOW *w = screen->status_window.w;
mpd_Status *status = c->status;
mpd_Song *song = c->song;
int elapsedTime = c->status->elapsedTime;
+ char *str = NULL;
int x = 0;
if( time(NULL) - screen->status_timestamp <= STATUS_MESSAGE_TIMEOUT )
@@ -238,16 +242,21 @@ paint_status_window(mpd_client_t *c)
switch(status->state)
{
case MPD_STATUS_STATE_PLAY:
- waddstr(w, _("Playing:"));
+ str = _("Playing:");
break;
case MPD_STATUS_STATE_PAUSE:
- waddstr(w, _("[Paused]"));
+ str = _("[Paused]");
break;
case MPD_STATUS_STATE_STOP:
default:
break;
}
- x += 9;
+
+ if( str )
+ {
+ waddstr(w, str);
+ x += strlen(str)+1;
+ }
/* create time string */
memset(screen->buf, 0, screen->buf_size);
@@ -255,8 +264,8 @@ paint_status_window(mpd_client_t *c)
{
if( status->totalTime > 0 )
{
- if( c->seek_song_id == c->song_id )
- elapsedTime = c->seek_target_time;
+ if( seek_id == c->song->id )
+ elapsedTime = seek_target_time;
snprintf(screen->buf, screen->buf_size,
" [%i:%02i/%i:%02i]",
elapsedTime/60, elapsedTime%60,
@@ -273,18 +282,21 @@ paint_status_window(mpd_client_t *c)
time_t timep;
time(&timep);
- /* Note: setlocale(LC_TIME,"") should be used first */
- //strftime(screen->buf, screen->buf_size, "%x - %X ",localtime(&timep));
strftime(screen->buf, screen->buf_size, "%X ",localtime(&timep));
}
#endif
/* display song */
- if( (IS_PLAYING(status->state) || IS_PAUSED(status->state)) && song )
+ if( (IS_PLAYING(status->state) || IS_PAUSED(status->state)) )
{
- char *songname = mpc_get_song_name(song);
+ char songname[STATUS_LINE_MAX_SIZE];
int width = COLS-x-strlen(screen->buf);
+ if( song )
+ strfsong(songname, STATUS_LINE_MAX_SIZE, STATUS_FORMAT, song);
+ else
+ songname[0] = '\0';
+
colors_use(w, COLOR_STATUS);
#ifdef ENABLE_SCROLLING
if( strlen(songname) > width )
@@ -361,12 +373,7 @@ screen_resize(void)
{
GList *list;
-#ifdef DEBUG
- fprintf(stderr, "Resize rows %d->%d, cols %d->%d\n",
- screen->rows, LINES,
- screen->cols, COLS);
-#endif
-
+ D("Resize rows %d->%d, cols %d->%d\n",screen->rows,LINES,screen->cols,COLS);
if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
{
screen_exit();
@@ -447,7 +454,7 @@ screen_status_printf(char *format, ...)
}
int
-screen_init(void)
+screen_init(mpdclient_t *c)
{
GList *list;
@@ -544,7 +551,7 @@ screen_init(void)
screen->screen_list = g_list_append(screen->screen_list,
(gpointer) get_screen_playlist());
screen->screen_list = g_list_append(screen->screen_list,
- (gpointer) get_screen_file());
+ (gpointer) get_screen_browse());
screen->screen_list = g_list_append(screen->screen_list,
(gpointer) get_screen_help());
#ifdef ENABLE_KEYDEF_SCREEN
@@ -570,6 +577,8 @@ screen_init(void)
}
mode_fn = get_screen_playlist();
+ if( mode_fn && mode_fn->open )
+ mode_fn->open(screen, c);
/* initialize wreadln */
wrln_resize_callback = screen_resize;
@@ -579,7 +588,7 @@ screen_init(void)
}
void
-screen_paint(mpd_client_t *c)
+screen_paint(mpdclient_t *c)
{
/* paint the title/header window */
if( mode_fn && mode_fn->get_title )
@@ -602,7 +611,7 @@ screen_paint(mpd_client_t *c)
}
void
-screen_update(mpd_client_t *c)
+screen_update(mpdclient_t *c)
{
static int repeat = -1;
static int random = -1;
@@ -633,7 +642,10 @@ screen_update(mpd_client_t *c)
if( crossfade != c->status->crossfade )
screen_status_printf(_("Crossfade %d seconds"), c->status->crossfade);
if( dbupdate && dbupdate != c->status->updatingDb )
- screen_status_printf(_("Database updated!"));
+ {
+ screen_status_printf(_("Database updated!"));
+ mpdclient_browse_callback(c, BROWSE_DB_UPDATED, NULL);
+ }
repeat = c->status->repeat;
random = c->status->random;
@@ -677,26 +689,22 @@ screen_update(mpd_client_t *c)
}
void
-screen_idle(mpd_client_t *c)
+screen_idle(mpdclient_t *c)
{
- if( c->seek_song_id == c->song_id &&
+ if( c->song && seek_id == c->song->id &&
(screen->last_cmd == CMD_SEEK_FORWARD ||
screen->last_cmd == CMD_SEEK_BACKWARD) )
{
- mpd_sendSeekCommand(c->connection,
- c->seek_song_id,
- c->seek_target_time);
- mpd_finishCommand(c->connection);
+ mpdclient_cmd_seek(c, seek_id, seek_target_time);
}
screen->last_cmd = CMD_NONE;
- c->seek_song_id = -1;
+ seek_id = -1;
}
void
-screen_cmd(mpd_client_t *c, command_t cmd)
+screen_cmd(mpdclient_t *c, command_t cmd)
{
- int n = 0;
screen_mode_t new_mode = screen->mode;
screen->input_timestamp = time(NULL);
@@ -709,118 +717,82 @@ screen_cmd(mpd_client_t *c, command_t cmd)
switch(cmd)
{
case CMD_PLAY:
- if( screen->mode == SCREEN_PLAY_WINDOW )
- n = play_get_selected();
- else
- n = -1;
- mpd_sendPlayCommand(c->connection, n);
- mpd_finishCommand(c->connection);
+ mpdclient_cmd_play(c, MPD_PLAY_AT_BEGINNING);
break;
case CMD_PAUSE:
- mpd_sendPauseCommand(c->connection);
- mpd_finishCommand(c->connection);
+ mpdclient_cmd_pause(c, !IS_PAUSED(c->status->state));
break;
case CMD_STOP:
- mpd_sendStopCommand(c->connection);
- mpd_finishCommand(c->connection);
+ mpdclient_cmd_stop(c);
break;
case CMD_SEEK_FORWARD:
if( !IS_STOPPED(c->status->state) )
{
- if( c->seek_song_id != c->song_id )
+ if( c->song && seek_id != c->song->id )
{
- c->seek_song_id = c->song_id;
- c->seek_target_time = c->status->elapsedTime;
+ seek_id = c->song->id;
+ seek_target_time = c->status->elapsedTime;
}
- c->seek_target_time++;
- if( c->seek_target_time < c->status->totalTime )
+ seek_target_time++;
+ if( seek_target_time < c->status->totalTime )
break;
- c->seek_target_time=0;
+ seek_target_time=0;
}
/* fall through... */
case CMD_TRACK_NEXT:
if( !IS_STOPPED(c->status->state) )
- {
- mpd_sendNextCommand(c->connection);
- mpd_finishCommand(c->connection);
- }
+ mpdclient_cmd_next(c);
break;
case CMD_SEEK_BACKWARD:
if( !IS_STOPPED(c->status->state) )
{
- if( c->seek_song_id != c->song_id )
+ if( seek_id != c->song->id )
{
- c->seek_song_id = c->song_id;
- c->seek_target_time = c->status->elapsedTime;
+ seek_id = c->song->id;
+ seek_target_time = c->status->elapsedTime;
}
- c->seek_target_time--;
- if( c->seek_target_time < 0 )
- c->seek_target_time=0;
+ seek_target_time--;
+ if( seek_target_time < 0 )
+ seek_target_time=0;
}
break;
case CMD_TRACK_PREVIOUS:
if( !IS_STOPPED(c->status->state) )
- {
- mpd_sendPrevCommand(c->connection);
- mpd_finishCommand(c->connection);
- }
+ mpdclient_cmd_prev(c);
break;
case CMD_SHUFFLE:
- mpd_sendShuffleCommand(c->connection);
- mpd_finishCommand(c->connection);
- screen_status_message(_("Shuffled playlist!"));
+ if( mpdclient_cmd_shuffle(c) == 0 )
+ screen_status_message(_("Shuffled playlist!"));
break;
case CMD_CLEAR:
- mpd_sendClearCommand(c->connection);
- mpd_finishCommand(c->connection);
- file_clear_highlights(c);
- screen_status_message(_("Cleared playlist!"));
+ if( mpdclient_cmd_clear(c) == 0 )
+ screen_status_message(_("Cleared playlist!"));
break;
case CMD_REPEAT:
- n = !c->status->repeat;
- mpd_sendRepeatCommand(c->connection, n);
- mpd_finishCommand(c->connection);
+ mpdclient_cmd_repeat(c, !c->status->repeat);
break;
case CMD_RANDOM:
- n = !c->status->random;
- mpd_sendRandomCommand(c->connection, n);
- mpd_finishCommand(c->connection);
+ mpdclient_cmd_random(c, !c->status->random);
break;
case CMD_CROSSFADE:
- if( c->status->crossfade )
- n = 0;
- else
- n = DEFAULT_CROSSFADE_TIME;
- mpd_sendCrossfadeCommand(c->connection, n);
- mpd_finishCommand(c->connection);
+ mpdclient_cmd_crossfade(c, c->status->crossfade ? 0 : CROSSFADE_TIME);
break;
case CMD_DB_UPDATE:
if( !c->status->updatingDb )
{
- mpd_sendUpdateCommand(c->connection);
- n = mpd_getUpdateId(c->connection);
- mpd_finishCommand(c->connection);
- if( !mpc_error(c) )
- screen_status_printf(_("Database update started [%d]"), n);
+ if( mpdclient_cmd_db_update(c)==0 )
+ screen_status_printf(_("Database update started!"));
}
else
screen_status_printf(_("Database update running..."));
break;
case CMD_VOLUME_UP:
if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume<100 )
- {
- c->status->volume=c->status->volume+1;
- mpd_sendSetvolCommand(c->connection, c->status->volume );
- mpd_finishCommand(c->connection);
- }
+ mpdclient_cmd_volume(c, ++c->status->volume);
break;
case CMD_VOLUME_DOWN:
if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume>0 )
- {
- c->status->volume=c->status->volume-1;
- mpd_sendSetvolCommand(c->connection, c->status->volume );
- mpd_finishCommand(c->connection);
- }
+ mpdclient_cmd_volume(c, --c->status->volume);
break;
case CMD_TOGGLE_FIND_WRAP:
options.find_wrap = !options.find_wrap;
diff --git a/src/screen.h b/src/screen.h
index fe843daa6..262c6bd7e 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -63,12 +63,12 @@ typedef struct
typedef void (*screen_init_fn_t) (WINDOW *w, int cols, int rows);
typedef void (*screen_exit_fn_t) (void);
-typedef void (*screen_open_fn_t) (screen_t *screen, mpd_client_t *c);
+typedef void (*screen_open_fn_t) (screen_t *screen, mpdclient_t *c);
typedef void (*screen_close_fn_t) (void);
typedef void (*screen_resize_fn_t) (int cols, int rows);
-typedef void (*screen_paint_fn_t) (screen_t *screen, mpd_client_t *c);
-typedef void (*screen_update_fn_t) (screen_t *screen, mpd_client_t *c);
-typedef int (*screen_cmd_fn_t) (screen_t *scr, mpd_client_t *c, command_t cmd);
+typedef void (*screen_paint_fn_t) (screen_t *screen, mpdclient_t *c);
+typedef void (*screen_update_fn_t) (screen_t *screen, mpdclient_t *c);
+typedef int (*screen_cmd_fn_t) (screen_t *scr, mpdclient_t *c, command_t cmd);
typedef char * (*screen_title_fn_t) (char *s, size_t size);
typedef list_window_t * (*screen_get_lw_fn_t) (void);
@@ -88,15 +88,15 @@ typedef struct
} screen_functions_t;
-int screen_init(void);
+int screen_init(mpdclient_t *c);
int screen_exit(void);
void screen_resize(void);
void screen_status_message(char *msg);
void screen_status_printf(char *format, ...);
char *screen_error(void);
-void screen_paint(mpd_client_t *c);
-void screen_update(mpd_client_t *c);
-void screen_idle(mpd_client_t *c);
-void screen_cmd(mpd_client_t *c, command_t cmd);
+void screen_paint(mpdclient_t *c);
+void screen_update(mpdclient_t *c);
+void screen_idle(mpdclient_t *c);
+void screen_cmd(mpdclient_t *c, command_t cmd);
#endif
diff --git a/src/screen_clock.c b/src/screen_clock.c
index 3fe2ec1c9..d3d492559 100644
--- a/src/screen_clock.c
+++ b/src/screen_clock.c
@@ -1,4 +1,6 @@
/*
+ * $Id$
+ *
* This file is based on the 'Grand digital clock' (gdc.c) shipped with
* ncurses.
*/
@@ -13,9 +15,8 @@
#ifdef ENABLE_CLOCK_SCREEN
#include "ncmpc.h"
-#include "libmpdclient.h"
+#include "mpdclient.h"
#include "options.h"
-#include "mpc.h"
#include "command.h"
#include "screen.h"
#include "screen_utils.h"
@@ -133,7 +134,7 @@ clock_exit(void)
}
static void
-clock_open(screen_t *screen, mpd_client_t *c)
+clock_open(screen_t *screen, mpdclient_t *c)
{
int j;
@@ -154,7 +155,7 @@ clock_title(char *str, size_t size)
}
static void
-clock_update(screen_t *screen, mpd_client_t *c)
+clock_update(screen_t *screen, mpdclient_t *c)
{
time_t now;
struct tm *tm;
@@ -228,7 +229,7 @@ clock_update(screen_t *screen, mpd_client_t *c)
}
static void
-clock_paint(screen_t *screen, mpd_client_t *c)
+clock_paint(screen_t *screen, mpdclient_t *c)
{
/* this seems to be a better way to clear the window than wclear() ?! */
wmove(win.w, 0, 0);
@@ -239,7 +240,7 @@ clock_paint(screen_t *screen, mpd_client_t *c)
static int
-clock_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
+clock_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
{
return 0;
}
diff --git a/src/screen_file.c b/src/screen_file.c
index 8b7577fdf..f4a8c3dc0 100644
--- a/src/screen_file.c
+++ b/src/screen_file.c
@@ -27,55 +27,180 @@
#include "config.h"
#include "ncmpc.h"
#include "support.h"
-#include "libmpdclient.h"
-#include "mpc.h"
+#include "mpdclient.h"
+#include "strfsong.h"
#include "command.h"
#include "screen.h"
#include "screen_utils.h"
-#include "screen_play.h"
-#include "screen_file.h"
-#define BUFSIZE 1024
-#define TITLESIZE 256
#define USE_OLD_LAYOUT
-static list_window_t *lw;
-static mpd_client_t *mpc = NULL;
+#define BUFSIZE 1024
+
+#define HIGHLIGHT (0x01)
+
+
+static list_window_t *lw = NULL;
+static GList *lw_state_list = NULL;
+static mpdclient_filelist_t *filelist = NULL;
+
+
+
+/* clear the highlight flag for all items in the filelist */
+static void
+clear_highlights(mpdclient_filelist_t *filelist)
+{
+ GList *list = g_list_first(filelist->list);
+
+ while( list )
+ {
+ filelist_entry_t *entry = list->data;
+
+ entry->flags &= ~HIGHLIGHT;
+ list = list->next;
+ }
+}
+
+/* change the highlight flag for a song */
+static void
+set_highlight(mpdclient_filelist_t *filelist, mpd_Song *song, int highlight)
+{
+ GList *list = g_list_first(filelist->list);
+
+ if( !song )
+ return;
+
+ while( list )
+ {
+ filelist_entry_t *entry = list->data;
+ mpd_InfoEntity *entity = entry->entity;
+
+ if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
+ {
+ mpd_Song *song2 = entity->info.song;
+
+ if( strcmp(song->file, song2->file) == 0 )
+ {
+ if(highlight)
+ entry->flags |= HIGHLIGHT;
+ else
+ entry->flags &= ~HIGHLIGHT;
+ }
+ }
+ list = list->next;
+ }
+}
+
+/* sync highlight flags with playlist */
+static void
+sync_highlights(mpdclient_t *c, mpdclient_filelist_t *filelist)
+{
+ GList *list = g_list_first(filelist->list);
+
+ while(list)
+ {
+ filelist_entry_t *entry = list->data;
+ mpd_InfoEntity *entity = entry->entity;
+
+ if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
+ {
+ mpd_Song *song = entity->info.song;
+
+ if( playlist_get_index_from_file(c, song->file) >= 0 )
+ entry->flags |= HIGHLIGHT;
+ else
+ entry->flags &= ~HIGHLIGHT;
+ }
+ list=list->next;
+ }
+}
+
+/* the db have changed -> update the filelist */
+static void
+file_changed_callback(mpdclient_t *c, int event, gpointer data)
+{
+ D("screen_file.c> filelist_callback() [%d]\n", event);
+ filelist = mpdclient_filelist_update(c, filelist);
+ sync_highlights(c, filelist);
+ list_window_check_selected(lw, filelist->length);
+}
+
+/* the playlist have been updated -> fix highlights */
+static void
+playlist_changed_callback(mpdclient_t *c, int event, gpointer data)
+{
+ D("screen_file.c> playlist_callback() [%d]\n", event);
+ switch(event)
+ {
+ case PLAYLIST_EVENT_CLEAR:
+ clear_highlights(filelist);
+ break;
+ case PLAYLIST_EVENT_ADD:
+ set_highlight(filelist, (mpd_Song *) data, 1);
+ break;
+ case PLAYLIST_EVENT_DELETE:
+ set_highlight(filelist, (mpd_Song *) data, 0);
+ break;
+ case PLAYLIST_EVENT_MOVE:
+ break;
+ default:
+ sync_highlights(c, filelist);
+ break;
+ }
+}
+
+/* store current state when entering a subdirectory */
+static void
+push_lw_state(void)
+{
+ list_window_t *tmp = g_malloc(sizeof(list_window_t));
+
+ memcpy(tmp, lw, sizeof(list_window_t));
+ lw_state_list = g_list_prepend(lw_state_list, (gpointer) tmp);
+}
+
+/* get previous state when leaving a directory */
+static void
+pop_lw_state(void)
+{
+ if( lw_state_list )
+ {
+ list_window_t *tmp = lw_state_list->data;
+
+ memcpy(lw, tmp, sizeof(list_window_t));
+ g_free(tmp);
+ lw_state_list->data = NULL;
+ lw_state_list = g_list_delete_link(lw_state_list, lw_state_list);
+ }
+}
+/* list_window callback */
static char *
list_callback(int index, int *highlight, void *data)
{
static char buf[BUFSIZE];
- mpd_client_t *c = (mpd_client_t *) data;
+ //mpdclient_t *c = (mpdclient_t *) data;
filelist_entry_t *entry;
mpd_InfoEntity *entity;
*highlight = 0;
- if( (entry=(filelist_entry_t *) g_list_nth_data(c->filelist, index))==NULL )
+ if( (entry=(filelist_entry_t *)g_list_nth_data(filelist->list,index))==NULL )
return NULL;
entity = entry->entity;
- *highlight = entry->selected;
+ *highlight = (entry->flags & HIGHLIGHT);
if( entity == NULL )
{
-#ifdef USE_OLD_LAYOUT
return "[..]";
-#else
- return "d ..";
-#endif
}
if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY )
{
mpd_Directory *dir = entity->info.directory;
char *dirname = utf8_to_locale(basename(dir->path));
-#ifdef USE_OLD_LAYOUT
snprintf(buf, BUFSIZE, "[%s]", dirname);
-#else
- snprintf(buf, BUFSIZE, "d %s", dirname);
-#endif
g_free(dirname);
return buf;
}
@@ -83,13 +208,8 @@ list_callback(int index, int *highlight, void *data)
{
mpd_Song *song = entity->info.song;
-#ifdef USE_OLD_LAYOUT
- return mpc_get_song_name(song);
-#else
- snprintf(buf, BUFSIZE, "m %s", mpc_get_song_name(song));
+ strfsong(buf, BUFSIZE, LIST_FORMAT, song);
return buf;
-#endif
-
}
else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE )
{
@@ -98,8 +218,8 @@ list_callback(int index, int *highlight, void *data)
#ifdef USE_OLD_LAYOUT
snprintf(buf, BUFSIZE, "*%s*", filename);
-#else
- snprintf(buf, BUFSIZE, "p %s", filename);
+#else
+ snprintf(buf, BUFSIZE, "<Playlist> %s", filename);
#endif
g_free(filename);
return buf;
@@ -107,56 +227,62 @@ list_callback(int index, int *highlight, void *data)
return "Error: Unknow entry!";
}
+/* chdir */
static int
-change_directory(screen_t *screen, mpd_client_t *c, filelist_entry_t *entry)
+change_directory(screen_t *screen, mpdclient_t *c, filelist_entry_t *entry)
{
mpd_InfoEntity *entity = entry->entity;
+ gchar *path = NULL;
if( entity==NULL )
{
- char *parent = g_path_get_dirname(c->cwd);
-
- if( strcmp(parent,".") == 0 )
+ /* return to parent */
+ char *parent = g_path_get_dirname(filelist->path);
+ if( strcmp(parent, ".") == 0 )
{
parent[0] = '\0';
}
- if( c->cwd )
- g_free(c->cwd);
- c->cwd = parent;
+ path = g_strdup(parent);
+ list_window_reset(lw);
+ /* restore previous list window state */
+ pop_lw_state();
}
else
if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY)
{
+ /* enter sub */
mpd_Directory *dir = entity->info.directory;
- if( c->cwd )
- g_free(c->cwd);
- c->cwd = g_strdup(dir->path);
+ path = utf8_to_locale(dir->path);
+ /* save current list window state */
+ push_lw_state();
+ list_window_reset(lw);
}
else
return -1;
-
- mpc_update_filelist(c);
- list_window_reset(lw);
+
+ filelist = mpdclient_filelist_free(filelist);
+ filelist = mpdclient_filelist_get(c, path);
+ sync_highlights(c, filelist);
+ list_window_check_selected(lw, filelist->length);
+ g_free(path);
return 0;
}
static int
-load_playlist(screen_t *screen, mpd_client_t *c, filelist_entry_t *entry)
+load_playlist(screen_t *screen, mpdclient_t *c, filelist_entry_t *entry)
{
mpd_InfoEntity *entity = entry->entity;
mpd_PlaylistFile *plf = entity->info.playlistFile;
- char *filename = utf8_to_locale(basename(plf->path));
-
- mpd_sendLoadCommand(c->connection, plf->path);
- mpd_finishCommand(c->connection);
+ char *filename = utf8_to_locale(plf->path);
- screen_status_printf(_("Loading playlist %s..."), filename);
+ if( mpdclient_cmd_load_playlist(c, plf->path) == 0 )
+ screen_status_printf(_("Loading playlist %s..."), basename(filename));
g_free(filename);
return 0;
}
static int
-handle_delete(screen_t *screen, mpd_client_t *c)
+handle_delete(screen_t *screen, mpdclient_t *c)
{
filelist_entry_t *entry;
mpd_InfoEntity *entity;
@@ -164,7 +290,7 @@ handle_delete(screen_t *screen, mpd_client_t *c)
char *str, buf[BUFSIZE];
int key;
- entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected);
+ entry=( filelist_entry_t *) g_list_nth_data(filelist->list,lw->selected);
if( entry==NULL || entry->entity==NULL )
return -1;
@@ -190,30 +316,23 @@ handle_delete(screen_t *screen, mpd_client_t *c)
return 0;
}
- mpd_sendRmCommand(c->connection, plf->path);
- mpd_finishCommand(c->connection);
- if( mpc_error(c))
+ if( mpdclient_cmd_delete_playlist(c, plf->path) )
{
- str = utf8_to_locale(mpc_error_str(c));
- screen_status_printf("Error: %s", str);
- g_free(str);
beep();
return -1;
}
screen_status_printf(_("Playlist deleted!"));
- mpc_update_filelist(c);
- list_window_check_selected(lw, c->filelist_length);
return 0;
}
static int
-handle_play_cmd(screen_t *screen, mpd_client_t *c)
+handle_enter(screen_t *screen, mpdclient_t *c)
{
filelist_entry_t *entry;
mpd_InfoEntity *entity;
- entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected);
+ entry = ( filelist_entry_t *) g_list_nth_data(filelist->list, lw->selected);
if( entry==NULL )
return -1;
@@ -225,8 +344,12 @@ handle_play_cmd(screen_t *screen, mpd_client_t *c)
return -1;
}
+
+/* NOTE - The add_directory functions should move to mpdclient.c */
+extern gint mpdclient_finish_command(mpdclient_t *c);
+
static int
-add_directory(mpd_client_t *c, char *dir)
+add_directory(mpdclient_t *c, char *dir)
{
mpd_InfoEntity *entity;
GList *subdir_list = NULL;
@@ -257,7 +380,8 @@ add_directory(mpd_client_t *c, char *dir)
mpd_freeInfoEntity(entity);
}
mpd_sendCommandListEnd(c->connection);
- mpd_finishCommand(c->connection);
+ mpdclient_finish_command(c);
+ c->need_update = TRUE;
list = g_list_first(subdir_list);
while( list!=NULL )
@@ -276,14 +400,17 @@ add_directory(mpd_client_t *c, char *dir)
}
static int
-handle_select(screen_t *screen, mpd_client_t *c)
+handle_select(screen_t *screen, mpdclient_t *c)
{
filelist_entry_t *entry;
- entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected);
+ entry=( filelist_entry_t *) g_list_nth_data(filelist->list, lw->selected);
if( entry==NULL || entry->entity==NULL)
return -1;
+ if( entry->entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE )
+ return load_playlist(screen, c, entry);
+
if( entry->entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY )
{
mpd_Directory *dir = entry->entity->info.directory;
@@ -294,18 +421,24 @@ handle_select(screen_t *screen, mpd_client_t *c)
if( entry->entity->type!=MPD_INFO_ENTITY_TYPE_SONG )
return -1;
- entry->selected = !entry->selected;
+ if( entry->flags & HIGHLIGHT )
+ entry->flags &= ~HIGHLIGHT;
+ else
+ entry->flags |= HIGHLIGHT;
- if( entry->selected )
+ if( entry->flags & HIGHLIGHT )
{
if( entry->entity->type==MPD_INFO_ENTITY_TYPE_SONG )
{
mpd_Song *song = entry->entity->info.song;
- playlist_add_song(c, song);
-
- screen_status_printf(_("Adding \'%s\' to playlist\n"),
- mpc_get_song_name(song));
+ if( mpdclient_cmd_add(c, song) == 0 )
+ {
+ char buf[BUFSIZE];
+
+ strfsong(buf, BUFSIZE, LIST_FORMAT, song);
+ screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
+ }
}
}
else
@@ -317,10 +450,10 @@ handle_select(screen_t *screen, mpd_client_t *c)
if( song )
{
- int index = mpc_playlist_get_song_index(c, song->file);
+ int index = playlist_get_index_from_file(c, song->file);
- while( (index=mpc_playlist_get_song_index(c, song->file))>=0 )
- playlist_delete_song(c, index);
+ while( (index=playlist_get_index_from_file(c, song->file))>=0 )
+ mpdclient_cmd_delete(c, index);
}
}
}
@@ -328,53 +461,64 @@ handle_select(screen_t *screen, mpd_client_t *c)
}
static void
-file_init(WINDOW *w, int cols, int rows)
+browse_init(WINDOW *w, int cols, int rows)
{
lw = list_window_init(w, cols, rows);
}
static void
-file_resize(int cols, int rows)
+browse_resize(int cols, int rows)
{
lw->cols = cols;
lw->rows = rows;
}
static void
-file_exit(void)
+browse_exit(void)
{
+ if( lw_state_list )
+ {
+ GList *list = lw_state_list;
+ while( list )
+ {
+ g_free(list->data);
+ list->data = NULL;
+ list = list->next;
+ }
+ g_list_free(lw_state_list);
+ lw_state_list = NULL;
+
+ }
+ if( filelist )
+ filelist = mpdclient_filelist_free(filelist);
list_window_free(lw);
}
static void
-file_open(screen_t *screen, mpd_client_t *c)
+browse_open(screen_t *screen, mpdclient_t *c)
{
- if( c->filelist == NULL )
+ if( filelist == NULL )
{
- mpc_update_filelist(c);
+ filelist = mpdclient_filelist_get(c, "");
+ mpdclient_install_playlist_callback(c, playlist_changed_callback);
+ mpdclient_install_browse_callback(c, file_changed_callback);
}
- mpc = c;
}
static void
-file_close(void)
+browse_close(void)
{
}
static char *
-file_title(char *str, size_t size)
+browse_title(char *str, size_t size)
{
- char *tmp;
-
- tmp = utf8_to_locale(basename(mpc->cwd));
- snprintf(str, size, _("Browse: %s"), tmp);
- g_free(tmp);
-
+ snprintf(str, size, _("Browse: %s"), basename(filelist->path));
return str;
}
static void
-file_paint(screen_t *screen, mpd_client_t *c)
+browse_paint(screen_t *screen, mpdclient_t *c)
{
lw->clear = 1;
@@ -383,12 +527,12 @@ file_paint(screen_t *screen, mpd_client_t *c)
}
static void
-file_update(screen_t *screen, mpd_client_t *c)
+browse_update(screen_t *screen, mpdclient_t *c)
{
- if( c->filelist_updated )
+ if( filelist->updated )
{
- file_paint(screen, c);
- c->filelist_updated = 0;
+ browse_paint(screen, c);
+ filelist->updated = FALSE;
return;
}
list_window_paint(lw, list_callback, (void *) c);
@@ -397,12 +541,12 @@ file_update(screen_t *screen, mpd_client_t *c)
static int
-file_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
+browse_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
{
switch(cmd)
{
case CMD_PLAY:
- handle_play_cmd(screen, c);
+ handle_enter(screen, c);
return 1;
case CMD_SELECT:
if( handle_select(screen, c) == 0 )
@@ -415,8 +559,8 @@ file_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
handle_delete(screen, c);
break;
case CMD_SCREEN_UPDATE:
- mpc_update_filelist(c);
- list_window_check_selected(lw, c->filelist_length);
+ filelist = mpdclient_filelist_update(c, filelist);
+ list_window_check_selected(lw, filelist->length);
screen_status_printf(_("Screen updated!"));
return 1;
case CMD_LIST_FIND:
@@ -424,12 +568,12 @@ file_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
case CMD_LIST_FIND_NEXT:
case CMD_LIST_RFIND_NEXT:
return screen_find(screen, c,
- lw, c->filelist_length,
+ lw, filelist->length,
cmd, list_callback);
default:
break;
}
- return list_window_cmd(lw, c->filelist_length, cmd);
+ return list_window_cmd(lw, filelist->length, cmd);
}
@@ -440,62 +584,24 @@ get_filelist_window()
}
-void
-file_clear_highlights(mpd_client_t *c)
-{
- GList *list = g_list_first(c->filelist);
-
- while( list )
- {
- filelist_entry_t *entry = list->data;
-
- entry->selected = 0;
- list = list->next;
- }
-}
-
-void
-file_set_highlight(mpd_client_t *c, mpd_Song *song, int highlight)
-{
- GList *list = g_list_first(c->filelist);
-
- if( !song )
- return;
-
- while( list )
- {
- filelist_entry_t *entry = list->data;
- mpd_InfoEntity *entity = entry->entity;
- if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
- {
- mpd_Song *song2 = entity->info.song;
-
- if( strcmp(song->file, song2->file) == 0 )
- {
- entry->selected = highlight;
- }
- }
- list = list->next;
- }
-}
screen_functions_t *
-get_screen_file(void)
+get_screen_browse(void)
{
static screen_functions_t functions;
memset(&functions, 0, sizeof(screen_functions_t));
- functions.init = file_init;
- functions.exit = file_exit;
- functions.open = file_open;
- functions.close = file_close;
- functions.resize = file_resize;
- functions.paint = file_paint;
- functions.update = file_update;
- functions.cmd = file_cmd;
+ functions.init = browse_init;
+ functions.exit = browse_exit;
+ functions.open = browse_open;
+ functions.close = browse_close;
+ functions.resize = browse_resize;
+ functions.paint = browse_paint;
+ functions.update = browse_update;
+ functions.cmd = browse_cmd;
functions.get_lw = get_filelist_window;
- functions.get_title = file_title;
+ functions.get_title = browse_title;
return &functions;
}
diff --git a/src/screen_file.h b/src/screen_file.h
deleted file mode 100644
index a7199a62e..000000000
--- a/src/screen_file.h
+++ /dev/null
@@ -1,7 +0,0 @@
-
-void file_set_highlight(mpd_client_t *c, mpd_Song *song, int hightlight);
-void file_clear_highlights(mpd_client_t *c);
-
-list_window_t *get_filelist_window(void);
-
-screen_functions_t *get_screen_file(void);
diff --git a/src/screen_help.c b/src/screen_help.c
index 8584bb7c9..2f042499f 100644
--- a/src/screen_help.c
+++ b/src/screen_help.c
@@ -25,12 +25,10 @@
#include "config.h"
#include "ncmpc.h"
-#include "libmpdclient.h"
-#include "mpc.h"
+#include "mpdclient.h"
#include "command.h"
#include "screen.h"
#include "screen_utils.h"
-#include "screen_help.h"
typedef struct
@@ -212,7 +210,7 @@ help_title(char *str, size_t size)
}
static void
-help_paint(screen_t *screen, mpd_client_t *c)
+help_paint(screen_t *screen, mpdclient_t *c)
{
lw->clear = 1;
list_window_paint(lw, list_callback, NULL);
@@ -220,7 +218,7 @@ help_paint(screen_t *screen, mpd_client_t *c)
}
static void
-help_update(screen_t *screen, mpd_client_t *c)
+help_update(screen_t *screen, mpdclient_t *c)
{
if( lw->repaint )
{
@@ -232,7 +230,7 @@ help_update(screen_t *screen, mpd_client_t *c)
static int
-help_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
+help_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
{
int retval;
diff --git a/src/screen_help.h b/src/screen_help.h
deleted file mode 100644
index ba2c57c8e..000000000
--- a/src/screen_help.h
+++ /dev/null
@@ -1,2 +0,0 @@
-
-screen_functions_t *get_screen_help(void);
diff --git a/src/screen_keydef.c b/src/screen_keydef.c
index 2dda43db9..809561b80 100644
--- a/src/screen_keydef.c
+++ b/src/screen_keydef.c
@@ -28,10 +28,9 @@
#ifdef ENABLE_KEYDEF_SCREEN
#include "ncmpc.h"
-#include "libmpdclient.h"
+#include "mpdclient.h"
#include "options.h"
#include "conf.h"
-#include "mpc.h"
#include "command.h"
#include "screen.h"
#include "screen_utils.h"
@@ -238,7 +237,7 @@ keydef_exit(void)
}
static void
-keydef_open(screen_t *screen, mpd_client_t *c)
+keydef_open(screen_t *screen, mpdclient_t *c)
{
if( cmds == NULL )
{
@@ -283,7 +282,7 @@ keydef_title(char *str, size_t size)
}
static void
-keydef_paint(screen_t *screen, mpd_client_t *c)
+keydef_paint(screen_t *screen, mpdclient_t *c)
{
lw->clear = 1;
list_window_paint(lw, list_callback, NULL);
@@ -291,7 +290,7 @@ keydef_paint(screen_t *screen, mpd_client_t *c)
}
static void
-keydef_update(screen_t *screen, mpd_client_t *c)
+keydef_update(screen_t *screen, mpdclient_t *c)
{
if( lw->repaint )
{
@@ -302,7 +301,7 @@ keydef_update(screen_t *screen, mpd_client_t *c)
}
static int
-keydef_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
+keydef_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
{
int length = LIST_LENGTH();
diff --git a/src/screen_play.c b/src/screen_play.c
index 9dc2a9651..73c0bc679 100644
--- a/src/screen_play.c
+++ b/src/screen_play.c
@@ -27,49 +27,71 @@
#include "ncmpc.h"
#include "options.h"
#include "support.h"
-#include "libmpdclient.h"
-#include "mpc.h"
+#include "mpdclient.h"
+#include "strfsong.h"
#include "command.h"
#include "screen.h"
#include "screen_utils.h"
-#include "screen_file.h"
-#include "screen_play.h"
-#define BUFSIZE 256
+#define MAX_SONG_LENGTH 512
static list_window_t *lw = NULL;
+static void
+playlist_changed_callback(mpdclient_t *c, int event, gpointer data)
+{
+ D("screen_play.c> playlist_callback() [%d]\n", event);
+ switch(event)
+ {
+ case PLAYLIST_EVENT_DELETE:
+ break;
+ case PLAYLIST_EVENT_MOVE:
+ lw->selected = *((int *) data);
+ break;
+ default:
+ break;
+ }
+ /* make shure the playlist is repainted */
+ lw->clear = 1;
+ lw->repaint = 1;
+ list_window_check_selected(lw, c->playlist.length);
+}
+
static char *
list_callback(int index, int *highlight, void *data)
{
- mpd_client_t *c = (mpd_client_t *) data;
+ static char songname[MAX_SONG_LENGTH];
+ mpdclient_t *c = (mpdclient_t *) data;
mpd_Song *song;
*highlight = 0;
- if( (song=mpc_playlist_get_song(c, index)) == NULL )
+ if( (song=playlist_get_song(c, index)) == NULL )
{
return NULL;
}
- if( index==c->song_id && !IS_STOPPED(c->status->state) )
+ if( c->song && song->id==c->song->id && !IS_STOPPED(c->status->state) )
{
*highlight = 1;
}
-
- return mpc_get_song_name2(song);
+ strfsong(songname, MAX_SONG_LENGTH, LIST_FORMAT, song);
+ return songname;
}
static int
-center_playing_item(screen_t *screen, mpd_client_t *c)
+center_playing_item(screen_t *screen, mpdclient_t *c)
{
- int length = c->playlist_length;
+ int length = c->playlist.length;
int offset = lw->selected-lw->start;
+ int index;
- if( !lw || length<lw->rows || IS_STOPPED(c->status->state) )
+ if( !lw || !c->song || length<lw->rows || IS_STOPPED(c->status->state) )
return 0;
/* try to center the song that are playing */
- lw->start = c->song_id-(lw->rows/2);
+ index = playlist_get_index(c, c->song);
+ D("Autocenter song id:%d pos:%d index:%d\n", c->song->id,c->song->pos,index);
+ lw->start = index-(lw->rows/2);
if( lw->start+lw->rows > length )
lw->start = length-lw->rows;
if( lw->start<0 )
@@ -86,47 +108,23 @@ center_playing_item(screen_t *screen, mpd_client_t *c)
}
static int
-handle_save_playlist(screen_t *screen, mpd_client_t *c)
+handle_save_playlist(screen_t *screen, mpdclient_t *c)
{
- char *filename, *filename_utf8;
+ char *filename;
filename=screen_getstr(screen->status_window.w, _("Save playlist as: "));
filename=trim(filename);
if( filename==NULL || filename[0]=='\0' )
return -1;
- /* convert filename to utf-8 */
- filename_utf8 = locale_to_utf8(filename);
/* send save command to mpd */
- mpd_sendSaveCommand(c->connection, filename_utf8);
- mpd_finishCommand(c->connection);
- g_free(filename_utf8);
- /* handle errors */
- if( mpc_error(c))
+ if( mpdclient_cmd_save_playlist(c, filename) )
{
- if( mpc_error_str(c) )
- {
- char *str = utf8_to_locale(mpc_error_str(c));
- screen_status_message(str);
- g_free(str);
- }
- else
- screen_status_printf(_("Error: Unable to save playlist as %s"),
- filename);
- mpd_clearError(c->connection);
beep();
return -1;
}
/* success */
screen_status_printf(_("Saved %s"), filename);
g_free(filename);
- /* update the file list if it has been initalized */
- if( c->filelist )
- {
- list_window_t *file_lw = get_filelist_window();
-
- mpc_update_filelist(c);
- list_window_check_selected(file_lw, c->filelist_length);
- }
return 0;
}
@@ -137,6 +135,18 @@ play_init(WINDOW *w, int cols, int rows)
}
static void
+play_open(screen_t *screen, mpdclient_t *c)
+{
+ static gboolean install_cb = TRUE;
+
+ if( install_cb )
+ {
+ mpdclient_install_playlist_callback(c, playlist_changed_callback);
+ install_cb = FALSE;
+ }
+}
+
+static void
play_resize(int cols, int rows)
{
lw->cols = cols;
@@ -162,7 +172,7 @@ play_title(char *str, size_t size)
}
static void
-play_paint(screen_t *screen, mpd_client_t *c)
+play_paint(screen_t *screen, mpdclient_t *c)
{
lw->clear = 1;
@@ -171,28 +181,28 @@ play_paint(screen_t *screen, mpd_client_t *c)
}
static void
-play_update(screen_t *screen, mpd_client_t *c)
+play_update(screen_t *screen, mpdclient_t *c)
{
if( options.auto_center )
{
static int prev_song_id = 0;
- if( prev_song_id != c->song_id )
+ if( c->song && prev_song_id != c->song->id )
{
center_playing_item(screen, c);
- prev_song_id = c->song_id;
+ prev_song_id = c->song->id;
}
}
- if( c->playlist_updated )
+ if( c->playlist.updated )
{
- if( lw->selected >= c->playlist_length )
- lw->selected = c->playlist_length-1;
- if( lw->start >= c->playlist_length )
+ if( lw->selected >= c->playlist.length )
+ lw->selected = c->playlist.length-1;
+ if( lw->start >= c->playlist.length )
list_window_reset(lw);
play_paint(screen, c);
- c->playlist_updated = 0;
+ c->playlist.updated = FALSE;
}
else if( lw->repaint || 1)
{
@@ -203,12 +213,15 @@ play_update(screen_t *screen, mpd_client_t *c)
}
static int
-play_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
+play_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
{
switch(cmd)
{
+ case CMD_PLAY:
+ mpdclient_cmd_play(c, lw->selected);
+ break;
case CMD_DELETE:
- playlist_delete_song(c, lw->selected);
+ mpdclient_cmd_delete(c, lw->selected);
return 1;
case CMD_SAVE_PLAYLIST:
handle_save_playlist(screen, c);
@@ -217,22 +230,22 @@ play_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
center_playing_item(screen, c);
return 1;
case CMD_LIST_MOVE_UP:
- playlist_move_song(c, lw->selected, lw->selected-1);
+ mpdclient_cmd_move(c, lw->selected, lw->selected-1);
break;
case CMD_LIST_MOVE_DOWN:
- playlist_move_song(c, lw->selected, lw->selected+1);
+ mpdclient_cmd_move(c, lw->selected, lw->selected+1);
break;
case CMD_LIST_FIND:
case CMD_LIST_RFIND:
case CMD_LIST_FIND_NEXT:
case CMD_LIST_RFIND_NEXT:
return screen_find(screen, c,
- lw, c->playlist_length,
+ lw, c->playlist.length,
cmd, list_callback);
default:
break;
}
- return list_window_cmd(lw, c->playlist_length, cmd) ;
+ return list_window_cmd(lw, c->playlist.length, cmd) ;
}
@@ -243,134 +256,6 @@ play_lw(void)
return lw;
}
-int
-play_get_selected(void)
-{
- return lw->selected;
-}
-
-int
-playlist_move_song(mpd_client_t *c, int old_index, int new_index)
-{
- int index1, index2;
- GList *item1, *item2;
- gpointer data1, data2;
-
- if( old_index==new_index || new_index<0 || new_index>=c->playlist_length )
- return -1;
-
- /* send the move command to mpd */
- mpd_sendMoveCommand(c->connection, old_index, new_index);
- mpd_finishCommand(c->connection);
- if( mpc_error(c) )
- return -1;
-
- index1 = MIN(old_index, new_index);
- index2 = MAX(old_index, new_index);
- item1 = g_list_nth(c->playlist, index1);
- item2 = g_list_nth(c->playlist, index2);
- data1 = item1->data;
- data2 = item2->data;
-
- /* move the second item */
- D(fprintf(stderr, "move second item [%d->%d]...\n", index2, index1));
- c->playlist = g_list_remove(c->playlist, data2);
- c->playlist = g_list_insert_before(c->playlist, item1, data2);
-
- /* move the first item */
- if( index2-index1 >1 )
- {
- D(fprintf(stderr, "move first item [%d->%d]...\n", index1, index2));
- item2 = g_list_nth(c->playlist, index2);
- c->playlist = g_list_remove(c->playlist, data1);
- c->playlist = g_list_insert_before(c->playlist, item2, data1);
- }
-
- /* increment the playlist id, so we dont retrives a new playlist */
- c->playlist_id++;
-
- /* make shure the playlist is repainted */
- lw->clear = 1;
- lw->repaint = 1;
-
- /* keep song selected */
- lw->selected = new_index;
-
- return 0;
-}
-
-int
-playlist_add_song(mpd_client_t *c, mpd_Song *song)
-{
- if( !song || !song->file )
- return -1;
-
- /* send the add command to mpd */
- mpd_sendAddCommand(c->connection, song->file);
- mpd_finishCommand(c->connection);
- if( mpc_error(c) )
- return -1;
-
- /* add the song to playlist */
- c->playlist = g_list_append(c->playlist, (gpointer) mpd_songDup(song));
- c->playlist_length++;
-
- /* increment the playlist id, so we dont retrives a new playlist */
- c->playlist_id++;
-
- /* make shure the playlist is repainted */
- lw->clear = 1;
- lw->repaint = 1;
-
- /* set selected highlight in the browse screen */
- file_set_highlight(c, song, 1);
-
- return 0;
-}
-
-int
-playlist_delete_song(mpd_client_t *c, int index)
-{
- mpd_Song *song = mpc_playlist_get_song(c, index);
-
- if( !song )
- return -1;
-
- /* send the delete command to mpd */
- mpd_sendDeleteCommand(c->connection, index);
- mpd_finishCommand(c->connection);
- if( mpc_error(c) )
- return -1;
-
- /* print a status message */
- screen_status_printf(_("Removed \'%s\' from playlist!"),
- mpc_get_song_name2(song));
- /* clear selected highlight in the browse screen */
- file_set_highlight(c, song, 0);
-
- /* increment the playlist id, so we dont retrives a new playlist */
- c->playlist_id++;
-
- /* remove references to the song */
- if( c->song == song )
- {
- c->song = NULL;
- c->song_id = -1;
- }
-
- /* remove the song from the playlist */
- c->playlist = g_list_remove(c->playlist, (gpointer) song);
- c->playlist_length = g_list_length(c->playlist);
- mpd_freeSong(song);
-
- /* make shure the playlist is repainted */
- lw->clear = 1;
- lw->repaint = 1;
- list_window_check_selected(lw, c->playlist_length);
-
- return 0;
-}
-
screen_functions_t *
get_screen_playlist(void)
@@ -380,7 +265,7 @@ get_screen_playlist(void)
memset(&functions, 0, sizeof(screen_functions_t));
functions.init = play_init;
functions.exit = play_exit;
- functions.open = NULL;
+ functions.open = play_open;
functions.close = NULL;
functions.resize = play_resize;
functions.paint = play_paint;
diff --git a/src/screen_play.h b/src/screen_play.h
deleted file mode 100644
index 2155ae593..000000000
--- a/src/screen_play.h
+++ /dev/null
@@ -1,9 +0,0 @@
-
-int play_get_selected(void);
-
-int playlist_move_song(mpd_client_t *c, int old_index, int new_index);
-int playlist_add_song(mpd_client_t *c, mpd_Song *song);
-int playlist_delete_song(mpd_client_t *c, int index);
-
-screen_functions_t *get_screen_playlist(void);
-
diff --git a/src/screen_search.c b/src/screen_search.c
index 6b6719e30..d82a049ef 100644
--- a/src/screen_search.c
+++ b/src/screen_search.c
@@ -3,10 +3,8 @@
#include <glib.h>
#include <ncurses.h>
-#include "libmpdclient.h"
#include "config.h"
-#include "mpc.h"
+#include "mpdclient.h"
#include "command.h"
#include "screen.h"
-#include "screen_search.h"
diff --git a/src/screen_search.h b/src/screen_search.h
deleted file mode 100644
index e69de29bb..000000000
--- a/src/screen_search.h
+++ /dev/null
diff --git a/src/screen_utils.c b/src/screen_utils.c
index b14b2a0ee..6473244bb 100644
--- a/src/screen_utils.c
+++ b/src/screen_utils.c
@@ -26,8 +26,7 @@
#include "config.h"
#include "ncmpc.h"
-#include "libmpdclient.h"
-#include "mpc.h"
+#include "mpdclient.h"
#include "support.h"
#include "command.h"
#include "options.h"
@@ -55,7 +54,9 @@ screen_getch(WINDOW *w, char *prompt)
curs_set(1);
timeout(-1);
- key = wgetch(w);
+ while( (key=wgetch(w)) == ERR )
+ ;
+
if( key==KEY_RESIZE )
screen_resize();
@@ -92,7 +93,7 @@ screen_getstr(WINDOW *w, char *prompt)
/* query user for a string and find it in a list window */
int
screen_find(screen_t *screen,
- mpd_client_t *c,
+ mpdclient_t *c,
list_window_t *lw,
int rows,
command_t findcmd,
diff --git a/src/screen_utils.h b/src/screen_utils.h
index 30c58bfca..b6e8d1171 100644
--- a/src/screen_utils.h
+++ b/src/screen_utils.h
@@ -7,7 +7,7 @@ char *screen_getstr(WINDOW *w, char *prompt);
/* query user for a string and find it in a list window */
int screen_find(screen_t *screen,
- mpd_client_t *c,
+ mpdclient_t *c,
list_window_t *lw,
int rows,
command_t findcmd,
diff --git a/src/strfsong.c b/src/strfsong.c
new file mode 100644
index 000000000..a7eb011f8
--- /dev/null
+++ b/src/strfsong.c
@@ -0,0 +1,214 @@
+/*
+ * $Id$
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <glib.h>
+
+#include "config.h"
+#include "libmpdclient.h"
+#include "ncmpc.h"
+#include "support.h"
+#include "strfsong.h"
+
+static char *
+skip(char * p)
+{
+ int stack = 0;
+
+ while (*p != '\0') {
+ if(*p == '[') stack++;
+ if(*p == '#' && p[1] != '\0') {
+ /* skip escaped stuff */
+ ++p;
+ }
+ else if(stack) {
+ if(*p == ']') stack--;
+ }
+ else {
+ if(*p == '&' || *p == '|' || *p == ']') {
+ break;
+ }
+ }
+ ++p;
+ }
+
+ return p;
+}
+
+static gsize
+_strfsong(gchar *s,
+ gsize max,
+ const gchar *format,
+ mpd_Song *song,
+ gchar **last)
+{
+ gchar *p, *end;
+ gchar *temp;
+ gsize n, length = 0;
+ gboolean found = FALSE;
+
+ memset(s, 0, max);
+ if( song==NULL )
+ return 0;
+
+ for( p=(gchar *) format; *p != '\0' && length<max; )
+ {
+ /* OR */
+ if (p[0] == '|')
+ {
+ ++p;
+ if(!found)
+ {
+ memset(s, 0, max);
+ length = 0;
+ }
+ else
+ {
+ p = skip(p);
+ }
+ continue;
+ }
+
+ /* AND */
+ if (p[0] == '&')
+ {
+ ++p;
+ if(!found)
+ {
+ p = skip(p);
+ }
+ else
+ {
+ found = FALSE;
+ }
+ continue;
+ }
+
+ /* EXPRESSION START */
+ if (p[0] == '[')
+ {
+ temp = g_malloc0(max);
+ if( _strfsong(temp, max, p+1, song, &p) >0 )
+ {
+ strncat(s, temp, max-length);
+ length = strlen(s);
+ found = TRUE;
+ }
+ g_free(temp);
+ continue;
+ }
+
+ /* EXPRESSION END */
+ if (p[0] == ']')
+ {
+ if(last) *last = p+1;
+ if(!found && length)
+ {
+ memset(s, 0, max);
+ length = 0;
+ }
+ return length;
+ }
+
+ /* pass-through non-escaped portions of the format string */
+ if (p[0] != '#' && p[0] != '%' && length<max)
+ {
+ strncat(s, p, 1);
+ length++;
+ ++p;
+ continue;
+ }
+
+ /* let the escape character escape itself */
+ if (p[0] == '#' && p[1] != '\0' && length<max)
+ {
+ strncat(s, p+1, 1);
+ length++;
+ p+=2;
+ continue;
+ }
+
+ /* advance past the esc character */
+
+ /* find the extent of this format specifier (stop at \0, ' ', or esc) */
+ temp = NULL;
+ end = p+1;
+ while(*end >= 'a' && *end <= 'z')
+ {
+ end++;
+ }
+ n = end - p + 1;
+ if(*end != '%')
+ n--;
+ else if (strncmp("%basename%", p, n) == 0)
+ temp = utf8_to_locale(basename(song->file));
+ else if (strncmp("%file%", p, n) == 0)
+ temp = utf8_to_locale(song->file);
+ else if (strncmp("%artist%", p, n) == 0)
+ temp = song->artist ? utf8_to_locale(song->artist) : NULL;
+ else if (strncmp("%title%", p, n) == 0)
+ temp = song->title ? utf8_to_locale(song->title) : NULL;
+ else if (strncmp("%album%", p, n) == 0)
+ temp = song->album ? utf8_to_locale(song->album) : NULL;
+ else if (strncmp("%track%", p, n) == 0)
+ temp = song->track ? utf8_to_locale(song->track) : NULL;
+ else if (strncmp("%name%", p, n) == 0)
+ temp = song->name ? utf8_to_locale(song->name) : NULL;
+ else if (strncmp("%time%", p, n) == 0)
+ {
+ if (song->time != MPD_SONG_NO_TIME) {
+ gchar s[10];
+ snprintf(s, 9, "%d:%d", song->time / 60,
+ song->time % 60 + 1);
+ /* nasty hack to use static buffer */
+ temp = g_strdup(s);
+ }
+ }
+
+ if( temp == NULL)
+ {
+ gsize templen=n;
+ /* just pass-through any unknown specifiers (including esc) */
+ /* drop a null char in so printf stops at the end of this specifier,
+ but put the real character back in (pseudo-const) */
+ if( length+templen > max )
+ templen = max-length;
+ strncat(s, p, templen);
+ length+=templen;
+ }
+ else {
+ gsize templen = strlen(temp);
+
+ found = TRUE;
+ if( length+templen > max )
+ templen = max-length;
+ strncat(s, temp, templen);
+ length+=templen;
+ g_free(temp);
+ }
+
+ /* advance past the specifier */
+ p += n;
+ }
+
+ if(last) *last = p;
+
+ return length;
+}
+
+
+/* a modified version of mpc's songToFormatedString (util.c)
+ * added - %basename%
+ */
+
+gsize
+strfsong(gchar *s, gsize max, const gchar *format, mpd_Song *song)
+{
+ return _strfsong(s, max, format, song, NULL);
+}
+
diff --git a/src/strfsong.h b/src/strfsong.h
new file mode 100644
index 000000000..74f9d7306
--- /dev/null
+++ b/src/strfsong.h
@@ -0,0 +1,3 @@
+
+gsize strfsong(gchar *s, gsize max, const gchar *format, mpd_Song *song);
+
diff --git a/src/support.c b/src/support.c
index 23b67d3e7..90ecb8b0d 100644
--- a/src/support.c
+++ b/src/support.c
@@ -1,7 +1,7 @@
/*
* $Id$
*
- * (c) 2004 by Kalle Wallin (kaw@linux.se)
+ * (c) 2004 by Kalle Wallin <kaw@linux.se>
*
* 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
@@ -18,6 +18,7 @@
*
*/
+#include <time.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
@@ -184,7 +185,7 @@ utf8_to_locale(char *utf8str)
g_get_charset(&charset);
screen_status_printf(_("Error: Unable to convert characters to %s"),
charset);
- D(g_printerr("utf8_to_locale(): %s\n", error->message));
+ D("utf8_to_locale(): %s\n", error->message);
g_error_free(error);
return g_strdup(utf8str);
}
@@ -212,7 +213,7 @@ locale_to_utf8(char *localestr)
if( error )
{
screen_status_printf(_("Error: Unable to convert characters to UTF-8"));
- D(g_printerr("locale_to_utf8: %s\n", error->message));
+ D("locale_to_utf8: %s\n", error->message);
g_error_free(error);
return g_strdup(localestr);
}