summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 677eb1a)
raw | patch | inline | side by side (parent: 677eb1a)
author | Kalle Wallin <kaw@linux.se> | |
Sat, 5 Jun 2004 11:21:43 +0000 (11:21 +0000) | ||
committer | Kalle Wallin <kaw@linux.se> | |
Sat, 5 Jun 2004 11:21:43 +0000 (11:21 +0000) |
65 files changed:
ChangeLog | patch | blob | history | |
Makefile.am | patch | blob | history | |
autogen.sh | patch | blob | history | |
colors.c | [deleted file] | patch | blob | history |
colors.h | [deleted file] | patch | blob | history |
command.c | [deleted file] | patch | blob | history |
command.h | [deleted file] | patch | blob | history |
conf.c | [deleted file] | patch | blob | history |
conf.h | [deleted file] | patch | blob | history |
configure.ac | patch | blob | history | |
libmpdclient.c | [deleted file] | patch | blob | history |
libmpdclient.h | [deleted file] | patch | blob | history |
list_window.c | [deleted file] | patch | blob | history |
list_window.h | [deleted file] | patch | blob | history |
main.c | [deleted file] | patch | blob | history |
mpc.c | [deleted file] | patch | blob | history |
mpc.h | [deleted file] | patch | blob | history |
options.c | [deleted file] | patch | blob | history |
options.h | [deleted file] | patch | blob | history |
screen.c | [deleted file] | patch | blob | history |
screen.h | [deleted file] | patch | blob | history |
screen_file.c | [deleted file] | patch | blob | history |
screen_file.h | [deleted file] | patch | blob | history |
screen_help.c | [deleted file] | patch | blob | history |
screen_help.h | [deleted file] | patch | blob | history |
screen_keydef.c | [deleted file] | patch | blob | history |
screen_play.c | [deleted file] | patch | blob | history |
screen_play.h | [deleted file] | patch | blob | history |
screen_search.c | [deleted file] | patch | blob | history |
screen_search.h | [deleted file] | patch | blob | history |
screen_utils.c | [deleted file] | patch | blob | history |
screen_utils.h | [deleted file] | patch | blob | history |
src/Makefile.am | [new file with mode: 0644] | patch | blob |
src/colors.c | [new file with mode: 0644] | patch | blob |
src/colors.h | [new file with mode: 0644] | patch | blob |
src/command.c | [new file with mode: 0644] | patch | blob |
src/command.h | [new file with mode: 0644] | patch | blob |
src/conf.c | [new file with mode: 0644] | patch | blob |
src/conf.h | [new file with mode: 0644] | patch | blob |
src/libmpdclient.c | [new file with mode: 0644] | patch | blob |
src/libmpdclient.h | [new file with mode: 0644] | patch | blob |
src/list_window.c | [new file with mode: 0644] | patch | blob |
src/list_window.h | [new file with mode: 0644] | patch | blob |
src/main.c | [new file with mode: 0644] | patch | blob |
src/mpc.c | [new file with mode: 0644] | patch | blob |
src/mpc.h | [new file with mode: 0644] | patch | blob |
src/options.c | [new file with mode: 0644] | patch | blob |
src/options.h | [new file with mode: 0644] | patch | blob |
src/screen.c | [new file with mode: 0644] | patch | blob |
src/screen.h | [new file with mode: 0644] | patch | blob |
src/screen_file.c | [new file with mode: 0644] | patch | blob |
src/screen_file.h | [new file with mode: 0644] | patch | blob |
src/screen_help.c | [new file with mode: 0644] | patch | blob |
src/screen_help.h | [new file with mode: 0644] | patch | blob |
src/screen_keydef.c | [new file with mode: 0644] | patch | blob |
src/screen_play.c | [new file with mode: 0644] | patch | blob |
src/screen_play.h | [new file with mode: 0644] | patch | blob |
src/screen_search.c | [new file with mode: 0644] | patch | blob |
src/screen_search.h | [new file with mode: 0644] | patch | blob |
src/screen_utils.c | [new file with mode: 0644] | patch | blob |
src/screen_utils.h | [new file with mode: 0644] | patch | blob |
src/support.c | [new file with mode: 0644] | patch | blob |
src/support.h | [new file with mode: 0644] | patch | blob |
support.c | [deleted file] | patch | blob | history |
support.h | [deleted file] | patch | blob | history |
diff --git a/ChangeLog b/ChangeLog
index e43c8a012590d1bc5c03bdbc6c0cc7b425fd6697..2a4de6102756a07f509341096983bf9ce7762e62 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
+2004-06-05 Kalle Wallin <kaw@linux.se>
+ * 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 <kaw@linux.se>
* 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 8ac5da7de15cb5e3b3b8e83a45ada462d78707bb..8bf3267ee26653491bb3ea9028560f55778aeffa 100644 (file)
--- a/Makefile.am
+++ b/Makefile.am
#
-# $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 72a2352343087ba9f949882f97a40dd316a4290c..22e7897d79ea25af63dbb0bbc4a0aa6ef2b87191 100755 (executable)
--- a/autogen.sh
+++ b/autogen.sh
-#! /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
--- 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ncurses.h>
-#include <glib.h>
-
-#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
--- 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
--- 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 <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <glib.h>
-#include <ncurses.h>
-
-#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( j<MAX_COMMAND_KEYS && cmds[i].keys[j]>0 )
- {
- 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<MAX_COMMAND_KEYS; j++)
- if( cmds[i].keys[j] &&
- (cmd=get_key_command(cmds[i].keys[j])) != cmds[i].command )
- {
- fprintf(stderr, "Error: Key %s assigned to %s and %s !!!\n",
- key2str(cmds[i].keys[j]),
- get_key_command_name(cmds[i].command),
- get_key_command_name(cmd));
- retval = -1;
- }
- i++;
- }
- return retval;
-}
-
-int
-write_key_bindings(FILE *f)
-{
- int i,j;
-
- i=0;
- while( cmds[i].name && !ferror(f) )
- {
- fprintf(f, "# %s\n", cmds[i].description);
- fprintf(f, "key %s = ", cmds[i].name);
- for(j=0; j<MAX_COMMAND_KEYS; j++)
- {
- if( j && cmds[i].keys[j] )
- fprintf(f, ", ");
- if( !j || cmds[i].keys[j] )
- {
- if( cmds[i].keys[j]<256 && (isalpha(cmds[i].keys[j]) ||
- isdigit(cmds[i].keys[j])) )
- fprintf(f, "\'%c\'", cmds[i].keys[j]);
- else
- fprintf(f, "%d", cmds[i].keys[j]);
- }
- }
- fprintf(f,"\n\n");
- i++;
- }
- return ferror(f);
-}
diff --git a/command.h b/command.h
--- a/command.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef COMMAND_H
-#define COMMAND_H
-
-#define MAX_COMMAND_KEYS 3
-
-typedef enum
-{
- CMD_NONE = 0,
- CMD_PLAY,
- CMD_SELECT,
- CMD_PAUSE,
- CMD_STOP,
- CMD_TRACK_NEXT,
- CMD_TRACK_PREVIOUS,
- CMD_SEEK_FORWARD,
- CMD_SEEK_BACKWARD,
- CMD_SHUFFLE,
- CMD_RANDOM,
- CMD_CLEAR,
- CMD_DELETE,
- CMD_REPEAT,
- CMD_CROSSFADE,
- CMD_VOLUME_UP,
- CMD_VOLUME_DOWN,
- CMD_SAVE_PLAYLIST,
- CMD_TOGGLE_FIND_WRAP,
- CMD_TOGGLE_AUTOCENTER,
- CMD_LIST_PREVIOUS,
- CMD_LIST_NEXT,
- CMD_LIST_FIRST,
- CMD_LIST_LAST,
- CMD_LIST_NEXT_PAGE,
- CMD_LIST_PREVIOUS_PAGE,
- CMD_LIST_FIND,
- CMD_LIST_FIND_NEXT,
- CMD_LIST_RFIND,
- CMD_LIST_RFIND_NEXT,
- CMD_LIST_MOVE_UP,
- CMD_LIST_MOVE_DOWN,
- CMD_SCREEN_UPDATE,
- CMD_SCREEN_PREVIOUS,
- CMD_SCREEN_NEXT,
- CMD_SCREEN_PLAY,
- CMD_SCREEN_FILE,
- CMD_SCREEN_SEARCH,
- CMD_SCREEN_KEYDEF,
- CMD_SCREEN_HELP,
- CMD_QUIT
-} command_t;
-
-typedef struct
-{
- int keys[MAX_COMMAND_KEYS];
- command_t command;
- char *name;
- char *description;
-} command_definition_t;
-
-command_definition_t *get_command_definitions(void);
-command_t find_key_command(int key, command_definition_t *cmds);
-
-void command_dump_keys(void);
-int check_key_bindings(void);
-int write_key_bindings(FILE *f);
-
-char *key2str(int key);
-char *get_key_description(command_t command);
-char *get_key_command_name(command_t command);
-char *get_key_names(command_t command, int all);
-command_t get_key_command(int key);
-command_t get_key_command_from_name(char *name);
-int assign_keys(command_t command, int keys[MAX_COMMAND_KEYS]);
-
-command_t get_keyboard_command(void);
-
-#endif
diff --git a/conf.c b/conf.c
--- a/conf.c
+++ /dev/null
@@ -1,594 +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 <ctype.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include <glib.h>
-#include <ncurses.h>
-
-#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<len && state!=KEY_PARSER_DONE )
- {
- int next = 0;
- int c = str[i];
-
- if( i+1<len )
- next = str[i+1];
-
- switch(state)
- {
- case KEY_PARSER_UNKNOWN:
- if( c=='\'' )
- state = KEY_PARSER_CHAR;
- else if( c=='0' && next=='x' )
- state = KEY_PARSER_HEX;
- else if( isdigit(c) )
- state = KEY_PARSER_DEC;
- else {
- fprintf(stderr, "Error: Unsupported key definition - %s\n", str);
- return -1;
- }
- break;
- case KEY_PARSER_CHAR:
- if( next!='\'' )
- {
- fprintf(stderr, "Error: Unsupported key definition - %s\n", str);
- return -1;
- }
- value = c;
- *end = str+i+2;
- state = KEY_PARSER_DONE;
- break;
- case KEY_PARSER_DEC:
- value = (int) strtol(str+(i-1), end, 10);
- state = KEY_PARSER_DONE;
- break;
- case KEY_PARSER_HEX:
- if( !isdigit(next) )
- {
- fprintf(stderr, "Error: Digit expexted after 0x - %s\n", str);
- return -1;
- }
- value = (int) strtol(str+(i+1), end, 16);
- state = KEY_PARSER_DONE;
- break;
- case KEY_PARSER_DONE:
- break;
- }
- i++;
- }
-
- if( *end> 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<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
- buf[j++] = str[i++];
- if( (cmd=get_key_command_from_name(buf)) == CMD_NONE )
- {
- fprintf(stderr, "Error: Unknown key command %s\n", buf);
- return -1;
- }
-
- /* skip whitespace */
- while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
- i++;
-
- /* get the value part */
- memset(buf, 0, MAX_LINE_LENGTH);
- strncpy(buf, str+i, len-i);
- len = strlen(buf);
- if( len==0 )
- {
- fprintf(stderr,"Error: Incomplete key definition - %s\n", str);
- return -1;
- }
-
- /* parse key values */
- i = 0;
- key = 0;
- len = strlen(buf);
- p = buf;
- end = buf+len;
- memset(keys, 0, sizeof(int)*MAX_COMMAND_KEYS);
- while( i<MAX_COMMAND_KEYS && p<end && (key=parse_key_value(p,len+1,&p))>=0 )
- {
- keys[i++] = key;
- while( p<end && (*p==',' || *p==' ' || *p=='\t') )
- p++;
- len = strlen(p);
- }
- if( key<0 )
- {
- fprintf(stderr,"Error: Bad key definition - %s\n", str);
- return -1;
- }
-
- return assign_keys(cmd, keys);
-}
-
-static int
-parse_color(char *str)
-{
- char *name = str;
- char *value = NULL;
- int len,i;
-
- i=0;
- len=strlen(str);
- /* get the color name */
- while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
- i++;
-
- /* skip whitespace */
- while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
- {
- str[i]='\0';
- i++;
- }
-
- if( i<len )
- value = str+i;
-
- return colors_assign(name, value);
-}
-
-
-static int
-parse_color_definition(char *str)
-{
- char buf[MAX_LINE_LENGTH];
- char *p, *end, *name;
- size_t len = strlen(str);
- int i,j,value;
- short color, rgb[3];
-
- /* get the command name */
- i=0;
- j=0;
- memset(buf, 0, MAX_LINE_LENGTH);
- while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
- buf[j++] = str[i++];
- color=colors_str2color(buf);
- if( color<0 )
- {
- fprintf(stderr, "Error: Bad color %s [%d]\n", buf, color);
- return -1;
- }
- name = g_strdup(buf);
-
- /* skip whitespace */
- while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
- i++;
-
- /* get the value part */
- memset(buf, 0, MAX_LINE_LENGTH);
- strncpy(buf, str+i, len-i);
- len = strlen(buf);
- if( len==0 )
- {
- fprintf(stderr,"Error: Incomplete color definition - %s\n", str);
- g_free(name);
- return -1;
- }
-
- /* parse r,g.b values with the key definition parser */
- i = 0;
- value = 0;
- len = strlen(buf);
- p = buf;
- end = buf+len;
- memset(rgb, 0, sizeof(short)*3);
- while( i<3 && p<end && (value=parse_key_value(p,len+1,&p))>=0 )
- {
- rgb[i++] = value;
- while( p<end && (*p==',' || *p==' ' || *p=='\t') )
- p++;
- len = strlen(p);
- }
- if( value<0 || i!=3)
- {
- fprintf(stderr,"Error: Bad color definition - %s\n", str);
- g_free(name);
- return -1;
- }
- value = colors_define(name, rgb[0], rgb[1], rgb[2]);
- g_free(name);
- return value;
-}
-
-
-static int
-read_rc_file(char *filename, options_t *options)
-{
- int fd;
- int quit = 0;
- int free_filename = 0;
-
- if( filename==NULL )
- return -1;
-
- D(printf("Reading configuration file %s\n", filename));
- if( (fd=open(filename,O_RDONLY)) <0 )
- {
- perror(filename);
- if( free_filename )
- g_free(filename);
- return -1;
- }
-
- while( !quit )
- {
- int i,j;
- int len;
- int match_found;
- char line[MAX_LINE_LENGTH];
- char name[MAX_LINE_LENGTH];
- char value[MAX_LINE_LENGTH];
-
- line[0] = '\0';
- value[0] = '\0';
-
- i = 0;
- /* read a line ending with '\n' */
- do {
- len = read( fd, &line[i], 1 );
- if( len == 1 )
- i++;
- else
- quit = 1;
- } while( !quit && i<MAX_LINE_LENGTH && line[i-1]!='\n' );
-
-
- /* remove trailing whitespace */
- line[i] = '\0';
- i--;
- while( i>=0 && IS_WHITESPACE(line[i]) )
- {
- line[i] = '\0';
- i--;
- }
- len = i+1;
-
- if( len>0 )
- {
- i = 0;
- /* skip whitespace */
- while( i<len && IS_WHITESPACE(line[i]) )
- i++;
-
- /* continue if this line is not a comment */
- if( line[i] != COMMENT_TOKEN )
- {
- /* get the name part */
- j=0;
- while( i<len && line[i]!='=' && !IS_WHITESPACE(line[i]) )
- {
- name[j++] = line[i++];
- }
- name[j] = '\0';
-
- /* skip '=' and whitespace */
- while( i<len && (line[i]=='=' || IS_WHITESPACE(line[i])) )
- i++;
-
- /* get the value part */
- j=0;
- while( i<len )
- {
- value[j++] = line[i++];
- }
- value[j] = '\0';
-
- match_found = 1;
-
- /* key definition */
- if( !strcasecmp(CONF_KEY_DEFINITION, name) )
- {
- parse_key_definition(value);
- }
- /* enable colors */
- else if( !strcasecmp(CONF_ENABLE_COLORS, name) )
- {
- options->enable_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
--- 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 87dbc6a529553340b4c38b235cfc36ddd43d6b7b..d1601f9c83b2fe6f5ee91198190034e0676be0f6 100644 (file)
--- a/configure.ac
+++ b/configure.ac
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
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)\\\""
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
--- 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 <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <sys/param.h>
-#include <string.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#ifndef HAVE_SOCKLEN_T
-typedef SOCKLEN_T socklen_t;
-#endif
-#endif
-
-#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;i<strlen(arg);i++) {
- if(arg[i]=='"' || arg[i]=='\\') count++;
- }
-
- ret = malloc(strlen(arg)+count+1);
-
- count = 0;
- for(i=0;i<strlen(arg)+1;i++) {
- if(arg[i]=='"' || arg[i]=='\\') {
- ret[i+count] = '\\';
- count++;
- }
- ret[i+count] = arg[i];
- }
-
- return ret;
-}
-
-mpd_ReturnElement * mpd_newReturnElement(const char * name, const char * value)
-{
- mpd_ReturnElement * ret = malloc(sizeof(mpd_ReturnElement));
-
- ret->name = 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
--- 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 <sys/time.h>
-
-#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
--- 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 <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <glib.h>
-#include <ncurses.h>
-
-#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->selected<lw->start )
- 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; i<lw->rows; 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
--- 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
--- 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 <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-#include <glib.h>
-
-#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
--- a/mpc.c
+++ /dev/null
@@ -1,359 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <time.h>
-#include <string.h>
-#include <glib.h>
-
-#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
--- 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
--- 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 <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <ncurses.h>
-#include <glib.h>
-#include <popt.h>
-
-#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
--- 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
--- 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 <stdlib.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <string.h>
-#include <time.h>
-#include <signal.h>
-#include <glib.h>
-#include <ncurses.h>
-
-#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( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
- {
- screen_exit();
- fprintf(stderr, "Error: Screen to small!\n");
- exit(EXIT_FAILURE);
- }
-
- resizeterm(LINES, COLS);
-
- screen->cols = 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( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
- {
- fprintf(stderr, "Error: Screen to small!\n");
- exit(EXIT_FAILURE);
- }
-
- screen = g_malloc(sizeof(screen_t));
- memset(screen, 0, sizeof(screen_t));
- screen->mode = 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
--- a/screen.h
+++ /dev/null
@@ -1,113 +0,0 @@
-#ifndef SCREEN_H
-#define SCREEN_H
-#include <ncurses.h>
-#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
--- 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 <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include <ncurses.h>
-
-#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
--- 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
--- 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 <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include <ncurses.h>
-
-#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<help_text_rows )
- {
- *highlight = help_text[index].highlight > 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
--- 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
--- 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 <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include <ncurses.h>
-
-#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_length<MAX_COMMAND_KEYS && cmds[subcmd].keys[subcmd_length]>0 )
- subcmd_length ++;
-
- if( subcmd_length<MAX_COMMAND_KEYS )
- {
- subcmd_addpos = subcmd_length;
- subcmd_length++;
- }
- else
- subcmd_addpos = 0;
- subcmd_length += STATIC_SUB_ITEMS;
-}
-
-static void
-delete_key(int cmd_index, int key_index)
-{
- int i = key_index+1;
-
- screen_status_printf("Delete...");
- while( i<MAX_COMMAND_KEYS && cmds[cmd_index].keys[i] )
- cmds[cmd_index].keys[key_index++] = cmds[cmd_index].keys[i++];
- cmds[cmd_index].keys[key_index] = 0;
-
- check_subcmd_length();
- lw->clear = 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( index<command_list_length )
- return cmds[index].name;
- else if( index==LIST_ITEM_APPLY() )
- return LIST_ITEM_APPLY_LABEL;
- else if( index==LIST_ITEM_SAVE() )
- return LIST_ITEM_SAVE_LABEL;
- }
- else
- {
- if( index== 0 )
- return "[..]";
- index--;
- if( index<MAX_COMMAND_KEYS && cmds[subcmd].keys[index]>0 )
- {
- 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
--- 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 <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include <ncurses.h>
-
-#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 || length<lw->rows || IS_STOPPED(c->status->state) )
- return 0;
-
- /* try to center the song that are playing */
- lw->start = c->song_id-(lw->rows/2);
- 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
--- 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
--- a/screen_search.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include <ncurses.h>
-
-#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
diff --git a/screen_utils.c b/screen_utils.c
--- 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 <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <glib.h>
-#include <ncurses.h>
-
-#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
--- 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
--- /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
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ncurses.h>
+#include <glib.h>
+
+#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
--- /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
--- /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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <glib.h>
+#include <ncurses.h>
+
+#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( j<MAX_COMMAND_KEYS && cmds[i].keys[j]>0 )
+ {
+ 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<MAX_COMMAND_KEYS; j++)
+ if( cmds[i].keys[j] &&
+ (cmd=get_key_command(cmds[i].keys[j])) != cmds[i].command )
+ {
+ fprintf(stderr, "Error: Key %s assigned to %s and %s !!!\n",
+ key2str(cmds[i].keys[j]),
+ get_key_command_name(cmds[i].command),
+ get_key_command_name(cmd));
+ retval = -1;
+ }
+ i++;
+ }
+ return retval;
+}
+
+int
+write_key_bindings(FILE *f)
+{
+ int i,j;
+
+ i=0;
+ while( cmds[i].name && !ferror(f) )
+ {
+ fprintf(f, "# %s\n", cmds[i].description);
+ fprintf(f, "key %s = ", cmds[i].name);
+ for(j=0; j<MAX_COMMAND_KEYS; j++)
+ {
+ if( j && cmds[i].keys[j] )
+ fprintf(f, ", ");
+ if( !j || cmds[i].keys[j] )
+ {
+ if( cmds[i].keys[j]<256 && (isalpha(cmds[i].keys[j]) ||
+ isdigit(cmds[i].keys[j])) )
+ fprintf(f, "\'%c\'", cmds[i].keys[j]);
+ else
+ fprintf(f, "%d", cmds[i].keys[j]);
+ }
+ }
+ fprintf(f,"\n\n");
+ i++;
+ }
+ return ferror(f);
+}
diff --git a/src/command.h b/src/command.h
--- /dev/null
+++ b/src/command.h
@@ -0,0 +1,76 @@
+#ifndef COMMAND_H
+#define COMMAND_H
+
+#define MAX_COMMAND_KEYS 3
+
+typedef enum
+{
+ CMD_NONE = 0,
+ CMD_PLAY,
+ CMD_SELECT,
+ CMD_PAUSE,
+ CMD_STOP,
+ CMD_TRACK_NEXT,
+ CMD_TRACK_PREVIOUS,
+ CMD_SEEK_FORWARD,
+ CMD_SEEK_BACKWARD,
+ CMD_SHUFFLE,
+ CMD_RANDOM,
+ CMD_CLEAR,
+ CMD_DELETE,
+ CMD_REPEAT,
+ CMD_CROSSFADE,
+ CMD_VOLUME_UP,
+ CMD_VOLUME_DOWN,
+ CMD_SAVE_PLAYLIST,
+ CMD_TOGGLE_FIND_WRAP,
+ CMD_TOGGLE_AUTOCENTER,
+ CMD_LIST_PREVIOUS,
+ CMD_LIST_NEXT,
+ CMD_LIST_FIRST,
+ CMD_LIST_LAST,
+ CMD_LIST_NEXT_PAGE,
+ CMD_LIST_PREVIOUS_PAGE,
+ CMD_LIST_FIND,
+ CMD_LIST_FIND_NEXT,
+ CMD_LIST_RFIND,
+ CMD_LIST_RFIND_NEXT,
+ CMD_LIST_MOVE_UP,
+ CMD_LIST_MOVE_DOWN,
+ CMD_SCREEN_UPDATE,
+ CMD_SCREEN_PREVIOUS,
+ CMD_SCREEN_NEXT,
+ CMD_SCREEN_PLAY,
+ CMD_SCREEN_FILE,
+ CMD_SCREEN_SEARCH,
+ CMD_SCREEN_KEYDEF,
+ CMD_SCREEN_HELP,
+ CMD_QUIT
+} command_t;
+
+typedef struct
+{
+ int keys[MAX_COMMAND_KEYS];
+ command_t command;
+ char *name;
+ char *description;
+} command_definition_t;
+
+command_definition_t *get_command_definitions(void);
+command_t find_key_command(int key, command_definition_t *cmds);
+
+void command_dump_keys(void);
+int check_key_bindings(void);
+int write_key_bindings(FILE *f);
+
+char *key2str(int key);
+char *get_key_description(command_t command);
+char *get_key_command_name(command_t command);
+char *get_key_names(command_t command, int all);
+command_t get_key_command(int key);
+command_t get_key_command_from_name(char *name);
+int assign_keys(command_t command, int keys[MAX_COMMAND_KEYS]);
+
+command_t get_keyboard_command(void);
+
+#endif
diff --git a/src/conf.c b/src/conf.c
--- /dev/null
+++ b/src/conf.c
@@ -0,0 +1,594 @@
+/*
+ * (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 <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <glib.h>
+#include <ncurses.h>
+
+#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<len && state!=KEY_PARSER_DONE )
+ {
+ int next = 0;
+ int c = str[i];
+
+ if( i+1<len )
+ next = str[i+1];
+
+ switch(state)
+ {
+ case KEY_PARSER_UNKNOWN:
+ if( c=='\'' )
+ state = KEY_PARSER_CHAR;
+ else if( c=='0' && next=='x' )
+ state = KEY_PARSER_HEX;
+ else if( isdigit(c) )
+ state = KEY_PARSER_DEC;
+ else {
+ fprintf(stderr, "Error: Unsupported key definition - %s\n", str);
+ return -1;
+ }
+ break;
+ case KEY_PARSER_CHAR:
+ if( next!='\'' )
+ {
+ fprintf(stderr, "Error: Unsupported key definition - %s\n", str);
+ return -1;
+ }
+ value = c;
+ *end = str+i+2;
+ state = KEY_PARSER_DONE;
+ break;
+ case KEY_PARSER_DEC:
+ value = (int) strtol(str+(i-1), end, 10);
+ state = KEY_PARSER_DONE;
+ break;
+ case KEY_PARSER_HEX:
+ if( !isdigit(next) )
+ {
+ fprintf(stderr, "Error: Digit expexted after 0x - %s\n", str);
+ return -1;
+ }
+ value = (int) strtol(str+(i+1), end, 16);
+ state = KEY_PARSER_DONE;
+ break;
+ case KEY_PARSER_DONE:
+ break;
+ }
+ i++;
+ }
+
+ if( *end> 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<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
+ buf[j++] = str[i++];
+ if( (cmd=get_key_command_from_name(buf)) == CMD_NONE )
+ {
+ fprintf(stderr, "Error: Unknown key command %s\n", buf);
+ return -1;
+ }
+
+ /* skip whitespace */
+ while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
+ i++;
+
+ /* get the value part */
+ memset(buf, 0, MAX_LINE_LENGTH);
+ strncpy(buf, str+i, len-i);
+ len = strlen(buf);
+ if( len==0 )
+ {
+ fprintf(stderr,"Error: Incomplete key definition - %s\n", str);
+ return -1;
+ }
+
+ /* parse key values */
+ i = 0;
+ key = 0;
+ len = strlen(buf);
+ p = buf;
+ end = buf+len;
+ memset(keys, 0, sizeof(int)*MAX_COMMAND_KEYS);
+ while( i<MAX_COMMAND_KEYS && p<end && (key=parse_key_value(p,len+1,&p))>=0 )
+ {
+ keys[i++] = key;
+ while( p<end && (*p==',' || *p==' ' || *p=='\t') )
+ p++;
+ len = strlen(p);
+ }
+ if( key<0 )
+ {
+ fprintf(stderr,"Error: Bad key definition - %s\n", str);
+ return -1;
+ }
+
+ return assign_keys(cmd, keys);
+}
+
+static int
+parse_color(char *str)
+{
+ char *name = str;
+ char *value = NULL;
+ int len,i;
+
+ i=0;
+ len=strlen(str);
+ /* get the color name */
+ while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
+ i++;
+
+ /* skip whitespace */
+ while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
+ {
+ str[i]='\0';
+ i++;
+ }
+
+ if( i<len )
+ value = str+i;
+
+ return colors_assign(name, value);
+}
+
+
+static int
+parse_color_definition(char *str)
+{
+ char buf[MAX_LINE_LENGTH];
+ char *p, *end, *name;
+ size_t len = strlen(str);
+ int i,j,value;
+ short color, rgb[3];
+
+ /* get the command name */
+ i=0;
+ j=0;
+ memset(buf, 0, MAX_LINE_LENGTH);
+ while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
+ buf[j++] = str[i++];
+ color=colors_str2color(buf);
+ if( color<0 )
+ {
+ fprintf(stderr, "Error: Bad color %s [%d]\n", buf, color);
+ return -1;
+ }
+ name = g_strdup(buf);
+
+ /* skip whitespace */
+ while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
+ i++;
+
+ /* get the value part */
+ memset(buf, 0, MAX_LINE_LENGTH);
+ strncpy(buf, str+i, len-i);
+ len = strlen(buf);
+ if( len==0 )
+ {
+ fprintf(stderr,"Error: Incomplete color definition - %s\n", str);
+ g_free(name);
+ return -1;
+ }
+
+ /* parse r,g.b values with the key definition parser */
+ i = 0;
+ value = 0;
+ len = strlen(buf);
+ p = buf;
+ end = buf+len;
+ memset(rgb, 0, sizeof(short)*3);
+ while( i<3 && p<end && (value=parse_key_value(p,len+1,&p))>=0 )
+ {
+ rgb[i++] = value;
+ while( p<end && (*p==',' || *p==' ' || *p=='\t') )
+ p++;
+ len = strlen(p);
+ }
+ if( value<0 || i!=3)
+ {
+ fprintf(stderr,"Error: Bad color definition - %s\n", str);
+ g_free(name);
+ return -1;
+ }
+ value = colors_define(name, rgb[0], rgb[1], rgb[2]);
+ g_free(name);
+ return value;
+}
+
+
+static int
+read_rc_file(char *filename, options_t *options)
+{
+ int fd;
+ int quit = 0;
+ int free_filename = 0;
+
+ if( filename==NULL )
+ return -1;
+
+ D(printf("Reading configuration file %s\n", filename));
+ if( (fd=open(filename,O_RDONLY)) <0 )
+ {
+ perror(filename);
+ if( free_filename )
+ g_free(filename);
+ return -1;
+ }
+
+ while( !quit )
+ {
+ int i,j;
+ int len;
+ int match_found;
+ char line[MAX_LINE_LENGTH];
+ char name[MAX_LINE_LENGTH];
+ char value[MAX_LINE_LENGTH];
+
+ line[0] = '\0';
+ value[0] = '\0';
+
+ i = 0;
+ /* read a line ending with '\n' */
+ do {
+ len = read( fd, &line[i], 1 );
+ if( len == 1 )
+ i++;
+ else
+ quit = 1;
+ } while( !quit && i<MAX_LINE_LENGTH && line[i-1]!='\n' );
+
+
+ /* remove trailing whitespace */
+ line[i] = '\0';
+ i--;
+ while( i>=0 && IS_WHITESPACE(line[i]) )
+ {
+ line[i] = '\0';
+ i--;
+ }
+ len = i+1;
+
+ if( len>0 )
+ {
+ i = 0;
+ /* skip whitespace */
+ while( i<len && IS_WHITESPACE(line[i]) )
+ i++;
+
+ /* continue if this line is not a comment */
+ if( line[i] != COMMENT_TOKEN )
+ {
+ /* get the name part */
+ j=0;
+ while( i<len && line[i]!='=' && !IS_WHITESPACE(line[i]) )
+ {
+ name[j++] = line[i++];
+ }
+ name[j] = '\0';
+
+ /* skip '=' and whitespace */
+ while( i<len && (line[i]=='=' || IS_WHITESPACE(line[i])) )
+ i++;
+
+ /* get the value part */
+ j=0;
+ while( i<len )
+ {
+ value[j++] = line[i++];
+ }
+ value[j] = '\0';
+
+ match_found = 1;
+
+ /* key definition */
+ if( !strcasecmp(CONF_KEY_DEFINITION, name) )
+ {
+ parse_key_definition(value);
+ }
+ /* enable colors */
+ else if( !strcasecmp(CONF_ENABLE_COLORS, name) )
+ {
+ options->enable_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
--- /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
--- /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 <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#ifndef HAVE_SOCKLEN_T
+typedef SOCKLEN_T socklen_t;
+#endif
+#endif
+
+
+#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;i<strlen(arg);i++) {
+ if(arg[i]=='"' || arg[i]=='\\') count++;
+ }
+
+ ret = malloc(strlen(arg)+count+1);
+
+ count = 0;
+ for(i=0;i<strlen(arg)+1;i++) {
+ if(arg[i]=='"' || arg[i]=='\\') {
+ ret[i+count] = '\\';
+ count++;
+ }
+ ret[i+count] = arg[i];
+ }
+
+ return ret;
+}
+
+mpd_ReturnElement * mpd_newReturnElement(const char * name, const char * value)
+{
+ mpd_ReturnElement * ret = malloc(sizeof(mpd_ReturnElement));
+
+ ret->name = 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
--- /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 <sys/time.h>
+
+#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
--- /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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <glib.h>
+#include <ncurses.h>
+
+#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->selected<lw->start )
+ 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; i<lw->rows; 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
--- /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
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <glib.h>
+
+#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
--- /dev/null
+++ b/src/mpc.c
@@ -0,0 +1,359 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <glib.h>
+
+#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
--- /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
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ncurses.h>
+#include <glib.h>
+#include <popt.h>
+
+#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
--- /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
--- /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 <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+//#include <signal.h>
+#include <locale.h>
+#include <glib.h>
+#include <ncurses.h>
+
+#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( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
+ {
+ screen_exit();
+ fprintf(stderr, "Error: Screen to small!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ resizeterm(LINES, COLS);
+
+ screen->cols = 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( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
+ {
+ fprintf(stderr, "Error: Screen to small!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ screen = g_malloc(sizeof(screen_t));
+ memset(screen, 0, sizeof(screen_t));
+ screen->mode = 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
--- /dev/null
+++ b/src/screen.h
@@ -0,0 +1,113 @@
+#ifndef SCREEN_H
+#define SCREEN_H
+#include <ncurses.h>
+#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
--- /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 <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <ncurses.h>
+
+#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
--- /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
--- /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 <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <ncurses.h>
+
+#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<help_text_rows )
+ {
+ *highlight = help_text[index].highlight > 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
--- /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
--- /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 <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <ncurses.h>
+
+#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_length<MAX_COMMAND_KEYS && cmds[subcmd].keys[subcmd_length]>0 )
+ subcmd_length ++;
+
+ if( subcmd_length<MAX_COMMAND_KEYS )
+ {
+ subcmd_addpos = subcmd_length;
+ subcmd_length++;
+ }
+ else
+ subcmd_addpos = 0;
+ subcmd_length += STATIC_SUB_ITEMS;
+}
+
+static void
+delete_key(int cmd_index, int key_index)
+{
+ int i = key_index+1;
+
+ screen_status_printf("Delete...");
+ while( i<MAX_COMMAND_KEYS && cmds[cmd_index].keys[i] )
+ cmds[cmd_index].keys[key_index++] = cmds[cmd_index].keys[i++];
+ cmds[cmd_index].keys[key_index] = 0;
+
+ check_subcmd_length();
+ lw->clear = 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( index<command_list_length )
+ return cmds[index].name;
+ else if( index==LIST_ITEM_APPLY() )
+ return LIST_ITEM_APPLY_LABEL;
+ else if( index==LIST_ITEM_SAVE() )
+ return LIST_ITEM_SAVE_LABEL;
+ }
+ else
+ {
+ if( index== 0 )
+ return "[..]";
+ index--;
+ if( index<MAX_COMMAND_KEYS && cmds[subcmd].keys[index]>0 )
+ {
+ 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
--- /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 <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <ncurses.h>
+
+#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 || length<lw->rows || IS_STOPPED(c->status->state) )
+ return 0;
+
+ /* try to center the song that are playing */
+ lw->start = c->song_id-(lw->rows/2);
+ 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
--- /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
--- /dev/null
+++ b/src/screen_search.c
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <ncurses.h>
+
+#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
diff --git a/src/screen_utils.c b/src/screen_utils.c
--- /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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <glib.h>
+#include <ncurses.h>
+
+#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
--- /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
--- /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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include "config.h"
+#include "support.h"
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#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(i<len && str[i])
+ {
+ str[i] = tolower(str[i]);
+ i++;
+ }
+ return str;
+}
+
+
+#ifndef HAVE_BASENAME
+char *
+basename(char *path)
+{
+ char *end;
+
+ path = remove_trailing_slash(path);
+ end = path + strlen(path);
+
+ while( end>path && *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
--- /dev/null
+++ b/src/support.h
@@ -0,0 +1,24 @@
+#ifndef SUPPORT_H
+#define SUPPORT_H
+
+#ifdef HAVE_LIBGEN_H
+#include <libgen.h>
+#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
--- 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 <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-
-#include "config.h"
-#include "support.h"
-
-#ifdef HAVE_LOCALE_H
-#include <locale.h>
-#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(i<len && str[i])
- {
- str[i] = tolower(str[i]);
- i++;
- }
- return str;
-}
-
-
-#ifndef HAVE_BASENAME
-char *
-basename(char *path)
-{
- char *end;
-
- path = remove_trailing_slash(path);
- end = path + strlen(path);
-
- while( end>path && *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
--- a/support.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef SUPPORT_H
-#define SUPPORT_H
-
-#ifdef HAVE_LIBGEN_H
-#include <libgen.h>
-#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