diff options
-rw-r--r-- | src/Makefile.am | 12 | ||||
-rw-r--r-- | src/colors.c | 10 | ||||
-rw-r--r-- | src/conf.c | 8 | ||||
-rw-r--r-- | src/libmpdclient.c | 270 | ||||
-rw-r--r-- | src/libmpdclient.h | 35 | ||||
-rw-r--r-- | src/main.c | 109 | ||||
-rw-r--r-- | src/mpc.c | 559 | ||||
-rw-r--r-- | src/mpc.h | 51 | ||||
-rw-r--r-- | src/mpdclient.c | 868 | ||||
-rw-r--r-- | src/mpdclient.h | 173 | ||||
-rw-r--r-- | src/ncmpc.h | 9 | ||||
-rw-r--r-- | src/screen.c | 188 | ||||
-rw-r--r-- | src/screen.h | 18 | ||||
-rw-r--r-- | src/screen_clock.c | 13 | ||||
-rw-r--r-- | src/screen_file.c | 396 | ||||
-rw-r--r-- | src/screen_file.h | 7 | ||||
-rw-r--r-- | src/screen_help.c | 10 | ||||
-rw-r--r-- | src/screen_help.h | 2 | ||||
-rw-r--r-- | src/screen_keydef.c | 11 | ||||
-rw-r--r-- | src/screen_play.c | 255 | ||||
-rw-r--r-- | src/screen_play.h | 9 | ||||
-rw-r--r-- | src/screen_search.c | 4 | ||||
-rw-r--r-- | src/screen_search.h | 0 | ||||
-rw-r--r-- | src/screen_utils.c | 9 | ||||
-rw-r--r-- | src/screen_utils.h | 2 | ||||
-rw-r--r-- | src/strfsong.c | 214 | ||||
-rw-r--r-- | src/strfsong.h | 3 | ||||
-rw-r--r-- | src/support.c | 7 |
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); } |