From: Kalle Wallin Date: Sat, 5 Jun 2004 11:21:43 +0000 (+0000) Subject: Changed directory layout (for future use of gettext) X-Git-Tag: v0.12_alpha1~553 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=f55a67b3f882641abe5a9b14b045d7ce71964af7;p=ncmpc.git Changed directory layout (for future use of gettext) git-svn-id: https://svn.musicpd.org/ncmpc/trunk@1342 09075e82-0dd4-0310-85a5-a0d7c8717e4f --- diff --git a/ChangeLog b/ChangeLog index e43c8a0..2a4de61 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2004-06-05 Kalle Wallin + * Changed directory layout to suit future use of gettext + * screen.c: Added mpd update flag [U] and display a status message + when a update has finished + * screen.c: Display bit rate instead of time when the total time + is zero and display local time when mpd is stopped. + 2004-05-07 Kalle Wallin * Redesigned ncmpc's color support - view the manual for details! * Added support for moving songs in a playlist (move-up, move-down) diff --git a/Makefile.am b/Makefile.am index 8ac5da7..8bf3267 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,27 +1,15 @@ # -# $Id: Makefile.am,v 1.5 2004/03/16 23:49:14 kalle Exp $ +# $Id$ # -bin_PROGRAMS = ncmpc +AUTOMAKE_OPTIONS = foreign 1.6 + +SUBDIRS = doc src pkgdata_DATA = docdir = $(prefix)/share/doc/$(PACKAGE) -doc_DATA = AUTHORS README ChangeLog -EXTRA_DIST = COPYING $(pkgdata_DATA) $(doc_DATA) - -SUBDIRS = doc - -#EXTRA_ncmpc_SOURCES = -#ncmpc_LDADD = -#ncmpc_DEPENDENCIES = - -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 +doc_DATA = AUTHORS README +EXTRA_DIST = ChangeLog COPYING $(pkgdata_DATA) $(doc_DATA) -ncmpc_SOURCES = libmpdclient.c main.c mpc.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 \ - list_window.c colors.c support.c $(ncmpc_headers) diff --git a/autogen.sh b/autogen.sh index 72a2352..22e7897 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,54 +1,122 @@ -#! /bin/sh -# Check Autoconf version -if [ -x `which autoconf` ]; then - AC_VER=`autoconf --version | head -n 1 | sed 's/^[^0-9]*//'` - AC_VER_MAJOR=`echo $AC_VER | cut -f1 -d'.'` - AC_VER_MINOR=`echo $AC_VER | cut -f2 -d'.' | sed 's/[^0-9]*$//'` - - if [ "$AC_VER_MAJOR" -lt "2" ]; then - echo "Autoconf 2.13 or greater needed to build configure." - exit 1 - fi - - if [ "$AC_VER_MINOR" -lt "13" ]; then - echo "Autoconf 2.13 or greater needed to build configure." - exit 1 - fi - - if [ "$AC_VER_MINOR" -lt "50" ]; then - if [ ! -e configure.in ]; then - ln -s configure.ac configure.in - fi - echo "If you see some warnings about cross-compiling, don't worry; this is normal." - else - echo "rm -f configure.in ?" - fi -else - echo Autoconf not found. AlsaPlayer CVS requires autoconf to bootstrap itself. - exit 1 -fi +#!/bin/sh +# Run this to set up the build system: configure, makefiles, etc. +# (based on the version in enlightenment's cvs) + +package="ncmpc" + +olddir=`pwd` +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +cd "$srcdir" +DIE=0 + +echo "checking for autoconf... " +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have autoconf installed to compile $package." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +VERSIONGREP="sed -e s/.*[^0-9\.]\([0-9]\.[0-9]\).*/\1/" +VERSIONMKINT="sed -e s/[^0-9]//" -run_cmd() { - echo running $* ... - if ! $*; then - echo failed! - exit 1 +# do we need automake? +if test -r Makefile.am; then + AM_NEEDED=`fgrep AUTOMAKE_OPTIONS Makefile.am | $VERSIONGREP` + if test -z $AM_NEEDED; then + echo -n "checking for automake... " + AUTOMAKE=automake + ACLOCAL=aclocal + if ($AUTOMAKE --version < /dev/null > /dev/null 2>&1); then + echo "no" + AUTOMAKE= + else + echo "yes" fi + else + echo -n "checking for automake $AM_NEEDED or later... " + for am in automake-$AM_NEEDED automake$AM_NEEDED automake; do + ($am --version < /dev/null > /dev/null 2>&1) || continue + ver=`$am --version < /dev/null | head -n 1 | $VERSIONGREP | $VERSIONMKINT` + verneeded=`echo $AM_NEEDED | $VERSIONMKINT` + if test $ver -ge $verneeded; then + AUTOMAKE=$am + echo $AUTOMAKE + break + fi + done + test -z $AUTOMAKE && echo "no" + echo -n "checking for aclocal $AM_NEEDED or later... " + for ac in aclocal-$AM_NEEDED aclocal$AM_NEEDED aclocal; do + ($ac --version < /dev/null > /dev/null 2>&1) || continue + ver=`$ac --version < /dev/null | head -n 1 | $VERSIONGREP | $VERSIONMKINT` + verneeded=`echo $AM_NEEDED | $VERSIONMKINT` + if test $ver -ge $verneeded; then + ACLOCAL=$ac + echo $ACLOCAL + break + fi + done + test -z $ACLOCAL && echo "no" + fi + test -z $AUTOMAKE || test -z $ACLOCAL && { + echo + echo "You must have automake installed to compile $package." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + exit 1 + } +fi + +echo -n "checking for libtool... " +for LIBTOOLIZE in libtoolize glibtoolize nope; do + (which $LIBTOOLIZE) > /dev/null 2>&1 && break +done +if test x$LIBTOOLIZE = xnope; then + echo "nope." + LIBTOOLIZE=libtoolize +else + echo $LIBTOOLIZE +fi +($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have libtool installed to compile $package." + echo "Download the appropriate package for your system," + echo "or get the source from one of the GNU ftp sites" + echo "listed in http://www.gnu.org/order/ftp.html" + DIE=1 } -# Check if /usr/local/share/aclocal exists -if [ -d /usr/local/share/aclocal ]; then - ACLOCAL_INCLUDE="$ACLOCAL_INCLUDE -I /usr/local/share/aclocal" -fi +if test "$DIE" -eq 1; then + exit 1 +fi + +echo "Generating configuration files for $package, please wait...." if [ -d m4 ] ; then - run_cmd cat m4/*.m4 > acinclude.m4 + cat m4/*.m4 > acinclude.m4 +fi + +if [ -d /usr/local/share/aclocal ]; then + ACLOCAL_FLAGS="$ACLOCAL_FLAGS -I /usr/local/share/aclocal" fi -run_cmd aclocal $ACLOCAL_INCLUDE -run_cmd autoheader -run_cmd libtoolize --automake -run_cmd automake --add-missing -run_cmd autoconf -echo -echo "Now run './configure'" -echo +echo " $ACLOCAL $ACLOCAL_FLAGS" +$ACLOCAL $ACLOCAL_FLAGS + +echo " autoheader" +autoheader + +echo " $LIBTOOLIZE --automake" +$LIBTOOLIZE --automake + +echo " $AUTOMAKE --add-missing $AUTOMAKE_FLAGS" +$AUTOMAKE --add-missing $AUTOMAKE_FLAGS + +echo " autoconf" +autoconf + +cd $olddir +$srcdir/configure "$@" && echo diff --git a/colors.c b/colors.c deleted file mode 100644 index f709693..0000000 --- a/colors.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * (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 -#include -#include -#include -#include - -#include "config.h" -#include "options.h" -#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) -#define COLOR_BRIGHT_RED (COLOR_RED | COLOR_BRIGHT_MASK) -#define COLOR_BRIGHT_GREEN (COLOR_GREEN | COLOR_BRIGHT_MASK) -#define COLOR_BRIGHT_YELLOW (COLOR_YELLOW | COLOR_BRIGHT_MASK) -#define COLOR_BRIGHT_BLUE (COLOR_BLUE | COLOR_BRIGHT_MASK) -#define COLOR_BRIGHT_MAGENTA (COLOR_MAGENTA | COLOR_BRIGHT_MASK) -#define COLOR_BRIGHT_CYAN (COLOR_CYAN | COLOR_BRIGHT_MASK) -#define COLOR_BRIGHT_WHITE (COLOR_WHITE | COLOR_BRIGHT_MASK) - -#define IS_BRIGHT(color) (color & COLOR_BRIGHT_MASK) - -/* name of the color fields */ -#define NAME_TITLE "title" -#define NAME_TITLE_BOLD "title-bold" -#define NAME_LINE "line" -#define NAME_LINE_BOLD "line-flags" -#define NAME_LIST "list" -#define NAME_LIST_BOLD "list-bold" -#define NAME_PROGRESS "progressbar" -#define NAME_STATUS "status-song" -#define NAME_STATUS_BOLD "status-state" -#define NAME_STATUS_TIME "status-time" -#define NAME_ALERT "alert" -#define NAME_BGCOLOR "background" - -typedef struct { - short color; - short r,g,b; -} color_definition_entry_t; - -typedef struct { - int id; - char *name; - short fg; - attr_t attrs; -} color_entry_t; - -static color_entry_t colors[] = { - - /* color pair, field name, color, mono attribute */ - /*-------------------------------------------------------------------------*/ - { COLOR_TITLE, NAME_TITLE, COLOR_YELLOW, A_NORMAL }, - { COLOR_TITLE_BOLD, NAME_TITLE_BOLD, COLOR_BRIGHT_YELLOW, A_BOLD }, - { COLOR_LINE, NAME_LINE, COLOR_WHITE, A_NORMAL }, - { COLOR_LINE_BOLD, NAME_LINE_BOLD, COLOR_BRIGHT_WHITE, A_BOLD }, - { COLOR_LIST, NAME_LIST, COLOR_GREEN, A_NORMAL }, - { COLOR_LIST_BOLD, NAME_LIST_BOLD, COLOR_BRIGHT_GREEN, A_BOLD }, - { COLOR_PROGRESSBAR, NAME_PROGRESS, COLOR_WHITE, A_NORMAL }, - { COLOR_STATUS, NAME_STATUS, COLOR_YELLOW, A_NORMAL }, - { COLOR_STATUS_BOLD, NAME_STATUS_BOLD, COLOR_BRIGHT_YELLOW, A_BOLD }, - { COLOR_STATUS_TIME, NAME_STATUS_TIME, COLOR_RED, A_NORMAL }, - { COLOR_STATUS_ALERT, NAME_ALERT, COLOR_BRIGHT_RED, A_BOLD }, - { 0, NULL, 0, 0 } -}; - -/* background color */ -static short bg = COLOR_BLACK; - -static GList *color_definition_list = NULL; - -static color_entry_t * -colors_lookup(int id) -{ - int i; - - i=0; - while( colors[i].name != NULL ) - { - if( colors[i].id == id ) - return &colors[i]; - i++; - } - return NULL; -} - -static color_entry_t * -colors_lookup_by_name(char *name) -{ - int i; - - i=0; - while( colors[i].name != NULL ) - { - if( !strcasecmp(colors[i].name, name) ) - return &colors[i]; - i++; - } - return NULL; -} - -static int -colors_update_pair(int id) -{ - color_entry_t *entry = colors_lookup(id); - short fg = -1; - - if( !entry ) - return -1; - - if( IS_BRIGHT(entry->fg) ) - { - entry->attrs = A_BOLD; - fg = entry->fg & ~COLOR_BRIGHT_MASK; - } - else - { - entry->attrs = A_NORMAL; - fg = entry->fg; - } - - init_pair(entry->id, fg, bg); - - return 0; -} - -short -colors_str2color(char *str) -{ - if( !strcasecmp(str,"black") ) - return COLOR_BLACK; - else if( !strcasecmp(str,"red") ) - return COLOR_RED; - else if( !strcasecmp(str,"green") ) - return COLOR_GREEN; - else if( !strcasecmp(str,"yellow") ) - return COLOR_YELLOW; - else if( !strcasecmp(str,"blue") ) - return COLOR_BLUE; - else if( !strcasecmp(str,"magenta") ) - return COLOR_MAGENTA; - else if( !strcasecmp(str,"cyan") ) - return COLOR_CYAN; - else if( !strcasecmp(str,"white") ) - return COLOR_WHITE; - else if( !strcasecmp(str,"brightred") ) - return COLOR_BRIGHT_RED; - else if( !strcasecmp(str,"brightgreen") ) - return COLOR_BRIGHT_GREEN; - else if( !strcasecmp(str,"brightyellow") ) - return COLOR_BRIGHT_YELLOW; - else if( !strcasecmp(str,"brightblue") ) - return COLOR_BRIGHT_BLUE; - else if( !strcasecmp(str,"brightmagenta") ) - return COLOR_BRIGHT_MAGENTA; - else if( !strcasecmp(str,"brightcyan") ) - return COLOR_BRIGHT_CYAN; - else if( !strcasecmp(str,"brightwhite") ) - return COLOR_BRIGHT_WHITE; - else if( !strcasecmp(str,"grey") || !strcasecmp(str,"gray") ) - return COLOR_BRIGHT_BLACK; - else if( !strcasecmp(str,"none") ) - return -1; - fprintf(stderr,"Warning: Unknown color - %s\n", str); - return -2; -} - -/* This function is called from conf.c before curses have been started, - * it adds the definition to the color_definition_list and init_color() is - * done in colors_start() */ -int -colors_define(char *name, short r, short g, short b) -{ - color_definition_entry_t *entry; - short color = colors_str2color(name); - - if( color<0 ) - return -1; - - entry = g_malloc(sizeof(color_definition_entry_t)); - entry->color = color; - entry->r = r; - entry->g = g; - entry->b = b; - - color_definition_list = g_list_append(color_definition_list, entry); - - return 0; -} - - -int -colors_assign(char *name, char *value) -{ - color_entry_t *entry = colors_lookup_by_name(name); - short color; - - if( !entry ) - { - if( !strcasecmp(NAME_BGCOLOR, name) ) - { - if( (color=colors_str2color(value)) < -1 ) - return -1; - if( color > COLORS ) - color = color & ~COLOR_BRIGHT_MASK; - bg = color; - return 0; - } - fprintf(stderr,"Warning: Unknown color field - %s\n", name); - return -1; - } - - if( (color=colors_str2color(value)) < -1 ) - return -1; - entry->fg = color; - - return 0; -} - - -int -colors_start(void) -{ - if( has_colors() ) - { - /* initialize color support */ - start_color(); - use_default_colors(); - /* define any custom colors defined in the configuration file */ - if( color_definition_list && can_change_color() ) - { - GList *list = color_definition_list; - - while( list ) - { - color_definition_entry_t *entry = list->data; - - if( entry->color <= COLORS ) - init_color(entry->color, entry->r, entry->g, entry->b); - list=list->next; - } - } - else if( !can_change_color() ) - fprintf(stderr, "Terminal lacks support for changing colors!\n"); - - if( options.enable_colors ) - { - int i = 0; - - while(colors[i].name) - { - /* update the color pairs */ - colors_update_pair(colors[i].id); - i++; - } - - } - } - else if( options.enable_colors ) - { - fprintf(stderr, "Terminal lacks color capabilities!\n"); - options.enable_colors = 0; - } - - /* free the color_definition_list */ - if( color_definition_list ) - { - GList *list = color_definition_list; - - while( list ) - { - g_free(list->data); - list=list->next; - } - g_list_free(color_definition_list); - color_definition_list = NULL; - } - - return 0; -} - - -int -colors_use(WINDOW *w, int id) -{ - color_entry_t *entry = colors_lookup(id); - short pair; - attr_t attrs; - - if( !entry ) - return -1; - - wattr_get(w, &attrs, &pair, NULL); - - if( options.enable_colors ) - { - /* color mode */ - if( attrs != entry->attrs || id!=pair ) - wattr_set(w, entry->attrs, id, NULL); - } - else - { - /* mono mode */ - if( attrs != entry->attrs ) - wattrset(w, entry->attrs); - } - - return 0; -} - diff --git a/colors.h b/colors.h deleted file mode 100644 index a66d693..0000000 --- a/colors.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef COLORS_H -#define COLORS_H - -#define COLOR_TITLE 1 -#define COLOR_TITLE_BOLD 2 -#define COLOR_LINE 3 -#define COLOR_LINE_BOLD 4 -#define COLOR_LIST 5 -#define COLOR_LIST_BOLD 6 -#define COLOR_PROGRESSBAR 7 -#define COLOR_STATUS 8 -#define COLOR_STATUS_BOLD 9 -#define COLOR_STATUS_TIME 10 -#define COLOR_STATUS_ALERT 11 - -short colors_str2color(char *str); - -int colors_assign(char *name, char *value); -int colors_define(char *name, short r, short g, short b); -int colors_start(void); -int colors_use(WINDOW *w, int id); - - -#endif /* COLORS_H */ - - - diff --git a/command.c b/command.c deleted file mode 100644 index 1e9edcd..0000000 --- a/command.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * (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 -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "command.h" - -#undef DEBUG_KEYS - -#ifdef DEBUG_KEYS -#define DK(x) x -#else -#define DK(x) -#endif - -extern void screen_resize(void); - -#define BS KEY_BACKSPACE -#define DEL KEY_DC -#define UP KEY_UP -#define DWN KEY_DOWN -#define LEFT KEY_LEFT -#define RGHT KEY_RIGHT -#define HOME KEY_HOME -#define END KEY_END -#define PGDN KEY_NPAGE -#define PGUP KEY_PPAGE -#define TAB 0x09 -#define STAB 0x161 -#define ESC 0x1B -#define F1 KEY_F(1) -#define F2 KEY_F(2) -#define F3 KEY_F(3) -#define F4 KEY_F(4) -#define F5 KEY_F(5) -#define F6 KEY_F(6) - - -static command_definition_t cmds[] = -{ - { { 13, 0, 0 }, CMD_PLAY, "play", - "Play/Enter directory" }, - { { 'P', 0, 0 }, CMD_PAUSE,"pause", - "Pause" }, - { { 's', BS, 0 }, CMD_STOP, "stop", - "Stop" }, - { { '>', 0, 0 }, CMD_TRACK_NEXT, "next", - "Next track" }, - { { '<', 0, 0 }, CMD_TRACK_PREVIOUS, "prev", - "Previous track" }, - { { 'f', 0, 0 }, CMD_SEEK_FORWARD, "seek-forward", - "Seek forward" }, - { { 'b', 0, 0 }, CMD_SEEK_BACKWARD, "seek-backward", - "Seek backward" }, - - { { '+', RGHT, 0 }, CMD_VOLUME_UP, "volume-up", - "Increase volume" }, - { { '-', LEFT, 0 }, CMD_VOLUME_DOWN, "volume-down", - "Decrease volume" }, - - { { 'w', 0, 0 }, CMD_TOGGLE_FIND_WRAP, "wrap-mode", - "Toggle find mode" }, - { { 'U', 0, 0 }, CMD_TOGGLE_AUTOCENTER, "autocenter-mode", - "Toggle auto center mode" }, - - { { ' ', 'a', 0 }, CMD_SELECT, "select", - "Select/deselect song in playlist" }, - { { DEL, 'd', 0 }, CMD_DELETE, "delete", - "Delete song from playlist" }, - { { 'Z', 0, 0 }, CMD_SHUFFLE, "shuffle", - "Shuffle playlist" }, - { { 'c', 0, 0 }, CMD_CLEAR, "clear", - "Clear playlist" }, - { { 'r', 0, 0 }, CMD_REPEAT, "repeat", - "Toggle repeat mode" }, - { { 'z', 0, 0 }, CMD_RANDOM, "random", - "Toggle random mode" }, - { { 'x', 0, 0 }, CMD_CROSSFADE, "crossfade", - "Toggle crossfade mode" }, - { { 'S', 0, 0 }, CMD_SAVE_PLAYLIST, "save", - "Save playlist" }, - - { { 0, 0, 0 }, CMD_LIST_MOVE_UP, "move-up", - "Move item up" }, - { { 0, 0, 0 }, CMD_LIST_MOVE_DOWN, "move-down", - "Move item down" }, - - { { UP, ',', 0 }, CMD_LIST_PREVIOUS, "up", - "Move cursor up" }, - { { DWN, '.', 0 }, CMD_LIST_NEXT, "down", - "Move cursor down" }, - { { HOME, 0x01, 0 }, CMD_LIST_FIRST, "home", - "Home " }, - { { END, 0x05, 0 }, CMD_LIST_LAST, "end", - "End " }, - { { PGUP, 'A', 0 }, CMD_LIST_PREVIOUS_PAGE, "pgup", - "Page up" }, - { { PGDN, 'B', 0 }, CMD_LIST_NEXT_PAGE, "pgdn", - "Page down" }, - { { '/', 0, 0 }, CMD_LIST_FIND, "find", - "Forward find" }, - { { 'n', 0, 0 }, CMD_LIST_FIND_NEXT, "find-next", - "Forward find next" }, - { { '?', 0, 0 }, CMD_LIST_RFIND, "rfind", - "Backward find" }, - { { 'p', 0, 0 }, CMD_LIST_RFIND_NEXT, "rfind-next", - "Backward find previous" }, - - - { { TAB, 0, 0 }, CMD_SCREEN_NEXT, "screen-next", - "Next screen" }, - - { { STAB, 0, 0 }, CMD_SCREEN_PREVIOUS, "screen-prev", - "Previous screen" }, - - { { '1', F1, 'h' }, CMD_SCREEN_HELP, "screen-help", - "Help screen" }, - { { '2', F2, 0 }, CMD_SCREEN_PLAY, "screen-playlist", - "Playlist screen" }, - { { '3', F3, 0 }, CMD_SCREEN_FILE, "screen-browse", - "Browse screen" }, - { {'u', 0, 0 }, CMD_SCREEN_UPDATE, "update", - "Update screen" }, -#ifdef ENABLE_KEYDEF_SCREEN - { {'K', 0, 0 }, CMD_SCREEN_KEYDEF, "screen-keyedit", - "Key configuration screen" }, -#endif - - { { 'q', 0, 0 }, CMD_QUIT, "quit", - "Quit " PACKAGE }, - - { { -1, -1, -1 }, CMD_NONE, NULL, NULL } -}; - -command_definition_t * -get_command_definitions(void) -{ - return cmds; -} - -char * -key2str(int key) -{ - static char buf[32]; - int i; - - buf[0] = 0; - switch(key) - { - case 0: - return "Undefined"; - case ' ': - return "Space"; - case 13: - return "Enter"; - case BS: - return "Backspace"; - case DEL: - return "Delete"; - case UP: - return "Up"; - case DWN: - return "Down"; - case LEFT: - return "Left"; - case RGHT: - return "Right"; - case HOME: - return "Home"; - case END: - return "End"; - case PGDN: - return "PageDown"; - case PGUP: - return "PageUp"; - case TAB: - return "Tab"; - case STAB: - return "Shift+Tab"; - case ESC: - return "Esc"; - case KEY_IC: - return "Insert"; - default: - for(i=0; i<=63; i++) - if( key==KEY_F(i) ) - { - snprintf(buf, 32, "F%d", i ); - return buf; - } - if( !(key & ~037) ) - snprintf(buf, 32, "Ctrl-%c", 'A'+(key & 037)-1 ); - else if( (key & ~037) == 224 ) - snprintf(buf, 32, "Alt-%c", 'A'+(key & 037)-1 ); - else if( key>32 && key<256 ) - snprintf(buf, 32, "%c", key); - else - snprintf(buf, 32, "0x%03X", key); - } - return buf; -} - -void -command_dump_keys(void) -{ - int i; - - i=0; - while( cmds[i].description ) - { - if( cmds[i].command != CMD_NONE ) - printf(" %20s : %s\n", get_key_names(cmds[i].command,1),cmds[i].name); - i++; - } -} - -char * -get_key_names(command_t command, int all) -{ - int i; - - i=0; - while( cmds[i].description ) - { - if( cmds[i].command == command ) - { - int j; - static char keystr[80]; - - strncpy(keystr, key2str(cmds[i].keys[0]), 80); - if( !all ) - return keystr; - j=1; - while( j0 ) - { - strcat(keystr, " "); - strcat(keystr, key2str(cmds[i].keys[j])); - j++; - } - return keystr; - } - i++; - } - return NULL; -} - -char * -get_key_description(command_t command) -{ - int i; - - i=0; - while( cmds[i].description ) - { - if( cmds[i].command == command ) - return cmds[i].description; - i++; - } - return NULL; -} - -char * -get_key_command_name(command_t command) -{ - int i; - - i=0; - while( cmds[i].name ) - { - if( cmds[i].command == command ) - return cmds[i].name; - i++; - } - return NULL; -} - -command_t -get_key_command_from_name(char *name) -{ - int i; - - i=0; - while( cmds[i].name ) - { - if( strcmp(name, cmds[i].name) == 0 ) - return cmds[i].command; - i++; - } - return CMD_NONE; -} - - -command_t -find_key_command(int key, command_definition_t *cmds) -{ - int i; - - i=0; - while( cmds && cmds[i].name ) - { - if( cmds[i].keys[0] == key || - cmds[i].keys[1] == key || - cmds[i].keys[2] == key ) - return cmds[i].command; - i++; - } - return CMD_NONE; -} - -command_t -get_key_command(int key) -{ - return find_key_command(key, cmds); -} - - -command_t -get_keyboard_command(void) -{ - int key; - - key = wgetch(stdscr); - - if( key==KEY_RESIZE ) - screen_resize(); - - if( key==ERR ) - return CMD_NONE; - - DK(fprintf(stderr, "key = 0x%02X\t", key)); - - return get_key_command(key); -} - -int -assign_keys(command_t command, int keys[MAX_COMMAND_KEYS]) -{ - int i; - - i=0; - while( cmds[i].name ) - { - if( cmds[i].command == command ) - { - memcpy(cmds[i].keys, keys, sizeof(int)*MAX_COMMAND_KEYS); - return 0; - } - i++; - } - return -1; -} - -int -check_key_bindings(void) -{ - int i; - int retval = 0; - - i=0; - while( cmds[i].name ) - { - int j; - command_t cmd; - - for(j=0; j -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "config.h" -#include "options.h" -#include "support.h" -#include "command.h" -#include "colors.h" -#include "conf.h" - -#ifdef DEBUG -#define D(x) x -#else -#define D(x) -#endif - -#define ENABLE_OLD_COLOR_SYNTAX - -#define MAX_LINE_LENGTH 1024 -#define COMMENT_TOKEN '#' - -/* configuration field names */ -#define CONF_ENABLE_COLORS "enable_colors" -#define CONF_AUTO_CENTER "auto_center" -#define CONF_WIDE_CURSOR "wide_cursor" -#define CONF_KEY_DEFINITION "key" -#define CONF_COLOR "color" -#define CONF_COLOR_DEFINITION "colordef" - -/* Deprecated - configuration field names */ -#define CONF_COLOR_BACKGROUND "background_color" -#define CONF_COLOR_TITLE "title_color" -#define CONF_COLOR_LINE "line_color" -#define CONF_COLOR_LIST "list_color" -#define CONF_COLOR_PROGRESS "progress_color" -#define CONF_COLOR_STATUS "status_color" -#define CONF_COLOR_ALERT "alert_color" - - -typedef enum { - KEY_PARSER_UNKNOWN, - KEY_PARSER_CHAR, - KEY_PARSER_DEC, - KEY_PARSER_HEX, - KEY_PARSER_DONE -} key_parser_state_t; - -static int -str2bool(char *str) -{ - if( !strcasecmp(str,"no") || !strcasecmp(str,"false") || - !strcasecmp(str,"off") || !strcasecmp(str,"0") ) - return 0; - return 1; -} - -static int -parse_key_value(char *str, size_t len, char **end) -{ - int i, value; - key_parser_state_t state; - - i=0; - value=0; - state=KEY_PARSER_UNKNOWN; - *end = str; - - while( i str+len ) - *end = str+len; - - return value; -} - -static int -parse_key_definition(char *str) -{ - char buf[MAX_LINE_LENGTH]; - char *p, *end; - size_t len = strlen(str); - int i,j,key; - int keys[MAX_COMMAND_KEYS]; - command_t cmd; - - /* get the command name */ - i=0; - j=0; - memset(buf, 0, MAX_LINE_LENGTH); - while( i=0 ) - { - keys[i++] = key; - while( p=0 ) - { - rgb[i++] = value; - while( p=0 && IS_WHITESPACE(line[i]) ) - { - line[i] = '\0'; - i--; - } - len = i+1; - - if( len>0 ) - { - i = 0; - /* skip whitespace */ - while( ienable_colors = str2bool(value); - } - /* auto center */ - else if( !strcasecmp(CONF_AUTO_CENTER, name) ) - { - options->auto_center = str2bool(value); - } - /* color assignment */ - else if( !strcasecmp(CONF_COLOR, name) ) - { - parse_color(value); - } -#ifdef ENABLE_OLD_COLOR_SYNTAX - /* background color */ - else if( !strcasecmp(CONF_COLOR_BACKGROUND, name) ) - { - fprintf(stderr,"%s: %s - deprecated!\n", filename,name); - colors_assign("background", value); - } - /* color - top (title) window */ - else if( !strcasecmp(CONF_COLOR_TITLE, name) ) - { - fprintf(stderr,"%s: %s - deprecated!\n", filename,name); - colors_assign("title", value); - colors_assign("title2", value); - } - /* color - line (title) window */ - else if( !strcasecmp(CONF_COLOR_LINE, name) ) - { - fprintf(stderr,"%s: %s - deprecated!\n", filename,name); - colors_assign("line", value); - colors_assign("line2", value); - } - /* color - list window */ - else if( !strcasecmp(CONF_COLOR_LIST, name) ) - { - fprintf(stderr,"%s: %s - deprecated!\n", filename,name); - colors_assign("list", value); - } - /* color - progress bar */ - else if( !strcasecmp(CONF_COLOR_PROGRESS, name) ) - { - fprintf(stderr,"%s: %s - deprecated!\n", filename,name); - colors_assign("progressbar", value); - } - /* color - status window */ - else if( !strcasecmp(CONF_COLOR_STATUS, name) ) - { - fprintf(stderr,"%s: %s - deprecated!\n", filename,name); - colors_assign("status", value); - colors_assign("status2", value); - } - /* color - alerts */ - else if( !strcasecmp(CONF_COLOR_ALERT, name) ) - { - fprintf(stderr,"%s: %s - deprecated!\n", filename,name); - colors_assign("alert", value); - } -#endif - /* wide cursor */ - else if( !strcasecmp(CONF_WIDE_CURSOR, name) ) - { - options->wide_cursor = str2bool(value); - } - /* color definition */ - else if( !strcasecmp(CONF_COLOR_DEFINITION, name) ) - { - parse_color_definition(value); - } - else - { - match_found = 0; - } - - - if( !match_found ) - fprintf(stderr, - "Unknown configuration parameter: %s\n", - name); -#ifdef DEBUG - printf( " %s = %s %s\n", - name, - value, - match_found ? "" : "- UNKNOWN SETTING!" ); -#endif - - } - } - } - - D(printf( "--\n\n" )); - - if( free_filename ) - g_free(filename); - - return 0; -} - -int -check_user_conf_dir(void) -{ - int retval; - char *dirname = g_build_filename(g_get_home_dir(), "." PACKAGE, NULL); - - if( g_file_test(dirname, G_FILE_TEST_IS_DIR) ) - { - g_free(dirname); - return 0; - } - retval = mkdir(dirname, 0755); - g_free(dirname); - return retval; -} - -char * -get_user_key_binding_filename(void) -{ - return g_build_filename(g_get_home_dir(), "." PACKAGE, "keys", NULL); -} - - -int -read_configuration(options_t *options) -{ - char *filename = NULL; - - /* check for command line configuration file */ - if( options->config_file ) - filename = g_strdup(options->config_file); - - /* check for user configuration ~/.ncmpc/config */ - if( filename == NULL ) - { - filename = g_build_filename(g_get_home_dir(), - "." PACKAGE, "config", NULL); - if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) ) - { - g_free(filename); - filename = NULL; - } - } - - /* check for global configuration SYSCONFDIR/ncmpc/config */ - if( filename == NULL ) - { - filename = g_build_filename(SYSCONFDIR, PACKAGE, "config", NULL); - if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) ) - { - g_free(filename); - filename = NULL; - } - } - - /* load configuration */ - if( filename ) - { - read_rc_file(filename, options); - g_free(filename); - filename = NULL; - } - - /* check for command line key binding file */ - if( options->key_file ) - filename = g_strdup(options->key_file); - - /* check for user key bindings ~/.ncmpc/keys */ - if( filename == NULL ) - { - filename = get_user_key_binding_filename(); - if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) ) - { - g_free(filename); - filename = NULL; - } - } - - /* check for global key bindings SYSCONFDIR/ncmpc/keys */ - if( filename == NULL ) - { - filename = g_build_filename(SYSCONFDIR, PACKAGE, "keys", NULL); - if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) ) - { - g_free(filename); - filename = NULL; - } - } - - /* load key bindings */ - if( filename ) - { - read_rc_file(filename, options); - g_free(filename); - filename = NULL; - } - - return 0; -} - - - diff --git a/conf.h b/conf.h deleted file mode 100644 index 20b4f5e..0000000 --- a/conf.h +++ /dev/null @@ -1,7 +0,0 @@ - -int check_user_conf_dir(void); - -char *get_user_key_binding_filename(void); - -int read_configuration(options_t *options); - diff --git a/configure.ac b/configure.ac index 87dbc6a..d1601f9 100644 --- a/configure.ac +++ b/configure.ac @@ -3,8 +3,8 @@ dnl $Id$ dnl AC_INIT -AC_CONFIG_SRCDIR([main.c]) -AM_INIT_AUTOMAKE(ncmpc, 0.10.2-svn) +AC_CONFIG_SRCDIR([src/main.c]) +AM_INIT_AUTOMAKE(ncmpc, 0.11.0-svn) dnl Check for programs AC_PROG_CC @@ -96,9 +96,9 @@ AC_ARG_WITH(default-host, dnl Default port AC_ARG_WITH(default-port, - AC_HELP_STRING(--with-default-port=ARG,Default port (2100)), + AC_HELP_STRING(--with-default-port=ARG,Default port (6600)), DEFAULT_PORT="$withval", - DEFAULT_PORT="2100") + DEFAULT_PORT="6600") CFLAGS="$CFLAGS $GLIB_CFLAGS -DSYSCONFDIR=\\\"\$(sysconfdir)\\\"" @@ -112,7 +112,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_HOST, "$DEFAULT_HOST", Default MPD host) AM_CONFIG_HEADER(config.h) -AC_CONFIG_FILES([doc/Makefile Makefile]) +AC_CONFIG_FILES([doc/Makefile src/Makefile Makefile]) AC_OUTPUT echo " diff --git a/libmpdclient.c b/libmpdclient.c deleted file mode 100644 index aa7b757..0000000 --- a/libmpdclient.c +++ /dev/null @@ -1,1180 +0,0 @@ -/* libmpdclient - * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) - * This project's homepage is: http://www.musicpd.org - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser 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 "libmpdclient.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_CONFIG_H -#include "config.h" -#ifndef HAVE_SOCKLEN_T -typedef SOCKLEN_T socklen_t; -#endif -#endif - -#ifndef MPD_NO_IPV6 -#ifdef AF_INET6 -#define MPD_HAVE_IPV6 -#endif -#endif - -#ifdef MPD_HAVE_IPV6 -int mpd_ipv6Supported() { - int s; - s = socket(AF_INET6,SOCK_STREAM,0); - if(s == -1) return 0; - close(s); - return 1; -} -#endif - - -char * mpd_sanitizeArg(const char * arg) { - size_t i; - int count=0; - char * ret; - - for(i=0;iname = strdup(name); - ret->value = strdup(value); - - return ret; -} - -void mpd_freeReturnElement(mpd_ReturnElement * re) { - free(re->name); - free(re->value); - free(re); -} - -void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout) { - connection->timeout.tv_sec = (int)timeout; - connection->timeout.tv_usec = (int)(timeout*1e6 - - connection->timeout.tv_sec*1000000+0.5); -} - -mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) { - int err; - struct hostent * he; - struct sockaddr * dest; - socklen_t destlen; - struct sockaddr_in sin; - char * rt; - char * output; - mpd_Connection * connection = malloc(sizeof(mpd_Connection)); - struct timeval tv; - fd_set fds; -#ifdef MPD_HAVE_IPV6 - struct sockaddr_in6 sin6; -#endif - strcpy(connection->buffer,""); - connection->buflen = 0; - connection->bufstart = 0; - strcpy(connection->errorStr,""); - connection->error = 0; - connection->doneProcessing = 0; - connection->commandList = 0; - connection->returnElement = NULL; - - if(!(he=gethostbyname(host))) { - snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, - "host \"%s\" not found",host); - connection->error = MPD_ERROR_UNKHOST; - return connection; - } - - memset(&sin,0,sizeof(struct sockaddr_in)); - /*dest.sin_family = he->h_addrtype;*/ - sin.sin_family = AF_INET; - sin.sin_port = htons(port); -#ifdef MPD_HAVE_IPV6 - memset(&sin6,0,sizeof(struct sockaddr_in6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_port = htons(port); -#endif - switch(he->h_addrtype) { - case AF_INET: - memcpy((char *)&sin.sin_addr.s_addr,(char *)he->h_addr, - he->h_length); - dest = (struct sockaddr *)&sin; - destlen = sizeof(struct sockaddr_in); - break; -#ifdef MPD_HAVE_IPV6 - case AF_INET6: - if(!mpd_ipv6Supported()) { - strcpy(connection->errorStr,"no IPv6 suuport but a " - "IPv6 address found\n"); - connection->error = MPD_ERROR_SYSTEM; - return connection; - } - memcpy((char *)&sin6.sin6_addr.s6_addr,(char *)he->h_addr, - he->h_length); - dest = (struct sockaddr *)&sin6; - destlen = sizeof(struct sockaddr_in6); - break; -#endif - default: - strcpy(connection->errorStr,"address type is not IPv4 or " - "IPv6\n"); - connection->error = MPD_ERROR_SYSTEM; - return connection; - break; - } - - if((connection->sock = socket(dest->sa_family,SOCK_STREAM,0))<0) { - strcpy(connection->errorStr,"problems creating socket"); - connection->error = MPD_ERROR_SYSTEM; - return connection; - } - - /* connect stuff */ - { -#ifdef SO_RCVTIMEO - struct timeval rcvoldto; - struct timeval sndoldto; - socklen_t oldlen = sizeof(struct timeval); - - 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) - { - 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"))) { - tv.tv_sec = connection->timeout.tv_sec; - tv.tv_usec = connection->timeout.tv_usec; - FD_ZERO(&fds); - FD_SET(connection->sock,&fds); - if((err = select(connection->sock+1,&fds,NULL,NULL,&tv)) == 1) { - int readed; - readed = recv(connection->sock, - &(connection->buffer[connection->buflen]), - MPD_BUFFER_MAX_LENGTH-connection->buflen,0); - if(readed<=0) { - snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, - "problems getting a response from" - " \"%s\" on port %i",host, - port); - connection->error = MPD_ERROR_NORESPONSE; - return connection; - } - connection->buflen+=readed; - connection->buffer[connection->buflen] = '\0'; - tv.tv_sec = connection->timeout.tv_sec; - tv.tv_usec = connection->timeout.tv_usec; - } - else if(err<0 && errno==EINTR) continue; - else { - snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, - "timeout in attempting to get a response from" - " \"%s\" on port %i",host,port); - connection->error = MPD_ERROR_NORESPONSE; - return connection; - } - } - - *rt = '\0'; - output = strdup(connection->buffer); - strcpy(connection->buffer,rt+1); - connection->buflen = strlen(connection->buffer); - - if(strncmp(output,MPD_WELCOME_MESSAGE,strlen(MPD_WELCOME_MESSAGE))) { - free(output); - snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, - "mpd not running on port %i on host \"%s\"", - port,host); - connection->error = MPD_ERROR_NOTMPD; - return connection; - } - - { - char * test; - char * version[3]; - char * tmp = &output[strlen(MPD_WELCOME_MESSAGE)]; - char * search = "."; - int i; - - for(i=0;i<3;i++) { - char * tok; - if(i==3) search = " "; - version[i] = strtok_r(tmp,search,&tok); - if(!version[i]) { - free(output); - snprintf(connection->errorStr, - MPD_BUFFER_MAX_LENGTH, - "error parsing version number at " - "\"%s\"", - &output[strlen(MPD_WELCOME_MESSAGE)]); - connection->error = MPD_ERROR_NOTMPD; - return connection; - } - connection->version[i] = strtol(version[i],&test,10); - if(version[i]==test || *test!='\0') { - free(output); - snprintf(connection->errorStr, - MPD_BUFFER_MAX_LENGTH, - "error parsing version number at " - "\"%s\"", - &output[strlen(MPD_WELCOME_MESSAGE)]); - connection->error = MPD_ERROR_NOTMPD; - return connection; - } - tmp = NULL; - } - } - - free(output); - - connection->doneProcessing = 1; - - return connection; -} - -void mpd_clearError(mpd_Connection * connection) { - connection->error = 0; - connection->errorStr[0] = '\0'; -} - -void mpd_closeConnection(mpd_Connection * connection) { - close(connection->sock); - if(connection->returnElement) free(connection->returnElement); - free(connection); -} - -void mpd_executeCommand(mpd_Connection * connection, char * command) { - int ret; - struct timeval tv; - fd_set fds; - char * commandPtr = command; - int commandLen = strlen(command); - - if(!connection->doneProcessing && !connection->commandList) { - strcpy(connection->errorStr,"not done processing current command"); - connection->error = 1; - return; - } - - mpd_clearError(connection); - - FD_ZERO(&fds); - FD_SET(connection->sock,&fds); - tv.tv_sec = connection->timeout.tv_sec; - tv.tv_usec = connection->timeout.tv_usec; - - while((ret = select(connection->sock+1,NULL,&fds,NULL,&tv)==1) || - (ret==-1 && errno==EINTR)) { - ret = send(connection->sock,commandPtr,commandLen, - MSG_DONTWAIT); - if(ret<=0) - { - if(ret==EAGAIN || ret==EINTR) continue; - snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, - "problems giving command \"%s\"",command); - connection->error = MPD_ERROR_SENDING; - return; - } - else { - commandPtr+=ret; - commandLen-=ret; - } - - if(commandLen<=0) break; - } - - if(commandLen>0) { - perror(""); - snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, - "timeout sending command \"%s\"",command); - connection->error = MPD_ERROR_TIMEOUT; - return; - } - - if(!connection->commandList) connection->doneProcessing = 0; -} - -void mpd_getNextReturnElement(mpd_Connection * connection) { - char * output = NULL; - char * rt = NULL; - char * name; - char * value; - fd_set fds; - struct timeval tv; - char * tok; - int readed; - char * bufferCheck; - int err; - - if(connection->returnElement) mpd_freeReturnElement(connection->returnElement); - connection->returnElement = NULL; - - if(connection->doneProcessing) { - strcpy(connection->errorStr,"already done processing current command"); - connection->error = 1; - return; - } - - bufferCheck = connection->buffer+connection->bufstart; - while(connection->bufstart>=connection->buflen || - !(rt = strstr(bufferCheck,"\n"))) { - if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) { - memmove(connection->buffer, - connection->buffer+ - connection->bufstart, - connection->buflen- - connection->bufstart+1); - bufferCheck-=connection->bufstart; - connection->buflen-=connection->bufstart; - connection->bufstart = 0; - } - if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) { - strcpy(connection->errorStr,"buffer overrun"); - connection->error = MPD_ERROR_BUFFEROVERRUN; - connection->doneProcessing = 1; - return; - } - bufferCheck+=connection->buflen-connection->bufstart; - tv.tv_sec = connection->timeout.tv_sec; - tv.tv_usec = connection->timeout.tv_usec; - FD_ZERO(&fds); - FD_SET(connection->sock,&fds); - if((err = select(connection->sock+1,&fds,NULL,NULL,&tv) == 1)) { - readed = recv(connection->sock, - connection->buffer+connection->buflen, - MPD_BUFFER_MAX_LENGTH-connection->buflen, - MSG_DONTWAIT); - if(readed<0 && (errno==EAGAIN || errno==EINTR)) { - continue; - } - if(readed<=0) { - strcpy(connection->errorStr,"connection" - " closed"); - connection->error = MPD_ERROR_CONNCLOSED; - connection->doneProcessing = 1; - return; - } - connection->buflen+=readed; - connection->buffer[connection->buflen] = '\0'; - } - else if(err<0 && errno==EINTR) continue; - else { - strcpy(connection->errorStr,"connection timeout"); - connection->error = MPD_ERROR_TIMEOUT; - connection->doneProcessing = 1; - return; - } - } - - *rt = '\0'; - output = connection->buffer+connection->bufstart; - connection->bufstart = rt - connection->buffer + 1; - - if(strcmp(output,"OK")==0) { - connection->doneProcessing = 1; - return; - } - if(strncmp(output,"ACK",strlen("ACK"))==0) { - strcpy(connection->errorStr,output); - connection->error = MPD_ERROR_ACK; - connection->doneProcessing = 1; - return; - } - - name = strtok_r(output,":",&tok); - if(name && (value = strtok_r(NULL,"",&tok)) && value[0]==' ') { - connection->returnElement = mpd_newReturnElement(name,&(value[1])); - } - else { - if(!name || !value) { - snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, - "error parsing: %s",output); - } - else { - snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, - "error parsing: %s:%s",name,value); - } - connection->errorStr[MPD_BUFFER_MAX_LENGTH] = '\0'; - connection->error = 1; - } -} - -void mpd_finishCommand(mpd_Connection * connection) { - while(!connection->doneProcessing) mpd_getNextReturnElement(connection); -} - - -mpd_Status * mpd_getStatus(mpd_Connection * connection) { - mpd_Status * status; - - mpd_executeCommand(connection,"status\n"); - - if(connection->error) return NULL; - - status = malloc(sizeof(mpd_Status)); - status->volume = -1; - status->repeat = 0; - status->random = 0; - status->playlist = -1; - status->playlistLength = -1; - status->state = -1; - status->song = 0; - status->elapsedTime = 0; - status->totalTime = 0; - status->bitRate = 0; - status->sampleRate = 0; - status->bits = 0; - status->channels = 0; - status->crossfade = -1; - status->error = NULL; - - mpd_getNextReturnElement(connection); - if(connection->error) { - free(status); - return NULL; - } - while(connection->returnElement) { - mpd_ReturnElement * re = connection->returnElement; - if(strcmp(re->name,"volume")==0) { - status->volume = atoi(re->value); - } - else if(strcmp(re->name,"repeat")==0) { - status->repeat = atoi(re->value); - } - else if(strcmp(re->name,"random")==0) { - status->random = atoi(re->value); - } - else if(strcmp(re->name,"playlist")==0) { - status->playlist = strtol(re->value,NULL,10); - } - else if(strcmp(re->name,"playlistlength")==0) { - status->playlistLength = atoi(re->value); - } - else if(strcmp(re->name,"bitrate")==0) { - status->bitRate = atoi(re->value); - } - else if(strcmp(re->name,"state")==0) { - if(strcmp(re->value,"play")==0) { - status->state = MPD_STATUS_STATE_PLAY; - } - else if(strcmp(re->value,"stop")==0) { - status->state = MPD_STATUS_STATE_STOP; - } - else if(strcmp(re->value,"pause")==0) { - status->state = MPD_STATUS_STATE_PAUSE; - } - else { - status->state = MPD_STATUS_STATE_UNKNOWN; - } - } - else if(strcmp(re->name,"song")==0) { - status->song = atoi(re->value); - } - else if(strcmp(re->name,"time")==0) { - char * tok; - char * copy; - copy = strdup(re->value); - status->elapsedTime = atoi(strtok_r(copy,":",&tok)); - status->totalTime = atoi(strtok_r(NULL,"",&tok)); - free(copy); - } - else if(strcmp(re->name,"error")==0) { - status->error = strdup(re->value); - } - else if(strcmp(re->name,"xfade")==0) { - status->crossfade = atoi(re->value); - } - else if(strcmp(re->name,"audio")==0) { - char * tok; - char * copy; - copy = strdup(re->value); - status->sampleRate = atoi(strtok_r(copy,":",&tok)); - status->bits = atoi(strtok_r(NULL,":",&tok)); - status->channels = atoi(strtok_r(NULL,"",&tok)); - free(copy); - } - - mpd_getNextReturnElement(connection); - if(connection->error) { - free(status); - return NULL; - } - } - - if(connection->error) { - free(status); - return NULL; - } - else if(status->state<0) { - strcpy(connection->errorStr,"state not found"); - connection->error = 1; - free(status); - return NULL; - } - - return status; -} - -void mpd_freeStatus(mpd_Status * status) { - if(status->error) free(status->error); - free(status); -} - -mpd_Stats * mpd_getStats(mpd_Connection * connection) { - mpd_Stats * stats; - - mpd_executeCommand(connection,"stats\n"); - - if(connection->error) return NULL; - - stats = malloc(sizeof(mpd_Stats)); - stats->numberOfArtists = 0; - stats->numberOfAlbums = 0; - stats->numberOfSongs = 0; - stats->uptime = 0; - stats->dbUpdateTime = 0; - stats->playTime = 0; - stats->dbPlayTime = 0; - - mpd_getNextReturnElement(connection); - if(connection->error) { - free(stats); - return NULL; - } - while(connection->returnElement) { - mpd_ReturnElement * re = connection->returnElement; - if(strcmp(re->name,"artists")==0) { - stats->numberOfArtists = atoi(re->value); - } - else if(strcmp(re->name,"albums")==0) { - stats->numberOfAlbums = atoi(re->value); - } - else if(strcmp(re->name,"songs")==0) { - stats->numberOfSongs = atoi(re->value); - } - else if(strcmp(re->name,"uptime")==0) { - stats->uptime = strtol(re->value,NULL,10); - } - else if(strcmp(re->name,"db_update")==0) { - stats->dbUpdateTime = strtol(re->value,NULL,10); - } - else if(strcmp(re->name,"playtime")==0) { - stats->playTime = strtol(re->value,NULL,10); - } - else if(strcmp(re->name,"db_playtime")==0) { - stats->dbPlayTime = strtol(re->value,NULL,10); - } - - mpd_getNextReturnElement(connection); - if(connection->error) { - free(stats); - return NULL; - } - } - - if(connection->error) { - free(stats); - return NULL; - } - - return stats; -} - -void mpd_freeStats(mpd_Stats * stats) { - free(stats); -} - -void mpd_initSong(mpd_Song * song) { - song->file = NULL; - song->artist = NULL; - song->album = NULL; - song->track = NULL; - song->title = NULL; - song->time = MPD_SONG_NO_TIME; -} - -void mpd_finishSong(mpd_Song * song) { - if(song->file) free(song->file); - if(song->artist) free(song->artist); - if(song->album) free(song->album); - if(song->title) free(song->title); - if(song->track) free(song->track); -} - -mpd_Song * mpd_newSong() { - mpd_Song * ret = malloc(sizeof(mpd_Song)); - - mpd_initSong(ret); - - return ret; -} - -void mpd_freeSong(mpd_Song * song) { - mpd_finishSong(song); - free(song); -} - -mpd_Song * mpd_songDup(mpd_Song * song) { - mpd_Song * ret = mpd_newSong(); - - if(song->file) ret->file = strdup(song->file); - if(song->artist) ret->artist = strdup(song->artist); - if(song->album) ret->album = strdup(song->album); - if(song->title) ret->title = strdup(song->title); - if(song->track) ret->track = strdup(song->track); - ret->time = song->time; - - return ret; -} - -void mpd_initDirectory(mpd_Directory * directory) { - directory->path = NULL; -} - -void mpd_finishDirectory(mpd_Directory * directory) { - if(directory->path) free(directory->path); -} - -mpd_Directory * mpd_newDirectory () { - mpd_Directory * directory = malloc(sizeof(mpd_Directory));; - - mpd_initDirectory(directory); - - return directory; -} - -void mpd_freeDirectory(mpd_Directory * directory) { - mpd_finishDirectory(directory); - - free(directory); -} - -mpd_Directory * mpd_directoryDup(mpd_Directory * directory) { - mpd_Directory * ret = mpd_newDirectory(); - - if(directory->path) ret->path = strdup(directory->path); - - return ret; -} - -void mpd_initPlaylistFile(mpd_PlaylistFile * playlist) { - playlist->path = NULL; -} - -void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist) { - if(playlist->path) free(playlist->path); -} - -mpd_PlaylistFile * mpd_newPlaylistFile() { - mpd_PlaylistFile * playlist = malloc(sizeof(mpd_PlaylistFile)); - - mpd_initPlaylistFile(playlist); - - return playlist; -} - -void mpd_freePlaylistFile(mpd_PlaylistFile * playlist) { - mpd_finishPlaylistFile(playlist); - free(playlist); -} - -mpd_PlaylistFile * mpd_playlistFileDup(mpd_PlaylistFile * playlist) { - mpd_PlaylistFile * ret = mpd_newPlaylistFile(); - - if(playlist->path) ret->path = strdup(playlist->path); - - return ret; -} - -void mpd_initInfoEntity(mpd_InfoEntity * entity) { - entity->info.directory = NULL; -} - -void mpd_finishInfoEntity(mpd_InfoEntity * entity) { - if(entity->info.directory) { - if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) { - mpd_freeDirectory(entity->info.directory); - } - else if(entity->type == MPD_INFO_ENTITY_TYPE_SONG) { - mpd_freeSong(entity->info.song); - } - else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) { - mpd_freePlaylistFile(entity->info.playlistFile); - } - } -} - -mpd_InfoEntity * mpd_newInfoEntity() { - mpd_InfoEntity * entity = malloc(sizeof(mpd_InfoEntity)); - - mpd_initInfoEntity(entity); - - return entity; -} - -void mpd_freeInfoEntity(mpd_InfoEntity * entity) { - mpd_finishInfoEntity(entity); - free(entity); -} - -void mpd_sendInfoCommand(mpd_Connection * connection, char * command) { - mpd_executeCommand(connection,command); -} - -mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection) { - mpd_InfoEntity * entity = NULL; - - if(connection->doneProcessing) return NULL; - - if(!connection->returnElement) mpd_getNextReturnElement(connection); - - if(connection->returnElement) { - if(strcmp(connection->returnElement->name,"file")==0) { - entity = mpd_newInfoEntity(); - entity->type = MPD_INFO_ENTITY_TYPE_SONG; - entity->info.song = mpd_newSong(); - entity->info.song->file = - strdup(connection->returnElement->value); - } - else if(strcmp(connection->returnElement->name, - "directory")==0) { - entity = mpd_newInfoEntity(); - entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY; - entity->info.directory = mpd_newDirectory(); - entity->info.directory->path = - strdup(connection->returnElement->value); - } - else if(strcmp(connection->returnElement->name,"playlist")==0) { - entity = mpd_newInfoEntity(); - entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE; - entity->info.playlistFile = mpd_newPlaylistFile(); - entity->info.playlistFile->path = - strdup(connection->returnElement->value); - } - else { - connection->error = 1; - strcpy(connection->errorStr,"problem parsing song info"); - return NULL; - } - } - else return NULL; - - mpd_getNextReturnElement(connection); - while(connection->returnElement) { - mpd_ReturnElement * re = connection->returnElement; - - if(strcmp(re->name,"file")==0) return entity; - else if(strcmp(re->name,"directory")==0) return entity; - else if(strcmp(re->name,"playlist")==0) return entity; - - if(entity->type == MPD_INFO_ENTITY_TYPE_SONG && - strlen(re->value)) { - if(!entity->info.song->artist && - strcmp(re->name,"Artist")==0) { - entity->info.song->artist = strdup(re->value); - } - else if(!entity->info.song->album && - strcmp(re->name,"Album")==0) { - entity->info.song->album = strdup(re->value); - } - else if(!entity->info.song->title && - strcmp(re->name,"Title")==0) { - entity->info.song->title = strdup(re->value); - } - else if(!entity->info.song->track && - strcmp(re->name,"Track")==0) { - entity->info.song->track = strdup(re->value); - } - else if(entity->info.song->time==MPD_SONG_NO_TIME && - strcmp(re->name,"Time")==0) { - entity->info.song->time = atoi(re->value); - } - } - else if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) { - } - else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) { - } - - mpd_getNextReturnElement(connection); - } - - return entity; -} - -char * mpd_getNextReturnElementNamed(mpd_Connection * connection, - const char * name) -{ - if(connection->doneProcessing) return NULL; - - mpd_getNextReturnElement(connection); - while(connection->returnElement) { - mpd_ReturnElement * re = connection->returnElement; - - if(strcmp(re->name,name)==0) return strdup(re->value); - mpd_getNextReturnElement(connection); - } - - return NULL; -} - -char * mpd_getNextArtist(mpd_Connection * connection) { - return mpd_getNextReturnElementNamed(connection,"Artist"); -} - -char * mpd_getNextAlbum(mpd_Connection * connection) { - return mpd_getNextReturnElementNamed(connection,"Album"); -} - -void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songNum) { - char * string = malloc(strlen("playlistinfo")+25); - sprintf(string,"playlistinfo \"%i\"\n",songNum); - mpd_sendInfoCommand(connection,string); - free(string); -} - -void mpd_sendListallCommand(mpd_Connection * connection, const char * dir) { - char * sDir = mpd_sanitizeArg(dir); - char * string = malloc(strlen("listall")+strlen(sDir)+5); - sprintf(string,"listall \"%s\"\n",sDir); - mpd_sendInfoCommand(connection,string); - free(string); - free(sDir); -} - -void mpd_sendListallInfoCommand(mpd_Connection * connection, const char * dir) { - char * sDir = mpd_sanitizeArg(dir); - char * string = malloc(strlen("listallinfo")+strlen(sDir)+5); - sprintf(string,"listallinfo \"%s\"\n",sDir); - mpd_sendInfoCommand(connection,string); - free(string); - free(sDir); -} - -void mpd_sendLsInfoCommand(mpd_Connection * connection, const char * dir) { - char * sDir = mpd_sanitizeArg(dir); - char * string = malloc(strlen("lsinfo")+strlen(sDir)+5); - sprintf(string,"lsinfo \"%s\"\n",sDir); - mpd_sendInfoCommand(connection,string); - free(string); - free(sDir); -} - -void mpd_sendSearchCommand(mpd_Connection * connection, int table, - const char * str) -{ - char st[10]; - char * string; - char * sanitStr = mpd_sanitizeArg(str); - if(table == MPD_TABLE_ARTIST) strcpy(st,"artist"); - else if(table == MPD_TABLE_ALBUM) strcpy(st,"album"); - else if(table == MPD_TABLE_TITLE) strcpy(st,"title"); - else if(table == MPD_TABLE_FILENAME) strcpy(st,"filename"); - else { - connection->error = 1; - strcpy(connection->errorStr,"unknown table for search"); - return; - } - string = malloc(strlen("search")+strlen(sanitStr)+strlen(st)+6); - sprintf(string,"search %s \"%s\"\n",st,sanitStr); - mpd_sendInfoCommand(connection,string); - free(string); - free(sanitStr); -} - -void mpd_sendFindCommand(mpd_Connection * connection, int table, - const char * str) -{ - char st[10]; - char * string; - char * sanitStr = mpd_sanitizeArg(str); - if(table == MPD_TABLE_ARTIST) strcpy(st,"artist"); - else if(table == MPD_TABLE_ALBUM) strcpy(st,"album"); - else if(table == MPD_TABLE_TITLE) strcpy(st,"title"); - else { - connection->error = 1; - strcpy(connection->errorStr,"unknown table for find"); - return; - } - string = malloc(strlen("find")+strlen(sanitStr)+strlen(st)+6); - sprintf(string,"find %s \"%s\"\n",st,sanitStr); - mpd_sendInfoCommand(connection,string); - free(string); - free(sanitStr); -} - -void mpd_sendListCommand(mpd_Connection * connection, int table, - const char * arg1) -{ - char st[10]; - char * string; - if(table == MPD_TABLE_ARTIST) strcpy(st,"artist"); - else if(table == MPD_TABLE_ALBUM) strcpy(st,"album"); - else { - connection->error = 1; - strcpy(connection->errorStr,"unknown table for list"); - return; - } - if(arg1) { - char * sanitArg1 = mpd_sanitizeArg(arg1); - string = malloc(strlen("list")+strlen(sanitArg1)+strlen(st)+6); - sprintf(string,"list %s \"%s\"\n",st,sanitArg1); - free(sanitArg1); - } - else { - string = malloc(strlen("list")+strlen(st)+3); - sprintf(string,"list %s\n",st); - } - mpd_sendInfoCommand(connection,string); - free(string); -} - -void mpd_sendAddCommand(mpd_Connection * connection, const char * file) { - char * sFile = mpd_sanitizeArg(file); - char * string = malloc(strlen("add")+strlen(sFile)+5); - sprintf(string,"add \"%s\"\n",sFile); - mpd_executeCommand(connection,string); - free(string); - free(sFile); -} - -void mpd_sendDeleteCommand(mpd_Connection * connection, int songNum) { - char * string = malloc(strlen("delete")+25); - sprintf(string,"delete \"%i\"\n",songNum); - mpd_sendInfoCommand(connection,string); - free(string); -} - -void mpd_sendSaveCommand(mpd_Connection * connection, const char * name) { - char * sName = mpd_sanitizeArg(name); - char * string = malloc(strlen("save")+strlen(sName)+5); - sprintf(string,"save \"%s\"\n",sName); - mpd_executeCommand(connection,string); - free(string); - free(sName); -} - -void mpd_sendLoadCommand(mpd_Connection * connection, const char * name) { - char * sName = mpd_sanitizeArg(name); - char * string = malloc(strlen("load")+strlen(sName)+5); - sprintf(string,"load \"%s\"\n",sName); - mpd_executeCommand(connection,string); - free(string); - free(sName); -} - -void mpd_sendRmCommand(mpd_Connection * connection, const char * name) { - char * sName = mpd_sanitizeArg(name); - char * string = malloc(strlen("rm")+strlen(sName)+5); - sprintf(string,"rm \"%s\"\n",sName); - mpd_executeCommand(connection,string); - free(string); - free(sName); -} - -void mpd_sendShuffleCommand(mpd_Connection * connection) { - mpd_executeCommand(connection,"shuffle\n"); -} - -void mpd_sendClearCommand(mpd_Connection * connection) { - mpd_executeCommand(connection,"clear\n"); -} - -void mpd_sendPlayCommand(mpd_Connection * connection, int songNum) { - char * string = malloc(strlen("play")+25); - sprintf(string,"play \"%i\"\n",songNum); - mpd_sendInfoCommand(connection,string); - free(string); -} - -void mpd_sendStopCommand(mpd_Connection * connection) { - mpd_executeCommand(connection,"stop\n"); -} - -void mpd_sendPauseCommand(mpd_Connection * connection) { - mpd_executeCommand(connection,"pause\n"); -} - -void mpd_sendNextCommand(mpd_Connection * connection) { - mpd_executeCommand(connection,"next\n"); -} - -void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to) { - char * string = malloc(strlen("move")+25); - sprintf(string,"move \"%i\" \"%i\"\n",from,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); - 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); - mpd_sendInfoCommand(connection,string); - free(string); -} - -void mpd_sendUpdateCommand(mpd_Connection * connection) { - mpd_executeCommand(connection,"update\n"); -} - -void mpd_sendPrevCommand(mpd_Connection * connection) { - mpd_executeCommand(connection,"previous\n"); -} - -void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode) { - char * string = malloc(strlen("repeat")+25); - sprintf(string,"repeat \"%i\"\n",repeatMode); - mpd_executeCommand(connection,string); - free(string); -} - -void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode) { - char * string = malloc(strlen("random")+25); - sprintf(string,"random \"%i\"\n",randomMode); - mpd_executeCommand(connection,string); - free(string); -} - -void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange) { - char * string = malloc(strlen("setvol")+25); - sprintf(string,"setvol \"%i\"\n",volumeChange); - mpd_executeCommand(connection,string); - free(string); -} - -void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange) { - char * string = malloc(strlen("volume")+25); - sprintf(string,"volume \"%i\"\n",volumeChange); - mpd_executeCommand(connection,string); - free(string); -} - -void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds) { - char * string = malloc(strlen("crossfade")+25); - sprintf(string,"crossfade \"%i\"\n",seconds); - mpd_executeCommand(connection,string); - free(string); -} - -void mpd_sendPasswordCommand(mpd_Connection * connection, const char * pass) { - char * sPass = mpd_sanitizeArg(pass); - char * string = malloc(strlen("password")+strlen(sPass)+5); - sprintf(string,"password \"%s\"\n",sPass); - mpd_executeCommand(connection,string); - free(string); - free(sPass); -} - -void mpd_sendCommandListBegin(mpd_Connection * connection) { - if(connection->commandList) { - strcpy(connection->errorStr,"already in command list mode"); - connection->error = 1; - return; - } - connection->commandList = 1; - mpd_executeCommand(connection,"command_list_begin\n"); -} - -void mpd_sendCommandListEnd(mpd_Connection * connection) { - if(!connection->commandList) { - strcpy(connection->errorStr,"not in command list mode"); - connection->error = 1; - return; - } - connection->commandList = 0; - mpd_executeCommand(connection,"command_list_end\n"); -} diff --git a/libmpdclient.h b/libmpdclient.h deleted file mode 100644 index 6d749fb..0000000 --- a/libmpdclient.h +++ /dev/null @@ -1,397 +0,0 @@ -/* libmpdclient - * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) - * This project's homepage is: http://www.musicpd.org - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser 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 - */ - -#ifndef LIBMPDCLIENT_H -#define LIBMPDCLIENT_H - -#include - -#define MPD_BUFFER_MAX_LENGTH 50000 -#define MPD_WELCOME_MESSAGE "OK MPD " - -#define MPD_ERROR_TIMEOUT 10 /* timeout trying to talk to mpd */ -#define MPD_ERROR_SYSTEM 11 /* system error */ -#define MPD_ERROR_UNKHOST 12 /* unknown host */ -#define MPD_ERROR_CONNPORT 13 /* problems connecting to port on host */ -#define MPD_ERROR_NOTMPD 14 /* mpd not running on port at host */ -#define MPD_ERROR_NORESPONSE 15 /* no response on attempting to connect */ -#define MPD_ERROR_SENDING 16 /* error sending command */ -#define MPD_ERROR_CONNCLOSED 17 /* connection closed by mpd */ -#define MPD_ERROR_ACK 18 /* ACK returned! */ -#define MPD_ERROR_BUFFEROVERRUN 19 /* Buffer was overrun! */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* internal stuff don't touch this struct */ -typedef struct _mpd_ReturnElement { - char * name; - char * value; -} mpd_ReturnElement; - -/* mpd_Connection - * holds info about connection to mpd - * use error, and errorStr to detect errors - */ -typedef struct _mpd_Connection { - /* use this to check the version of mpd */ - int version[3]; - /* IMPORTANT, you want to get the error messages from here */ - char errorStr[MPD_BUFFER_MAX_LENGTH+1]; - /* this will be set to 1 if there is an error, 0 if not */ - int error; - /* DON'T TOUCH any of the rest of this stuff */ - int sock; - char buffer[MPD_BUFFER_MAX_LENGTH+1]; - int buflen; - int bufstart; - int doneProcessing; - int commandList; - mpd_ReturnElement * returnElement; - struct timeval timeout; -} mpd_Connection; - -/* mpd_newConnection - * use this to open a new connection - * you should use mpd_closeConnection, when your done with the connection, - * even if an error has occurred - * _timeout_ is the connection timeout period in seconds - */ -mpd_Connection * mpd_newConnection(const char * host, int port, float timeout); - -void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout); - -/* mpd_closeConnection - * use this to close a connection and free'ing subsequent memory - */ -void mpd_closeConnection(mpd_Connection * connection); - -/* mpd_clearError - * clears error - */ -void mpd_clearError(mpd_Connection * connection); - -/* STATUS STUFF */ - -/* use these with status.state to determine what state the player is in */ -#define MPD_STATUS_STATE_UNKNOWN 0 -#define MPD_STATUS_STATE_STOP 1 -#define MPD_STATUS_STATE_PLAY 2 -#define MPD_STATUS_STATE_PAUSE 3 - -/* us this with status.volume to determine if mpd has volume support */ -#define MPD_STATUS_NO_VOLUME -1 - -/* mpd_Status - * holds info return from status command - */ -typedef struct mpd_Status { - /* 0-100, or MPD_STATUS_NO_VOLUME when there is no volume support */ - int volume; - /* 1 if repeat is on, 0 otherwise */ - int repeat; - /* 1 if random is on, 0 otherwise */ - int random; - /* playlist length */ - int playlistLength; - /* playlist, use this to determine when the playlist has changed */ - long long playlist; - /* use with MPD_STATUS_STATE_* to determine state of player */ - int state; - /* crossfade setting in seconds */ - int crossfade; - /* if in PLAY or PAUSE state, this is the number of the currently - * playing song in the playlist, beginning with 0 - */ - int song; - /* time in seconds that have elapsed in the currently playing/paused - * song - */ - int elapsedTime; - /* length in seconds of the currently playing/paused song */ - int totalTime; - /* current bit rate in kbs */ - int bitRate; - /* audio sample rate */ - unsigned int sampleRate; - /* audio bits */ - int bits; - /* audio channels */ - int channels; - /* error */ - char * error; -} mpd_Status; - -/* mpd_getStatus - * returns status info, be sure to free it with mpd_freeStatus() - */ -mpd_Status * mpd_getStatus(mpd_Connection * connection); - -/* mpd_freeStatus - * free's status info malloc'd and returned by mpd_getStatus - */ -void mpd_freeStatus(mpd_Status * status); - -typedef struct _mpd_Stats { - int numberOfArtists; - int numberOfAlbums; - int numberOfSongs; - unsigned long uptime; - unsigned long dbUpdateTime; - unsigned long playTime; - unsigned long dbPlayTime; -} mpd_Stats; - -mpd_Stats * mpd_getStats(mpd_Connection * connection); - -void mpd_freeStats(mpd_Stats * stats); - -/* SONG STUFF */ - -#define MPD_SONG_NO_TIME -1 - -/* mpd_Song - * for storing song info returned by mpd - */ -typedef struct _mpd_Song { - /* filename of song */ - char * file; - /* artist, maybe NULL if there is no tag */ - char * artist; - /* title, maybe NULL if there is no tag */ - char * title; - /* album, maybe NULL if there is no tag */ - char * album; - /* track, maybe NULL if there is no tag */ - char * track; - /* length of song in seconds, check that it is not MPD_SONG_NO_TIME */ - int time; -} mpd_Song; - -/* mpd_newSong - * use to allocate memory for a new mpd_Song - * file, artist, etc all initialized to NULL - * if your going to assign values to file, artist, etc - * be sure to malloc or strdup the memory - * use mpd_freeSong to free the memory for the mpd_Song, it will also - * free memory for file, artist, etc, so don't do it yourself - */ -mpd_Song * mpd_newSong(); - -/* mpd_freeSong - * use to free memory allocated by mpd_newSong - * also it will free memory pointed to by file, artist, etc, so be careful - */ -void mpd_freeSong(mpd_Song * song); - -/* mpd_songDup - * works like strDup, but for a mpd_Song - */ -mpd_Song * mpd_songDup(mpd_Song * song); - -/* DIRECTORY STUFF */ - -/* mpd_Directory - * used to store info fro directory (right now that just the path) - */ -typedef struct _mpd_Directory { - char * path; -} mpd_Directory; - -/* mpd_newDirectory - * allocates memory for a new directory - * use mpd_freeDirectory to free this memory - */ -mpd_Directory * mpd_newDirectory (); - -/* mpd_freeDirectory - * used to free memory allocated with mpd_newDirectory, and it frees - * path of mpd_Directory, so be careful - */ -void mpd_freeDirectory(mpd_Directory * directory); - -/* mpd_directoryDup - * works like strdup, but for mpd_Directory - */ -mpd_Directory * mpd_directoryDup(mpd_Directory * directory); - -/* PLAYLISTFILE STUFF */ - -/* mpd_PlaylistFile - * stores info about playlist file returned by lsinfo - */ -typedef struct _mpd_PlaylistFile { - char * path; -} mpd_PlaylistFile; - -/* mpd_newPlaylistFile - * allocates memory for new mpd_PlaylistFile, path is set to NULL - * free this memory with mpd_freePlaylistFile - */ -mpd_PlaylistFile * mpd_newPlaylistFile(); - -/* mpd_freePlaylist - * free memory allocated for freePlaylistFile, will also free - * path, so be careful - */ -void mpd_freePlaylistFile(mpd_PlaylistFile * playlist); - -/* mpd_playlistFileDup - * works like strdup, but for mpd_PlaylistFile - */ -mpd_PlaylistFile * mpd_playlistFileDup(mpd_PlaylistFile * playlist); - -/* INFO ENTITY STUFF */ - -/* the type of entity returned from one of the commands that generates info - * use in conjunction with mpd_InfoEntity.type - */ -#define MPD_INFO_ENTITY_TYPE_DIRECTORY 0 -#define MPD_INFO_ENTITY_TYPE_SONG 1 -#define MPD_INFO_ENTITY_TYPE_PLAYLISTFILE 2 - -/* mpd_InfoEntity - * stores info on stuff returned info commands - */ -typedef struct mpd_InfoEntity { - /* the type of entity, use with MPD_INFO_ENTITY_TYPE_* to determine - * what this entity is (song, directory, etc...) - */ - int type; - /* the actual data you want, mpd_Song, mpd_Directory, etc */ - union { - mpd_Directory * directory; - mpd_Song * song; - mpd_PlaylistFile * playlistFile; - } info; -} mpd_InfoEntity; - -mpd_InfoEntity * mpd_newInfoEntity(); - -void mpd_freeInfoEntity(mpd_InfoEntity * entity); - -/* INFO COMMANDS AND STUFF */ - -/* use this function to loop over after calling Info/Listall functions */ -mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection); - -/* songNum of -1, means to display the whole list */ -void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songNum); - -void mpd_sendListallCommand(mpd_Connection * connection, const char * dir); - -void mpd_sendListallInfoCommand(mpd_Connection * connection, const char * dir); - -void mpd_sendLsInfoCommand(mpd_Connection * connection, const char * dir); - -#define MPD_TABLE_ARTIST 0 -#define MPD_TABLE_ALBUM 1 -#define MPD_TABLE_TITLE 2 -#define MPD_TABLE_FILENAME 3 - -void mpd_sendSearchCommand(mpd_Connection * connection, int table, - const char * str); - -void mpd_sendFindCommand(mpd_Connection * connection, int table, - const char * str); - -/* LIST TAG COMMANDS */ - -/* use this function fetch next artist entry, be sure to free the returned - * string. NULL means there are no more. Best used with sendListArtists - */ -char * mpd_getNextArtist(mpd_Connection * connection); - -char * mpd_getNextAlbum(mpd_Connection * connection); - -/* list artist or albums by artist, arg1 should be set to the artist if - * listing albums by a artist, otherwise NULL for listing all artists or albums - */ -void mpd_sendListCommand(mpd_Connection * connection, int table, - const char * arg1); - -void mpd_sendListAlbumsCommand(mpd_Connection * connection, - const char * artist); - -/* SIMPLE COMMANDS */ - -void mpd_sendAddCommand(mpd_Connection * connection, const char * file); - -void mpd_sendDeleteCommand(mpd_Connection * connection, int songNum); - -void mpd_sendSaveCommand(mpd_Connection * connection, const char * name); - -void mpd_sendLoadCommand(mpd_Connection * connection, const char * name); - -void mpd_sendRmCommand(mpd_Connection * connection, const char * name); - -void mpd_sendShuffleCommand(mpd_Connection * connection); - -void mpd_sendClearCommand(mpd_Connection * connection); - -/* use this to start playing at the beginning, useful when in random mode */ -#define MPD_PLAY_AT_BEGINNING -1 - -void mpd_sendPlayCommand(mpd_Connection * connection, int songNum); - -void mpd_sendStopCommand(mpd_Connection * connection); - -void mpd_sendPauseCommand(mpd_Connection * connection); - -void mpd_sendNextCommand(mpd_Connection * connection); - -void mpd_sendPrevCommand(mpd_Connection * connection); - -void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to); - -void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2); - -void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time); - -void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode); - -void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode); - -void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange); - -/* WARNING: don't use volume command, its depreacted */ -void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange); - -void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds); - -void mpd_sendUpdateCommand(mpd_Connection * connection); - -void mpd_sendPasswordCommand(mpd_Connection * connection, const char * pass); - -/* after executing a command, when your done with it to get its status - * (you want to check connection->error for an error) - */ -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_sendCommandListEnd(mpd_Connection * connection); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/list_window.c b/list_window.c deleted file mode 100644 index 6b4a41f..0000000 --- a/list_window.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * (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 -#include -#include -#include -#include - -#include "config.h" -#include "options.h" -#include "support.h" -#include "command.h" -#include "colors.h" -#include "list_window.h" - -list_window_t * -list_window_init(WINDOW *w, int width, int height) -{ - list_window_t *lw; - - lw = g_malloc(sizeof(list_window_t)); - memset(lw, 0, sizeof(list_window_t)); - lw->w = w; - lw->cols = width; - lw->rows = height; - lw->clear = 1; - return lw; -} - -list_window_t * -list_window_free(list_window_t *lw) -{ - if( lw ) - { - memset(lw, 0, sizeof(list_window_t)); - g_free(lw); - } - return NULL; -} - -void -list_window_reset(list_window_t *lw) -{ - lw->selected = 0; - lw->start = 0; - lw->clear = 1; -} - -void -list_window_check_selected(list_window_t *lw, int length) -{ - while( lw->start && lw->start+lw->rows>length) - lw->start--; - - if( lw->selected<0 ) - lw->selected=0; - - while( lw->selectedstart ) - lw->selected++; - - while( lw->selected>0 && length>0 && lw->selected>=length ) - lw->selected--; -} - -void -list_window_set_selected(list_window_t *lw, int n) -{ - lw->selected=n; -} - -void -list_window_next(list_window_t *lw, int length) -{ - if( lw->selected < length-1 ) - lw->selected++; -} - -void -list_window_previous(list_window_t *lw) -{ - if( lw->selected > 0 ) - lw->selected--; -} - -void -list_window_first(list_window_t *lw) -{ - lw->selected = 0; -} - -void -list_window_last(list_window_t *lw, int length) -{ - lw->selected = length-1; -} - -void -list_window_next_page(list_window_t *lw, int length) -{ - int step = lw->rows-1; - if( step<= 0 ) - return; - if( lw->selected+step < length-1 ) - lw->selected+=step; - else - return list_window_last(lw,length); -} - -void -list_window_previous_page(list_window_t *lw) -{ - int step = lw->rows-1; - if( step<= 0 ) - return; - if( lw->selected-step > 0 ) - lw->selected-=step; - else - list_window_first(lw); -} - - -void -list_window_paint(list_window_t *lw, - list_window_callback_fn_t callback, - void *callback_data) -{ - int i; - int fill = options.wide_cursor; - - while( lw->selected < lw->start ) - { - lw->start--; - lw->clear=1; - } - while( lw->selected >= lw->start+lw->rows ) - { - lw->start++; - lw->clear=1; - } - - for(i=0; irows; i++) - { - int highlight = 0; - char *label; - - label = (callback) (lw->start+i, &highlight, callback_data); - wmove(lw->w, i, 0); - if( lw->clear && (!fill || !label) ) - wclrtoeol(lw->w); - if( label ) - { - int selected = lw->start+i == lw->selected; - - if( highlight ) - colors_use(lw->w, COLOR_LIST_BOLD); - else - colors_use(lw->w, COLOR_LIST); - - if( selected ) - wattron(lw->w, A_REVERSE); - - waddnstr(lw->w, label, lw->cols-1); - if( fill ) - mvwhline(lw->w, i, strlen(label), ' ', lw->cols-1); - - if( selected ) - wattroff(lw->w, A_REVERSE); - } - - } - lw->clear=0; -} - - -int -list_window_find(list_window_t *lw, - list_window_callback_fn_t callback, - void *callback_data, - char *str, - int wrap) -{ - int h; - int i = lw->selected+1; - char *label; - - while( wrap || i==lw->selected+1 ) - { - while( (label=(callback) (i,&h,callback_data)) ) - { - if( str && label && strcasestr(label, str) ) - { - lw->selected = i; - return 0; - } - if( wrap && i==lw->selected ) - return 1; - i++; - } - if( wrap ) - { - i=0; /* first item */ - beep(); - } - } - return 1; -} - - -int -list_window_rfind(list_window_t *lw, - list_window_callback_fn_t callback, - void *callback_data, - char *str, - int wrap, - int rows) -{ - int h; - int i = lw->selected-1; - char *label; - - while( wrap || i==lw->selected-1 ) - { - while( i>=0 && (label=(callback) (i,&h,callback_data)) ) - { - if( str && label && strcasestr(label, str) ) - { - lw->selected = i; - return 0; - } - if( wrap && i==lw->selected ) - return 1; - i--; - } - if( wrap ) - { - i=rows-1; /* last item */ - beep(); - } - } - return 1; -} - - -/* perform basic list window commands (movement) */ -int -list_window_cmd(list_window_t *lw, int rows, command_t cmd) -{ - switch(cmd) - { - case CMD_LIST_PREVIOUS: - list_window_previous(lw); - lw->repaint=1; - break; - case CMD_LIST_NEXT: - list_window_next(lw, rows); - lw->repaint=1; - break; - case CMD_LIST_FIRST: - list_window_first(lw); - lw->repaint = 1; - break; - case CMD_LIST_LAST: - list_window_last(lw, rows); - lw->repaint = 1; - break; - case CMD_LIST_NEXT_PAGE: - list_window_next_page(lw, rows); - lw->repaint = 1; - break; - case CMD_LIST_PREVIOUS_PAGE: - list_window_previous_page(lw); - lw->repaint = 1; - break; - default: - return 0; - } - return 1; -} - - diff --git a/list_window.h b/list_window.h deleted file mode 100644 index 9e91703..0000000 --- a/list_window.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef LIST_WINDOW_H -#define LIST_WINDOW_H - -#define LW_ROW(lw) (lw ? lw->selected-lw->start : 0) - -typedef char * (*list_window_callback_fn_t) (int index, - int *highlight, - void *data); - -typedef struct -{ - WINDOW *w; - int rows, cols; - - int start; - int selected; - int clear; - int repaint; - -} list_window_t; - - -/* create a new list window */ -list_window_t *list_window_init(WINDOW *w, int width, int height); - -/* destroy a list window (returns NULL) */ -list_window_t *list_window_free(list_window_t *lw); - -/* reset a list window (selected=0, start=0, clear=1) */ -void list_window_reset(list_window_t *lw); - -/* paint a list window */ -void list_window_paint(list_window_t *lw, - list_window_callback_fn_t callback, - void *callback_data); - -/* perform basic list window commands (movement) */ -int list_window_cmd(list_window_t *lw, int rows, command_t cmd); - - -/* select functions */ -void list_window_set_selected(list_window_t *lw, int n); -void list_window_previous(list_window_t *lw); -void list_window_next(list_window_t *lw, int length); -void list_window_first(list_window_t *lw); -void list_window_last(list_window_t *lw, int length); -void list_window_previous_page(list_window_t *lw); -void list_window_next_page(list_window_t *lw, int length); -void list_window_check_selected(list_window_t *lw, int length); - -/* find a string in a list window */ -int list_window_find(list_window_t *lw, - list_window_callback_fn_t callback, - void *callback_data, - char *str, - int wrap); - -/* find a string in a list window (reversed) */ -int -list_window_rfind(list_window_t *lw, - list_window_callback_fn_t callback, - void *callback_data, - char *str, - int wrap, - int rows); - -#endif diff --git a/main.c b/main.c deleted file mode 100644 index bb3740b..0000000 --- a/main.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * (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 -#include -#include -#include -#include - -#include "config.h" -#include "libmpdclient.h" -#include "support.h" -#include "mpc.h" -#include "options.h" -#include "command.h" -#include "screen.h" -#include "conf.h" - -/* time in seconds between mpd updates (double) */ -#define MPD_UPDATE_TIME 0.5 - -/* timout in seconds before trying to reconnect (int) */ -#define MPD_RECONNECT_TIMEOUT 3 - - -static mpd_client_t *mpc = NULL; -static GTimer *timer = NULL; - -void -exit_and_cleanup(void) -{ - screen_exit(); - printf("\n"); - charset_close(); - if( mpc ) - { - if( mpc_error(mpc) ) - fprintf(stderr,"Error: %s\n", mpc_error_str(mpc)); - mpc_close(mpc); - } - g_free(options.host); - g_free(options.password); - if( timer ) - g_timer_destroy(timer); -} - -void -catch_sigint( int sig ) -{ - printf( "\nExiting...\n"); - exit(EXIT_SUCCESS); -} - -int -main(int argc, const char *argv[]) -{ - options_t *options; - struct sigaction act; - gboolean connected; - - /* initialize options */ - options = options_init(); - - /* parse command line options - 1 pass get configuration files */ - options_parse(argc, argv); - - /* read configuration */ - read_configuration(options); - - /* check key bindings */ - if( check_key_bindings() ) - { - fprintf(stderr, "Confusing key bindings - exiting!\n"); - exit(EXIT_FAILURE); - } - - /* parse command line options - 2 pass */ - options_parse(argc, argv); - - /* initialize local charset */ - if( charset_init() ) - exit(EXIT_FAILURE); - - /* setup signal behavior - SIGINT */ - sigemptyset( &act.sa_mask ); - act.sa_flags = 0; - act.sa_handler = catch_sigint; - if( sigaction( SIGINT, &act, NULL )<0 ) - { - perror("signal"); - exit(EXIT_FAILURE); - } - /* setup signal behavior - SIGTERM */ - sigemptyset( &act.sa_mask ); - act.sa_flags = 0; - act.sa_handler = catch_sigint; - if( sigaction( SIGTERM, &act, NULL )<0 ) - { - perror("sigaction()"); - exit(EXIT_FAILURE); - } - - /* set xterm title */ - if( g_getenv("DISPLAY") ) - printf("%c]0;%s%c", '\033', PACKAGE " version " VERSION, '\007'); - - /* install exit function */ - 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); - - /* initialize curses */ - screen_init(); - - /* initialize timer */ - timer = g_timer_new(); - - connected = TRUE; - while( connected || options->reconnect ) - { - static gdouble t = G_MAXDOUBLE; - - if( connected && t>=MPD_UPDATE_TIME ) - { - 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); - g_timer_start(timer); - } - - if( connected ) - { - command_t cmd; - - screen_update(mpc); - if( (cmd=get_keyboard_command()) != CMD_NONE ) - { - screen_cmd(mpc, 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); - } - else if( options->reconnect ) - { - sleep(MPD_RECONNECT_TIMEOUT); - screen_status_printf("Connecting to %s... [Press Ctrl-C to abort]", - options->host); - if( mpc_reconnect(mpc, - options->host, - options->port, - options->password) == 0 ) - { - screen_status_printf("Connected to %s!", options->host); - connected = TRUE; - } - doupdate(); - } - - t = g_timer_elapsed(timer, NULL); - } - - exit(EXIT_FAILURE); -} diff --git a/mpc.c b/mpc.c deleted file mode 100644 index 0a80af4..0000000 --- a/mpc.c +++ /dev/null @@ -1,359 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "support.h" -#include "libmpdclient.h" -#include "mpc.h" -#include "options.h" - -#define MAX_SONG_LENGTH 1024 - -#ifdef DEBUG -#define D(x) x -#else -#define D(x) -#endif - -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, 10); - 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_update_playlist(mpd_client_t *c) -{ - mpd_InfoEntity *entity; - - D(fprintf(stderr, "mpc_update_playlist() [%d]\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); - } - 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_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; -} - -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 ) - 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_sendListallCommand(conn,""); - 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/mpc.h b/mpc.h deleted file mode 100644 index a09aeee..0000000 --- a/mpc.h +++ /dev/null @@ -1,50 +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); -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/options.c b/options.c deleted file mode 100644 index 416727a..0000000 --- a/options.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * (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 -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "options.h" -#include "command.h" -#include "support.h" - -options_t options; - -static char *mpd_host = NULL; -static char *mpd_password = NULL; -static char *config_file = NULL; -static char *key_file = NULL; - -static struct poptOption optionsTable[] = { -#ifdef DEBUG - { "debug", 'D', 0, 0, 'D', "Enable debug output." }, -#endif - { "version", 'V', 0, 0, 'V', "Display version information." }, - { "colors", 'c', 0, 0, 'c', "Enable colors." }, - { "no-colors", 'C', 0, 0, 'C', "Disable colors." }, - { "exit", 'e', 0, 0, 'e', "Exit on connection errors." }, - { "port", 'p', POPT_ARG_INT, &options.port, 0, - "Connect to server on port [" DEFAULT_PORT_STR "].", "PORT" }, - { "host", 'h', POPT_ARG_STRING, &mpd_host, 0, - "Connect to server [" DEFAULT_HOST "].", "HOSTNAME" }, - { "password", 'P', POPT_ARG_STRING, &mpd_password, 0, - "Connect with password.", "PASSWORD" }, - { "config", 'f', POPT_ARG_STRING, &config_file, 0, - "Read config from FILE." , "FILE" }, - { "key-file", 'k', POPT_ARG_STRING, &key_file, 0, - "Read key bindings from FILE." , "FILE" }, - - POPT_AUTOHELP - { NULL, 0, 0, NULL, 0 } -}; - -static void -usage(poptContext optCon, int exitcode, char *error, char *addl) -{ - poptPrintUsage(optCon, stderr, 0); - if (error) - fprintf(stderr, "%s: %s0", error, addl); - exit(exitcode); -} - -options_t * -options_parse( int argc, const char **argv) -{ - int c; - poptContext optCon; /* context for parsing command-line options */ - - mpd_host = NULL; - mpd_password = NULL; - config_file = NULL; - key_file = NULL; - optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); - while ((c = poptGetNextOpt(optCon)) >= 0) - { - switch (c) - { -#ifdef DEBUG - case 'D': - options.debug = 1; - break; -#endif - case 'c': - options.enable_colors = 1; - break; - case 'C': - options.enable_colors = 0; - break; - case 'V': - printf("Version " VERSION "\n"); - exit(EXIT_SUCCESS); - case 'e': - options.reconnect = 0; - break; - default: - fprintf(stderr, "%s: %s\n", - poptBadOption(optCon, POPT_BADOPTION_NOALIAS), - poptStrerror(c)); - poptFreeContext(optCon); - exit(EXIT_FAILURE); - break; - } - } - if (c < -1) - { - /* an error occurred during option processing */ - fprintf(stderr, "%s: %s\n", - poptBadOption(optCon, POPT_BADOPTION_NOALIAS), - poptStrerror(c)); - poptFreeContext(optCon); - exit(EXIT_FAILURE); - } - - if( mpd_host ) - { - g_free(options.host); - options.host = mpd_host; - } - if( mpd_password ) - { - g_free(options.password); - options.password = mpd_password; - } - if( config_file ) - { - g_free(options.config_file); - options.config_file = config_file; - } - if( key_file ) - { - g_free(options.key_file); - options.key_file = key_file; - } - - poptFreeContext(optCon); - return &options; -} - -options_t * -options_init( void ) -{ - const char *value; - char *tmp; - - memset(&options, 0, sizeof(options_t)); - - if( (value=g_getenv(MPD_HOST_ENV)) ) - options.host = g_strdup(value); - else - options.host = g_strdup(DEFAULT_HOST); - if( (tmp=g_strstr_len(options.host, strlen(options.host), "@")) ) - { - char *oldhost = options.host; - *tmp = '\0'; - options.password = locale_to_utf8(oldhost); - options.host = g_strdup(tmp+1); - g_free(oldhost); - } - - if( (value=g_getenv(MPD_PORT_ENV)) ) - options.port = atoi(value); - else - options.port = DEFAULT_PORT; - - options.reconnect = 1; - options.find_wrap = 1; - options.wide_cursor = 1; - - return &options; -} - - -options_t * -options_get(void) -{ - return &options; -} diff --git a/options.h b/options.h deleted file mode 100644 index 2a6681e..0000000 --- a/options.h +++ /dev/null @@ -1,28 +0,0 @@ - -#define MPD_HOST_ENV "MPD_HOST" -#define MPD_PORT_ENV "MPD_PORT" - -typedef struct -{ - char *host; - char *username; - char *password; - char *config_file; - char *key_file; - int port; - int reconnect; - int debug; - int find_wrap; - int auto_center; - int wide_cursor; - int enable_colors; - -} options_t; - -extern options_t options; - -options_t *options_init(void); -options_t *options_parse(int argc, const char **argv); - - - diff --git a/screen.c b/screen.c deleted file mode 100644 index 20ece65..0000000 --- a/screen.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * (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 -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "libmpdclient.h" -#include "mpc.h" -#include "command.h" -#include "options.h" -#include "colors.h" -#include "screen.h" -#include "screen_play.h" -#include "screen_file.h" -#include "screen_help.h" -#include "screen_search.h" -#include "screen_utils.h" - -#undef ENABLE_STATUS_LINE_CLOCK -#define ENABLE_SCROLLING - -#define DEFAULT_CROSSFADE_TIME 10 - -#define STATUS_MESSAGE_TIMEOUT 3 -#define STATUS_LINE_MAX_SIZE 512 - -#ifdef ENABLE_KEYDEF_SCREEN -extern screen_functions_t *get_screen_keydef(void); -#endif - -static screen_t *screen = NULL; -static screen_functions_t *mode_fn = NULL; - -static void -switch_screen_mode(screen_mode_t new_mode, mpd_client_t *c) -{ - if( new_mode == screen->mode ) - return; - - /* close the old mode */ - if( mode_fn && mode_fn->close ) - mode_fn->close(); - - /* get functions for the new mode */ - switch(new_mode) - { - case SCREEN_PLAY_WINDOW: - mode_fn = get_screen_playlist(); - break; - case SCREEN_FILE_WINDOW: - mode_fn = get_screen_file(); - break; - case SCREEN_HELP_WINDOW: - mode_fn = get_screen_help(); - break; -#ifdef ENABLE_KEYDEF_SCREEN - case SCREEN_KEYDEF_WINDOW: - mode_fn = get_screen_keydef(); - break; -#endif - default: - break; - } - - screen->mode = new_mode; - screen->painted = 0; - - /* open the new mode */ - if( mode_fn && mode_fn->open ) - mode_fn->open(screen, c); - -} - -static void -paint_top_window(char *header, mpd_client_t *c, int clear) -{ - char flags[4]; - static int prev_volume = -1; - static int prev_header_len = -1; - WINDOW *w = screen->top_window.w; - - if(prev_header_len!=strlen(header)) - { - prev_header_len = strlen(header); - clear = 1; - } - - if(clear) - { - wmove(w, 0, 0); - wclrtoeol(w); - } - - if(prev_volume!=c->status->volume || clear) - { - char buf[12]; - - if( header[0] ) - { - colors_use(w, COLOR_TITLE_BOLD); - mvwaddstr(w, 0, 0, header); - } - else - { - colors_use(w, COLOR_TITLE_BOLD); - waddstr(w, get_key_names(CMD_SCREEN_HELP, FALSE)); - colors_use(w, COLOR_TITLE); - waddstr(w, ":Help "); - colors_use(w, COLOR_TITLE_BOLD); - waddstr(w, get_key_names(CMD_SCREEN_PLAY, FALSE)); - colors_use(w, COLOR_TITLE); - waddstr(w, ":Playlist "); - colors_use(w, COLOR_TITLE_BOLD); - waddstr(w, get_key_names(CMD_SCREEN_FILE, FALSE)); - colors_use(w, COLOR_TITLE); - waddstr(w, ":Browse"); - } - if( c->status->volume==MPD_STATUS_NO_VOLUME ) - { - snprintf(buf, 12, "Volume n/a "); - } - else - { - snprintf(buf, 12, "Volume %3d%%", c->status->volume); - } - colors_use(w, COLOR_TITLE); - mvwaddstr(w, 0, screen->top_window.cols-12, buf); - - flags[0] = 0; - if( c->status->repeat ) - strcat(flags, "r"); - if( c->status->random ) - strcat(flags, "z"); - if( c->status->crossfade ) - strcat(flags, "x"); - colors_use(w, COLOR_LINE); - mvwhline(w, 1, 0, ACS_HLINE, screen->top_window.cols); - if( flags[0] ) - { - wmove(w,1,screen->top_window.cols-strlen(flags)-3); - waddch(w, '['); - colors_use(w, COLOR_LINE_BOLD); - waddstr(w, flags); - colors_use(w, COLOR_LINE); - waddch(w, ']'); - } - wnoutrefresh(w); - } -} - -static void -paint_progress_window(mpd_client_t *c) -{ - double p; - int width; - int elapsedTime = c->status->elapsedTime; - - if( c->status==NULL || IS_STOPPED(c->status->state) ) - { - mvwhline(screen->progress_window.w, 0, 0, ACS_HLINE, - screen->progress_window.cols); - wnoutrefresh(screen->progress_window.w); - return; - } - - if( c->seek_song_id == c->song_id ) - elapsedTime = c->seek_target_time; - - p = ((double) elapsedTime) / ((double) c->status->totalTime); - - width = (int) (p * (double) screen->progress_window.cols); - mvwhline(screen->progress_window.w, - 0, 0, - ACS_HLINE, - screen->progress_window.cols); - whline(screen->progress_window.w, '=', width-1); - mvwaddch(screen->progress_window.w, 0, width-1, 'O'); - wnoutrefresh(screen->progress_window.w); -} - -#ifdef ENABLE_SCROLLING -static char * -scroll_string(char *str, char *sep, int width) -{ - static int offset = 0; - static time_t t = 0; - char *tmp, *buf; - size_t len; - - if( offset==0 ) - { - offset++; - return g_strdup(str); - } - - /* create a buffer containing the string and the separator */ - tmp = g_malloc(strlen(str)+strlen(sep)+1); - strcpy(tmp, str); - strcat(tmp, sep); - len = strlen(tmp); - - if( offset >= len ) - offset = 0; - - /* create the new scrolled string */ - buf = g_malloc(width+1); - strncpy(buf, tmp+offset, width); - if( strlen(buf) < width ) - strncat(buf, tmp, width-strlen(buf)); - - if( time(NULL)-t >= 1 ) - { - t = time(NULL); - offset++; - } - g_free(tmp); - return buf; -} -#endif - -static void -paint_status_window(mpd_client_t *c) -{ - WINDOW *w = screen->status_window.w; - mpd_Status *status = c->status; - mpd_Song *song = c->song; - int elapsedTime = c->status->elapsedTime; - int x = 0; - - if( time(NULL) - screen->status_timestamp <= STATUS_MESSAGE_TIMEOUT ) - return; - - - wmove(w, 0, 0); - wclrtoeol(w); - colors_use(w, COLOR_STATUS_BOLD); - - switch(status->state) - { - case MPD_STATUS_STATE_STOP: - waddstr(w, "Stopped! "); - break; - case MPD_STATUS_STATE_PLAY: - waddstr(w, "Playing:"); - break; - case MPD_STATUS_STATE_PAUSE: - waddstr(w, "[Paused]"); - break; - default: - break; - } - x += 9; - - /* create time string */ - memset(screen->buf, 0, screen->buf_size); - if( c->seek_song_id == c->song_id ) - elapsedTime = c->seek_target_time; - if( IS_PLAYING(status->state) || IS_PAUSED(status->state) ) - snprintf(screen->buf, screen->buf_size, - " [%i:%02i/%i:%02i] ", - elapsedTime/60, elapsedTime%60, - status->totalTime/60, status->totalTime%60 ); - - /* display song */ - if( (IS_PLAYING(status->state) || IS_PAUSED(status->state)) && song ) - { - char *songname = mpc_get_song_name(song); - int width = COLS-x-strlen(screen->buf); - - colors_use(w, COLOR_STATUS); -#ifdef ENABLE_SCROLLING - if( strlen(songname) > width ) - { - char *tmp = scroll_string(songname, " *** ", width); - strcpy(songname, tmp); - g_free(tmp); - } -#endif - mvwaddnstr(w, 0, x, songname, width); - } - - /* distplay time string */ - if( screen->buf[0] ) - { - x = screen->status_window.cols - strlen(screen->buf); - colors_use(w, COLOR_STATUS_TIME); - mvwaddstr(w, 0, x, screen->buf); - } - -#ifdef ENABLE_STATUS_LINE_CLOCK - else if( c->status->state == MPD_STATUS_STATE_STOP ) - { - time_t timep; - - /* Note: setlocale(LC_TIME,"") should be used first */ - time(&timep); - strftime(screen->buf, screen->buf_size, "%X ", localtime(&timep)); - x = screen->status_window.cols - strlen(screen->buf) ; - colors_use(w, COLOR_STATUS_TIME); - mvwaddstr(w, 0, x, screen->buf); - } -#endif - - wnoutrefresh(w); -} - - - -int -screen_exit(void) -{ - endwin(); - if( screen ) - { - GList *list = g_list_first(screen->screen_list); - - /* close and exit all screens (playlist,browse,help...) */ - while( list ) - { - screen_functions_t *mode_fn = list->data; - - if( mode_fn && mode_fn->close ) - mode_fn->close(); - if( mode_fn && mode_fn->exit ) - mode_fn->exit(); - list->data = NULL; - list=list->next; - } - g_list_free(screen->screen_list); - - g_free(screen->buf); - g_free(screen->findbuf); - g_free(screen); - screen = NULL; - } - return 0; -} - -void -screen_resize(void) -{ - GList *list; - -#ifdef DEBUG - fprintf(stderr, "Resize rows %d->%d, cols %d->%d\n", - screen->rows, LINES, - screen->cols, COLS); -#endif - - if( COLScols = COLS; - screen->rows = LINES; - - /* top window */ - screen->top_window.cols = screen->cols; - wresize(screen->top_window.w, 2, screen->cols); - - /* main window */ - screen->main_window.cols = screen->cols; - screen->main_window.rows = screen->rows-4; - wresize(screen->main_window.w, screen->main_window.rows, screen->cols); - wclear(screen->main_window.w); - - /* progress window */ - screen->progress_window.cols = screen->cols; - wresize(screen->progress_window.w, 1, screen->cols); - mvwin(screen->progress_window.w, screen->rows-2, 0); - - /* status window */ - screen->status_window.cols = screen->cols; - wresize(screen->status_window.w, 1, screen->cols); - mvwin(screen->status_window.w, screen->rows-1, 0); - - screen->buf_size = screen->cols; - g_free(screen->buf); - screen->buf = g_malloc(screen->cols); - - list = g_list_first(screen->screen_list); - while( list ) - { - screen_functions_t *mode_fn = list->data; - - if( mode_fn && mode_fn->resize ) - mode_fn->resize(screen->main_window.cols, screen->main_window.rows); - - list=list->next; - } - - /* ? - without this the cursor becomes visible with aterm & Eterm */ - curs_set(1); - curs_set(0); - - screen->painted = 0; -} - -void -screen_status_message(char *msg) -{ - WINDOW *w = screen->status_window.w; - - wmove(w, 0, 0); - wclrtoeol(w); - colors_use(w, COLOR_STATUS_ALERT); - waddstr(w, msg); - wnoutrefresh(w); - screen->status_timestamp = time(NULL); -} - -void -screen_status_printf(char *format, ...) -{ - char buffer[STATUS_LINE_MAX_SIZE]; - va_list ap; - - va_start(ap,format); - vsnprintf(buffer,sizeof(buffer),format,ap); - va_end(ap); - screen_status_message(buffer); -} - -int -screen_init(void) -{ - GList *list; - - /* initialize the curses library */ - initscr(); - /* initialize color support */ - colors_start(); - /* tell curses not to do NL->CR/NL on output */ - nonl(); - /* take input chars one at a time, no wait for \n */ - cbreak(); - /* don't echo input */ - noecho(); - /* set cursor invisible */ - curs_set(0); - /* return from getch() without blocking */ - // nodelay(stdscr, TRUE); - keypad(stdscr, TRUE); - timeout(SCREEN_TIMEOUT); - - if( COLSmode = SCREEN_PLAY_WINDOW; - screen->cols = COLS; - screen->rows = LINES; - screen->buf = g_malloc(screen->cols); - screen->buf_size = screen->cols; - screen->findbuf = NULL; - screen->painted = 0; - screen->start_timestamp = time(NULL); - screen->input_timestamp = time(NULL); - screen->last_cmd = CMD_NONE; - - /* create top window */ - screen->top_window.rows = 2; - screen->top_window.cols = screen->cols; - screen->top_window.w = newwin(screen->top_window.rows, - screen->top_window.cols, - 0, 0); - leaveok(screen->top_window.w, TRUE); - keypad(screen->top_window.w, TRUE); - - /* create main window */ - screen->main_window.rows = screen->rows-4; - screen->main_window.cols = screen->cols; - screen->main_window.w = newwin(screen->main_window.rows, - screen->main_window.cols, - 2, - 0); - - // leaveok(screen->main_window.w, TRUE); temporary disabled - keypad(screen->main_window.w, TRUE); - - /* create progress window */ - screen->progress_window.rows = 1; - screen->progress_window.cols = screen->cols; - screen->progress_window.w = newwin(screen->progress_window.rows, - screen->progress_window.cols, - screen->rows-2, - 0); - leaveok(screen->progress_window.w, TRUE); - - /* create status window */ - screen->status_window.rows = 1; - screen->status_window.cols = screen->cols; - screen->status_window.w = newwin(screen->status_window.rows, - screen->status_window.cols, - screen->rows-1, - 0); - - leaveok(screen->status_window.w, FALSE); - keypad(screen->status_window.w, TRUE); - - if( options.enable_colors ) - { - /* set background attributes */ - wbkgd(stdscr, COLOR_PAIR(COLOR_LIST)); - wbkgd(screen->main_window.w, COLOR_PAIR(COLOR_LIST)); - wbkgd(screen->top_window.w, COLOR_PAIR(COLOR_TITLE)); - wbkgd(screen->progress_window.w, COLOR_PAIR(COLOR_PROGRESSBAR)); - wbkgd(screen->status_window.w, COLOR_PAIR(COLOR_STATUS)); - colors_use(screen->progress_window.w, COLOR_PROGRESSBAR); - } - - /* initialize screens */ - screen->screen_list = NULL; - 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()); - screen->screen_list = g_list_append(screen->screen_list, - (gpointer) get_screen_help()); -#ifdef ENABLE_KEYDEF_SCREEN - screen->screen_list = g_list_append(screen->screen_list, - (gpointer) get_screen_keydef()); -#endif - - list = screen->screen_list; - while( list ) - { - screen_functions_t *fn = list->data; - - if( fn && fn->init ) - fn->init(screen->main_window.w, - screen->main_window.cols, - screen->main_window.rows); - - list = list->next; - } - - mode_fn = get_screen_playlist(); - - return 0; -} - -void -screen_paint(mpd_client_t *c) -{ - /* paint the title/header window */ - if( mode_fn && mode_fn->get_title ) - paint_top_window(mode_fn->get_title(), c, 1); - else - paint_top_window("", c, 1); - - /* paint the main window */ - if( mode_fn && mode_fn->paint ) - mode_fn->paint(screen, c); - - paint_progress_window(c); - paint_status_window(c); - screen->painted = 1; - wmove(screen->main_window.w, 0, 0); - wnoutrefresh(screen->main_window.w); - - /* tell curses to update */ - doupdate(); -} - -void -screen_update(mpd_client_t *c) -{ - static int repeat = -1; - static int random = -1; - static int crossfade = -1; - static int welcome = 1; - list_window_t *lw = NULL; - - if( !screen->painted ) - return screen_paint(c); - - /* print a message if mpd status has changed */ - if( repeat<0 ) - { - repeat = c->status->repeat; - random = c->status->random; - crossfade = c->status->crossfade; - } - if( repeat != c->status->repeat ) - screen_status_printf("Repeat is %s", - c->status->repeat ? "On" : "Off"); - if( random != c->status->random ) - screen_status_printf("Random is %s", - c->status->random ? "On" : "Off"); - if( crossfade != c->status->crossfade ) - screen_status_printf("Crossfade %d seconds", c->status->crossfade); - - repeat = c->status->repeat; - random = c->status->random; - crossfade = c->status->crossfade; - - /* update title/header window */ - if( welcome && screen->last_cmd==CMD_NONE && - time(NULL)-screen->start_timestamp <= SCREEN_WELCOME_TIME) - paint_top_window("", c, 0); - else if( mode_fn && mode_fn->get_title ) - { - paint_top_window(mode_fn->get_title(), c, 0); - welcome = 0; - } - else - paint_top_window("", c, 0); - - /* update the main window */ - if( mode_fn && mode_fn->paint ) - mode_fn->update(screen, c); - - if( mode_fn && mode_fn->get_lw ) - lw = mode_fn->get_lw(); - - /* update progress window */ - paint_progress_window(c); - - /* update status window */ - paint_status_window(c); - - /* move the cursor to the selected row in the main window */ - if( lw ) - wmove(screen->main_window.w, LW_ROW(lw), 0); - else - wmove(screen->main_window.w, 0, 0); - wnoutrefresh(screen->main_window.w); - - /* tell curses to update */ - doupdate(); -} - -void -screen_idle(mpd_client_t *c) -{ - if( c->seek_song_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); - } - - screen->last_cmd = CMD_NONE; - c->seek_song_id = -1; -} - -void -screen_cmd(mpd_client_t *c, command_t cmd) -{ - int n; - screen_mode_t new_mode = screen->mode; - - screen->input_timestamp = time(NULL); - screen->last_cmd = cmd; - - if( mode_fn && mode_fn->cmd && mode_fn->cmd(screen, c, cmd) ) - return; - - switch(cmd) - { - case CMD_PLAY: - mpd_sendPlayCommand(c->connection, play_get_selected()); - mpd_finishCommand(c->connection); - break; - case CMD_PAUSE: - mpd_sendPauseCommand(c->connection); - mpd_finishCommand(c->connection); - break; - case CMD_STOP: - mpd_sendStopCommand(c->connection); - mpd_finishCommand(c->connection); - break; - case CMD_SEEK_FORWARD: - if( !IS_STOPPED(c->status->state) ) - { - if( c->seek_song_id != c->song_id ) - { - c->seek_song_id = c->song_id; - c->seek_target_time = c->status->elapsedTime; - } - c->seek_target_time++; - if( c->seek_target_time < c->status->totalTime ) - break; - c->seek_target_time=0; - } - /* fall through... */ - case CMD_TRACK_NEXT: - if( !IS_STOPPED(c->status->state) ) - { - mpd_sendNextCommand(c->connection); - mpd_finishCommand(c->connection); - } - break; - case CMD_SEEK_BACKWARD: - if( !IS_STOPPED(c->status->state) ) - { - if( c->seek_song_id != c->song_id ) - { - c->seek_song_id = c->song_id; - c->seek_target_time = c->status->elapsedTime; - } - c->seek_target_time--; - if( c->seek_target_time < 0 ) - c->seek_target_time=0; - } - break; - case CMD_TRACK_PREVIOUS: - if( !IS_STOPPED(c->status->state) ) - { - mpd_sendPrevCommand(c->connection); - mpd_finishCommand(c->connection); - } - break; - case CMD_SHUFFLE: - mpd_sendShuffleCommand(c->connection); - mpd_finishCommand(c->connection); - 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!"); - break; - case CMD_REPEAT: - n = !c->status->repeat; - mpd_sendRepeatCommand(c->connection, n); - mpd_finishCommand(c->connection); - break; - case CMD_RANDOM: - n = !c->status->random; - mpd_sendRandomCommand(c->connection, n); - mpd_finishCommand(c->connection); - break; - case CMD_CROSSFADE: - if( c->status->crossfade ) - n = 0; - else - n = DEFAULT_CROSSFADE_TIME; - mpd_sendCrossfadeCommand(c->connection, n); - mpd_finishCommand(c->connection); - 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); - } - 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); - } - break; - case CMD_TOGGLE_FIND_WRAP: - options.find_wrap = !options.find_wrap; - screen_status_printf("Find mode: %s", - options.find_wrap ? "Wrapped" : "Normal"); - break; - case CMD_TOGGLE_AUTOCENTER: - options.auto_center = !options.auto_center; - screen_status_printf("Auto center mode: %s", - options.auto_center ? "On" : "Off"); - break; - case CMD_SCREEN_PREVIOUS: - if( screen->mode > SCREEN_PLAY_WINDOW ) - new_mode = screen->mode - 1; - else - new_mode = SCREEN_HELP_WINDOW-1; - switch_screen_mode(new_mode, c); - break; - case CMD_SCREEN_NEXT: - new_mode = screen->mode + 1; - if( new_mode >= SCREEN_HELP_WINDOW ) - new_mode = SCREEN_PLAY_WINDOW; - switch_screen_mode(new_mode, c); - break; - case CMD_SCREEN_PLAY: - switch_screen_mode(SCREEN_PLAY_WINDOW, c); - break; - case CMD_SCREEN_FILE: - switch_screen_mode(SCREEN_FILE_WINDOW, c); - break; - case CMD_SCREEN_SEARCH: - switch_screen_mode(SCREEN_SEARCH_WINDOW, c); - break; - case CMD_SCREEN_HELP: - switch_screen_mode(SCREEN_HELP_WINDOW, c); - break; -#ifdef ENABLE_KEYDEF_SCREEN - case CMD_SCREEN_KEYDEF: - switch_screen_mode(SCREEN_KEYDEF_WINDOW, c); - break; -#endif - case CMD_QUIT: - exit(EXIT_SUCCESS); - default: - break; - } - -} - - - diff --git a/screen.h b/screen.h deleted file mode 100644 index a7e6b72..0000000 --- a/screen.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef SCREEN_H -#define SCREEN_H -#include -#include "list_window.h" - -/* top window headers */ -#define TOP_HEADER_PREFIX "Music Player Client - " -#define TOP_HEADER_PLAY TOP_HEADER_PREFIX "Playlist" -#define TOP_HEADER_FILE TOP_HEADER_PREFIX "Browse" -#define TOP_HEADER_HELP TOP_HEADER_PREFIX "Help " -#define TOP_HEADER_SEARCH TOP_HEADER_PREFIX "Search " - -/* minumum window size */ -#define SCREEN_MIN_COLS 14 -#define SCREEN_MIN_ROWS 5 - -/* timeout for non blocking read [ms] */ -#define SCREEN_TIMEOUT 500 - -/* welcome message time [s] */ -#define SCREEN_WELCOME_TIME 10 - -#define IS_PLAYING(s) (s==MPD_STATUS_STATE_PLAY) -#define IS_PAUSED(s) (s==MPD_STATUS_STATE_PAUSE) -#define IS_STOPPED(s) (!(IS_PLAYING(s) | IS_PAUSED(s))) - - -typedef enum -{ - SCREEN_PLAY_WINDOW = 0, - SCREEN_FILE_WINDOW, - SCREEN_HELP_WINDOW, - SCREEN_KEYDEF_WINDOW, - SCREEN_SEARCH_WINDOW - -} screen_mode_t; - -typedef struct -{ - WINDOW *w; - int rows, cols; - -} window_t; - - - -typedef struct -{ - window_t top_window; - window_t main_window; - window_t progress_window; - window_t status_window; - - GList *screen_list; - - time_t start_timestamp; - time_t status_timestamp; - time_t input_timestamp; - command_t last_cmd; - - int cols, rows; - - screen_mode_t mode; - - char *buf; - size_t buf_size; - - char *findbuf; - - int painted; - -} screen_t; - - -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_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 char * (*screen_title_fn_t) (void); -typedef list_window_t * (*screen_get_lw_fn_t) (void); - -typedef struct -{ - screen_init_fn_t init; - screen_exit_fn_t exit; - screen_open_fn_t open; - screen_close_fn_t close; - screen_resize_fn_t resize; - screen_paint_fn_t paint; - screen_update_fn_t update; - screen_cmd_fn_t cmd; - screen_title_fn_t get_title; - screen_get_lw_fn_t get_lw; - -} screen_functions_t; - - -int screen_init(void); -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); - -#endif diff --git a/screen_file.c b/screen_file.c deleted file mode 100644 index d2b1f78..0000000 --- a/screen_file.c +++ /dev/null @@ -1,503 +0,0 @@ -/* - * (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 -#include -#include -#include -#include - -#include "config.h" -#include "support.h" -#include "libmpdclient.h" -#include "mpc.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; - -static char * -list_callback(int index, int *highlight, void *data) -{ - static char buf[BUFSIZE]; - mpd_client_t *c = (mpd_client_t *) data; - filelist_entry_t *entry; - mpd_InfoEntity *entity; - - *highlight = 0; - if( (entry=(filelist_entry_t *) g_list_nth_data(c->filelist, index))==NULL ) - return NULL; - - entity = entry->entity; - *highlight = entry->selected; - - 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; - } - else if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) - { - 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)); - return buf; -#endif - - } - else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) - { - mpd_PlaylistFile *plf = entity->info.playlistFile; - char *filename = utf8_to_locale(basename(plf->path)); - -#ifdef USE_OLD_LAYOUT - snprintf(buf, BUFSIZE, "*%s*", filename); -#else - snprintf(buf, BUFSIZE, "p %s", filename); -#endif - g_free(filename); - return buf; - } - return "Error: Unknow entry!"; -} - -static int -change_directory(screen_t *screen, mpd_client_t *c, filelist_entry_t *entry) -{ - mpd_InfoEntity *entity = entry->entity; - - if( entity==NULL ) - { - char *parent = g_path_get_dirname(c->cwd); - - if( strcmp(parent,".") == 0 ) - { - parent[0] = '\0'; - } - if( c->cwd ) - g_free(c->cwd); - c->cwd = parent; - } - else - if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY) - { - mpd_Directory *dir = entity->info.directory; - if( c->cwd ) - g_free(c->cwd); - c->cwd = g_strdup(dir->path); - } - else - return -1; - - mpc_update_filelist(c); - list_window_reset(lw); - return 0; -} - -static int -load_playlist(screen_t *screen, mpd_client_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); - - screen_status_printf("Loading playlist %s...", filename); - g_free(filename); - return 0; -} - -static int -handle_delete(screen_t *screen, mpd_client_t *c) -{ - filelist_entry_t *entry; - mpd_InfoEntity *entity; - mpd_PlaylistFile *plf; - char *str, buf[BUFSIZE]; - int key; - - entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected); - if( entry==NULL || entry->entity==NULL ) - return -1; - - entity = entry->entity; - - if( entity->type!=MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) - { - screen_status_printf("You can only delete playlists!"); - beep(); - return -1; - } - - plf = entity->info.playlistFile; - str = utf8_to_locale(basename(plf->path)); - snprintf(buf, BUFSIZE, "Delete playlist %s [y/n] ? ", str); - g_free(str); - key = tolower(screen_getch(screen->status_window.w, buf)); - if( key==KEY_RESIZE ) - screen_resize(); - if( key!='y' ) - { - screen_status_printf("Aborted!"); - return 0; - } - - mpd_sendRmCommand(c->connection, plf->path); - mpd_finishCommand(c->connection); - if( mpc_error(c)) - { - 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) -{ - filelist_entry_t *entry; - mpd_InfoEntity *entity; - - entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected); - if( entry==NULL ) - return -1; - - entity = entry->entity; - if( entity==NULL || entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) - return change_directory(screen, c, entry); - else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) - return load_playlist(screen, c, entry); - return -1; -} - -static int -add_directory(mpd_client_t *c, char *dir) -{ - mpd_InfoEntity *entity; - GList *subdir_list = NULL; - GList *list = NULL; - char *dirname; - - dirname = utf8_to_locale(dir); - screen_status_printf("Adding directory %s...\n", dirname); - doupdate(); - g_free(dirname); - dirname = NULL; - - mpd_sendLsInfoCommand(c->connection, dir); - mpd_sendCommandListBegin(c->connection); - while( (entity=mpd_getNextInfoEntity(c->connection)) ) - { - if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) - { - mpd_Song *song = entity->info.song; - mpd_sendAddCommand(c->connection, song->file); - mpd_freeInfoEntity(entity); - } - else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) - { - subdir_list = g_list_append(subdir_list, (gpointer) entity); - } - else - mpd_freeInfoEntity(entity); - } - mpd_sendCommandListEnd(c->connection); - mpd_finishCommand(c->connection); - - list = g_list_first(subdir_list); - while( list!=NULL ) - { - mpd_Directory *dir; - - entity = list->data; - dir = entity->info.directory; - add_directory(c, dir->path); - mpd_freeInfoEntity(entity); - list->data=NULL; - list=list->next; - } - g_list_free(subdir_list); - return 0; -} - -static int -handle_select(screen_t *screen, mpd_client_t *c) -{ - filelist_entry_t *entry; - - entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected); - if( entry==NULL || entry->entity==NULL) - return -1; - - if( entry->entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) - { - mpd_Directory *dir = entry->entity->info.directory; - add_directory(c, dir->path); - return 0; - } - - if( entry->entity->type!=MPD_INFO_ENTITY_TYPE_SONG ) - return -1; - - entry->selected = !entry->selected; - - if( entry->selected ) - { - 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)); - } - } - else - { - /* remove song from playlist */ - if( entry->entity->type==MPD_INFO_ENTITY_TYPE_SONG ) - { - mpd_Song *song = entry->entity->info.song; - - if( song ) - { - int index = mpc_playlist_get_song_index(c, song->file); - - while( (index=mpc_playlist_get_song_index(c, song->file))>=0 ) - playlist_delete_song(c, index); - } - } - } - return 0; -} - -static void -file_init(WINDOW *w, int cols, int rows) -{ - lw = list_window_init(w, cols, rows); -} - -static void -file_resize(int cols, int rows) -{ - lw->cols = cols; - lw->rows = rows; -} - -static void -file_exit(void) -{ - list_window_free(lw); -} - -static void -file_open(screen_t *screen, mpd_client_t *c) -{ - if( c->filelist == NULL ) - { - mpc_update_filelist(c); - } - mpc = c; -} - -static void -file_close(void) -{ -} - -static char * -file_title(void) -{ - static char buf[TITLESIZE]; - char *tmp; - - tmp = utf8_to_locale(basename(mpc->cwd)); - snprintf(buf, TITLESIZE, - TOP_HEADER_FILE ": %s ", - tmp - ); - g_free(tmp); - - return buf; -} - -static void -file_paint(screen_t *screen, mpd_client_t *c) -{ - lw->clear = 1; - - list_window_paint(lw, list_callback, (void *) c); - wnoutrefresh(lw->w); -} - -static void -file_update(screen_t *screen, mpd_client_t *c) -{ - if( c->filelist_updated ) - { - file_paint(screen, c); - c->filelist_updated = 0; - return; - } - list_window_paint(lw, list_callback, (void *) c); - wnoutrefresh(lw->w); -} - - -static int -file_cmd(screen_t *screen, mpd_client_t *c, command_t cmd) -{ - switch(cmd) - { - case CMD_PLAY: - handle_play_cmd(screen, c); - return 1; - case CMD_SELECT: - if( handle_select(screen, c) == 0 ) - { - /* continue and select next item... */ - cmd = CMD_LIST_NEXT; - } - break; - case CMD_DELETE: - handle_delete(screen, c); - break; - case CMD_SCREEN_UPDATE: - mpc_update_filelist(c); - list_window_check_selected(lw, c->filelist_length); - screen_status_printf("Screen updated!"); - return 1; - 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->filelist_length, - cmd, list_callback); - default: - break; - } - return list_window_cmd(lw, c->filelist_length, cmd); -} - - -list_window_t * -get_filelist_window() -{ - return lw; -} - - -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) -{ - 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.get_lw = get_filelist_window; - functions.get_title = file_title; - - return &functions; -} - diff --git a/screen_file.h b/screen_file.h deleted file mode 100644 index a7199a6..0000000 --- a/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/screen_help.c b/screen_help.c deleted file mode 100644 index c55c963..0000000 --- a/screen_help.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * (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 -#include -#include -#include - -#include "config.h" -#include "libmpdclient.h" -#include "mpc.h" -#include "command.h" -#include "screen.h" -#include "screen_utils.h" -#include "screen_help.h" - - -typedef struct -{ - signed char highlight; - command_t command; - char *text; -} help_text_row_t; - -static help_text_row_t help_text[] = -{ - { 1, CMD_NONE, " Movement keys " }, - { 0, CMD_NONE, " -----------------" }, - { 0, CMD_LIST_PREVIOUS, NULL }, - { 0, CMD_LIST_NEXT, NULL }, - { 0, CMD_LIST_PREVIOUS_PAGE, NULL }, - { 0, CMD_LIST_NEXT_PAGE, NULL }, - { 0, CMD_LIST_FIRST, NULL }, - { 0, CMD_LIST_LAST, NULL }, - { 0, CMD_NONE, NULL }, - { 0, CMD_SCREEN_NEXT, NULL }, - { 0, CMD_SCREEN_HELP, NULL }, - { 0, CMD_SCREEN_PLAY, NULL }, - { 0, CMD_SCREEN_FILE, NULL }, -#ifdef ENABLE_KEYDEF_SCREEN - { 0, CMD_SCREEN_KEYDEF, NULL }, -#endif - - { 0, CMD_NONE, NULL }, - { 0, CMD_NONE, NULL }, - { 1, CMD_NONE, " General keys " }, - { 0, CMD_NONE, " ----------------" }, - { 0, CMD_STOP, NULL }, - { 0, CMD_PAUSE, NULL }, - { 0, CMD_TRACK_NEXT, NULL }, - { 0, CMD_TRACK_PREVIOUS, NULL }, - { 0, CMD_SEEK_FORWARD, NULL }, - { 0, CMD_SEEK_BACKWARD, NULL }, - { 0, CMD_VOLUME_DOWN, NULL }, - { 0, CMD_VOLUME_UP, NULL }, - { 0, CMD_NONE, NULL }, - { 0, CMD_SHUFFLE, NULL }, - { 0, CMD_REPEAT, NULL }, - { 0, CMD_RANDOM, NULL }, - { 0, CMD_CROSSFADE, NULL }, - { 0, CMD_NONE, NULL }, - { 0, CMD_QUIT, NULL }, - - { 0, CMD_NONE, NULL }, - { 0, CMD_NONE, NULL }, - { 1, CMD_NONE, " Keys - Playlist screen " }, - { 0, CMD_NONE, " --------------------------" }, - { 0, CMD_PLAY, "Play" }, - { 0, CMD_DELETE, NULL }, - { 0, CMD_CLEAR, NULL }, - { 0, CMD_LIST_MOVE_UP, "Move song up" }, - { 0, CMD_LIST_MOVE_DOWN, "Move song down" }, - { 0, CMD_SAVE_PLAYLIST, NULL }, - { 0, CMD_SCREEN_UPDATE, "Center" }, - { 0, CMD_TOGGLE_AUTOCENTER, NULL }, - - { 0, CMD_NONE, NULL }, - { 0, CMD_NONE, NULL }, - { 1, CMD_NONE, " Keys - Browse screen " }, - { 0, CMD_NONE, " ------------------------" }, - { 0, CMD_PLAY, "Enter directory" }, - { 0, CMD_SELECT, NULL }, - { 0, CMD_DELETE, NULL }, - { 0, CMD_SCREEN_UPDATE, NULL }, - - { 0, CMD_NONE, NULL }, - { 0, CMD_NONE, NULL }, - { 1, CMD_NONE, " Find keys " }, - { 0, CMD_NONE, " -------------" }, - { 0, CMD_LIST_FIND, NULL }, - { 0, CMD_LIST_RFIND, NULL }, - { 0, CMD_LIST_FIND_NEXT, NULL }, - { 0, CMD_LIST_RFIND_NEXT, NULL }, - { 0, CMD_TOGGLE_FIND_WRAP, NULL }, - - { 0, CMD_NONE, NULL }, - { 0, CMD_NONE, NULL }, - { 1, CMD_NONE, " ncmpc build information " }, - { 0, CMD_NONE, " ---------------------------" }, - { 0, CMD_NONE, " Version : " VERSION }, - { 0, CMD_NONE, " Configuration dirs : ~/.ncmpc, " SYSCONFDIR "/" PACKAGE }, -#ifdef ENABLE_KEYDEF_SCREEN - { 0, CMD_NONE, " Key Editor : yes" }, -#else - { 0, CMD_NONE, " Key Editor : no" }, -#endif - - { 0, CMD_NONE, NULL }, - {-1, CMD_NONE, NULL } -}; - -static int help_text_rows = -1; -static list_window_t *lw = NULL; - - -static char * -list_callback(int index, int *highlight, void *data) -{ - static char buf[256]; - - if( help_text_rows<0 ) - { - help_text_rows = 0; - while( help_text[help_text_rows].highlight != -1 ) - help_text_rows++; - } - - *highlight = 0; - if( index 0; - if( help_text[index].command == CMD_NONE ) - { - if( help_text[index].text ) - return help_text[index].text; - else - return " "; - } - if( help_text[index].text ) - snprintf(buf, 256, - "%20s : %s ", - get_key_names(help_text[index].command, TRUE), - help_text[index].text); - else - snprintf(buf, 256, - "%20s : %s ", - get_key_names(help_text[index].command, TRUE), - get_key_description(help_text[index].command)); - return buf; - } - - return NULL; -} - -static void -help_init(WINDOW *w, int cols, int rows) -{ - lw = list_window_init(w, cols, rows); -} - -static void -help_resize(int cols, int rows) -{ - lw->cols = cols; - lw->rows = rows; -} - -static void -help_exit(void) -{ - list_window_free(lw); -} - - -static char * -help_title(void) -{ - return (TOP_HEADER_PREFIX "Help"); -} - -static void -help_paint(screen_t *screen, mpd_client_t *c) -{ - lw->clear = 1; - list_window_paint(lw, list_callback, NULL); - wrefresh(lw->w); -} - -static void -help_update(screen_t *screen, mpd_client_t *c) -{ - if( lw->repaint ) - { - list_window_paint(lw, list_callback, NULL); - wrefresh(lw->w); - lw->repaint = 0; - } -} - - -static int -help_cmd(screen_t *screen, mpd_client_t *c, command_t cmd) -{ - int retval; - - retval = list_window_cmd(lw, help_text_rows, cmd); - if( !retval ) - return screen_find(screen, c, - lw, help_text_rows, - cmd, list_callback); - - return retval; -} - -static list_window_t * -help_lw(void) -{ - return lw; -} - -screen_functions_t * -get_screen_help(void) -{ - static screen_functions_t functions; - - memset(&functions, 0, sizeof(screen_functions_t)); - functions.init = help_init; - functions.exit = help_exit; - functions.open = NULL; - functions.close = NULL; - functions.resize = help_resize; - functions.paint = help_paint; - functions.update = help_update; - functions.cmd = help_cmd; - functions.get_lw = help_lw; - functions.get_title = help_title; - - return &functions; -} diff --git a/screen_help.h b/screen_help.h deleted file mode 100644 index ba2c57c..0000000 --- a/screen_help.h +++ /dev/null @@ -1,2 +0,0 @@ - -screen_functions_t *get_screen_help(void); diff --git a/screen_keydef.c b/screen_keydef.c deleted file mode 100644 index 4bda6ea..0000000 --- a/screen_keydef.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * (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 -#include -#include -#include -#include - -#include "config.h" - -#ifdef ENABLE_KEYDEF_SCREEN -#include "libmpdclient.h" -#include "options.h" -#include "conf.h" -#include "mpc.h" -#include "command.h" -#include "screen.h" -#include "screen_utils.h" - -#define STATIC_ITEMS 0 -#define STATIC_SUB_ITEMS 1 -#define BUFSIZE 256 - -#define LIST_ITEM_APPLY() (command_list_length) -#define LIST_ITEM_SAVE() (LIST_ITEM_APPLY()+1) -#define LIST_LENGTH() (LIST_ITEM_SAVE()+1) - -#define LIST_ITEM_SAVE_LABEL "===> Apply & Save key bindings " -#define LIST_ITEM_APPLY_LABEL "===> Apply key bindings " - - -static list_window_t *lw = NULL; -static int command_list_length = 0; -static command_definition_t *cmds = NULL; - -static int subcmd = -1; -static int subcmd_length = 0; -static int subcmd_addpos = 0; - -static int -keybindings_changed(void) -{ - command_definition_t *orginal_cmds = get_command_definitions(); - size_t size = command_list_length*sizeof(command_definition_t); - - return memcmp(orginal_cmds, cmds, size); -} - -static void -apply_keys(void) -{ - if( keybindings_changed() ) - { - command_definition_t *orginal_cmds = get_command_definitions(); - size_t size = command_list_length*sizeof(command_definition_t); - - memcpy(orginal_cmds, cmds, size); - screen_status_printf("You have new key bindings!"); - } - else - screen_status_printf("Keybindings unchanged."); -} - -static int -save_keys(void) -{ - FILE *f; - char *filename; - - if( check_user_conf_dir() ) - { - screen_status_printf("Error: Unable to create direcory ~/.ncmpc - %s", - strerror(errno)); - beep(); - return -1; - } - - filename = get_user_key_binding_filename(); - - if( (f=fopen(filename,"w")) == NULL ) - { - screen_status_printf("Error: %s - %s", filename, strerror(errno)); - beep(); - g_free(filename); - return -1; - } - if( write_key_bindings(f) ) - screen_status_printf("Error: %s - %s", filename, strerror(errno)); - else - screen_status_printf("Wrote %s", filename); - - g_free(filename); - return fclose(f); -} - -static void -check_subcmd_length(void) -{ - subcmd_length = 0; - while( subcmd_length0 ) - subcmd_length ++; - - if( subcmd_lengthclear = 1; - lw->repaint = 1; -} - -static void -assign_new_key(WINDOW *w, int cmd_index, int key_index) -{ - int key; - char buf[BUFSIZE]; - command_t cmd; - - snprintf(buf, BUFSIZE, "Enter new key for %s: ", cmds[cmd_index].name); - key = screen_getch(w, buf); - if( key==KEY_RESIZE ) - screen_resize(); - if( key==ERR ) - { - screen_status_printf("Aborted!"); - return; - } - cmd = find_key_command(key, cmds); - if( cmd!=CMD_NONE && cmd!= cmds[cmd_index].command ) - { - screen_status_printf("Error: key %s is already used for %s", - key2str(key), - get_key_command_name(cmd)); - beep(); - return; - } - cmds[cmd_index].keys[key_index] = key; - screen_status_printf("Assigned %s to %s", key2str(key),cmds[cmd_index].name); - check_subcmd_length(); - lw->repaint = 1; -} - -static char * -list_callback(int index, int *highlight, void *data) -{ - static char buf[BUFSIZE]; - - if( subcmd <0 ) - { - if( index0 ) - { - snprintf(buf, - BUFSIZE, "%d. %-20s (%d) ", - index+1, - key2str(cmds[subcmd].keys[index]), - cmds[subcmd].keys[index]); - return buf; - } - else if ( index==subcmd_addpos ) - { - snprintf(buf, BUFSIZE, "%d. Add new key ", index+1 ); - return buf; - } - } - - return NULL; -} - -static void -keydef_init(WINDOW *w, int cols, int rows) -{ - lw = list_window_init(w, cols, rows); -} - -static void -keydef_resize(int cols, int rows) -{ - lw->cols = cols; - lw->rows = rows; -} - -static void -keydef_exit(void) -{ - list_window_free(lw); - if( cmds ) - g_free(cmds); - cmds = NULL; - lw = NULL; -} - -static void -keydef_open(screen_t *screen, mpd_client_t *c) -{ - if( cmds == NULL ) - { - command_definition_t *current_cmds = get_command_definitions(); - size_t cmds_size; - - command_list_length = 0; - while( current_cmds[command_list_length].name ) - command_list_length++; - - cmds_size = (command_list_length+1)*sizeof(command_definition_t); - cmds = g_malloc0(cmds_size); - memcpy(cmds, current_cmds, cmds_size); - command_list_length += STATIC_ITEMS; - screen_status_printf("Welcome to the key editor!"); - } - - subcmd = -1; - list_window_check_selected(lw, LIST_LENGTH()); -} - -static void -keydef_close(void) -{ - if( cmds && !keybindings_changed() ) - { - g_free(cmds); - cmds = NULL; - } - else - screen_status_printf("Note: Did you forget to \'Apply\' your changes?"); -} - -static char * -keydef_title(void) -{ - static char buf[BUFSIZE]; - - if( subcmd<0 ) - return (TOP_HEADER_PREFIX "Edit key bindings"); - - snprintf(buf, BUFSIZE, - TOP_HEADER_PREFIX "Edit keys for %s", - cmds[subcmd].name); - return buf; -} - -static void -keydef_paint(screen_t *screen, mpd_client_t *c) -{ - lw->clear = 1; - list_window_paint(lw, list_callback, NULL); - wrefresh(lw->w); -} - -static void -keydef_update(screen_t *screen, mpd_client_t *c) -{ - if( lw->repaint ) - { - list_window_paint(lw, list_callback, NULL); - wrefresh(lw->w); - lw->repaint = 0; - } -} - -static int -keydef_cmd(screen_t *screen, mpd_client_t *c, command_t cmd) -{ - int length = LIST_LENGTH(); - - if( subcmd>=0 ) - length = subcmd_length; - - switch(cmd) - { - case CMD_PLAY: - if( subcmd<0 ) - { - if( lw->selected == LIST_ITEM_APPLY() ) - apply_keys(); - else if( lw->selected == LIST_ITEM_SAVE() ) - { - apply_keys(); - save_keys(); - } - else - { - subcmd = lw->selected; - lw->selected=0; - check_subcmd_length(); - } - } - else - { - if( lw->selected == 0 ) /* up */ - { - lw->selected = subcmd; - subcmd = -1; - } - else - assign_new_key(screen->status_window.w, - subcmd, - lw->selected-STATIC_SUB_ITEMS); - } - lw->repaint = 1; - lw->clear = 1; - return 1; - case CMD_DELETE: - if( subcmd>=0 && lw->selected-STATIC_SUB_ITEMS>=0 ) - delete_key(subcmd, lw->selected-STATIC_SUB_ITEMS); - return 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, length, - cmd, list_callback); - - default: - break; - } - - return list_window_cmd(lw, length, cmd); -} - -static list_window_t * -keydef_lw(void) -{ - return lw; -} - -screen_functions_t * -get_screen_keydef(void) -{ - static screen_functions_t functions; - - memset(&functions, 0, sizeof(screen_functions_t)); - functions.init = keydef_init; - functions.exit = keydef_exit; - functions.open = keydef_open; - functions.close = keydef_close; - functions.resize = keydef_resize; - functions.paint = keydef_paint; - functions.update = keydef_update; - functions.cmd = keydef_cmd; - functions.get_lw = keydef_lw; - functions.get_title = keydef_title; - - return &functions; -} - - -#endif diff --git a/screen_play.c b/screen_play.c deleted file mode 100644 index cdec4f7..0000000 --- a/screen_play.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * (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 -#include -#include -#include - -#include "config.h" -#include "options.h" -#include "support.h" -#include "libmpdclient.h" -#include "mpc.h" -#include "command.h" -#include "screen.h" -#include "screen_utils.h" -#include "screen_file.h" -#include "screen_play.h" - -#ifdef DEBUG -#define D(x) x -#else -#define D(x) -#endif - -#define BUFSIZE 256 - -static list_window_t *lw = NULL; - -static char * -list_callback(int index, int *highlight, void *data) -{ - mpd_client_t *c = (mpd_client_t *) data; - mpd_Song *song; - - *highlight = 0; - if( (song=mpc_playlist_get_song(c, index)) == NULL ) - { - return NULL; - } - - if( index==c->song_id && !IS_STOPPED(c->status->state) ) - { - *highlight = 1; - } - - return mpc_get_song_name(song); -} - -static int -center_playing_item(screen_t *screen, mpd_client_t *c) -{ - int length = c->playlist_length; - int offset = lw->selected-lw->start; - - if( !lw || lengthrows || IS_STOPPED(c->status->state) ) - return 0; - - /* try to center the song that are playing */ - lw->start = c->song_id-(lw->rows/2); - if( lw->start+lw->rows > length ) - lw->start = length-lw->rows; - if( lw->start<0 ) - lw->start=0; - - /* make sure the cursor is in the window */ - lw->selected = lw->start+offset; - list_window_check_selected(lw, length); - - lw->clear = 1; - lw->repaint = 1; - - return 0; -} - -static int -handle_save_playlist(screen_t *screen, mpd_client_t *c) -{ - char *filename, *filename_utf8; - - 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( 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; -} - -static void -play_init(WINDOW *w, int cols, int rows) -{ - lw = list_window_init(w, cols, rows); -} - -static void -play_resize(int cols, int rows) -{ - lw->cols = cols; - lw->rows = rows; -} - - -static void -play_exit(void) -{ - list_window_free(lw); -} - -static char * -play_title(void) -{ - return (TOP_HEADER_PREFIX "Playlist"); -} - -static void -play_paint(screen_t *screen, mpd_client_t *c) -{ - lw->clear = 1; - - list_window_paint(lw, list_callback, (void *) c); - wnoutrefresh(lw->w); -} - -static void -play_update(screen_t *screen, mpd_client_t *c) -{ - if( options.auto_center ) - { - static int prev_song_id = 0; - - if( prev_song_id != c->song_id ) - { - center_playing_item(screen, c); - prev_song_id = c->song_id; - } - } - - if( c->playlist_updated ) - { - 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; - } - else if( lw->repaint || 1) - { - list_window_paint(lw, list_callback, (void *) c); - wnoutrefresh(lw->w); - lw->repaint = 0; - } -} - -static int -play_cmd(screen_t *screen, mpd_client_t *c, command_t cmd) -{ - switch(cmd) - { - case CMD_DELETE: - playlist_delete_song(c, lw->selected); - return 1; - case CMD_SAVE_PLAYLIST: - handle_save_playlist(screen, c); - return 1; - case CMD_SCREEN_UPDATE: - center_playing_item(screen, c); - return 1; - case CMD_LIST_MOVE_UP: - playlist_move_song(c, lw->selected, lw->selected-1); - break; - case CMD_LIST_MOVE_DOWN: - playlist_move_song(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, - cmd, list_callback); - default: - break; - } - return list_window_cmd(lw, c->playlist_length, cmd) ; -} - - - -static list_window_t * -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_name(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) -{ - static screen_functions_t functions; - - memset(&functions, 0, sizeof(screen_functions_t)); - functions.init = play_init; - functions.exit = play_exit; - functions.open = NULL; - functions.close = NULL; - functions.resize = play_resize; - functions.paint = play_paint; - functions.update = play_update; - functions.cmd = play_cmd; - functions.get_lw = play_lw; - functions.get_title = play_title; - - return &functions; -} diff --git a/screen_play.h b/screen_play.h deleted file mode 100644 index 2155ae5..0000000 --- a/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/screen_search.c b/screen_search.c deleted file mode 100644 index 6b6719e..0000000 --- a/screen_search.c +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include -#include -#include - -#include "libmpdclient.h" -#include "config.h" -#include "mpc.h" -#include "command.h" -#include "screen.h" -#include "screen_search.h" - diff --git a/screen_search.h b/screen_search.h deleted file mode 100644 index e69de29..0000000 diff --git a/screen_utils.c b/screen_utils.c deleted file mode 100644 index f8dfa4c..0000000 --- a/screen_utils.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * (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 -#include -#include -#include -#include - -#include "config.h" -#include "libmpdclient.h" -#include "mpc.h" -#include "support.h" -#include "command.h" -#include "options.h" -#include "list_window.h" -#include "colors.h" -#include "screen.h" - -#define FIND_PROMPT "Find: " -#define RFIND_PROMPT "Find backward: " - -int -screen_getch(WINDOW *w, char *prompt) -{ - int key = -1; - int prompt_len = strlen(prompt); - - colors_use(w, COLOR_STATUS_ALERT); - wclear(w); - wmove(w, 0, 0); - waddstr(w, prompt); - wmove(w, 0, prompt_len); - - echo(); - curs_set(1); - timeout(-1); - - key = wgetch(w); - if( key==KEY_RESIZE ) - screen_resize(); - - noecho(); - curs_set(0); - timeout(SCREEN_TIMEOUT); - - return key; -} - - -char * -screen_getstr(WINDOW *w, char *prompt) -{ - char buf[256], *line = NULL; - int prompt_len = strlen(prompt); - - colors_use(w, COLOR_STATUS_ALERT); - wclear(w); - wmove(w, 0, 0); - waddstr(w, prompt); - wmove(w, 0, prompt_len); - - echo(); - curs_set(1); - - if( wgetnstr(w, buf, 256) == OK ) - line = g_strdup(buf); - - noecho(); - curs_set(0); - - return line; -} - - -/* query user for a string and find it in a list window */ -int -screen_find(screen_t *screen, - mpd_client_t *c, - list_window_t *lw, - int rows, - command_t findcmd, - list_window_callback_fn_t callback_fn) -{ - int reversed = 0; - int retval = 0; - char *prompt = FIND_PROMPT; - - if( findcmd==CMD_LIST_RFIND ||findcmd==CMD_LIST_RFIND_NEXT ) - { - prompt = RFIND_PROMPT; - reversed = 1; - } - - switch(findcmd) - { - case CMD_LIST_FIND: - case CMD_LIST_RFIND: - if( screen->findbuf ) - { - g_free(screen->findbuf); - screen->findbuf=NULL; - } - /* continue... */ - case CMD_LIST_FIND_NEXT: - case CMD_LIST_RFIND_NEXT: - if( !screen->findbuf ) - screen->findbuf=screen_getstr(screen->status_window.w, prompt); - if( reversed ) - retval = list_window_rfind(lw, - callback_fn, - c, - screen->findbuf, - options.find_wrap, - rows); - else - retval = list_window_find(lw, - callback_fn, - c, - screen->findbuf, - options.find_wrap); - if( retval == 0 ) - { - lw->repaint = 1; - } - else - { - screen_status_printf("Unable to find \'%s\'", screen->findbuf); - beep(); - } - return 1; - default: - break; - } - return 0; -} - - diff --git a/screen_utils.h b/screen_utils.h deleted file mode 100644 index 30c58bf..0000000 --- a/screen_utils.h +++ /dev/null @@ -1,18 +0,0 @@ - -/* read a characher from the status window */ -int screen_getch(WINDOW *w, char *prompt); - -/* read a string from the status window */ -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, - list_window_t *lw, - int rows, - command_t findcmd, - list_window_callback_fn_t callback_fn); - - -int my_waddstr(WINDOW *, const char *, int); -int my_mvwaddstr(WINDOW *, int, int, const char *, int); diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..abf121c --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,20 @@ +# +# $Id$ +# + +bin_PROGRAMS = ncmpc + +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 + +ncmpc_SOURCES = libmpdclient.c main.c mpc.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 \ + list_window.c colors.c support.c $(ncmpc_headers) + + + + + + diff --git a/src/colors.c b/src/colors.c new file mode 100644 index 0000000..f709693 --- /dev/null +++ b/src/colors.c @@ -0,0 +1,336 @@ +/* + * (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 +#include +#include +#include +#include + +#include "config.h" +#include "options.h" +#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) +#define COLOR_BRIGHT_RED (COLOR_RED | COLOR_BRIGHT_MASK) +#define COLOR_BRIGHT_GREEN (COLOR_GREEN | COLOR_BRIGHT_MASK) +#define COLOR_BRIGHT_YELLOW (COLOR_YELLOW | COLOR_BRIGHT_MASK) +#define COLOR_BRIGHT_BLUE (COLOR_BLUE | COLOR_BRIGHT_MASK) +#define COLOR_BRIGHT_MAGENTA (COLOR_MAGENTA | COLOR_BRIGHT_MASK) +#define COLOR_BRIGHT_CYAN (COLOR_CYAN | COLOR_BRIGHT_MASK) +#define COLOR_BRIGHT_WHITE (COLOR_WHITE | COLOR_BRIGHT_MASK) + +#define IS_BRIGHT(color) (color & COLOR_BRIGHT_MASK) + +/* name of the color fields */ +#define NAME_TITLE "title" +#define NAME_TITLE_BOLD "title-bold" +#define NAME_LINE "line" +#define NAME_LINE_BOLD "line-flags" +#define NAME_LIST "list" +#define NAME_LIST_BOLD "list-bold" +#define NAME_PROGRESS "progressbar" +#define NAME_STATUS "status-song" +#define NAME_STATUS_BOLD "status-state" +#define NAME_STATUS_TIME "status-time" +#define NAME_ALERT "alert" +#define NAME_BGCOLOR "background" + +typedef struct { + short color; + short r,g,b; +} color_definition_entry_t; + +typedef struct { + int id; + char *name; + short fg; + attr_t attrs; +} color_entry_t; + +static color_entry_t colors[] = { + + /* color pair, field name, color, mono attribute */ + /*-------------------------------------------------------------------------*/ + { COLOR_TITLE, NAME_TITLE, COLOR_YELLOW, A_NORMAL }, + { COLOR_TITLE_BOLD, NAME_TITLE_BOLD, COLOR_BRIGHT_YELLOW, A_BOLD }, + { COLOR_LINE, NAME_LINE, COLOR_WHITE, A_NORMAL }, + { COLOR_LINE_BOLD, NAME_LINE_BOLD, COLOR_BRIGHT_WHITE, A_BOLD }, + { COLOR_LIST, NAME_LIST, COLOR_GREEN, A_NORMAL }, + { COLOR_LIST_BOLD, NAME_LIST_BOLD, COLOR_BRIGHT_GREEN, A_BOLD }, + { COLOR_PROGRESSBAR, NAME_PROGRESS, COLOR_WHITE, A_NORMAL }, + { COLOR_STATUS, NAME_STATUS, COLOR_YELLOW, A_NORMAL }, + { COLOR_STATUS_BOLD, NAME_STATUS_BOLD, COLOR_BRIGHT_YELLOW, A_BOLD }, + { COLOR_STATUS_TIME, NAME_STATUS_TIME, COLOR_RED, A_NORMAL }, + { COLOR_STATUS_ALERT, NAME_ALERT, COLOR_BRIGHT_RED, A_BOLD }, + { 0, NULL, 0, 0 } +}; + +/* background color */ +static short bg = COLOR_BLACK; + +static GList *color_definition_list = NULL; + +static color_entry_t * +colors_lookup(int id) +{ + int i; + + i=0; + while( colors[i].name != NULL ) + { + if( colors[i].id == id ) + return &colors[i]; + i++; + } + return NULL; +} + +static color_entry_t * +colors_lookup_by_name(char *name) +{ + int i; + + i=0; + while( colors[i].name != NULL ) + { + if( !strcasecmp(colors[i].name, name) ) + return &colors[i]; + i++; + } + return NULL; +} + +static int +colors_update_pair(int id) +{ + color_entry_t *entry = colors_lookup(id); + short fg = -1; + + if( !entry ) + return -1; + + if( IS_BRIGHT(entry->fg) ) + { + entry->attrs = A_BOLD; + fg = entry->fg & ~COLOR_BRIGHT_MASK; + } + else + { + entry->attrs = A_NORMAL; + fg = entry->fg; + } + + init_pair(entry->id, fg, bg); + + return 0; +} + +short +colors_str2color(char *str) +{ + if( !strcasecmp(str,"black") ) + return COLOR_BLACK; + else if( !strcasecmp(str,"red") ) + return COLOR_RED; + else if( !strcasecmp(str,"green") ) + return COLOR_GREEN; + else if( !strcasecmp(str,"yellow") ) + return COLOR_YELLOW; + else if( !strcasecmp(str,"blue") ) + return COLOR_BLUE; + else if( !strcasecmp(str,"magenta") ) + return COLOR_MAGENTA; + else if( !strcasecmp(str,"cyan") ) + return COLOR_CYAN; + else if( !strcasecmp(str,"white") ) + return COLOR_WHITE; + else if( !strcasecmp(str,"brightred") ) + return COLOR_BRIGHT_RED; + else if( !strcasecmp(str,"brightgreen") ) + return COLOR_BRIGHT_GREEN; + else if( !strcasecmp(str,"brightyellow") ) + return COLOR_BRIGHT_YELLOW; + else if( !strcasecmp(str,"brightblue") ) + return COLOR_BRIGHT_BLUE; + else if( !strcasecmp(str,"brightmagenta") ) + return COLOR_BRIGHT_MAGENTA; + else if( !strcasecmp(str,"brightcyan") ) + return COLOR_BRIGHT_CYAN; + else if( !strcasecmp(str,"brightwhite") ) + return COLOR_BRIGHT_WHITE; + else if( !strcasecmp(str,"grey") || !strcasecmp(str,"gray") ) + return COLOR_BRIGHT_BLACK; + else if( !strcasecmp(str,"none") ) + return -1; + fprintf(stderr,"Warning: Unknown color - %s\n", str); + return -2; +} + +/* This function is called from conf.c before curses have been started, + * it adds the definition to the color_definition_list and init_color() is + * done in colors_start() */ +int +colors_define(char *name, short r, short g, short b) +{ + color_definition_entry_t *entry; + short color = colors_str2color(name); + + if( color<0 ) + return -1; + + entry = g_malloc(sizeof(color_definition_entry_t)); + entry->color = color; + entry->r = r; + entry->g = g; + entry->b = b; + + color_definition_list = g_list_append(color_definition_list, entry); + + return 0; +} + + +int +colors_assign(char *name, char *value) +{ + color_entry_t *entry = colors_lookup_by_name(name); + short color; + + if( !entry ) + { + if( !strcasecmp(NAME_BGCOLOR, name) ) + { + if( (color=colors_str2color(value)) < -1 ) + return -1; + if( color > COLORS ) + color = color & ~COLOR_BRIGHT_MASK; + bg = color; + return 0; + } + fprintf(stderr,"Warning: Unknown color field - %s\n", name); + return -1; + } + + if( (color=colors_str2color(value)) < -1 ) + return -1; + entry->fg = color; + + return 0; +} + + +int +colors_start(void) +{ + if( has_colors() ) + { + /* initialize color support */ + start_color(); + use_default_colors(); + /* define any custom colors defined in the configuration file */ + if( color_definition_list && can_change_color() ) + { + GList *list = color_definition_list; + + while( list ) + { + color_definition_entry_t *entry = list->data; + + if( entry->color <= COLORS ) + init_color(entry->color, entry->r, entry->g, entry->b); + list=list->next; + } + } + else if( !can_change_color() ) + fprintf(stderr, "Terminal lacks support for changing colors!\n"); + + if( options.enable_colors ) + { + int i = 0; + + while(colors[i].name) + { + /* update the color pairs */ + colors_update_pair(colors[i].id); + i++; + } + + } + } + else if( options.enable_colors ) + { + fprintf(stderr, "Terminal lacks color capabilities!\n"); + options.enable_colors = 0; + } + + /* free the color_definition_list */ + if( color_definition_list ) + { + GList *list = color_definition_list; + + while( list ) + { + g_free(list->data); + list=list->next; + } + g_list_free(color_definition_list); + color_definition_list = NULL; + } + + return 0; +} + + +int +colors_use(WINDOW *w, int id) +{ + color_entry_t *entry = colors_lookup(id); + short pair; + attr_t attrs; + + if( !entry ) + return -1; + + wattr_get(w, &attrs, &pair, NULL); + + if( options.enable_colors ) + { + /* color mode */ + if( attrs != entry->attrs || id!=pair ) + wattr_set(w, entry->attrs, id, NULL); + } + else + { + /* mono mode */ + if( attrs != entry->attrs ) + wattrset(w, entry->attrs); + } + + return 0; +} + diff --git a/src/colors.h b/src/colors.h new file mode 100644 index 0000000..a66d693 --- /dev/null +++ b/src/colors.h @@ -0,0 +1,27 @@ +#ifndef COLORS_H +#define COLORS_H + +#define COLOR_TITLE 1 +#define COLOR_TITLE_BOLD 2 +#define COLOR_LINE 3 +#define COLOR_LINE_BOLD 4 +#define COLOR_LIST 5 +#define COLOR_LIST_BOLD 6 +#define COLOR_PROGRESSBAR 7 +#define COLOR_STATUS 8 +#define COLOR_STATUS_BOLD 9 +#define COLOR_STATUS_TIME 10 +#define COLOR_STATUS_ALERT 11 + +short colors_str2color(char *str); + +int colors_assign(char *name, char *value); +int colors_define(char *name, short r, short g, short b); +int colors_start(void); +int colors_use(WINDOW *w, int id); + + +#endif /* COLORS_H */ + + + diff --git a/src/command.c b/src/command.c new file mode 100644 index 0000000..1e9edcd --- /dev/null +++ b/src/command.c @@ -0,0 +1,429 @@ +/* + * (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 +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "command.h" + +#undef DEBUG_KEYS + +#ifdef DEBUG_KEYS +#define DK(x) x +#else +#define DK(x) +#endif + +extern void screen_resize(void); + +#define BS KEY_BACKSPACE +#define DEL KEY_DC +#define UP KEY_UP +#define DWN KEY_DOWN +#define LEFT KEY_LEFT +#define RGHT KEY_RIGHT +#define HOME KEY_HOME +#define END KEY_END +#define PGDN KEY_NPAGE +#define PGUP KEY_PPAGE +#define TAB 0x09 +#define STAB 0x161 +#define ESC 0x1B +#define F1 KEY_F(1) +#define F2 KEY_F(2) +#define F3 KEY_F(3) +#define F4 KEY_F(4) +#define F5 KEY_F(5) +#define F6 KEY_F(6) + + +static command_definition_t cmds[] = +{ + { { 13, 0, 0 }, CMD_PLAY, "play", + "Play/Enter directory" }, + { { 'P', 0, 0 }, CMD_PAUSE,"pause", + "Pause" }, + { { 's', BS, 0 }, CMD_STOP, "stop", + "Stop" }, + { { '>', 0, 0 }, CMD_TRACK_NEXT, "next", + "Next track" }, + { { '<', 0, 0 }, CMD_TRACK_PREVIOUS, "prev", + "Previous track" }, + { { 'f', 0, 0 }, CMD_SEEK_FORWARD, "seek-forward", + "Seek forward" }, + { { 'b', 0, 0 }, CMD_SEEK_BACKWARD, "seek-backward", + "Seek backward" }, + + { { '+', RGHT, 0 }, CMD_VOLUME_UP, "volume-up", + "Increase volume" }, + { { '-', LEFT, 0 }, CMD_VOLUME_DOWN, "volume-down", + "Decrease volume" }, + + { { 'w', 0, 0 }, CMD_TOGGLE_FIND_WRAP, "wrap-mode", + "Toggle find mode" }, + { { 'U', 0, 0 }, CMD_TOGGLE_AUTOCENTER, "autocenter-mode", + "Toggle auto center mode" }, + + { { ' ', 'a', 0 }, CMD_SELECT, "select", + "Select/deselect song in playlist" }, + { { DEL, 'd', 0 }, CMD_DELETE, "delete", + "Delete song from playlist" }, + { { 'Z', 0, 0 }, CMD_SHUFFLE, "shuffle", + "Shuffle playlist" }, + { { 'c', 0, 0 }, CMD_CLEAR, "clear", + "Clear playlist" }, + { { 'r', 0, 0 }, CMD_REPEAT, "repeat", + "Toggle repeat mode" }, + { { 'z', 0, 0 }, CMD_RANDOM, "random", + "Toggle random mode" }, + { { 'x', 0, 0 }, CMD_CROSSFADE, "crossfade", + "Toggle crossfade mode" }, + { { 'S', 0, 0 }, CMD_SAVE_PLAYLIST, "save", + "Save playlist" }, + + { { 0, 0, 0 }, CMD_LIST_MOVE_UP, "move-up", + "Move item up" }, + { { 0, 0, 0 }, CMD_LIST_MOVE_DOWN, "move-down", + "Move item down" }, + + { { UP, ',', 0 }, CMD_LIST_PREVIOUS, "up", + "Move cursor up" }, + { { DWN, '.', 0 }, CMD_LIST_NEXT, "down", + "Move cursor down" }, + { { HOME, 0x01, 0 }, CMD_LIST_FIRST, "home", + "Home " }, + { { END, 0x05, 0 }, CMD_LIST_LAST, "end", + "End " }, + { { PGUP, 'A', 0 }, CMD_LIST_PREVIOUS_PAGE, "pgup", + "Page up" }, + { { PGDN, 'B', 0 }, CMD_LIST_NEXT_PAGE, "pgdn", + "Page down" }, + { { '/', 0, 0 }, CMD_LIST_FIND, "find", + "Forward find" }, + { { 'n', 0, 0 }, CMD_LIST_FIND_NEXT, "find-next", + "Forward find next" }, + { { '?', 0, 0 }, CMD_LIST_RFIND, "rfind", + "Backward find" }, + { { 'p', 0, 0 }, CMD_LIST_RFIND_NEXT, "rfind-next", + "Backward find previous" }, + + + { { TAB, 0, 0 }, CMD_SCREEN_NEXT, "screen-next", + "Next screen" }, + + { { STAB, 0, 0 }, CMD_SCREEN_PREVIOUS, "screen-prev", + "Previous screen" }, + + { { '1', F1, 'h' }, CMD_SCREEN_HELP, "screen-help", + "Help screen" }, + { { '2', F2, 0 }, CMD_SCREEN_PLAY, "screen-playlist", + "Playlist screen" }, + { { '3', F3, 0 }, CMD_SCREEN_FILE, "screen-browse", + "Browse screen" }, + { {'u', 0, 0 }, CMD_SCREEN_UPDATE, "update", + "Update screen" }, +#ifdef ENABLE_KEYDEF_SCREEN + { {'K', 0, 0 }, CMD_SCREEN_KEYDEF, "screen-keyedit", + "Key configuration screen" }, +#endif + + { { 'q', 0, 0 }, CMD_QUIT, "quit", + "Quit " PACKAGE }, + + { { -1, -1, -1 }, CMD_NONE, NULL, NULL } +}; + +command_definition_t * +get_command_definitions(void) +{ + return cmds; +} + +char * +key2str(int key) +{ + static char buf[32]; + int i; + + buf[0] = 0; + switch(key) + { + case 0: + return "Undefined"; + case ' ': + return "Space"; + case 13: + return "Enter"; + case BS: + return "Backspace"; + case DEL: + return "Delete"; + case UP: + return "Up"; + case DWN: + return "Down"; + case LEFT: + return "Left"; + case RGHT: + return "Right"; + case HOME: + return "Home"; + case END: + return "End"; + case PGDN: + return "PageDown"; + case PGUP: + return "PageUp"; + case TAB: + return "Tab"; + case STAB: + return "Shift+Tab"; + case ESC: + return "Esc"; + case KEY_IC: + return "Insert"; + default: + for(i=0; i<=63; i++) + if( key==KEY_F(i) ) + { + snprintf(buf, 32, "F%d", i ); + return buf; + } + if( !(key & ~037) ) + snprintf(buf, 32, "Ctrl-%c", 'A'+(key & 037)-1 ); + else if( (key & ~037) == 224 ) + snprintf(buf, 32, "Alt-%c", 'A'+(key & 037)-1 ); + else if( key>32 && key<256 ) + snprintf(buf, 32, "%c", key); + else + snprintf(buf, 32, "0x%03X", key); + } + return buf; +} + +void +command_dump_keys(void) +{ + int i; + + i=0; + while( cmds[i].description ) + { + if( cmds[i].command != CMD_NONE ) + printf(" %20s : %s\n", get_key_names(cmds[i].command,1),cmds[i].name); + i++; + } +} + +char * +get_key_names(command_t command, int all) +{ + int i; + + i=0; + while( cmds[i].description ) + { + if( cmds[i].command == command ) + { + int j; + static char keystr[80]; + + strncpy(keystr, key2str(cmds[i].keys[0]), 80); + if( !all ) + return keystr; + j=1; + while( j0 ) + { + strcat(keystr, " "); + strcat(keystr, key2str(cmds[i].keys[j])); + j++; + } + return keystr; + } + i++; + } + return NULL; +} + +char * +get_key_description(command_t command) +{ + int i; + + i=0; + while( cmds[i].description ) + { + if( cmds[i].command == command ) + return cmds[i].description; + i++; + } + return NULL; +} + +char * +get_key_command_name(command_t command) +{ + int i; + + i=0; + while( cmds[i].name ) + { + if( cmds[i].command == command ) + return cmds[i].name; + i++; + } + return NULL; +} + +command_t +get_key_command_from_name(char *name) +{ + int i; + + i=0; + while( cmds[i].name ) + { + if( strcmp(name, cmds[i].name) == 0 ) + return cmds[i].command; + i++; + } + return CMD_NONE; +} + + +command_t +find_key_command(int key, command_definition_t *cmds) +{ + int i; + + i=0; + while( cmds && cmds[i].name ) + { + if( cmds[i].keys[0] == key || + cmds[i].keys[1] == key || + cmds[i].keys[2] == key ) + return cmds[i].command; + i++; + } + return CMD_NONE; +} + +command_t +get_key_command(int key) +{ + return find_key_command(key, cmds); +} + + +command_t +get_keyboard_command(void) +{ + int key; + + key = wgetch(stdscr); + + if( key==KEY_RESIZE ) + screen_resize(); + + if( key==ERR ) + return CMD_NONE; + + DK(fprintf(stderr, "key = 0x%02X\t", key)); + + return get_key_command(key); +} + +int +assign_keys(command_t command, int keys[MAX_COMMAND_KEYS]) +{ + int i; + + i=0; + while( cmds[i].name ) + { + if( cmds[i].command == command ) + { + memcpy(cmds[i].keys, keys, sizeof(int)*MAX_COMMAND_KEYS); + return 0; + } + i++; + } + return -1; +} + +int +check_key_bindings(void) +{ + int i; + int retval = 0; + + i=0; + while( cmds[i].name ) + { + int j; + command_t cmd; + + for(j=0; j +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "config.h" +#include "options.h" +#include "support.h" +#include "command.h" +#include "colors.h" +#include "conf.h" + +#ifdef DEBUG +#define D(x) x +#else +#define D(x) +#endif + +#define ENABLE_OLD_COLOR_SYNTAX + +#define MAX_LINE_LENGTH 1024 +#define COMMENT_TOKEN '#' + +/* configuration field names */ +#define CONF_ENABLE_COLORS "enable_colors" +#define CONF_AUTO_CENTER "auto_center" +#define CONF_WIDE_CURSOR "wide_cursor" +#define CONF_KEY_DEFINITION "key" +#define CONF_COLOR "color" +#define CONF_COLOR_DEFINITION "colordef" + +/* Deprecated - configuration field names */ +#define CONF_COLOR_BACKGROUND "background_color" +#define CONF_COLOR_TITLE "title_color" +#define CONF_COLOR_LINE "line_color" +#define CONF_COLOR_LIST "list_color" +#define CONF_COLOR_PROGRESS "progress_color" +#define CONF_COLOR_STATUS "status_color" +#define CONF_COLOR_ALERT "alert_color" + + +typedef enum { + KEY_PARSER_UNKNOWN, + KEY_PARSER_CHAR, + KEY_PARSER_DEC, + KEY_PARSER_HEX, + KEY_PARSER_DONE +} key_parser_state_t; + +static int +str2bool(char *str) +{ + if( !strcasecmp(str,"no") || !strcasecmp(str,"false") || + !strcasecmp(str,"off") || !strcasecmp(str,"0") ) + return 0; + return 1; +} + +static int +parse_key_value(char *str, size_t len, char **end) +{ + int i, value; + key_parser_state_t state; + + i=0; + value=0; + state=KEY_PARSER_UNKNOWN; + *end = str; + + while( i str+len ) + *end = str+len; + + return value; +} + +static int +parse_key_definition(char *str) +{ + char buf[MAX_LINE_LENGTH]; + char *p, *end; + size_t len = strlen(str); + int i,j,key; + int keys[MAX_COMMAND_KEYS]; + command_t cmd; + + /* get the command name */ + i=0; + j=0; + memset(buf, 0, MAX_LINE_LENGTH); + while( i=0 ) + { + keys[i++] = key; + while( p=0 ) + { + rgb[i++] = value; + while( p=0 && IS_WHITESPACE(line[i]) ) + { + line[i] = '\0'; + i--; + } + len = i+1; + + if( len>0 ) + { + i = 0; + /* skip whitespace */ + while( ienable_colors = str2bool(value); + } + /* auto center */ + else if( !strcasecmp(CONF_AUTO_CENTER, name) ) + { + options->auto_center = str2bool(value); + } + /* color assignment */ + else if( !strcasecmp(CONF_COLOR, name) ) + { + parse_color(value); + } +#ifdef ENABLE_OLD_COLOR_SYNTAX + /* background color */ + else if( !strcasecmp(CONF_COLOR_BACKGROUND, name) ) + { + fprintf(stderr,"%s: %s - deprecated!\n", filename,name); + colors_assign("background", value); + } + /* color - top (title) window */ + else if( !strcasecmp(CONF_COLOR_TITLE, name) ) + { + fprintf(stderr,"%s: %s - deprecated!\n", filename,name); + colors_assign("title", value); + colors_assign("title2", value); + } + /* color - line (title) window */ + else if( !strcasecmp(CONF_COLOR_LINE, name) ) + { + fprintf(stderr,"%s: %s - deprecated!\n", filename,name); + colors_assign("line", value); + colors_assign("line2", value); + } + /* color - list window */ + else if( !strcasecmp(CONF_COLOR_LIST, name) ) + { + fprintf(stderr,"%s: %s - deprecated!\n", filename,name); + colors_assign("list", value); + } + /* color - progress bar */ + else if( !strcasecmp(CONF_COLOR_PROGRESS, name) ) + { + fprintf(stderr,"%s: %s - deprecated!\n", filename,name); + colors_assign("progressbar", value); + } + /* color - status window */ + else if( !strcasecmp(CONF_COLOR_STATUS, name) ) + { + fprintf(stderr,"%s: %s - deprecated!\n", filename,name); + colors_assign("status", value); + colors_assign("status2", value); + } + /* color - alerts */ + else if( !strcasecmp(CONF_COLOR_ALERT, name) ) + { + fprintf(stderr,"%s: %s - deprecated!\n", filename,name); + colors_assign("alert", value); + } +#endif + /* wide cursor */ + else if( !strcasecmp(CONF_WIDE_CURSOR, name) ) + { + options->wide_cursor = str2bool(value); + } + /* color definition */ + else if( !strcasecmp(CONF_COLOR_DEFINITION, name) ) + { + parse_color_definition(value); + } + else + { + match_found = 0; + } + + + if( !match_found ) + fprintf(stderr, + "Unknown configuration parameter: %s\n", + name); +#ifdef DEBUG + printf( " %s = %s %s\n", + name, + value, + match_found ? "" : "- UNKNOWN SETTING!" ); +#endif + + } + } + } + + D(printf( "--\n\n" )); + + if( free_filename ) + g_free(filename); + + return 0; +} + +int +check_user_conf_dir(void) +{ + int retval; + char *dirname = g_build_filename(g_get_home_dir(), "." PACKAGE, NULL); + + if( g_file_test(dirname, G_FILE_TEST_IS_DIR) ) + { + g_free(dirname); + return 0; + } + retval = mkdir(dirname, 0755); + g_free(dirname); + return retval; +} + +char * +get_user_key_binding_filename(void) +{ + return g_build_filename(g_get_home_dir(), "." PACKAGE, "keys", NULL); +} + + +int +read_configuration(options_t *options) +{ + char *filename = NULL; + + /* check for command line configuration file */ + if( options->config_file ) + filename = g_strdup(options->config_file); + + /* check for user configuration ~/.ncmpc/config */ + if( filename == NULL ) + { + filename = g_build_filename(g_get_home_dir(), + "." PACKAGE, "config", NULL); + if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) ) + { + g_free(filename); + filename = NULL; + } + } + + /* check for global configuration SYSCONFDIR/ncmpc/config */ + if( filename == NULL ) + { + filename = g_build_filename(SYSCONFDIR, PACKAGE, "config", NULL); + if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) ) + { + g_free(filename); + filename = NULL; + } + } + + /* load configuration */ + if( filename ) + { + read_rc_file(filename, options); + g_free(filename); + filename = NULL; + } + + /* check for command line key binding file */ + if( options->key_file ) + filename = g_strdup(options->key_file); + + /* check for user key bindings ~/.ncmpc/keys */ + if( filename == NULL ) + { + filename = get_user_key_binding_filename(); + if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) ) + { + g_free(filename); + filename = NULL; + } + } + + /* check for global key bindings SYSCONFDIR/ncmpc/keys */ + if( filename == NULL ) + { + filename = g_build_filename(SYSCONFDIR, PACKAGE, "keys", NULL); + if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) ) + { + g_free(filename); + filename = NULL; + } + } + + /* load key bindings */ + if( filename ) + { + read_rc_file(filename, options); + g_free(filename); + filename = NULL; + } + + return 0; +} + + + diff --git a/src/conf.h b/src/conf.h new file mode 100644 index 0000000..20b4f5e --- /dev/null +++ b/src/conf.h @@ -0,0 +1,7 @@ + +int check_user_conf_dir(void); + +char *get_user_key_binding_filename(void); + +int read_configuration(options_t *options); + diff --git a/src/libmpdclient.c b/src/libmpdclient.c new file mode 100644 index 0000000..2e8b579 --- /dev/null +++ b/src/libmpdclient.c @@ -0,0 +1,1211 @@ +/* libmpdclient + * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) + * This project's homepage is: http://www.musicpd.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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 "libmpdclient.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#ifndef HAVE_SOCKLEN_T +typedef SOCKLEN_T socklen_t; +#endif +#endif + + +#ifndef MPD_NO_IPV6 +#ifdef AF_INET6 +#define MPD_HAVE_IPV6 +#endif +#endif + +#ifdef MPD_HAVE_IPV6 +int mpd_ipv6Supported() { + int s; + s = socket(AF_INET6,SOCK_STREAM,0); + if(s == -1) return 0; + close(s); + return 1; +} +#endif + + +char * mpd_sanitizeArg(const char * arg) { + size_t i; + int count=0; + char * ret; + + for(i=0;iname = strdup(name); + ret->value = strdup(value); + + return ret; +} + +void mpd_freeReturnElement(mpd_ReturnElement * re) { + free(re->name); + free(re->value); + free(re); +} + +void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout) { + connection->timeout.tv_sec = (int)timeout; + connection->timeout.tv_usec = (int)(timeout*1e6 - + connection->timeout.tv_sec*1000000+0.5); +} + +mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) { + int err; + struct hostent * he; + struct sockaddr * dest; + socklen_t destlen; + struct sockaddr_in sin; + char * rt; + char * output; + mpd_Connection * connection = malloc(sizeof(mpd_Connection)); + struct timeval tv; + fd_set fds; +#ifdef MPD_HAVE_IPV6 + struct sockaddr_in6 sin6; +#endif + strcpy(connection->buffer,""); + connection->buflen = 0; + connection->bufstart = 0; + strcpy(connection->errorStr,""); + connection->error = 0; + connection->doneProcessing = 0; + connection->commandList = 0; + connection->returnElement = NULL; + + if(!(he=gethostbyname(host))) { + snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, + "host \"%s\" not found",host); + connection->error = MPD_ERROR_UNKHOST; + return connection; + } + + memset(&sin,0,sizeof(struct sockaddr_in)); + /*dest.sin_family = he->h_addrtype;*/ + sin.sin_family = AF_INET; + sin.sin_port = htons(port); +#ifdef MPD_HAVE_IPV6 + memset(&sin6,0,sizeof(struct sockaddr_in6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(port); +#endif + switch(he->h_addrtype) { + case AF_INET: + memcpy((char *)&sin.sin_addr.s_addr,(char *)he->h_addr, + he->h_length); + dest = (struct sockaddr *)&sin; + destlen = sizeof(struct sockaddr_in); + break; +#ifdef MPD_HAVE_IPV6 + case AF_INET6: + if(!mpd_ipv6Supported()) { + strcpy(connection->errorStr,"no IPv6 suuport but a " + "IPv6 address found\n"); + connection->error = MPD_ERROR_SYSTEM; + return connection; + } + memcpy((char *)&sin6.sin6_addr.s6_addr,(char *)he->h_addr, + he->h_length); + dest = (struct sockaddr *)&sin6; + destlen = sizeof(struct sockaddr_in6); + break; +#endif + default: + strcpy(connection->errorStr,"address type is not IPv4 or " + "IPv6\n"); + connection->error = MPD_ERROR_SYSTEM; + return connection; + break; + } + + if((connection->sock = socket(dest->sa_family,SOCK_STREAM,0))<0) { + strcpy(connection->errorStr,"problems creating socket"); + connection->error = MPD_ERROR_SYSTEM; + return connection; + } + + /* connect stuff */ + { +#ifdef SO_RCVTIMEO + struct timeval rcvoldto; + struct timeval sndoldto; + socklen_t oldlen = sizeof(struct timeval); + + 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) + { + 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"))) { + tv.tv_sec = connection->timeout.tv_sec; + tv.tv_usec = connection->timeout.tv_usec; + FD_ZERO(&fds); + FD_SET(connection->sock,&fds); + if((err = select(connection->sock+1,&fds,NULL,NULL,&tv)) == 1) { + int readed; + readed = recv(connection->sock, + &(connection->buffer[connection->buflen]), + MPD_BUFFER_MAX_LENGTH-connection->buflen,0); + if(readed<=0) { + snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, + "problems getting a response from" + " \"%s\" on port %i",host, + port); + connection->error = MPD_ERROR_NORESPONSE; + return connection; + } + connection->buflen+=readed; + connection->buffer[connection->buflen] = '\0'; + tv.tv_sec = connection->timeout.tv_sec; + tv.tv_usec = connection->timeout.tv_usec; + } + else if(err<0 && errno==EINTR) continue; + else { + snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, + "timeout in attempting to get a response from" + " \"%s\" on port %i",host,port); + connection->error = MPD_ERROR_NORESPONSE; + return connection; + } + } + + *rt = '\0'; + output = strdup(connection->buffer); + strcpy(connection->buffer,rt+1); + connection->buflen = strlen(connection->buffer); + + if(strncmp(output,MPD_WELCOME_MESSAGE,strlen(MPD_WELCOME_MESSAGE))) { + free(output); + snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, + "mpd not running on port %i on host \"%s\"", + port,host); + connection->error = MPD_ERROR_NOTMPD; + return connection; + } + + { + char * test; + char * version[3]; + char * tmp = &output[strlen(MPD_WELCOME_MESSAGE)]; + char * search = "."; + int i; + + for(i=0;i<3;i++) { + char * tok; + if(i==3) search = " "; + version[i] = strtok_r(tmp,search,&tok); + if(!version[i]) { + free(output); + snprintf(connection->errorStr, + MPD_BUFFER_MAX_LENGTH, + "error parsing version number at " + "\"%s\"", + &output[strlen(MPD_WELCOME_MESSAGE)]); + connection->error = MPD_ERROR_NOTMPD; + return connection; + } + connection->version[i] = strtol(version[i],&test,10); + if(version[i]==test || *test!='\0') { + free(output); + snprintf(connection->errorStr, + MPD_BUFFER_MAX_LENGTH, + "error parsing version number at " + "\"%s\"", + &output[strlen(MPD_WELCOME_MESSAGE)]); + connection->error = MPD_ERROR_NOTMPD; + return connection; + } + tmp = NULL; + } + } + + free(output); + + connection->doneProcessing = 1; + + return connection; +} + +void mpd_clearError(mpd_Connection * connection) { + connection->error = 0; + connection->errorStr[0] = '\0'; +} + +void mpd_closeConnection(mpd_Connection * connection) { + close(connection->sock); + if(connection->returnElement) free(connection->returnElement); + free(connection); +} + +void mpd_executeCommand(mpd_Connection * connection, char * command) { + int ret; + struct timeval tv; + fd_set fds; + char * commandPtr = command; + int commandLen = strlen(command); + + if(!connection->doneProcessing && !connection->commandList) { + strcpy(connection->errorStr,"not done processing current command"); + connection->error = 1; + return; + } + + mpd_clearError(connection); + + FD_ZERO(&fds); + FD_SET(connection->sock,&fds); + tv.tv_sec = connection->timeout.tv_sec; + tv.tv_usec = connection->timeout.tv_usec; + + while((ret = select(connection->sock+1,NULL,&fds,NULL,&tv)==1) || + (ret==-1 && errno==EINTR)) { + ret = send(connection->sock,commandPtr,commandLen, + MSG_DONTWAIT); + if(ret<=0) + { + if(ret==EAGAIN || ret==EINTR) continue; + snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, + "problems giving command \"%s\"",command); + connection->error = MPD_ERROR_SENDING; + return; + } + else { + commandPtr+=ret; + commandLen-=ret; + } + + if(commandLen<=0) break; + } + + if(commandLen>0) { + perror(""); + snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, + "timeout sending command \"%s\"",command); + connection->error = MPD_ERROR_TIMEOUT; + return; + } + + if(!connection->commandList) connection->doneProcessing = 0; +} + +void mpd_getNextReturnElement(mpd_Connection * connection) { + char * output = NULL; + char * rt = NULL; + char * name; + char * value; + fd_set fds; + struct timeval tv; + char * tok; + int readed; + char * bufferCheck; + int err; + + if(connection->returnElement) mpd_freeReturnElement(connection->returnElement); + connection->returnElement = NULL; + + if(connection->doneProcessing) { + strcpy(connection->errorStr,"already done processing current command"); + connection->error = 1; + return; + } + + bufferCheck = connection->buffer+connection->bufstart; + while(connection->bufstart>=connection->buflen || + !(rt = strstr(bufferCheck,"\n"))) { + if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) { + memmove(connection->buffer, + connection->buffer+ + connection->bufstart, + connection->buflen- + connection->bufstart+1); + bufferCheck-=connection->bufstart; + connection->buflen-=connection->bufstart; + connection->bufstart = 0; + } + if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) { + strcpy(connection->errorStr,"buffer overrun"); + connection->error = MPD_ERROR_BUFFEROVERRUN; + connection->doneProcessing = 1; + return; + } + bufferCheck+=connection->buflen-connection->bufstart; + tv.tv_sec = connection->timeout.tv_sec; + tv.tv_usec = connection->timeout.tv_usec; + FD_ZERO(&fds); + FD_SET(connection->sock,&fds); + if((err = select(connection->sock+1,&fds,NULL,NULL,&tv) == 1)) { + readed = recv(connection->sock, + connection->buffer+connection->buflen, + MPD_BUFFER_MAX_LENGTH-connection->buflen, + MSG_DONTWAIT); + if(readed<0 && (errno==EAGAIN || errno==EINTR)) { + continue; + } + if(readed<=0) { + strcpy(connection->errorStr,"connection" + " closed"); + connection->error = MPD_ERROR_CONNCLOSED; + connection->doneProcessing = 1; + return; + } + connection->buflen+=readed; + connection->buffer[connection->buflen] = '\0'; + } + else if(err<0 && errno==EINTR) continue; + else { + strcpy(connection->errorStr,"connection timeout"); + connection->error = MPD_ERROR_TIMEOUT; + connection->doneProcessing = 1; + return; + } + } + + *rt = '\0'; + output = connection->buffer+connection->bufstart; + connection->bufstart = rt - connection->buffer + 1; + + if(strcmp(output,"OK")==0) { + connection->doneProcessing = 1; + return; + } + if(strncmp(output,"ACK",strlen("ACK"))==0) { + strcpy(connection->errorStr,output); + connection->error = MPD_ERROR_ACK; + connection->doneProcessing = 1; + return; + } + + name = strtok_r(output,":",&tok); + if(name && (value = strtok_r(NULL,"",&tok)) && value[0]==' ') { + connection->returnElement = mpd_newReturnElement(name,&(value[1])); + } + else { + if(!name || !value) { + snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, + "error parsing: %s",output); + } + else { + snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH, + "error parsing: %s:%s",name,value); + } + connection->errorStr[MPD_BUFFER_MAX_LENGTH] = '\0'; + connection->error = 1; + } +} + +void mpd_finishCommand(mpd_Connection * connection) { + while(!connection->doneProcessing) mpd_getNextReturnElement(connection); +} + + +mpd_Status * mpd_getStatus(mpd_Connection * connection) { + mpd_Status * status; + + mpd_executeCommand(connection,"status\n"); + + if(connection->error) return NULL; + + status = malloc(sizeof(mpd_Status)); + status->volume = -1; + status->repeat = 0; + status->random = 0; + status->playlist = -1; + status->playlistLength = -1; + status->state = -1; + status->song = 0; + status->elapsedTime = 0; + status->totalTime = 0; + status->bitRate = 0; + status->sampleRate = 0; + status->bits = 0; + status->channels = 0; + status->crossfade = -1; + status->error = NULL; + status->updatingDb = 0; + + mpd_getNextReturnElement(connection); + if(connection->error) { + free(status); + return NULL; + } + while(connection->returnElement) { + mpd_ReturnElement * re = connection->returnElement; + if(strcmp(re->name,"volume")==0) { + status->volume = atoi(re->value); + } + else if(strcmp(re->name,"repeat")==0) { + status->repeat = atoi(re->value); + } + else if(strcmp(re->name,"random")==0) { + status->random = atoi(re->value); + } + else if(strcmp(re->name,"playlist")==0) { + status->playlist = strtol(re->value,NULL,10); + } + else if(strcmp(re->name,"playlistlength")==0) { + status->playlistLength = atoi(re->value); + } + else if(strcmp(re->name,"bitrate")==0) { + status->bitRate = atoi(re->value); + } + else if(strcmp(re->name,"state")==0) { + if(strcmp(re->value,"play")==0) { + status->state = MPD_STATUS_STATE_PLAY; + } + else if(strcmp(re->value,"stop")==0) { + status->state = MPD_STATUS_STATE_STOP; + } + else if(strcmp(re->value,"pause")==0) { + status->state = MPD_STATUS_STATE_PAUSE; + } + else { + status->state = MPD_STATUS_STATE_UNKNOWN; + } + } + else if(strcmp(re->name,"song")==0) { + status->song = atoi(re->value); + } + else if(strcmp(re->name,"time")==0) { + char * tok; + char * copy; + char * temp; + copy = strdup(re->value); + temp = strtok_r(copy,":",&tok); + if(temp) { + status->elapsedTime = atoi(temp); + temp = strtok_r(NULL,"",&tok); + if(temp) status->totalTime = atoi(temp); + } + free(copy); + } + else if(strcmp(re->name,"error")==0) { + status->error = strdup(re->value); + } + else if(strcmp(re->name,"xfade")==0) { + status->crossfade = atoi(re->value); + } + else if(strcmp(re->name,"updating_db")==0) { + status->updatingDb = atoi(re->value); + } + else if(strcmp(re->name,"audio")==0) { + char * tok; + char * copy; + char * temp; + copy = strdup(re->value); + temp = strtok_r(copy,":",&tok); + if(temp) { + status->sampleRate = atoi(temp); + temp = strtok_r(NULL,":",&tok); + if(temp) { + status->bits = atoi(temp); + temp = strtok_r(NULL,"",&tok); + if(temp) status->channels = atoi(temp); + } + } + free(copy); + } + + mpd_getNextReturnElement(connection); + if(connection->error) { + free(status); + return NULL; + } + } + + if(connection->error) { + free(status); + return NULL; + } + else if(status->state<0) { + strcpy(connection->errorStr,"state not found"); + connection->error = 1; + free(status); + return NULL; + } + + return status; +} + +void mpd_freeStatus(mpd_Status * status) { + if(status->error) free(status->error); + free(status); +} + +mpd_Stats * mpd_getStats(mpd_Connection * connection) { + mpd_Stats * stats; + + mpd_executeCommand(connection,"stats\n"); + + if(connection->error) return NULL; + + stats = malloc(sizeof(mpd_Stats)); + stats->numberOfArtists = 0; + stats->numberOfAlbums = 0; + stats->numberOfSongs = 0; + stats->uptime = 0; + stats->dbUpdateTime = 0; + stats->playTime = 0; + stats->dbPlayTime = 0; + + mpd_getNextReturnElement(connection); + if(connection->error) { + free(stats); + return NULL; + } + while(connection->returnElement) { + mpd_ReturnElement * re = connection->returnElement; + if(strcmp(re->name,"artists")==0) { + stats->numberOfArtists = atoi(re->value); + } + else if(strcmp(re->name,"albums")==0) { + stats->numberOfAlbums = atoi(re->value); + } + else if(strcmp(re->name,"songs")==0) { + stats->numberOfSongs = atoi(re->value); + } + else if(strcmp(re->name,"uptime")==0) { + stats->uptime = strtol(re->value,NULL,10); + } + else if(strcmp(re->name,"db_update")==0) { + stats->dbUpdateTime = strtol(re->value,NULL,10); + } + else if(strcmp(re->name,"playtime")==0) { + stats->playTime = strtol(re->value,NULL,10); + } + else if(strcmp(re->name,"db_playtime")==0) { + stats->dbPlayTime = strtol(re->value,NULL,10); + } + + mpd_getNextReturnElement(connection); + if(connection->error) { + free(stats); + return NULL; + } + } + + if(connection->error) { + free(stats); + return NULL; + } + + return stats; +} + +void mpd_freeStats(mpd_Stats * stats) { + free(stats); +} + +void mpd_initSong(mpd_Song * song) { + song->file = NULL; + song->artist = NULL; + song->album = NULL; + song->track = NULL; + song->title = NULL; + song->time = MPD_SONG_NO_TIME; +} + +void mpd_finishSong(mpd_Song * song) { + if(song->file) free(song->file); + if(song->artist) free(song->artist); + if(song->album) free(song->album); + if(song->title) free(song->title); + if(song->track) free(song->track); +} + +mpd_Song * mpd_newSong() { + mpd_Song * ret = malloc(sizeof(mpd_Song)); + + mpd_initSong(ret); + + return ret; +} + +void mpd_freeSong(mpd_Song * song) { + mpd_finishSong(song); + free(song); +} + +mpd_Song * mpd_songDup(mpd_Song * song) { + mpd_Song * ret = mpd_newSong(); + + if(song->file) ret->file = strdup(song->file); + if(song->artist) ret->artist = strdup(song->artist); + if(song->album) ret->album = strdup(song->album); + if(song->title) ret->title = strdup(song->title); + if(song->track) ret->track = strdup(song->track); + ret->time = song->time; + + return ret; +} + +void mpd_initDirectory(mpd_Directory * directory) { + directory->path = NULL; +} + +void mpd_finishDirectory(mpd_Directory * directory) { + if(directory->path) free(directory->path); +} + +mpd_Directory * mpd_newDirectory () { + mpd_Directory * directory = malloc(sizeof(mpd_Directory));; + + mpd_initDirectory(directory); + + return directory; +} + +void mpd_freeDirectory(mpd_Directory * directory) { + mpd_finishDirectory(directory); + + free(directory); +} + +mpd_Directory * mpd_directoryDup(mpd_Directory * directory) { + mpd_Directory * ret = mpd_newDirectory(); + + if(directory->path) ret->path = strdup(directory->path); + + return ret; +} + +void mpd_initPlaylistFile(mpd_PlaylistFile * playlist) { + playlist->path = NULL; +} + +void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist) { + if(playlist->path) free(playlist->path); +} + +mpd_PlaylistFile * mpd_newPlaylistFile() { + mpd_PlaylistFile * playlist = malloc(sizeof(mpd_PlaylistFile)); + + mpd_initPlaylistFile(playlist); + + return playlist; +} + +void mpd_freePlaylistFile(mpd_PlaylistFile * playlist) { + mpd_finishPlaylistFile(playlist); + free(playlist); +} + +mpd_PlaylistFile * mpd_playlistFileDup(mpd_PlaylistFile * playlist) { + mpd_PlaylistFile * ret = mpd_newPlaylistFile(); + + if(playlist->path) ret->path = strdup(playlist->path); + + return ret; +} + +void mpd_initInfoEntity(mpd_InfoEntity * entity) { + entity->info.directory = NULL; +} + +void mpd_finishInfoEntity(mpd_InfoEntity * entity) { + if(entity->info.directory) { + if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) { + mpd_freeDirectory(entity->info.directory); + } + else if(entity->type == MPD_INFO_ENTITY_TYPE_SONG) { + mpd_freeSong(entity->info.song); + } + else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) { + mpd_freePlaylistFile(entity->info.playlistFile); + } + } +} + +mpd_InfoEntity * mpd_newInfoEntity() { + mpd_InfoEntity * entity = malloc(sizeof(mpd_InfoEntity)); + + mpd_initInfoEntity(entity); + + return entity; +} + +void mpd_freeInfoEntity(mpd_InfoEntity * entity) { + mpd_finishInfoEntity(entity); + free(entity); +} + +void mpd_sendInfoCommand(mpd_Connection * connection, char * command) { + mpd_executeCommand(connection,command); +} + +mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection) { + mpd_InfoEntity * entity = NULL; + + if(connection->doneProcessing) return NULL; + + if(!connection->returnElement) mpd_getNextReturnElement(connection); + + if(connection->returnElement) { + if(strcmp(connection->returnElement->name,"file")==0) { + entity = mpd_newInfoEntity(); + entity->type = MPD_INFO_ENTITY_TYPE_SONG; + entity->info.song = mpd_newSong(); + entity->info.song->file = + strdup(connection->returnElement->value); + } + else if(strcmp(connection->returnElement->name, + "directory")==0) { + entity = mpd_newInfoEntity(); + entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY; + entity->info.directory = mpd_newDirectory(); + entity->info.directory->path = + strdup(connection->returnElement->value); + } + else if(strcmp(connection->returnElement->name,"playlist")==0) { + entity = mpd_newInfoEntity(); + entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE; + entity->info.playlistFile = mpd_newPlaylistFile(); + entity->info.playlistFile->path = + strdup(connection->returnElement->value); + } + else { + connection->error = 1; + strcpy(connection->errorStr,"problem parsing song info"); + return NULL; + } + } + else return NULL; + + mpd_getNextReturnElement(connection); + while(connection->returnElement) { + mpd_ReturnElement * re = connection->returnElement; + + if(strcmp(re->name,"file")==0) return entity; + else if(strcmp(re->name,"directory")==0) return entity; + else if(strcmp(re->name,"playlist")==0) return entity; + + if(entity->type == MPD_INFO_ENTITY_TYPE_SONG && + strlen(re->value)) { + if(!entity->info.song->artist && + strcmp(re->name,"Artist")==0) { + entity->info.song->artist = strdup(re->value); + } + else if(!entity->info.song->album && + strcmp(re->name,"Album")==0) { + entity->info.song->album = strdup(re->value); + } + else if(!entity->info.song->title && + strcmp(re->name,"Title")==0) { + entity->info.song->title = strdup(re->value); + } + else if(!entity->info.song->track && + strcmp(re->name,"Track")==0) { + entity->info.song->track = strdup(re->value); + } + else if(entity->info.song->time==MPD_SONG_NO_TIME && + strcmp(re->name,"Time")==0) { + entity->info.song->time = atoi(re->value); + } + } + else if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) { + } + else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) { + } + + mpd_getNextReturnElement(connection); + } + + return entity; +} + +char * mpd_getNextReturnElementNamed(mpd_Connection * connection, + const char * name) +{ + if(connection->doneProcessing) return NULL; + + mpd_getNextReturnElement(connection); + while(connection->returnElement) { + mpd_ReturnElement * re = connection->returnElement; + + if(strcmp(re->name,name)==0) return strdup(re->value); + mpd_getNextReturnElement(connection); + } + + return NULL; +} + +char * mpd_getNextArtist(mpd_Connection * connection) { + return mpd_getNextReturnElementNamed(connection,"Artist"); +} + +char * mpd_getNextAlbum(mpd_Connection * connection) { + return mpd_getNextReturnElementNamed(connection,"Album"); +} + +void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songNum) { + char * string = malloc(strlen("playlistinfo")+25); + sprintf(string,"playlistinfo \"%i\"\n",songNum); + mpd_sendInfoCommand(connection,string); + free(string); +} + +void mpd_sendListallCommand(mpd_Connection * connection, const char * dir) { + char * sDir = mpd_sanitizeArg(dir); + char * string = malloc(strlen("listall")+strlen(sDir)+5); + sprintf(string,"listall \"%s\"\n",sDir); + mpd_sendInfoCommand(connection,string); + free(string); + free(sDir); +} + +void mpd_sendListallInfoCommand(mpd_Connection * connection, const char * dir) { + char * sDir = mpd_sanitizeArg(dir); + char * string = malloc(strlen("listallinfo")+strlen(sDir)+5); + sprintf(string,"listallinfo \"%s\"\n",sDir); + mpd_sendInfoCommand(connection,string); + free(string); + free(sDir); +} + +void mpd_sendLsInfoCommand(mpd_Connection * connection, const char * dir) { + char * sDir = mpd_sanitizeArg(dir); + char * string = malloc(strlen("lsinfo")+strlen(sDir)+5); + sprintf(string,"lsinfo \"%s\"\n",sDir); + mpd_sendInfoCommand(connection,string); + free(string); + free(sDir); +} + +void mpd_sendSearchCommand(mpd_Connection * connection, int table, + const char * str) +{ + char st[10]; + char * string; + char * sanitStr = mpd_sanitizeArg(str); + if(table == MPD_TABLE_ARTIST) strcpy(st,"artist"); + else if(table == MPD_TABLE_ALBUM) strcpy(st,"album"); + else if(table == MPD_TABLE_TITLE) strcpy(st,"title"); + else if(table == MPD_TABLE_FILENAME) strcpy(st,"filename"); + else { + connection->error = 1; + strcpy(connection->errorStr,"unknown table for search"); + return; + } + string = malloc(strlen("search")+strlen(sanitStr)+strlen(st)+6); + sprintf(string,"search %s \"%s\"\n",st,sanitStr); + mpd_sendInfoCommand(connection,string); + free(string); + free(sanitStr); +} + +void mpd_sendFindCommand(mpd_Connection * connection, int table, + const char * str) +{ + char st[10]; + char * string; + char * sanitStr = mpd_sanitizeArg(str); + if(table == MPD_TABLE_ARTIST) strcpy(st,"artist"); + else if(table == MPD_TABLE_ALBUM) strcpy(st,"album"); + else if(table == MPD_TABLE_TITLE) strcpy(st,"title"); + else { + connection->error = 1; + strcpy(connection->errorStr,"unknown table for find"); + return; + } + string = malloc(strlen("find")+strlen(sanitStr)+strlen(st)+6); + sprintf(string,"find %s \"%s\"\n",st,sanitStr); + mpd_sendInfoCommand(connection,string); + free(string); + free(sanitStr); +} + +void mpd_sendListCommand(mpd_Connection * connection, int table, + const char * arg1) +{ + char st[10]; + char * string; + if(table == MPD_TABLE_ARTIST) strcpy(st,"artist"); + else if(table == MPD_TABLE_ALBUM) strcpy(st,"album"); + else { + connection->error = 1; + strcpy(connection->errorStr,"unknown table for list"); + return; + } + if(arg1) { + char * sanitArg1 = mpd_sanitizeArg(arg1); + string = malloc(strlen("list")+strlen(sanitArg1)+strlen(st)+6); + sprintf(string,"list %s \"%s\"\n",st,sanitArg1); + free(sanitArg1); + } + else { + string = malloc(strlen("list")+strlen(st)+3); + sprintf(string,"list %s\n",st); + } + mpd_sendInfoCommand(connection,string); + free(string); +} + +void mpd_sendAddCommand(mpd_Connection * connection, const char * file) { + char * sFile = mpd_sanitizeArg(file); + char * string = malloc(strlen("add")+strlen(sFile)+5); + sprintf(string,"add \"%s\"\n",sFile); + mpd_executeCommand(connection,string); + free(string); + free(sFile); +} + +void mpd_sendDeleteCommand(mpd_Connection * connection, int songNum) { + char * string = malloc(strlen("delete")+25); + sprintf(string,"delete \"%i\"\n",songNum); + mpd_sendInfoCommand(connection,string); + free(string); +} + +void mpd_sendSaveCommand(mpd_Connection * connection, const char * name) { + char * sName = mpd_sanitizeArg(name); + char * string = malloc(strlen("save")+strlen(sName)+5); + sprintf(string,"save \"%s\"\n",sName); + mpd_executeCommand(connection,string); + free(string); + free(sName); +} + +void mpd_sendLoadCommand(mpd_Connection * connection, const char * name) { + char * sName = mpd_sanitizeArg(name); + char * string = malloc(strlen("load")+strlen(sName)+5); + sprintf(string,"load \"%s\"\n",sName); + mpd_executeCommand(connection,string); + free(string); + free(sName); +} + +void mpd_sendRmCommand(mpd_Connection * connection, const char * name) { + char * sName = mpd_sanitizeArg(name); + char * string = malloc(strlen("rm")+strlen(sName)+5); + sprintf(string,"rm \"%s\"\n",sName); + mpd_executeCommand(connection,string); + free(string); + free(sName); +} + +void mpd_sendShuffleCommand(mpd_Connection * connection) { + mpd_executeCommand(connection,"shuffle\n"); +} + +void mpd_sendClearCommand(mpd_Connection * connection) { + mpd_executeCommand(connection,"clear\n"); +} + +void mpd_sendPlayCommand(mpd_Connection * connection, int songNum) { + char * string = malloc(strlen("play")+25); + sprintf(string,"play \"%i\"\n",songNum); + mpd_sendInfoCommand(connection,string); + free(string); +} + +void mpd_sendStopCommand(mpd_Connection * connection) { + mpd_executeCommand(connection,"stop\n"); +} + +void mpd_sendPauseCommand(mpd_Connection * connection) { + mpd_executeCommand(connection,"pause\n"); +} + +void mpd_sendNextCommand(mpd_Connection * connection) { + mpd_executeCommand(connection,"next\n"); +} + +void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to) { + char * string = malloc(strlen("move")+25); + sprintf(string,"move \"%i\" \"%i\"\n",from,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); + 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); + mpd_sendInfoCommand(connection,string); + free(string); +} + +void mpd_sendUpdateCommand(mpd_Connection * connection) { + mpd_executeCommand(connection,"update\n"); +} + +int mpd_getUpdateId(mpd_Connection * connection) { + char * jobid; + int ret = 0; + + jobid = mpd_getNextReturnElementNamed(connection,"updating_db"); + if(jobid) { + ret = atoi(jobid); + free(jobid); + } + + return ret; +} + +void mpd_sendPrevCommand(mpd_Connection * connection) { + mpd_executeCommand(connection,"previous\n"); +} + +void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode) { + char * string = malloc(strlen("repeat")+25); + sprintf(string,"repeat \"%i\"\n",repeatMode); + mpd_executeCommand(connection,string); + free(string); +} + +void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode) { + char * string = malloc(strlen("random")+25); + sprintf(string,"random \"%i\"\n",randomMode); + mpd_executeCommand(connection,string); + free(string); +} + +void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange) { + char * string = malloc(strlen("setvol")+25); + sprintf(string,"setvol \"%i\"\n",volumeChange); + mpd_executeCommand(connection,string); + free(string); +} + +void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange) { + char * string = malloc(strlen("volume")+25); + sprintf(string,"volume \"%i\"\n",volumeChange); + mpd_executeCommand(connection,string); + free(string); +} + +void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds) { + char * string = malloc(strlen("crossfade")+25); + sprintf(string,"crossfade \"%i\"\n",seconds); + mpd_executeCommand(connection,string); + free(string); +} + +void mpd_sendPasswordCommand(mpd_Connection * connection, const char * pass) { + char * sPass = mpd_sanitizeArg(pass); + char * string = malloc(strlen("password")+strlen(sPass)+5); + sprintf(string,"password \"%s\"\n",sPass); + mpd_executeCommand(connection,string); + free(string); + free(sPass); +} + +void mpd_sendCommandListBegin(mpd_Connection * connection) { + if(connection->commandList) { + strcpy(connection->errorStr,"already in command list mode"); + connection->error = 1; + return; + } + connection->commandList = 1; + mpd_executeCommand(connection,"command_list_begin\n"); +} + +void mpd_sendCommandListEnd(mpd_Connection * connection) { + if(!connection->commandList) { + strcpy(connection->errorStr,"not in command list mode"); + connection->error = 1; + return; + } + connection->commandList = 0; + mpd_executeCommand(connection,"command_list_end\n"); +} diff --git a/src/libmpdclient.h b/src/libmpdclient.h new file mode 100644 index 0000000..e5e5879 --- /dev/null +++ b/src/libmpdclient.h @@ -0,0 +1,399 @@ +/* libmpdclient + * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) + * This project's homepage is: http://www.musicpd.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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 + */ + +#ifndef LIBMPDCLIENT_H +#define LIBMPDCLIENT_H + +#include + +#define MPD_BUFFER_MAX_LENGTH 50000 +#define MPD_WELCOME_MESSAGE "OK MPD " + +#define MPD_ERROR_TIMEOUT 10 /* timeout trying to talk to mpd */ +#define MPD_ERROR_SYSTEM 11 /* system error */ +#define MPD_ERROR_UNKHOST 12 /* unknown host */ +#define MPD_ERROR_CONNPORT 13 /* problems connecting to port on host */ +#define MPD_ERROR_NOTMPD 14 /* mpd not running on port at host */ +#define MPD_ERROR_NORESPONSE 15 /* no response on attempting to connect */ +#define MPD_ERROR_SENDING 16 /* error sending command */ +#define MPD_ERROR_CONNCLOSED 17 /* connection closed by mpd */ +#define MPD_ERROR_ACK 18 /* ACK returned! */ +#define MPD_ERROR_BUFFEROVERRUN 19 /* Buffer was overrun! */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* internal stuff don't touch this struct */ +typedef struct _mpd_ReturnElement { + char * name; + char * value; +} mpd_ReturnElement; + +/* mpd_Connection + * holds info about connection to mpd + * use error, and errorStr to detect errors + */ +typedef struct _mpd_Connection { + /* use this to check the version of mpd */ + int version[3]; + /* IMPORTANT, you want to get the error messages from here */ + char errorStr[MPD_BUFFER_MAX_LENGTH+1]; + /* this will be set to 1 if there is an error, 0 if not */ + int error; + /* DON'T TOUCH any of the rest of this stuff */ + int sock; + char buffer[MPD_BUFFER_MAX_LENGTH+1]; + int buflen; + int bufstart; + int doneProcessing; + int commandList; + mpd_ReturnElement * returnElement; + struct timeval timeout; +} mpd_Connection; + +/* mpd_newConnection + * use this to open a new connection + * you should use mpd_closeConnection, when your done with the connection, + * even if an error has occurred + * _timeout_ is the connection timeout period in seconds + */ +mpd_Connection * mpd_newConnection(const char * host, int port, float timeout); + +void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout); + +/* mpd_closeConnection + * use this to close a connection and free'ing subsequent memory + */ +void mpd_closeConnection(mpd_Connection * connection); + +/* mpd_clearError + * clears error + */ +void mpd_clearError(mpd_Connection * connection); + +/* STATUS STUFF */ + +/* use these with status.state to determine what state the player is in */ +#define MPD_STATUS_STATE_UNKNOWN 0 +#define MPD_STATUS_STATE_STOP 1 +#define MPD_STATUS_STATE_PLAY 2 +#define MPD_STATUS_STATE_PAUSE 3 + +/* us this with status.volume to determine if mpd has volume support */ +#define MPD_STATUS_NO_VOLUME -1 + +/* mpd_Status + * holds info return from status command + */ +typedef struct mpd_Status { + /* 0-100, or MPD_STATUS_NO_VOLUME when there is no volume support */ + int volume; + /* 1 if repeat is on, 0 otherwise */ + int repeat; + /* 1 if random is on, 0 otherwise */ + int random; + /* playlist length */ + int playlistLength; + /* playlist, use this to determine when the playlist has changed */ + long long playlist; + /* use with MPD_STATUS_STATE_* to determine state of player */ + int state; + /* crossfade setting in seconds */ + int crossfade; + /* if in PLAY or PAUSE state, this is the number of the currently + * playing song in the playlist, beginning with 0 + */ + int song; + /* time in seconds that have elapsed in the currently playing/paused + * song + */ + int elapsedTime; + /* length in seconds of the currently playing/paused song */ + int totalTime; + /* current bit rate in kbs */ + int bitRate; + /* audio sample rate */ + unsigned int sampleRate; + /* audio bits */ + int bits; + /* audio channels */ + int channels; + /* 1 if mpd is updating, 0 otherwise */ + int updatingDb; + /* error */ + char * error; +} mpd_Status; + +/* mpd_getStatus + * returns status info, be sure to free it with mpd_freeStatus() + */ +mpd_Status * mpd_getStatus(mpd_Connection * connection); + +/* mpd_freeStatus + * free's status info malloc'd and returned by mpd_getStatus + */ +void mpd_freeStatus(mpd_Status * status); + +typedef struct _mpd_Stats { + int numberOfArtists; + int numberOfAlbums; + int numberOfSongs; + unsigned long uptime; + unsigned long dbUpdateTime; + unsigned long playTime; + unsigned long dbPlayTime; +} mpd_Stats; + +mpd_Stats * mpd_getStats(mpd_Connection * connection); + +void mpd_freeStats(mpd_Stats * stats); + +/* SONG STUFF */ + +#define MPD_SONG_NO_TIME -1 + +/* mpd_Song + * for storing song info returned by mpd + */ +typedef struct _mpd_Song { + /* filename of song */ + char * file; + /* artist, maybe NULL if there is no tag */ + char * artist; + /* title, maybe NULL if there is no tag */ + char * title; + /* album, maybe NULL if there is no tag */ + char * album; + /* track, maybe NULL if there is no tag */ + char * track; + /* length of song in seconds, check that it is not MPD_SONG_NO_TIME */ + int time; +} mpd_Song; + +/* mpd_newSong + * use to allocate memory for a new mpd_Song + * file, artist, etc all initialized to NULL + * if your going to assign values to file, artist, etc + * be sure to malloc or strdup the memory + * use mpd_freeSong to free the memory for the mpd_Song, it will also + * free memory for file, artist, etc, so don't do it yourself + */ +mpd_Song * mpd_newSong(); + +/* mpd_freeSong + * use to free memory allocated by mpd_newSong + * also it will free memory pointed to by file, artist, etc, so be careful + */ +void mpd_freeSong(mpd_Song * song); + +/* mpd_songDup + * works like strDup, but for a mpd_Song + */ +mpd_Song * mpd_songDup(mpd_Song * song); + +/* DIRECTORY STUFF */ + +/* mpd_Directory + * used to store info fro directory (right now that just the path) + */ +typedef struct _mpd_Directory { + char * path; +} mpd_Directory; + +/* mpd_newDirectory + * allocates memory for a new directory + * use mpd_freeDirectory to free this memory + */ +mpd_Directory * mpd_newDirectory (); + +/* mpd_freeDirectory + * used to free memory allocated with mpd_newDirectory, and it frees + * path of mpd_Directory, so be careful + */ +void mpd_freeDirectory(mpd_Directory * directory); + +/* mpd_directoryDup + * works like strdup, but for mpd_Directory + */ +mpd_Directory * mpd_directoryDup(mpd_Directory * directory); + +/* PLAYLISTFILE STUFF */ + +/* mpd_PlaylistFile + * stores info about playlist file returned by lsinfo + */ +typedef struct _mpd_PlaylistFile { + char * path; +} mpd_PlaylistFile; + +/* mpd_newPlaylistFile + * allocates memory for new mpd_PlaylistFile, path is set to NULL + * free this memory with mpd_freePlaylistFile + */ +mpd_PlaylistFile * mpd_newPlaylistFile(); + +/* mpd_freePlaylist + * free memory allocated for freePlaylistFile, will also free + * path, so be careful + */ +void mpd_freePlaylistFile(mpd_PlaylistFile * playlist); + +/* mpd_playlistFileDup + * works like strdup, but for mpd_PlaylistFile + */ +mpd_PlaylistFile * mpd_playlistFileDup(mpd_PlaylistFile * playlist); + +/* INFO ENTITY STUFF */ + +/* the type of entity returned from one of the commands that generates info + * use in conjunction with mpd_InfoEntity.type + */ +#define MPD_INFO_ENTITY_TYPE_DIRECTORY 0 +#define MPD_INFO_ENTITY_TYPE_SONG 1 +#define MPD_INFO_ENTITY_TYPE_PLAYLISTFILE 2 + +/* mpd_InfoEntity + * stores info on stuff returned info commands + */ +typedef struct mpd_InfoEntity { + /* the type of entity, use with MPD_INFO_ENTITY_TYPE_* to determine + * what this entity is (song, directory, etc...) + */ + int type; + /* the actual data you want, mpd_Song, mpd_Directory, etc */ + union { + mpd_Directory * directory; + mpd_Song * song; + mpd_PlaylistFile * playlistFile; + } info; +} mpd_InfoEntity; + +mpd_InfoEntity * mpd_newInfoEntity(); + +void mpd_freeInfoEntity(mpd_InfoEntity * entity); + +/* INFO COMMANDS AND STUFF */ + +/* use this function to loop over after calling Info/Listall functions */ +mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection); + +/* songNum of -1, means to display the whole list */ +void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songNum); + +void mpd_sendListallCommand(mpd_Connection * connection, const char * dir); + +void mpd_sendListallInfoCommand(mpd_Connection * connection, const char * dir); + +void mpd_sendLsInfoCommand(mpd_Connection * connection, const char * dir); + +#define MPD_TABLE_ARTIST 0 +#define MPD_TABLE_ALBUM 1 +#define MPD_TABLE_TITLE 2 +#define MPD_TABLE_FILENAME 3 + +void mpd_sendSearchCommand(mpd_Connection * connection, int table, + const char * str); + +void mpd_sendFindCommand(mpd_Connection * connection, int table, + const char * str); + +/* LIST TAG COMMANDS */ + +/* use this function fetch next artist entry, be sure to free the returned + * string. NULL means there are no more. Best used with sendListArtists + */ +char * mpd_getNextArtist(mpd_Connection * connection); + +char * mpd_getNextAlbum(mpd_Connection * connection); + +/* list artist or albums by artist, arg1 should be set to the artist if + * listing albums by a artist, otherwise NULL for listing all artists or albums + */ +void mpd_sendListCommand(mpd_Connection * connection, int table, + const char * arg1); + +/* SIMPLE COMMANDS */ + +void mpd_sendAddCommand(mpd_Connection * connection, const char * file); + +void mpd_sendDeleteCommand(mpd_Connection * connection, int songNum); + +void mpd_sendSaveCommand(mpd_Connection * connection, const char * name); + +void mpd_sendLoadCommand(mpd_Connection * connection, const char * name); + +void mpd_sendRmCommand(mpd_Connection * connection, const char * name); + +void mpd_sendShuffleCommand(mpd_Connection * connection); + +void mpd_sendClearCommand(mpd_Connection * connection); + +/* use this to start playing at the beginning, useful when in random mode */ +#define MPD_PLAY_AT_BEGINNING -1 + +void mpd_sendPlayCommand(mpd_Connection * connection, int songNum); + +void mpd_sendStopCommand(mpd_Connection * connection); + +void mpd_sendPauseCommand(mpd_Connection * connection); + +void mpd_sendNextCommand(mpd_Connection * connection); + +void mpd_sendPrevCommand(mpd_Connection * connection); + +void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to); + +void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2); + +void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time); + +void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode); + +void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode); + +void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange); + +/* WARNING: don't use volume command, its depreacted */ +void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange); + +void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds); + +void mpd_sendUpdateCommand(mpd_Connection * connection); + +/* returns the update job id, call this after a update command*/ +int mpd_getUpdateId(mpd_Connection * connection); + +void mpd_sendPasswordCommand(mpd_Connection * connection, const char * pass); + +/* after executing a command, when your done with it to get its status + * (you want to check connection->error for an error) + */ +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_sendCommandListEnd(mpd_Connection * connection); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/list_window.c b/src/list_window.c new file mode 100644 index 0000000..6b4a41f --- /dev/null +++ b/src/list_window.c @@ -0,0 +1,296 @@ +/* + * (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 +#include +#include +#include +#include + +#include "config.h" +#include "options.h" +#include "support.h" +#include "command.h" +#include "colors.h" +#include "list_window.h" + +list_window_t * +list_window_init(WINDOW *w, int width, int height) +{ + list_window_t *lw; + + lw = g_malloc(sizeof(list_window_t)); + memset(lw, 0, sizeof(list_window_t)); + lw->w = w; + lw->cols = width; + lw->rows = height; + lw->clear = 1; + return lw; +} + +list_window_t * +list_window_free(list_window_t *lw) +{ + if( lw ) + { + memset(lw, 0, sizeof(list_window_t)); + g_free(lw); + } + return NULL; +} + +void +list_window_reset(list_window_t *lw) +{ + lw->selected = 0; + lw->start = 0; + lw->clear = 1; +} + +void +list_window_check_selected(list_window_t *lw, int length) +{ + while( lw->start && lw->start+lw->rows>length) + lw->start--; + + if( lw->selected<0 ) + lw->selected=0; + + while( lw->selectedstart ) + lw->selected++; + + while( lw->selected>0 && length>0 && lw->selected>=length ) + lw->selected--; +} + +void +list_window_set_selected(list_window_t *lw, int n) +{ + lw->selected=n; +} + +void +list_window_next(list_window_t *lw, int length) +{ + if( lw->selected < length-1 ) + lw->selected++; +} + +void +list_window_previous(list_window_t *lw) +{ + if( lw->selected > 0 ) + lw->selected--; +} + +void +list_window_first(list_window_t *lw) +{ + lw->selected = 0; +} + +void +list_window_last(list_window_t *lw, int length) +{ + lw->selected = length-1; +} + +void +list_window_next_page(list_window_t *lw, int length) +{ + int step = lw->rows-1; + if( step<= 0 ) + return; + if( lw->selected+step < length-1 ) + lw->selected+=step; + else + return list_window_last(lw,length); +} + +void +list_window_previous_page(list_window_t *lw) +{ + int step = lw->rows-1; + if( step<= 0 ) + return; + if( lw->selected-step > 0 ) + lw->selected-=step; + else + list_window_first(lw); +} + + +void +list_window_paint(list_window_t *lw, + list_window_callback_fn_t callback, + void *callback_data) +{ + int i; + int fill = options.wide_cursor; + + while( lw->selected < lw->start ) + { + lw->start--; + lw->clear=1; + } + while( lw->selected >= lw->start+lw->rows ) + { + lw->start++; + lw->clear=1; + } + + for(i=0; irows; i++) + { + int highlight = 0; + char *label; + + label = (callback) (lw->start+i, &highlight, callback_data); + wmove(lw->w, i, 0); + if( lw->clear && (!fill || !label) ) + wclrtoeol(lw->w); + if( label ) + { + int selected = lw->start+i == lw->selected; + + if( highlight ) + colors_use(lw->w, COLOR_LIST_BOLD); + else + colors_use(lw->w, COLOR_LIST); + + if( selected ) + wattron(lw->w, A_REVERSE); + + waddnstr(lw->w, label, lw->cols-1); + if( fill ) + mvwhline(lw->w, i, strlen(label), ' ', lw->cols-1); + + if( selected ) + wattroff(lw->w, A_REVERSE); + } + + } + lw->clear=0; +} + + +int +list_window_find(list_window_t *lw, + list_window_callback_fn_t callback, + void *callback_data, + char *str, + int wrap) +{ + int h; + int i = lw->selected+1; + char *label; + + while( wrap || i==lw->selected+1 ) + { + while( (label=(callback) (i,&h,callback_data)) ) + { + if( str && label && strcasestr(label, str) ) + { + lw->selected = i; + return 0; + } + if( wrap && i==lw->selected ) + return 1; + i++; + } + if( wrap ) + { + i=0; /* first item */ + beep(); + } + } + return 1; +} + + +int +list_window_rfind(list_window_t *lw, + list_window_callback_fn_t callback, + void *callback_data, + char *str, + int wrap, + int rows) +{ + int h; + int i = lw->selected-1; + char *label; + + while( wrap || i==lw->selected-1 ) + { + while( i>=0 && (label=(callback) (i,&h,callback_data)) ) + { + if( str && label && strcasestr(label, str) ) + { + lw->selected = i; + return 0; + } + if( wrap && i==lw->selected ) + return 1; + i--; + } + if( wrap ) + { + i=rows-1; /* last item */ + beep(); + } + } + return 1; +} + + +/* perform basic list window commands (movement) */ +int +list_window_cmd(list_window_t *lw, int rows, command_t cmd) +{ + switch(cmd) + { + case CMD_LIST_PREVIOUS: + list_window_previous(lw); + lw->repaint=1; + break; + case CMD_LIST_NEXT: + list_window_next(lw, rows); + lw->repaint=1; + break; + case CMD_LIST_FIRST: + list_window_first(lw); + lw->repaint = 1; + break; + case CMD_LIST_LAST: + list_window_last(lw, rows); + lw->repaint = 1; + break; + case CMD_LIST_NEXT_PAGE: + list_window_next_page(lw, rows); + lw->repaint = 1; + break; + case CMD_LIST_PREVIOUS_PAGE: + list_window_previous_page(lw); + lw->repaint = 1; + break; + default: + return 0; + } + return 1; +} + + diff --git a/src/list_window.h b/src/list_window.h new file mode 100644 index 0000000..9e91703 --- /dev/null +++ b/src/list_window.h @@ -0,0 +1,67 @@ +#ifndef LIST_WINDOW_H +#define LIST_WINDOW_H + +#define LW_ROW(lw) (lw ? lw->selected-lw->start : 0) + +typedef char * (*list_window_callback_fn_t) (int index, + int *highlight, + void *data); + +typedef struct +{ + WINDOW *w; + int rows, cols; + + int start; + int selected; + int clear; + int repaint; + +} list_window_t; + + +/* create a new list window */ +list_window_t *list_window_init(WINDOW *w, int width, int height); + +/* destroy a list window (returns NULL) */ +list_window_t *list_window_free(list_window_t *lw); + +/* reset a list window (selected=0, start=0, clear=1) */ +void list_window_reset(list_window_t *lw); + +/* paint a list window */ +void list_window_paint(list_window_t *lw, + list_window_callback_fn_t callback, + void *callback_data); + +/* perform basic list window commands (movement) */ +int list_window_cmd(list_window_t *lw, int rows, command_t cmd); + + +/* select functions */ +void list_window_set_selected(list_window_t *lw, int n); +void list_window_previous(list_window_t *lw); +void list_window_next(list_window_t *lw, int length); +void list_window_first(list_window_t *lw); +void list_window_last(list_window_t *lw, int length); +void list_window_previous_page(list_window_t *lw); +void list_window_next_page(list_window_t *lw, int length); +void list_window_check_selected(list_window_t *lw, int length); + +/* find a string in a list window */ +int list_window_find(list_window_t *lw, + list_window_callback_fn_t callback, + void *callback_data, + char *str, + int wrap); + +/* find a string in a list window (reversed) */ +int +list_window_rfind(list_window_t *lw, + list_window_callback_fn_t callback, + void *callback_data, + char *str, + int wrap, + int rows); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..bb3740b --- /dev/null +++ b/src/main.c @@ -0,0 +1,199 @@ +/* + * (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 +#include +#include +#include +#include + +#include "config.h" +#include "libmpdclient.h" +#include "support.h" +#include "mpc.h" +#include "options.h" +#include "command.h" +#include "screen.h" +#include "conf.h" + +/* time in seconds between mpd updates (double) */ +#define MPD_UPDATE_TIME 0.5 + +/* timout in seconds before trying to reconnect (int) */ +#define MPD_RECONNECT_TIMEOUT 3 + + +static mpd_client_t *mpc = NULL; +static GTimer *timer = NULL; + +void +exit_and_cleanup(void) +{ + screen_exit(); + printf("\n"); + charset_close(); + if( mpc ) + { + if( mpc_error(mpc) ) + fprintf(stderr,"Error: %s\n", mpc_error_str(mpc)); + mpc_close(mpc); + } + g_free(options.host); + g_free(options.password); + if( timer ) + g_timer_destroy(timer); +} + +void +catch_sigint( int sig ) +{ + printf( "\nExiting...\n"); + exit(EXIT_SUCCESS); +} + +int +main(int argc, const char *argv[]) +{ + options_t *options; + struct sigaction act; + gboolean connected; + + /* initialize options */ + options = options_init(); + + /* parse command line options - 1 pass get configuration files */ + options_parse(argc, argv); + + /* read configuration */ + read_configuration(options); + + /* check key bindings */ + if( check_key_bindings() ) + { + fprintf(stderr, "Confusing key bindings - exiting!\n"); + exit(EXIT_FAILURE); + } + + /* parse command line options - 2 pass */ + options_parse(argc, argv); + + /* initialize local charset */ + if( charset_init() ) + exit(EXIT_FAILURE); + + /* setup signal behavior - SIGINT */ + sigemptyset( &act.sa_mask ); + act.sa_flags = 0; + act.sa_handler = catch_sigint; + if( sigaction( SIGINT, &act, NULL )<0 ) + { + perror("signal"); + exit(EXIT_FAILURE); + } + /* setup signal behavior - SIGTERM */ + sigemptyset( &act.sa_mask ); + act.sa_flags = 0; + act.sa_handler = catch_sigint; + if( sigaction( SIGTERM, &act, NULL )<0 ) + { + perror("sigaction()"); + exit(EXIT_FAILURE); + } + + /* set xterm title */ + if( g_getenv("DISPLAY") ) + printf("%c]0;%s%c", '\033', PACKAGE " version " VERSION, '\007'); + + /* install exit function */ + 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); + + /* initialize curses */ + screen_init(); + + /* initialize timer */ + timer = g_timer_new(); + + connected = TRUE; + while( connected || options->reconnect ) + { + static gdouble t = G_MAXDOUBLE; + + if( connected && t>=MPD_UPDATE_TIME ) + { + 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); + g_timer_start(timer); + } + + if( connected ) + { + command_t cmd; + + screen_update(mpc); + if( (cmd=get_keyboard_command()) != CMD_NONE ) + { + screen_cmd(mpc, 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); + } + else if( options->reconnect ) + { + sleep(MPD_RECONNECT_TIMEOUT); + screen_status_printf("Connecting to %s... [Press Ctrl-C to abort]", + options->host); + if( mpc_reconnect(mpc, + options->host, + options->port, + options->password) == 0 ) + { + screen_status_printf("Connected to %s!", options->host); + connected = TRUE; + } + doupdate(); + } + + t = g_timer_elapsed(timer, NULL); + } + + exit(EXIT_FAILURE); +} diff --git a/src/mpc.c b/src/mpc.c new file mode 100644 index 0000000..0a80af4 --- /dev/null +++ b/src/mpc.c @@ -0,0 +1,359 @@ +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "support.h" +#include "libmpdclient.h" +#include "mpc.h" +#include "options.h" + +#define MAX_SONG_LENGTH 1024 + +#ifdef DEBUG +#define D(x) x +#else +#define D(x) +#endif + +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, 10); + 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_update_playlist(mpd_client_t *c) +{ + mpd_InfoEntity *entity; + + D(fprintf(stderr, "mpc_update_playlist() [%d]\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); + } + 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_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; +} + +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 ) + 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_sendListallCommand(conn,""); + 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 new file mode 100644 index 0000000..a09aeee --- /dev/null +++ b/src/mpc.h @@ -0,0 +1,50 @@ + +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); +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/options.c b/src/options.c new file mode 100644 index 0000000..416727a --- /dev/null +++ b/src/options.c @@ -0,0 +1,185 @@ +/* + * (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 +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "options.h" +#include "command.h" +#include "support.h" + +options_t options; + +static char *mpd_host = NULL; +static char *mpd_password = NULL; +static char *config_file = NULL; +static char *key_file = NULL; + +static struct poptOption optionsTable[] = { +#ifdef DEBUG + { "debug", 'D', 0, 0, 'D', "Enable debug output." }, +#endif + { "version", 'V', 0, 0, 'V', "Display version information." }, + { "colors", 'c', 0, 0, 'c', "Enable colors." }, + { "no-colors", 'C', 0, 0, 'C', "Disable colors." }, + { "exit", 'e', 0, 0, 'e', "Exit on connection errors." }, + { "port", 'p', POPT_ARG_INT, &options.port, 0, + "Connect to server on port [" DEFAULT_PORT_STR "].", "PORT" }, + { "host", 'h', POPT_ARG_STRING, &mpd_host, 0, + "Connect to server [" DEFAULT_HOST "].", "HOSTNAME" }, + { "password", 'P', POPT_ARG_STRING, &mpd_password, 0, + "Connect with password.", "PASSWORD" }, + { "config", 'f', POPT_ARG_STRING, &config_file, 0, + "Read config from FILE." , "FILE" }, + { "key-file", 'k', POPT_ARG_STRING, &key_file, 0, + "Read key bindings from FILE." , "FILE" }, + + POPT_AUTOHELP + { NULL, 0, 0, NULL, 0 } +}; + +static void +usage(poptContext optCon, int exitcode, char *error, char *addl) +{ + poptPrintUsage(optCon, stderr, 0); + if (error) + fprintf(stderr, "%s: %s0", error, addl); + exit(exitcode); +} + +options_t * +options_parse( int argc, const char **argv) +{ + int c; + poptContext optCon; /* context for parsing command-line options */ + + mpd_host = NULL; + mpd_password = NULL; + config_file = NULL; + key_file = NULL; + optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); + while ((c = poptGetNextOpt(optCon)) >= 0) + { + switch (c) + { +#ifdef DEBUG + case 'D': + options.debug = 1; + break; +#endif + case 'c': + options.enable_colors = 1; + break; + case 'C': + options.enable_colors = 0; + break; + case 'V': + printf("Version " VERSION "\n"); + exit(EXIT_SUCCESS); + case 'e': + options.reconnect = 0; + break; + default: + fprintf(stderr, "%s: %s\n", + poptBadOption(optCon, POPT_BADOPTION_NOALIAS), + poptStrerror(c)); + poptFreeContext(optCon); + exit(EXIT_FAILURE); + break; + } + } + if (c < -1) + { + /* an error occurred during option processing */ + fprintf(stderr, "%s: %s\n", + poptBadOption(optCon, POPT_BADOPTION_NOALIAS), + poptStrerror(c)); + poptFreeContext(optCon); + exit(EXIT_FAILURE); + } + + if( mpd_host ) + { + g_free(options.host); + options.host = mpd_host; + } + if( mpd_password ) + { + g_free(options.password); + options.password = mpd_password; + } + if( config_file ) + { + g_free(options.config_file); + options.config_file = config_file; + } + if( key_file ) + { + g_free(options.key_file); + options.key_file = key_file; + } + + poptFreeContext(optCon); + return &options; +} + +options_t * +options_init( void ) +{ + const char *value; + char *tmp; + + memset(&options, 0, sizeof(options_t)); + + if( (value=g_getenv(MPD_HOST_ENV)) ) + options.host = g_strdup(value); + else + options.host = g_strdup(DEFAULT_HOST); + if( (tmp=g_strstr_len(options.host, strlen(options.host), "@")) ) + { + char *oldhost = options.host; + *tmp = '\0'; + options.password = locale_to_utf8(oldhost); + options.host = g_strdup(tmp+1); + g_free(oldhost); + } + + if( (value=g_getenv(MPD_PORT_ENV)) ) + options.port = atoi(value); + else + options.port = DEFAULT_PORT; + + options.reconnect = 1; + options.find_wrap = 1; + options.wide_cursor = 1; + + return &options; +} + + +options_t * +options_get(void) +{ + return &options; +} diff --git a/src/options.h b/src/options.h new file mode 100644 index 0000000..2a6681e --- /dev/null +++ b/src/options.h @@ -0,0 +1,28 @@ + +#define MPD_HOST_ENV "MPD_HOST" +#define MPD_PORT_ENV "MPD_PORT" + +typedef struct +{ + char *host; + char *username; + char *password; + char *config_file; + char *key_file; + int port; + int reconnect; + int debug; + int find_wrap; + int auto_center; + int wide_cursor; + int enable_colors; + +} options_t; + +extern options_t options; + +options_t *options_init(void); +options_t *options_parse(int argc, const char **argv); + + + diff --git a/src/screen.c b/src/screen.c new file mode 100644 index 0000000..d846f3d --- /dev/null +++ b/src/screen.c @@ -0,0 +1,869 @@ +/* + * (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 +#include +#include +#include +#include +//#include +#include +#include +#include + +#include "config.h" +#include "libmpdclient.h" +#include "mpc.h" +#include "command.h" +#include "options.h" +#include "colors.h" +#include "screen.h" +#include "screen_play.h" +#include "screen_file.h" +#include "screen_help.h" +#include "screen_search.h" +#include "screen_utils.h" + +#undef ENABLE_STATUS_LINE_CLOCK +#define ENABLE_SCROLLING + +#define DEFAULT_CROSSFADE_TIME 10 + +#define STATUS_MESSAGE_TIMEOUT 3 +#define STATUS_LINE_MAX_SIZE 512 + +#ifdef ENABLE_KEYDEF_SCREEN +extern screen_functions_t *get_screen_keydef(void); +#endif + +static screen_t *screen = NULL; +static screen_functions_t *mode_fn = NULL; + +static void +switch_screen_mode(screen_mode_t new_mode, mpd_client_t *c) +{ + if( new_mode == screen->mode ) + return; + + /* close the old mode */ + if( mode_fn && mode_fn->close ) + mode_fn->close(); + + /* get functions for the new mode */ + switch(new_mode) + { + case SCREEN_PLAY_WINDOW: + mode_fn = get_screen_playlist(); + break; + case SCREEN_FILE_WINDOW: + mode_fn = get_screen_file(); + break; + case SCREEN_HELP_WINDOW: + mode_fn = get_screen_help(); + break; +#ifdef ENABLE_KEYDEF_SCREEN + case SCREEN_KEYDEF_WINDOW: + mode_fn = get_screen_keydef(); + break; +#endif + default: + break; + } + + screen->mode = new_mode; + screen->painted = 0; + + /* open the new mode */ + if( mode_fn && mode_fn->open ) + mode_fn->open(screen, c); + +} + +static void +paint_top_window(char *header, mpd_client_t *c, int clear) +{ + char flags[4]; + static int prev_volume = -1; + static int prev_header_len = -1; + WINDOW *w = screen->top_window.w; + + if(prev_header_len!=strlen(header)) + { + prev_header_len = strlen(header); + clear = 1; + } + + if(clear) + { + wmove(w, 0, 0); + wclrtoeol(w); + } + + if(prev_volume!=c->status->volume || clear) + { + char buf[32]; + + if( header[0] ) + { + colors_use(w, COLOR_TITLE_BOLD); + mvwaddstr(w, 0, 0, header); + } + else + { + colors_use(w, COLOR_TITLE_BOLD); + waddstr(w, get_key_names(CMD_SCREEN_HELP, FALSE)); + colors_use(w, COLOR_TITLE); + waddstr(w, ":Help "); + colors_use(w, COLOR_TITLE_BOLD); + waddstr(w, get_key_names(CMD_SCREEN_PLAY, FALSE)); + colors_use(w, COLOR_TITLE); + waddstr(w, ":Playlist "); + colors_use(w, COLOR_TITLE_BOLD); + waddstr(w, get_key_names(CMD_SCREEN_FILE, FALSE)); + colors_use(w, COLOR_TITLE); + waddstr(w, ":Browse"); + } + if( c->status->volume==MPD_STATUS_NO_VOLUME ) + { + snprintf(buf, 32, "Volume n/a "); + } + else + { + snprintf(buf, 32, " Volume %d%%", c->status->volume); + } + colors_use(w, COLOR_TITLE); + mvwaddstr(w, 0, screen->top_window.cols-strlen(buf), buf); + + flags[0] = 0; + if( c->status->repeat ) + strcat(flags, "r"); + if( c->status->random ) + strcat(flags, "z"); + if( c->status->crossfade ) + strcat(flags, "x"); + if( c->status->updatingDb ) + strcat(flags, "U"); + colors_use(w, COLOR_LINE); + mvwhline(w, 1, 0, ACS_HLINE, screen->top_window.cols); + if( flags[0] ) + { + wmove(w,1,screen->top_window.cols-strlen(flags)-3); + waddch(w, '['); + colors_use(w, COLOR_LINE_BOLD); + waddstr(w, flags); + colors_use(w, COLOR_LINE); + waddch(w, ']'); + } + wnoutrefresh(w); + } +} + +static void +paint_progress_window(mpd_client_t *c) +{ + double p; + int width; + int elapsedTime = c->status->elapsedTime; + + if( c->status==NULL || IS_STOPPED(c->status->state) ) + { + mvwhline(screen->progress_window.w, 0, 0, ACS_HLINE, + screen->progress_window.cols); + wnoutrefresh(screen->progress_window.w); + return; + } + + if( c->seek_song_id == c->song_id ) + elapsedTime = c->seek_target_time; + + p = ((double) elapsedTime) / ((double) c->status->totalTime); + + width = (int) (p * (double) screen->progress_window.cols); + mvwhline(screen->progress_window.w, + 0, 0, + ACS_HLINE, + screen->progress_window.cols); + whline(screen->progress_window.w, '=', width-1); + mvwaddch(screen->progress_window.w, 0, width-1, 'O'); + wnoutrefresh(screen->progress_window.w); +} + +#ifdef ENABLE_SCROLLING +static char * +scroll_string(char *str, char *sep, int width) +{ + static int offset = 0; + static time_t t = 0; + char *tmp, *buf; + size_t len; + + if( offset==0 ) + { + offset++; + return g_strdup(str); + } + + /* create a buffer containing the string and the separator */ + tmp = g_malloc(strlen(str)+strlen(sep)+1); + strcpy(tmp, str); + strcat(tmp, sep); + len = strlen(tmp); + + if( offset >= len ) + offset = 0; + + /* create the new scrolled string */ + buf = g_malloc(width+1); + strncpy(buf, tmp+offset, width); + if( strlen(buf) < width ) + strncat(buf, tmp, width-strlen(buf)); + + if( time(NULL)-t >= 1 ) + { + t = time(NULL); + offset++; + } + g_free(tmp); + return buf; +} +#endif + +static void +paint_status_window(mpd_client_t *c) +{ + WINDOW *w = screen->status_window.w; + mpd_Status *status = c->status; + mpd_Song *song = c->song; + int elapsedTime = c->status->elapsedTime; + int x = 0; + + if( time(NULL) - screen->status_timestamp <= STATUS_MESSAGE_TIMEOUT ) + return; + + + wmove(w, 0, 0); + wclrtoeol(w); + colors_use(w, COLOR_STATUS_BOLD); + + switch(status->state) + { + case MPD_STATUS_STATE_STOP: + waddstr(w, "Stopped! "); + break; + case MPD_STATUS_STATE_PLAY: + waddstr(w, "Playing:"); + break; + case MPD_STATUS_STATE_PAUSE: + waddstr(w, "[Paused]"); + break; + default: + break; + } + x += 9; + + /* create time string */ + memset(screen->buf, 0, screen->buf_size); + if( IS_PLAYING(status->state) || IS_PAUSED(status->state) ) + { + if( status->totalTime > 0 ) + { + if( c->seek_song_id == c->song_id ) + elapsedTime = c->seek_target_time; + snprintf(screen->buf, screen->buf_size, + " [%i:%02i/%i:%02i]", + elapsedTime/60, elapsedTime%60, + status->totalTime/60, status->totalTime%60 ); + } + else + { + snprintf(screen->buf, screen->buf_size, " [%d kbps]", status->bitRate ); + } + } + else + { + time_t timep; + + time(&timep); + /* Note: setlocale(LC_TIME,"") should be used first */ + //strftime(screen->buf, screen->buf_size, "%X ", localtime(&timep)); + strftime(screen->buf, screen->buf_size, " %k:%M", localtime(&timep)); + } + + /* display song */ + if( (IS_PLAYING(status->state) || IS_PAUSED(status->state)) && song ) + { + char *songname = mpc_get_song_name(song); + int width = COLS-x-strlen(screen->buf); + + colors_use(w, COLOR_STATUS); +#ifdef ENABLE_SCROLLING + if( strlen(songname) > width ) + { + char *tmp = scroll_string(songname, " *** ", width); + strcpy(songname, tmp); + g_free(tmp); + } +#endif + mvwaddnstr(w, 0, x, songname, width); + } + + /* distplay time string */ + if( screen->buf[0] ) + { + x = screen->status_window.cols - strlen(screen->buf); + colors_use(w, COLOR_STATUS_TIME); + mvwaddstr(w, 0, x, screen->buf); + } + +#ifdef ENABLE_STATUS_LINE_CLOCK + else if( c->status->state == MPD_STATUS_STATE_STOP ) + { + time_t timep; + + /* Note: setlocale(LC_TIME,"") should be used first */ + time(&timep); + strftime(screen->buf, screen->buf_size, "%X ", localtime(&timep)); + x = screen->status_window.cols - strlen(screen->buf) ; + colors_use(w, COLOR_STATUS_TIME); + mvwaddstr(w, 0, x, screen->buf); + } +#endif + + wnoutrefresh(w); +} + + + +int +screen_exit(void) +{ + endwin(); + if( screen ) + { + GList *list = g_list_first(screen->screen_list); + + /* close and exit all screens (playlist,browse,help...) */ + while( list ) + { + screen_functions_t *mode_fn = list->data; + + if( mode_fn && mode_fn->close ) + mode_fn->close(); + if( mode_fn && mode_fn->exit ) + mode_fn->exit(); + list->data = NULL; + list=list->next; + } + g_list_free(screen->screen_list); + + g_free(screen->buf); + g_free(screen->findbuf); + g_free(screen); + screen = NULL; + } + return 0; +} + +void +screen_resize(void) +{ + GList *list; + +#ifdef DEBUG + fprintf(stderr, "Resize rows %d->%d, cols %d->%d\n", + screen->rows, LINES, + screen->cols, COLS); +#endif + + if( COLScols = COLS; + screen->rows = LINES; + + /* top window */ + screen->top_window.cols = screen->cols; + wresize(screen->top_window.w, 2, screen->cols); + + /* main window */ + screen->main_window.cols = screen->cols; + screen->main_window.rows = screen->rows-4; + wresize(screen->main_window.w, screen->main_window.rows, screen->cols); + wclear(screen->main_window.w); + + /* progress window */ + screen->progress_window.cols = screen->cols; + wresize(screen->progress_window.w, 1, screen->cols); + mvwin(screen->progress_window.w, screen->rows-2, 0); + + /* status window */ + screen->status_window.cols = screen->cols; + wresize(screen->status_window.w, 1, screen->cols); + mvwin(screen->status_window.w, screen->rows-1, 0); + + screen->buf_size = screen->cols; + g_free(screen->buf); + screen->buf = g_malloc(screen->cols); + + list = g_list_first(screen->screen_list); + while( list ) + { + screen_functions_t *mode_fn = list->data; + + if( mode_fn && mode_fn->resize ) + mode_fn->resize(screen->main_window.cols, screen->main_window.rows); + + list=list->next; + } + + /* ? - without this the cursor becomes visible with aterm & Eterm */ + curs_set(1); + curs_set(0); + + screen->painted = 0; +} + +void +screen_status_message(char *msg) +{ + WINDOW *w = screen->status_window.w; + + wmove(w, 0, 0); + wclrtoeol(w); + colors_use(w, COLOR_STATUS_ALERT); + waddstr(w, msg); + wnoutrefresh(w); + screen->status_timestamp = time(NULL); +} + +void +screen_status_printf(char *format, ...) +{ + char buffer[STATUS_LINE_MAX_SIZE]; + va_list ap; + + va_start(ap,format); + vsnprintf(buffer,sizeof(buffer),format,ap); + va_end(ap); + screen_status_message(buffer); +} + +int +screen_init(void) +{ + GList *list; + + /* initialize the curses library */ + initscr(); + /* initialize color support */ + colors_start(); + /* tell curses not to do NL->CR/NL on output */ + nonl(); + /* take input chars one at a time, no wait for \n */ + cbreak(); + /* don't echo input */ + noecho(); + /* set cursor invisible */ + curs_set(0); + /* return from getch() without blocking */ + // nodelay(stdscr, TRUE); + keypad(stdscr, TRUE); + timeout(SCREEN_TIMEOUT); + + if( COLSmode = SCREEN_PLAY_WINDOW; + screen->cols = COLS; + screen->rows = LINES; + screen->buf = g_malloc(screen->cols); + screen->buf_size = screen->cols; + screen->findbuf = NULL; + screen->painted = 0; + screen->start_timestamp = time(NULL); + screen->input_timestamp = time(NULL); + screen->last_cmd = CMD_NONE; + + /* create top window */ + screen->top_window.rows = 2; + screen->top_window.cols = screen->cols; + screen->top_window.w = newwin(screen->top_window.rows, + screen->top_window.cols, + 0, 0); + leaveok(screen->top_window.w, TRUE); + keypad(screen->top_window.w, TRUE); + + /* create main window */ + screen->main_window.rows = screen->rows-4; + screen->main_window.cols = screen->cols; + screen->main_window.w = newwin(screen->main_window.rows, + screen->main_window.cols, + 2, + 0); + + // leaveok(screen->main_window.w, TRUE); temporary disabled + keypad(screen->main_window.w, TRUE); + + /* create progress window */ + screen->progress_window.rows = 1; + screen->progress_window.cols = screen->cols; + screen->progress_window.w = newwin(screen->progress_window.rows, + screen->progress_window.cols, + screen->rows-2, + 0); + leaveok(screen->progress_window.w, TRUE); + + /* create status window */ + screen->status_window.rows = 1; + screen->status_window.cols = screen->cols; + screen->status_window.w = newwin(screen->status_window.rows, + screen->status_window.cols, + screen->rows-1, + 0); + + leaveok(screen->status_window.w, FALSE); + keypad(screen->status_window.w, TRUE); + + if( options.enable_colors ) + { + /* set background attributes */ + wbkgd(stdscr, COLOR_PAIR(COLOR_LIST)); + wbkgd(screen->main_window.w, COLOR_PAIR(COLOR_LIST)); + wbkgd(screen->top_window.w, COLOR_PAIR(COLOR_TITLE)); + wbkgd(screen->progress_window.w, COLOR_PAIR(COLOR_PROGRESSBAR)); + wbkgd(screen->status_window.w, COLOR_PAIR(COLOR_STATUS)); + colors_use(screen->progress_window.w, COLOR_PROGRESSBAR); + } + + /* initialize screens */ + screen->screen_list = NULL; + 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()); + screen->screen_list = g_list_append(screen->screen_list, + (gpointer) get_screen_help()); +#ifdef ENABLE_KEYDEF_SCREEN + screen->screen_list = g_list_append(screen->screen_list, + (gpointer) get_screen_keydef()); +#endif + + list = screen->screen_list; + while( list ) + { + screen_functions_t *fn = list->data; + + if( fn && fn->init ) + fn->init(screen->main_window.w, + screen->main_window.cols, + screen->main_window.rows); + + list = list->next; + } + + mode_fn = get_screen_playlist(); + + return 0; +} + +void +screen_paint(mpd_client_t *c) +{ + /* paint the title/header window */ + if( mode_fn && mode_fn->get_title ) + paint_top_window(mode_fn->get_title(), c, 1); + else + paint_top_window("", c, 1); + + /* paint the main window */ + if( mode_fn && mode_fn->paint ) + mode_fn->paint(screen, c); + + paint_progress_window(c); + paint_status_window(c); + screen->painted = 1; + wmove(screen->main_window.w, 0, 0); + wnoutrefresh(screen->main_window.w); + + /* tell curses to update */ + doupdate(); +} + +void +screen_update(mpd_client_t *c) +{ + static int repeat = -1; + static int random = -1; + static int crossfade = -1; + static int dbupdate = -1; + static int welcome = 1; + list_window_t *lw = NULL; + + if( !screen->painted ) + return screen_paint(c); + + /* print a message if mpd status has changed */ + if( repeat<0 ) + { + repeat = c->status->repeat; + random = c->status->random; + crossfade = c->status->crossfade; + dbupdate = c->status->updatingDb; + } + if( repeat != c->status->repeat ) + screen_status_printf("Repeat is %s", + c->status->repeat ? "On" : "Off"); + if( random != c->status->random ) + screen_status_printf("Random is %s", + c->status->random ? "On" : "Off"); + 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!"); + + repeat = c->status->repeat; + random = c->status->random; + crossfade = c->status->crossfade; + dbupdate = c->status->updatingDb; + + /* update title/header window */ + if( welcome && screen->last_cmd==CMD_NONE && + time(NULL)-screen->start_timestamp <= SCREEN_WELCOME_TIME) + paint_top_window("", c, 0); + else if( mode_fn && mode_fn->get_title ) + { + paint_top_window(mode_fn->get_title(), c, 0); + welcome = 0; + } + else + paint_top_window("", c, 0); + + /* update the main window */ + if( mode_fn && mode_fn->paint ) + mode_fn->update(screen, c); + + if( mode_fn && mode_fn->get_lw ) + lw = mode_fn->get_lw(); + + /* update progress window */ + paint_progress_window(c); + + /* update status window */ + paint_status_window(c); + + /* move the cursor to the selected row in the main window */ + if( lw ) + wmove(screen->main_window.w, LW_ROW(lw), 0); + else + wmove(screen->main_window.w, 0, 0); + wnoutrefresh(screen->main_window.w); + + /* tell curses to update */ + doupdate(); +} + +void +screen_idle(mpd_client_t *c) +{ + if( c->seek_song_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); + } + + screen->last_cmd = CMD_NONE; + c->seek_song_id = -1; +} + +void +screen_cmd(mpd_client_t *c, command_t cmd) +{ + int n; + screen_mode_t new_mode = screen->mode; + + screen->input_timestamp = time(NULL); + screen->last_cmd = cmd; + + if( mode_fn && mode_fn->cmd && mode_fn->cmd(screen, c, cmd) ) + return; + + switch(cmd) + { + case CMD_PLAY: + mpd_sendPlayCommand(c->connection, play_get_selected()); + mpd_finishCommand(c->connection); + break; + case CMD_PAUSE: + mpd_sendPauseCommand(c->connection); + mpd_finishCommand(c->connection); + break; + case CMD_STOP: + mpd_sendStopCommand(c->connection); + mpd_finishCommand(c->connection); + break; + case CMD_SEEK_FORWARD: + if( !IS_STOPPED(c->status->state) ) + { + if( c->seek_song_id != c->song_id ) + { + c->seek_song_id = c->song_id; + c->seek_target_time = c->status->elapsedTime; + } + c->seek_target_time++; + if( c->seek_target_time < c->status->totalTime ) + break; + c->seek_target_time=0; + } + /* fall through... */ + case CMD_TRACK_NEXT: + if( !IS_STOPPED(c->status->state) ) + { + mpd_sendNextCommand(c->connection); + mpd_finishCommand(c->connection); + } + break; + case CMD_SEEK_BACKWARD: + if( !IS_STOPPED(c->status->state) ) + { + if( c->seek_song_id != c->song_id ) + { + c->seek_song_id = c->song_id; + c->seek_target_time = c->status->elapsedTime; + } + c->seek_target_time--; + if( c->seek_target_time < 0 ) + c->seek_target_time=0; + } + break; + case CMD_TRACK_PREVIOUS: + if( !IS_STOPPED(c->status->state) ) + { + mpd_sendPrevCommand(c->connection); + mpd_finishCommand(c->connection); + } + break; + case CMD_SHUFFLE: + mpd_sendShuffleCommand(c->connection); + mpd_finishCommand(c->connection); + 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!"); + break; + case CMD_REPEAT: + n = !c->status->repeat; + mpd_sendRepeatCommand(c->connection, n); + mpd_finishCommand(c->connection); + break; + case CMD_RANDOM: + n = !c->status->random; + mpd_sendRandomCommand(c->connection, n); + mpd_finishCommand(c->connection); + break; + case CMD_CROSSFADE: + if( c->status->crossfade ) + n = 0; + else + n = DEFAULT_CROSSFADE_TIME; + mpd_sendCrossfadeCommand(c->connection, n); + mpd_finishCommand(c->connection); + 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); + } + 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); + } + break; + case CMD_TOGGLE_FIND_WRAP: + options.find_wrap = !options.find_wrap; + screen_status_printf("Find mode: %s", + options.find_wrap ? "Wrapped" : "Normal"); + break; + case CMD_TOGGLE_AUTOCENTER: + options.auto_center = !options.auto_center; + screen_status_printf("Auto center mode: %s", + options.auto_center ? "On" : "Off"); + break; + case CMD_SCREEN_PREVIOUS: + if( screen->mode > SCREEN_PLAY_WINDOW ) + new_mode = screen->mode - 1; + else + new_mode = SCREEN_HELP_WINDOW-1; + switch_screen_mode(new_mode, c); + break; + case CMD_SCREEN_NEXT: + new_mode = screen->mode + 1; + if( new_mode >= SCREEN_HELP_WINDOW ) + new_mode = SCREEN_PLAY_WINDOW; + switch_screen_mode(new_mode, c); + break; + case CMD_SCREEN_PLAY: + switch_screen_mode(SCREEN_PLAY_WINDOW, c); + break; + case CMD_SCREEN_FILE: + switch_screen_mode(SCREEN_FILE_WINDOW, c); + break; + case CMD_SCREEN_SEARCH: + switch_screen_mode(SCREEN_SEARCH_WINDOW, c); + break; + case CMD_SCREEN_HELP: + switch_screen_mode(SCREEN_HELP_WINDOW, c); + break; +#ifdef ENABLE_KEYDEF_SCREEN + case CMD_SCREEN_KEYDEF: + switch_screen_mode(SCREEN_KEYDEF_WINDOW, c); + break; +#endif + case CMD_QUIT: + exit(EXIT_SUCCESS); + default: + break; + } + +} + + + diff --git a/src/screen.h b/src/screen.h new file mode 100644 index 0000000..a7e6b72 --- /dev/null +++ b/src/screen.h @@ -0,0 +1,113 @@ +#ifndef SCREEN_H +#define SCREEN_H +#include +#include "list_window.h" + +/* top window headers */ +#define TOP_HEADER_PREFIX "Music Player Client - " +#define TOP_HEADER_PLAY TOP_HEADER_PREFIX "Playlist" +#define TOP_HEADER_FILE TOP_HEADER_PREFIX "Browse" +#define TOP_HEADER_HELP TOP_HEADER_PREFIX "Help " +#define TOP_HEADER_SEARCH TOP_HEADER_PREFIX "Search " + +/* minumum window size */ +#define SCREEN_MIN_COLS 14 +#define SCREEN_MIN_ROWS 5 + +/* timeout for non blocking read [ms] */ +#define SCREEN_TIMEOUT 500 + +/* welcome message time [s] */ +#define SCREEN_WELCOME_TIME 10 + +#define IS_PLAYING(s) (s==MPD_STATUS_STATE_PLAY) +#define IS_PAUSED(s) (s==MPD_STATUS_STATE_PAUSE) +#define IS_STOPPED(s) (!(IS_PLAYING(s) | IS_PAUSED(s))) + + +typedef enum +{ + SCREEN_PLAY_WINDOW = 0, + SCREEN_FILE_WINDOW, + SCREEN_HELP_WINDOW, + SCREEN_KEYDEF_WINDOW, + SCREEN_SEARCH_WINDOW + +} screen_mode_t; + +typedef struct +{ + WINDOW *w; + int rows, cols; + +} window_t; + + + +typedef struct +{ + window_t top_window; + window_t main_window; + window_t progress_window; + window_t status_window; + + GList *screen_list; + + time_t start_timestamp; + time_t status_timestamp; + time_t input_timestamp; + command_t last_cmd; + + int cols, rows; + + screen_mode_t mode; + + char *buf; + size_t buf_size; + + char *findbuf; + + int painted; + +} screen_t; + + +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_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 char * (*screen_title_fn_t) (void); +typedef list_window_t * (*screen_get_lw_fn_t) (void); + +typedef struct +{ + screen_init_fn_t init; + screen_exit_fn_t exit; + screen_open_fn_t open; + screen_close_fn_t close; + screen_resize_fn_t resize; + screen_paint_fn_t paint; + screen_update_fn_t update; + screen_cmd_fn_t cmd; + screen_title_fn_t get_title; + screen_get_lw_fn_t get_lw; + +} screen_functions_t; + + +int screen_init(void); +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); + +#endif diff --git a/src/screen_file.c b/src/screen_file.c new file mode 100644 index 0000000..d2b1f78 --- /dev/null +++ b/src/screen_file.c @@ -0,0 +1,503 @@ +/* + * (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 +#include +#include +#include +#include + +#include "config.h" +#include "support.h" +#include "libmpdclient.h" +#include "mpc.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; + +static char * +list_callback(int index, int *highlight, void *data) +{ + static char buf[BUFSIZE]; + mpd_client_t *c = (mpd_client_t *) data; + filelist_entry_t *entry; + mpd_InfoEntity *entity; + + *highlight = 0; + if( (entry=(filelist_entry_t *) g_list_nth_data(c->filelist, index))==NULL ) + return NULL; + + entity = entry->entity; + *highlight = entry->selected; + + 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; + } + else if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) + { + 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)); + return buf; +#endif + + } + else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) + { + mpd_PlaylistFile *plf = entity->info.playlistFile; + char *filename = utf8_to_locale(basename(plf->path)); + +#ifdef USE_OLD_LAYOUT + snprintf(buf, BUFSIZE, "*%s*", filename); +#else + snprintf(buf, BUFSIZE, "p %s", filename); +#endif + g_free(filename); + return buf; + } + return "Error: Unknow entry!"; +} + +static int +change_directory(screen_t *screen, mpd_client_t *c, filelist_entry_t *entry) +{ + mpd_InfoEntity *entity = entry->entity; + + if( entity==NULL ) + { + char *parent = g_path_get_dirname(c->cwd); + + if( strcmp(parent,".") == 0 ) + { + parent[0] = '\0'; + } + if( c->cwd ) + g_free(c->cwd); + c->cwd = parent; + } + else + if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY) + { + mpd_Directory *dir = entity->info.directory; + if( c->cwd ) + g_free(c->cwd); + c->cwd = g_strdup(dir->path); + } + else + return -1; + + mpc_update_filelist(c); + list_window_reset(lw); + return 0; +} + +static int +load_playlist(screen_t *screen, mpd_client_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); + + screen_status_printf("Loading playlist %s...", filename); + g_free(filename); + return 0; +} + +static int +handle_delete(screen_t *screen, mpd_client_t *c) +{ + filelist_entry_t *entry; + mpd_InfoEntity *entity; + mpd_PlaylistFile *plf; + char *str, buf[BUFSIZE]; + int key; + + entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected); + if( entry==NULL || entry->entity==NULL ) + return -1; + + entity = entry->entity; + + if( entity->type!=MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) + { + screen_status_printf("You can only delete playlists!"); + beep(); + return -1; + } + + plf = entity->info.playlistFile; + str = utf8_to_locale(basename(plf->path)); + snprintf(buf, BUFSIZE, "Delete playlist %s [y/n] ? ", str); + g_free(str); + key = tolower(screen_getch(screen->status_window.w, buf)); + if( key==KEY_RESIZE ) + screen_resize(); + if( key!='y' ) + { + screen_status_printf("Aborted!"); + return 0; + } + + mpd_sendRmCommand(c->connection, plf->path); + mpd_finishCommand(c->connection); + if( mpc_error(c)) + { + 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) +{ + filelist_entry_t *entry; + mpd_InfoEntity *entity; + + entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected); + if( entry==NULL ) + return -1; + + entity = entry->entity; + if( entity==NULL || entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) + return change_directory(screen, c, entry); + else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) + return load_playlist(screen, c, entry); + return -1; +} + +static int +add_directory(mpd_client_t *c, char *dir) +{ + mpd_InfoEntity *entity; + GList *subdir_list = NULL; + GList *list = NULL; + char *dirname; + + dirname = utf8_to_locale(dir); + screen_status_printf("Adding directory %s...\n", dirname); + doupdate(); + g_free(dirname); + dirname = NULL; + + mpd_sendLsInfoCommand(c->connection, dir); + mpd_sendCommandListBegin(c->connection); + while( (entity=mpd_getNextInfoEntity(c->connection)) ) + { + if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) + { + mpd_Song *song = entity->info.song; + mpd_sendAddCommand(c->connection, song->file); + mpd_freeInfoEntity(entity); + } + else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) + { + subdir_list = g_list_append(subdir_list, (gpointer) entity); + } + else + mpd_freeInfoEntity(entity); + } + mpd_sendCommandListEnd(c->connection); + mpd_finishCommand(c->connection); + + list = g_list_first(subdir_list); + while( list!=NULL ) + { + mpd_Directory *dir; + + entity = list->data; + dir = entity->info.directory; + add_directory(c, dir->path); + mpd_freeInfoEntity(entity); + list->data=NULL; + list=list->next; + } + g_list_free(subdir_list); + return 0; +} + +static int +handle_select(screen_t *screen, mpd_client_t *c) +{ + filelist_entry_t *entry; + + entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected); + if( entry==NULL || entry->entity==NULL) + return -1; + + if( entry->entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) + { + mpd_Directory *dir = entry->entity->info.directory; + add_directory(c, dir->path); + return 0; + } + + if( entry->entity->type!=MPD_INFO_ENTITY_TYPE_SONG ) + return -1; + + entry->selected = !entry->selected; + + if( entry->selected ) + { + 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)); + } + } + else + { + /* remove song from playlist */ + if( entry->entity->type==MPD_INFO_ENTITY_TYPE_SONG ) + { + mpd_Song *song = entry->entity->info.song; + + if( song ) + { + int index = mpc_playlist_get_song_index(c, song->file); + + while( (index=mpc_playlist_get_song_index(c, song->file))>=0 ) + playlist_delete_song(c, index); + } + } + } + return 0; +} + +static void +file_init(WINDOW *w, int cols, int rows) +{ + lw = list_window_init(w, cols, rows); +} + +static void +file_resize(int cols, int rows) +{ + lw->cols = cols; + lw->rows = rows; +} + +static void +file_exit(void) +{ + list_window_free(lw); +} + +static void +file_open(screen_t *screen, mpd_client_t *c) +{ + if( c->filelist == NULL ) + { + mpc_update_filelist(c); + } + mpc = c; +} + +static void +file_close(void) +{ +} + +static char * +file_title(void) +{ + static char buf[TITLESIZE]; + char *tmp; + + tmp = utf8_to_locale(basename(mpc->cwd)); + snprintf(buf, TITLESIZE, + TOP_HEADER_FILE ": %s ", + tmp + ); + g_free(tmp); + + return buf; +} + +static void +file_paint(screen_t *screen, mpd_client_t *c) +{ + lw->clear = 1; + + list_window_paint(lw, list_callback, (void *) c); + wnoutrefresh(lw->w); +} + +static void +file_update(screen_t *screen, mpd_client_t *c) +{ + if( c->filelist_updated ) + { + file_paint(screen, c); + c->filelist_updated = 0; + return; + } + list_window_paint(lw, list_callback, (void *) c); + wnoutrefresh(lw->w); +} + + +static int +file_cmd(screen_t *screen, mpd_client_t *c, command_t cmd) +{ + switch(cmd) + { + case CMD_PLAY: + handle_play_cmd(screen, c); + return 1; + case CMD_SELECT: + if( handle_select(screen, c) == 0 ) + { + /* continue and select next item... */ + cmd = CMD_LIST_NEXT; + } + break; + case CMD_DELETE: + handle_delete(screen, c); + break; + case CMD_SCREEN_UPDATE: + mpc_update_filelist(c); + list_window_check_selected(lw, c->filelist_length); + screen_status_printf("Screen updated!"); + return 1; + 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->filelist_length, + cmd, list_callback); + default: + break; + } + return list_window_cmd(lw, c->filelist_length, cmd); +} + + +list_window_t * +get_filelist_window() +{ + return lw; +} + + +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) +{ + 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.get_lw = get_filelist_window; + functions.get_title = file_title; + + return &functions; +} + diff --git a/src/screen_file.h b/src/screen_file.h new file mode 100644 index 0000000..a7199a6 --- /dev/null +++ b/src/screen_file.h @@ -0,0 +1,7 @@ + +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 new file mode 100644 index 0000000..c55c963 --- /dev/null +++ b/src/screen_help.c @@ -0,0 +1,254 @@ +/* + * (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 +#include +#include +#include + +#include "config.h" +#include "libmpdclient.h" +#include "mpc.h" +#include "command.h" +#include "screen.h" +#include "screen_utils.h" +#include "screen_help.h" + + +typedef struct +{ + signed char highlight; + command_t command; + char *text; +} help_text_row_t; + +static help_text_row_t help_text[] = +{ + { 1, CMD_NONE, " Movement keys " }, + { 0, CMD_NONE, " -----------------" }, + { 0, CMD_LIST_PREVIOUS, NULL }, + { 0, CMD_LIST_NEXT, NULL }, + { 0, CMD_LIST_PREVIOUS_PAGE, NULL }, + { 0, CMD_LIST_NEXT_PAGE, NULL }, + { 0, CMD_LIST_FIRST, NULL }, + { 0, CMD_LIST_LAST, NULL }, + { 0, CMD_NONE, NULL }, + { 0, CMD_SCREEN_NEXT, NULL }, + { 0, CMD_SCREEN_HELP, NULL }, + { 0, CMD_SCREEN_PLAY, NULL }, + { 0, CMD_SCREEN_FILE, NULL }, +#ifdef ENABLE_KEYDEF_SCREEN + { 0, CMD_SCREEN_KEYDEF, NULL }, +#endif + + { 0, CMD_NONE, NULL }, + { 0, CMD_NONE, NULL }, + { 1, CMD_NONE, " General keys " }, + { 0, CMD_NONE, " ----------------" }, + { 0, CMD_STOP, NULL }, + { 0, CMD_PAUSE, NULL }, + { 0, CMD_TRACK_NEXT, NULL }, + { 0, CMD_TRACK_PREVIOUS, NULL }, + { 0, CMD_SEEK_FORWARD, NULL }, + { 0, CMD_SEEK_BACKWARD, NULL }, + { 0, CMD_VOLUME_DOWN, NULL }, + { 0, CMD_VOLUME_UP, NULL }, + { 0, CMD_NONE, NULL }, + { 0, CMD_SHUFFLE, NULL }, + { 0, CMD_REPEAT, NULL }, + { 0, CMD_RANDOM, NULL }, + { 0, CMD_CROSSFADE, NULL }, + { 0, CMD_NONE, NULL }, + { 0, CMD_QUIT, NULL }, + + { 0, CMD_NONE, NULL }, + { 0, CMD_NONE, NULL }, + { 1, CMD_NONE, " Keys - Playlist screen " }, + { 0, CMD_NONE, " --------------------------" }, + { 0, CMD_PLAY, "Play" }, + { 0, CMD_DELETE, NULL }, + { 0, CMD_CLEAR, NULL }, + { 0, CMD_LIST_MOVE_UP, "Move song up" }, + { 0, CMD_LIST_MOVE_DOWN, "Move song down" }, + { 0, CMD_SAVE_PLAYLIST, NULL }, + { 0, CMD_SCREEN_UPDATE, "Center" }, + { 0, CMD_TOGGLE_AUTOCENTER, NULL }, + + { 0, CMD_NONE, NULL }, + { 0, CMD_NONE, NULL }, + { 1, CMD_NONE, " Keys - Browse screen " }, + { 0, CMD_NONE, " ------------------------" }, + { 0, CMD_PLAY, "Enter directory" }, + { 0, CMD_SELECT, NULL }, + { 0, CMD_DELETE, NULL }, + { 0, CMD_SCREEN_UPDATE, NULL }, + + { 0, CMD_NONE, NULL }, + { 0, CMD_NONE, NULL }, + { 1, CMD_NONE, " Find keys " }, + { 0, CMD_NONE, " -------------" }, + { 0, CMD_LIST_FIND, NULL }, + { 0, CMD_LIST_RFIND, NULL }, + { 0, CMD_LIST_FIND_NEXT, NULL }, + { 0, CMD_LIST_RFIND_NEXT, NULL }, + { 0, CMD_TOGGLE_FIND_WRAP, NULL }, + + { 0, CMD_NONE, NULL }, + { 0, CMD_NONE, NULL }, + { 1, CMD_NONE, " ncmpc build information " }, + { 0, CMD_NONE, " ---------------------------" }, + { 0, CMD_NONE, " Version : " VERSION }, + { 0, CMD_NONE, " Configuration dirs : ~/.ncmpc, " SYSCONFDIR "/" PACKAGE }, +#ifdef ENABLE_KEYDEF_SCREEN + { 0, CMD_NONE, " Key Editor : yes" }, +#else + { 0, CMD_NONE, " Key Editor : no" }, +#endif + + { 0, CMD_NONE, NULL }, + {-1, CMD_NONE, NULL } +}; + +static int help_text_rows = -1; +static list_window_t *lw = NULL; + + +static char * +list_callback(int index, int *highlight, void *data) +{ + static char buf[256]; + + if( help_text_rows<0 ) + { + help_text_rows = 0; + while( help_text[help_text_rows].highlight != -1 ) + help_text_rows++; + } + + *highlight = 0; + if( index 0; + if( help_text[index].command == CMD_NONE ) + { + if( help_text[index].text ) + return help_text[index].text; + else + return " "; + } + if( help_text[index].text ) + snprintf(buf, 256, + "%20s : %s ", + get_key_names(help_text[index].command, TRUE), + help_text[index].text); + else + snprintf(buf, 256, + "%20s : %s ", + get_key_names(help_text[index].command, TRUE), + get_key_description(help_text[index].command)); + return buf; + } + + return NULL; +} + +static void +help_init(WINDOW *w, int cols, int rows) +{ + lw = list_window_init(w, cols, rows); +} + +static void +help_resize(int cols, int rows) +{ + lw->cols = cols; + lw->rows = rows; +} + +static void +help_exit(void) +{ + list_window_free(lw); +} + + +static char * +help_title(void) +{ + return (TOP_HEADER_PREFIX "Help"); +} + +static void +help_paint(screen_t *screen, mpd_client_t *c) +{ + lw->clear = 1; + list_window_paint(lw, list_callback, NULL); + wrefresh(lw->w); +} + +static void +help_update(screen_t *screen, mpd_client_t *c) +{ + if( lw->repaint ) + { + list_window_paint(lw, list_callback, NULL); + wrefresh(lw->w); + lw->repaint = 0; + } +} + + +static int +help_cmd(screen_t *screen, mpd_client_t *c, command_t cmd) +{ + int retval; + + retval = list_window_cmd(lw, help_text_rows, cmd); + if( !retval ) + return screen_find(screen, c, + lw, help_text_rows, + cmd, list_callback); + + return retval; +} + +static list_window_t * +help_lw(void) +{ + return lw; +} + +screen_functions_t * +get_screen_help(void) +{ + static screen_functions_t functions; + + memset(&functions, 0, sizeof(screen_functions_t)); + functions.init = help_init; + functions.exit = help_exit; + functions.open = NULL; + functions.close = NULL; + functions.resize = help_resize; + functions.paint = help_paint; + functions.update = help_update; + functions.cmd = help_cmd; + functions.get_lw = help_lw; + functions.get_title = help_title; + + return &functions; +} diff --git a/src/screen_help.h b/src/screen_help.h new file mode 100644 index 0000000..ba2c57c --- /dev/null +++ b/src/screen_help.h @@ -0,0 +1,2 @@ + +screen_functions_t *get_screen_help(void); diff --git a/src/screen_keydef.c b/src/screen_keydef.c new file mode 100644 index 0000000..4bda6ea --- /dev/null +++ b/src/screen_keydef.c @@ -0,0 +1,393 @@ +/* + * (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 +#include +#include +#include +#include + +#include "config.h" + +#ifdef ENABLE_KEYDEF_SCREEN +#include "libmpdclient.h" +#include "options.h" +#include "conf.h" +#include "mpc.h" +#include "command.h" +#include "screen.h" +#include "screen_utils.h" + +#define STATIC_ITEMS 0 +#define STATIC_SUB_ITEMS 1 +#define BUFSIZE 256 + +#define LIST_ITEM_APPLY() (command_list_length) +#define LIST_ITEM_SAVE() (LIST_ITEM_APPLY()+1) +#define LIST_LENGTH() (LIST_ITEM_SAVE()+1) + +#define LIST_ITEM_SAVE_LABEL "===> Apply & Save key bindings " +#define LIST_ITEM_APPLY_LABEL "===> Apply key bindings " + + +static list_window_t *lw = NULL; +static int command_list_length = 0; +static command_definition_t *cmds = NULL; + +static int subcmd = -1; +static int subcmd_length = 0; +static int subcmd_addpos = 0; + +static int +keybindings_changed(void) +{ + command_definition_t *orginal_cmds = get_command_definitions(); + size_t size = command_list_length*sizeof(command_definition_t); + + return memcmp(orginal_cmds, cmds, size); +} + +static void +apply_keys(void) +{ + if( keybindings_changed() ) + { + command_definition_t *orginal_cmds = get_command_definitions(); + size_t size = command_list_length*sizeof(command_definition_t); + + memcpy(orginal_cmds, cmds, size); + screen_status_printf("You have new key bindings!"); + } + else + screen_status_printf("Keybindings unchanged."); +} + +static int +save_keys(void) +{ + FILE *f; + char *filename; + + if( check_user_conf_dir() ) + { + screen_status_printf("Error: Unable to create direcory ~/.ncmpc - %s", + strerror(errno)); + beep(); + return -1; + } + + filename = get_user_key_binding_filename(); + + if( (f=fopen(filename,"w")) == NULL ) + { + screen_status_printf("Error: %s - %s", filename, strerror(errno)); + beep(); + g_free(filename); + return -1; + } + if( write_key_bindings(f) ) + screen_status_printf("Error: %s - %s", filename, strerror(errno)); + else + screen_status_printf("Wrote %s", filename); + + g_free(filename); + return fclose(f); +} + +static void +check_subcmd_length(void) +{ + subcmd_length = 0; + while( subcmd_length0 ) + subcmd_length ++; + + if( subcmd_lengthclear = 1; + lw->repaint = 1; +} + +static void +assign_new_key(WINDOW *w, int cmd_index, int key_index) +{ + int key; + char buf[BUFSIZE]; + command_t cmd; + + snprintf(buf, BUFSIZE, "Enter new key for %s: ", cmds[cmd_index].name); + key = screen_getch(w, buf); + if( key==KEY_RESIZE ) + screen_resize(); + if( key==ERR ) + { + screen_status_printf("Aborted!"); + return; + } + cmd = find_key_command(key, cmds); + if( cmd!=CMD_NONE && cmd!= cmds[cmd_index].command ) + { + screen_status_printf("Error: key %s is already used for %s", + key2str(key), + get_key_command_name(cmd)); + beep(); + return; + } + cmds[cmd_index].keys[key_index] = key; + screen_status_printf("Assigned %s to %s", key2str(key),cmds[cmd_index].name); + check_subcmd_length(); + lw->repaint = 1; +} + +static char * +list_callback(int index, int *highlight, void *data) +{ + static char buf[BUFSIZE]; + + if( subcmd <0 ) + { + if( index0 ) + { + snprintf(buf, + BUFSIZE, "%d. %-20s (%d) ", + index+1, + key2str(cmds[subcmd].keys[index]), + cmds[subcmd].keys[index]); + return buf; + } + else if ( index==subcmd_addpos ) + { + snprintf(buf, BUFSIZE, "%d. Add new key ", index+1 ); + return buf; + } + } + + return NULL; +} + +static void +keydef_init(WINDOW *w, int cols, int rows) +{ + lw = list_window_init(w, cols, rows); +} + +static void +keydef_resize(int cols, int rows) +{ + lw->cols = cols; + lw->rows = rows; +} + +static void +keydef_exit(void) +{ + list_window_free(lw); + if( cmds ) + g_free(cmds); + cmds = NULL; + lw = NULL; +} + +static void +keydef_open(screen_t *screen, mpd_client_t *c) +{ + if( cmds == NULL ) + { + command_definition_t *current_cmds = get_command_definitions(); + size_t cmds_size; + + command_list_length = 0; + while( current_cmds[command_list_length].name ) + command_list_length++; + + cmds_size = (command_list_length+1)*sizeof(command_definition_t); + cmds = g_malloc0(cmds_size); + memcpy(cmds, current_cmds, cmds_size); + command_list_length += STATIC_ITEMS; + screen_status_printf("Welcome to the key editor!"); + } + + subcmd = -1; + list_window_check_selected(lw, LIST_LENGTH()); +} + +static void +keydef_close(void) +{ + if( cmds && !keybindings_changed() ) + { + g_free(cmds); + cmds = NULL; + } + else + screen_status_printf("Note: Did you forget to \'Apply\' your changes?"); +} + +static char * +keydef_title(void) +{ + static char buf[BUFSIZE]; + + if( subcmd<0 ) + return (TOP_HEADER_PREFIX "Edit key bindings"); + + snprintf(buf, BUFSIZE, + TOP_HEADER_PREFIX "Edit keys for %s", + cmds[subcmd].name); + return buf; +} + +static void +keydef_paint(screen_t *screen, mpd_client_t *c) +{ + lw->clear = 1; + list_window_paint(lw, list_callback, NULL); + wrefresh(lw->w); +} + +static void +keydef_update(screen_t *screen, mpd_client_t *c) +{ + if( lw->repaint ) + { + list_window_paint(lw, list_callback, NULL); + wrefresh(lw->w); + lw->repaint = 0; + } +} + +static int +keydef_cmd(screen_t *screen, mpd_client_t *c, command_t cmd) +{ + int length = LIST_LENGTH(); + + if( subcmd>=0 ) + length = subcmd_length; + + switch(cmd) + { + case CMD_PLAY: + if( subcmd<0 ) + { + if( lw->selected == LIST_ITEM_APPLY() ) + apply_keys(); + else if( lw->selected == LIST_ITEM_SAVE() ) + { + apply_keys(); + save_keys(); + } + else + { + subcmd = lw->selected; + lw->selected=0; + check_subcmd_length(); + } + } + else + { + if( lw->selected == 0 ) /* up */ + { + lw->selected = subcmd; + subcmd = -1; + } + else + assign_new_key(screen->status_window.w, + subcmd, + lw->selected-STATIC_SUB_ITEMS); + } + lw->repaint = 1; + lw->clear = 1; + return 1; + case CMD_DELETE: + if( subcmd>=0 && lw->selected-STATIC_SUB_ITEMS>=0 ) + delete_key(subcmd, lw->selected-STATIC_SUB_ITEMS); + return 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, length, + cmd, list_callback); + + default: + break; + } + + return list_window_cmd(lw, length, cmd); +} + +static list_window_t * +keydef_lw(void) +{ + return lw; +} + +screen_functions_t * +get_screen_keydef(void) +{ + static screen_functions_t functions; + + memset(&functions, 0, sizeof(screen_functions_t)); + functions.init = keydef_init; + functions.exit = keydef_exit; + functions.open = keydef_open; + functions.close = keydef_close; + functions.resize = keydef_resize; + functions.paint = keydef_paint; + functions.update = keydef_update; + functions.cmd = keydef_cmd; + functions.get_lw = keydef_lw; + functions.get_title = keydef_title; + + return &functions; +} + + +#endif diff --git a/src/screen_play.c b/src/screen_play.c new file mode 100644 index 0000000..cdec4f7 --- /dev/null +++ b/src/screen_play.c @@ -0,0 +1,390 @@ +/* + * (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 +#include +#include +#include + +#include "config.h" +#include "options.h" +#include "support.h" +#include "libmpdclient.h" +#include "mpc.h" +#include "command.h" +#include "screen.h" +#include "screen_utils.h" +#include "screen_file.h" +#include "screen_play.h" + +#ifdef DEBUG +#define D(x) x +#else +#define D(x) +#endif + +#define BUFSIZE 256 + +static list_window_t *lw = NULL; + +static char * +list_callback(int index, int *highlight, void *data) +{ + mpd_client_t *c = (mpd_client_t *) data; + mpd_Song *song; + + *highlight = 0; + if( (song=mpc_playlist_get_song(c, index)) == NULL ) + { + return NULL; + } + + if( index==c->song_id && !IS_STOPPED(c->status->state) ) + { + *highlight = 1; + } + + return mpc_get_song_name(song); +} + +static int +center_playing_item(screen_t *screen, mpd_client_t *c) +{ + int length = c->playlist_length; + int offset = lw->selected-lw->start; + + if( !lw || lengthrows || IS_STOPPED(c->status->state) ) + return 0; + + /* try to center the song that are playing */ + lw->start = c->song_id-(lw->rows/2); + if( lw->start+lw->rows > length ) + lw->start = length-lw->rows; + if( lw->start<0 ) + lw->start=0; + + /* make sure the cursor is in the window */ + lw->selected = lw->start+offset; + list_window_check_selected(lw, length); + + lw->clear = 1; + lw->repaint = 1; + + return 0; +} + +static int +handle_save_playlist(screen_t *screen, mpd_client_t *c) +{ + char *filename, *filename_utf8; + + 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( 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; +} + +static void +play_init(WINDOW *w, int cols, int rows) +{ + lw = list_window_init(w, cols, rows); +} + +static void +play_resize(int cols, int rows) +{ + lw->cols = cols; + lw->rows = rows; +} + + +static void +play_exit(void) +{ + list_window_free(lw); +} + +static char * +play_title(void) +{ + return (TOP_HEADER_PREFIX "Playlist"); +} + +static void +play_paint(screen_t *screen, mpd_client_t *c) +{ + lw->clear = 1; + + list_window_paint(lw, list_callback, (void *) c); + wnoutrefresh(lw->w); +} + +static void +play_update(screen_t *screen, mpd_client_t *c) +{ + if( options.auto_center ) + { + static int prev_song_id = 0; + + if( prev_song_id != c->song_id ) + { + center_playing_item(screen, c); + prev_song_id = c->song_id; + } + } + + if( c->playlist_updated ) + { + 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; + } + else if( lw->repaint || 1) + { + list_window_paint(lw, list_callback, (void *) c); + wnoutrefresh(lw->w); + lw->repaint = 0; + } +} + +static int +play_cmd(screen_t *screen, mpd_client_t *c, command_t cmd) +{ + switch(cmd) + { + case CMD_DELETE: + playlist_delete_song(c, lw->selected); + return 1; + case CMD_SAVE_PLAYLIST: + handle_save_playlist(screen, c); + return 1; + case CMD_SCREEN_UPDATE: + center_playing_item(screen, c); + return 1; + case CMD_LIST_MOVE_UP: + playlist_move_song(c, lw->selected, lw->selected-1); + break; + case CMD_LIST_MOVE_DOWN: + playlist_move_song(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, + cmd, list_callback); + default: + break; + } + return list_window_cmd(lw, c->playlist_length, cmd) ; +} + + + +static list_window_t * +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_name(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) +{ + static screen_functions_t functions; + + memset(&functions, 0, sizeof(screen_functions_t)); + functions.init = play_init; + functions.exit = play_exit; + functions.open = NULL; + functions.close = NULL; + functions.resize = play_resize; + functions.paint = play_paint; + functions.update = play_update; + functions.cmd = play_cmd; + functions.get_lw = play_lw; + functions.get_title = play_title; + + return &functions; +} diff --git a/src/screen_play.h b/src/screen_play.h new file mode 100644 index 0000000..2155ae5 --- /dev/null +++ b/src/screen_play.h @@ -0,0 +1,9 @@ + +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 new file mode 100644 index 0000000..6b6719e --- /dev/null +++ b/src/screen_search.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +#include "libmpdclient.h" +#include "config.h" +#include "mpc.h" +#include "command.h" +#include "screen.h" +#include "screen_search.h" + diff --git a/src/screen_search.h b/src/screen_search.h new file mode 100644 index 0000000..e69de29 diff --git a/src/screen_utils.c b/src/screen_utils.c new file mode 100644 index 0000000..f8dfa4c --- /dev/null +++ b/src/screen_utils.c @@ -0,0 +1,153 @@ +/* + * (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 +#include +#include +#include +#include + +#include "config.h" +#include "libmpdclient.h" +#include "mpc.h" +#include "support.h" +#include "command.h" +#include "options.h" +#include "list_window.h" +#include "colors.h" +#include "screen.h" + +#define FIND_PROMPT "Find: " +#define RFIND_PROMPT "Find backward: " + +int +screen_getch(WINDOW *w, char *prompt) +{ + int key = -1; + int prompt_len = strlen(prompt); + + colors_use(w, COLOR_STATUS_ALERT); + wclear(w); + wmove(w, 0, 0); + waddstr(w, prompt); + wmove(w, 0, prompt_len); + + echo(); + curs_set(1); + timeout(-1); + + key = wgetch(w); + if( key==KEY_RESIZE ) + screen_resize(); + + noecho(); + curs_set(0); + timeout(SCREEN_TIMEOUT); + + return key; +} + + +char * +screen_getstr(WINDOW *w, char *prompt) +{ + char buf[256], *line = NULL; + int prompt_len = strlen(prompt); + + colors_use(w, COLOR_STATUS_ALERT); + wclear(w); + wmove(w, 0, 0); + waddstr(w, prompt); + wmove(w, 0, prompt_len); + + echo(); + curs_set(1); + + if( wgetnstr(w, buf, 256) == OK ) + line = g_strdup(buf); + + noecho(); + curs_set(0); + + return line; +} + + +/* query user for a string and find it in a list window */ +int +screen_find(screen_t *screen, + mpd_client_t *c, + list_window_t *lw, + int rows, + command_t findcmd, + list_window_callback_fn_t callback_fn) +{ + int reversed = 0; + int retval = 0; + char *prompt = FIND_PROMPT; + + if( findcmd==CMD_LIST_RFIND ||findcmd==CMD_LIST_RFIND_NEXT ) + { + prompt = RFIND_PROMPT; + reversed = 1; + } + + switch(findcmd) + { + case CMD_LIST_FIND: + case CMD_LIST_RFIND: + if( screen->findbuf ) + { + g_free(screen->findbuf); + screen->findbuf=NULL; + } + /* continue... */ + case CMD_LIST_FIND_NEXT: + case CMD_LIST_RFIND_NEXT: + if( !screen->findbuf ) + screen->findbuf=screen_getstr(screen->status_window.w, prompt); + if( reversed ) + retval = list_window_rfind(lw, + callback_fn, + c, + screen->findbuf, + options.find_wrap, + rows); + else + retval = list_window_find(lw, + callback_fn, + c, + screen->findbuf, + options.find_wrap); + if( retval == 0 ) + { + lw->repaint = 1; + } + else + { + screen_status_printf("Unable to find \'%s\'", screen->findbuf); + beep(); + } + return 1; + default: + break; + } + return 0; +} + + diff --git a/src/screen_utils.h b/src/screen_utils.h new file mode 100644 index 0000000..30c58bf --- /dev/null +++ b/src/screen_utils.h @@ -0,0 +1,18 @@ + +/* read a characher from the status window */ +int screen_getch(WINDOW *w, char *prompt); + +/* read a string from the status window */ +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, + list_window_t *lw, + int rows, + command_t findcmd, + list_window_callback_fn_t callback_fn); + + +int my_waddstr(WINDOW *, const char *, int); +int my_mvwaddstr(WINDOW *, int, int, const char *, int); diff --git a/src/support.c b/src/support.c new file mode 100644 index 0000000..d292e84 --- /dev/null +++ b/src/support.c @@ -0,0 +1,216 @@ +/* + * (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 +#include +#include +#include +#include + +#include "config.h" +#include "support.h" + +#ifdef HAVE_LOCALE_H +#include +#endif + +#ifdef DEBUG +#define D(x) x +#else +#define D(x) +#endif + +#define BUFSIZE 1024 + +extern void screen_status_printf(char *format, ...); + +static const char *charset = NULL; +static const char *locale = NULL; +static gboolean noconvert = TRUE; + +char * +trim(char *str) +{ + char *end; + + if( str==NULL ) + return NULL; + + while( IS_WHITESPACE(*str) ) + str++; + + end=str+strlen(str)-1; + while( end>str && IS_WHITESPACE(*end) ) + { + *end = '\0'; + end--; + } + return str; +} + +char * +remove_trailing_slash(char *path) +{ + int len; + + if( path==NULL ) + return NULL; + + len=strlen(path); + if( len>1 && path[len-1] == '/' ) + path[len-1] = '\0'; + + return path; +} + +char * +lowerstr(char *str) +{ + size_t i; + size_t len = strlen(str); + + if( str==NULL ) + return NULL; + + i=0; + while(ipath && *end!='/' ) + end--; + + if( *end=='/' && end!=path ) + return end+1; + + return path; +} +#endif /* HAVE_BASENAME */ + + +#ifndef HAVE_STRCASESTR +char * +strcasestr(const char *haystack, const char *needle) +{ + return strstr(lowerstr(haystack), lowerstr(needle)); +} +#endif /* HAVE_STRCASESTR */ + + +int +charset_init(void) +{ +#ifdef HAVE_LOCALE_H + /* get current locale */ + if( (locale=setlocale(LC_CTYPE,"")) == NULL ) + { + g_printerr("setlocale() - failed!\n"); + return -1; + } +#endif + + /* get charset */ + noconvert = g_get_charset(&charset); + +#ifdef DEBUG + g_printerr("charset: %s [%d]\n", charset, noconvert); + fflush(stderr); +#endif + + return 0; +} + +int +charset_close(void) +{ + return 0; +} + +char * +utf8_to_locale(char *utf8str) +{ + gchar *str; + gsize rb, wb; + GError *error; + + if( noconvert ) + return g_strdup(utf8str); + + rb = 0; /* bytes read */ + wb = 0; /* bytes written */ + error = NULL; + str=g_locale_from_utf8(utf8str, + strlen(utf8str), + &wb, &rb, + &error); + if( error ) + { + screen_status_printf("Error: Unable to convert characters to %s", + charset); + D(g_printerr("utf8_to_locale(): %s\n", error->message)); + g_error_free(error); + return g_strdup(utf8str); + } + + return str; +} + +char * +locale_to_utf8(char *localestr) +{ + gchar *str; + gsize rb, wb; + GError *error; + + if( noconvert ) + return g_strdup(localestr); + + rb = 0; /* bytes read */ + wb = 0; /* bytes written */ + error = NULL; + str=g_locale_to_utf8(localestr, + strlen(localestr), + &wb, &rb, + &error); + if( error ) + { + screen_status_printf("Error: Unable to convert characters to UTF-8"); + D(g_printerr("locale_to_utf8: %s\n", error->message)); + g_error_free(error); + return g_strdup(localestr); + } + + return str; +} + + + diff --git a/src/support.h b/src/support.h new file mode 100644 index 0000000..1f3aca1 --- /dev/null +++ b/src/support.h @@ -0,0 +1,24 @@ +#ifndef SUPPORT_H +#define SUPPORT_H + +#ifdef HAVE_LIBGEN_H +#include +#endif + +#ifndef HAVE_BASENAME +char *basename(char *path); +#endif + +#define IS_WHITESPACE(c) (c==' ' || c=='\t' || c=='\r' || c=='\n') + +char *trim(char *str); +char *remove_trailing_slash(char *path); +char *lowerstr(char *str); +char *strcasestr(const char *haystack, const char *needle); + +int charset_init(void); +int charset_close(void); +char *utf8_to_locale(char *str); +char *locale_to_utf8(char *str); + +#endif diff --git a/support.c b/support.c deleted file mode 100644 index d292e84..0000000 --- a/support.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * (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 -#include -#include -#include -#include - -#include "config.h" -#include "support.h" - -#ifdef HAVE_LOCALE_H -#include -#endif - -#ifdef DEBUG -#define D(x) x -#else -#define D(x) -#endif - -#define BUFSIZE 1024 - -extern void screen_status_printf(char *format, ...); - -static const char *charset = NULL; -static const char *locale = NULL; -static gboolean noconvert = TRUE; - -char * -trim(char *str) -{ - char *end; - - if( str==NULL ) - return NULL; - - while( IS_WHITESPACE(*str) ) - str++; - - end=str+strlen(str)-1; - while( end>str && IS_WHITESPACE(*end) ) - { - *end = '\0'; - end--; - } - return str; -} - -char * -remove_trailing_slash(char *path) -{ - int len; - - if( path==NULL ) - return NULL; - - len=strlen(path); - if( len>1 && path[len-1] == '/' ) - path[len-1] = '\0'; - - return path; -} - -char * -lowerstr(char *str) -{ - size_t i; - size_t len = strlen(str); - - if( str==NULL ) - return NULL; - - i=0; - while(ipath && *end!='/' ) - end--; - - if( *end=='/' && end!=path ) - return end+1; - - return path; -} -#endif /* HAVE_BASENAME */ - - -#ifndef HAVE_STRCASESTR -char * -strcasestr(const char *haystack, const char *needle) -{ - return strstr(lowerstr(haystack), lowerstr(needle)); -} -#endif /* HAVE_STRCASESTR */ - - -int -charset_init(void) -{ -#ifdef HAVE_LOCALE_H - /* get current locale */ - if( (locale=setlocale(LC_CTYPE,"")) == NULL ) - { - g_printerr("setlocale() - failed!\n"); - return -1; - } -#endif - - /* get charset */ - noconvert = g_get_charset(&charset); - -#ifdef DEBUG - g_printerr("charset: %s [%d]\n", charset, noconvert); - fflush(stderr); -#endif - - return 0; -} - -int -charset_close(void) -{ - return 0; -} - -char * -utf8_to_locale(char *utf8str) -{ - gchar *str; - gsize rb, wb; - GError *error; - - if( noconvert ) - return g_strdup(utf8str); - - rb = 0; /* bytes read */ - wb = 0; /* bytes written */ - error = NULL; - str=g_locale_from_utf8(utf8str, - strlen(utf8str), - &wb, &rb, - &error); - if( error ) - { - screen_status_printf("Error: Unable to convert characters to %s", - charset); - D(g_printerr("utf8_to_locale(): %s\n", error->message)); - g_error_free(error); - return g_strdup(utf8str); - } - - return str; -} - -char * -locale_to_utf8(char *localestr) -{ - gchar *str; - gsize rb, wb; - GError *error; - - if( noconvert ) - return g_strdup(localestr); - - rb = 0; /* bytes read */ - wb = 0; /* bytes written */ - error = NULL; - str=g_locale_to_utf8(localestr, - strlen(localestr), - &wb, &rb, - &error); - if( error ) - { - screen_status_printf("Error: Unable to convert characters to UTF-8"); - D(g_printerr("locale_to_utf8: %s\n", error->message)); - g_error_free(error); - return g_strdup(localestr); - } - - return str; -} - - - diff --git a/support.h b/support.h deleted file mode 100644 index 1f3aca1..0000000 --- a/support.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef SUPPORT_H -#define SUPPORT_H - -#ifdef HAVE_LIBGEN_H -#include -#endif - -#ifndef HAVE_BASENAME -char *basename(char *path); -#endif - -#define IS_WHITESPACE(c) (c==' ' || c=='\t' || c=='\r' || c=='\n') - -char *trim(char *str); -char *remove_trailing_slash(char *path); -char *lowerstr(char *str); -char *strcasestr(const char *haystack, const char *needle); - -int charset_init(void); -int charset_close(void); -char *utf8_to_locale(char *str); -char *locale_to_utf8(char *str); - -#endif