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