changeset 3867:e48f2f4c116d

- many remained audacious remote functions have been implemented. - audtool improvement in progress.
author Yoshiki Yazawa <yaz@cc.rim.or.jp>
date Mon, 29 Oct 2007 22:21:42 +0900
parents 5c5f56a710d1
children 7cfa1e7cec08
files src/audacious/dbus-service.h src/audacious/dbus.c src/audacious/objects.xml src/audacious/playlist.c src/audtool/Makefile src/audtool/audtool.h src/audtool/audtool_handlers_general.c src/audtool/audtool_handlers_playqueue.c src/audtool/audtool_handlers_test.c src/audtool/audtool_main.c src/libaudclient/audctrl.c src/libaudclient/audctrl.h
diffstat 12 files changed, 875 insertions(+), 77 deletions(-) [+]
line wrap: on
line diff
--- a/src/audacious/dbus-service.h	Sun Oct 28 21:37:05 2007 +0100
+++ b/src/audacious/dbus-service.h	Mon Oct 29 22:21:42 2007 +0900
@@ -183,4 +183,28 @@
 gboolean audacious_rc_shuffle(RemoteObject *obj, gboolean *is_shuffle,
                               GError **error);
 gboolean audacious_rc_toggle_shuffle(RemoteObject *obj, GError **error);
+
+/* new */
+gboolean audacious_rc_show_prefs_box(RemoteObject *obj, GError **error);
+gboolean audacious_rc_show_about_box(RemoteObject *obj, GError **error);
+gboolean audacious_rc_show_jtf_box(RemoteObject *obj, GError **error);
+gboolean audacious_rc_play_pause(RemoteObject *obj, GError **error);
+gboolean audacious_rc_activate(RemoteObject *obj, GError **error);
+gboolean audacious_rc_queue_get_list_pos(RemoteObject *obj, gint qpos, gint *pos, GError **error);
+gboolean audacious_rc_queue_get_queue_pos(RemoteObject *obj, gint pos, gint *qpos, GError **error);
+gboolean audacious_rc_get_skin(RemoteObject *obj, gchar **skin, GError **error);
+gboolean audacious_rc_set_skin(RemoteObject *obj, gchar *skin, GError **error);
+gboolean audacious_rc_get_info(RemoteObject *obj, gint *rate, gint *freq, gint *nch, GError **error);
+gboolean audacious_rc_toggle_aot(RemoteObject *obj, gboolean ontop, GError **error);
+gboolean audacious_rc_get_playqueue_length(RemoteObject *obj, gint *length, GError **error);
+gboolean audacious_rc_playqueue_add(RemoteObject *obj, gint pos, GError **error);
+gboolean audacious_rc_playqueue_remove(RemoteObject *obj, gint pos, GError **error);
+gboolean audacious_rc_playqueue_clear(RemoteObject *obj, GError **error);
+gboolean audacious_rc_playqueue_is_queued(RemoteObject *obj, gint pos, gboolean *is_queued, GError **error);
+
+/* in progress */
+gboolean audacious_rc_playlist_ins_url_string(RemoteObject *obj, gchar *url, gint *pos, GError **error);
+gboolean audacious_rc_playlist_add(RemoteObject *obj, gpointer list, GError **error);
+gboolean audacious_rc_playlist_enqueue_to_temp(RemoteObject *obj, char *list, gint num, gboolean enqueue, GError **error);
+
 #endif // !_DBUS_SERVICE_H
--- a/src/audacious/dbus.c	Sun Oct 28 21:37:05 2007 +0100
+++ b/src/audacious/dbus.c	Mon Oct 29 22:21:42 2007 +0900
@@ -41,6 +41,8 @@
 #include "tuple.h"
 #include "ui_jumptotrack.h"
 #include "strings.h"
+#include "ui_credits.h"
+#include "skin.h"
 
 static DBusGConnection *dbus_conn = NULL;
 static guint signals[LAST_SIG] = { 0 };
@@ -792,6 +794,128 @@
     return TRUE;
 }
 
+/* New on Oct 5 */
+gboolean audacious_rc_show_prefs_box(RemoteObject *obj, GError **error) {
+    if (has_x11_connection)
+        show_prefs_window();
+    return TRUE;
+}
+gboolean audacious_rc_show_about_box(RemoteObject *obj, GError **error) {
+    if (has_x11_connection)
+        show_about_window();
+    return TRUE;
+}
+
+gboolean audacious_rc_show_jtf_box(RemoteObject *obj, GError **error) {
+    if (has_x11_connection)
+        ui_jump_to_track();
+    return TRUE;
+}
+
+gboolean audacious_rc_play_pause(RemoteObject *obj, GError **error) {
+    if (playback_get_playing())
+        playback_pause();
+    else
+        playback_initiate();
+    return TRUE;
+}
+
+gboolean audacious_rc_activate(RemoteObject *obj, GError **error) {
+    gtk_window_present(GTK_WINDOW(mainwin));
+    return TRUE;
+}
+
+gboolean audacious_rc_get_skin(RemoteObject *obj, gchar **skin, GError **error) {
+    *skin = g_strdup(bmp_active_skin->path);
+    return TRUE;
+}
+
+gboolean audacious_rc_set_skin(RemoteObject *obj, gchar *skin, GError **error) {
+    if (has_x11_connection == TRUE)
+        bmp_active_skin_load(skin);
+    return TRUE;
+}
+
+gboolean audacious_rc_get_info(RemoteObject *obj, gint *rate, gint *freq, gint *nch, GError **error) {
+    playback_get_sample_params(rate, freq, nch);
+    return TRUE;
+}
+
+gboolean audacious_rc_toggle_aot(RemoteObject *obj, gboolean ontop, GError **error) {
+    if (has_x11_connection) {
+        mainwin_set_always_on_top(ontop);
+    }
+    return TRUE;
+}
+
+/* New on Oct9: Queue */
+gboolean audacious_rc_playqueue_add(RemoteObject *obj, gint pos, GError **error) {
+    if (pos < (guint)playlist_get_length(playlist_get_active()))
+        playlist_queue_position(playlist_get_active(), pos);
+    return TRUE;
+}
+
+gboolean audacious_rc_playqueue_remove(RemoteObject *obj, gint pos, GError **error) {
+    if (pos < (guint)playlist_get_length(playlist_get_active()))
+        playlist_queue_remove(playlist_get_active(), pos);
+    return TRUE;
+}
+
+gboolean audacious_rc_playqueue_clear(RemoteObject *obj, GError **error) {
+    playlist_clear_queue(playlist_get_active());
+    return TRUE;
+}
+
+gboolean audacious_rc_get_playqueue_length(RemoteObject *obj, gint *length, GError **error) {
+    *length = playlist_queue_get_length(playlist_get_active());
+    return TRUE;
+}
+
+gboolean audacious_rc_queue_get_list_pos(RemoteObject *obj, gint qpos, gint *pos, GError **error) {
+    if (playback_get_playing())
+        *pos = playlist_get_queue_qposition_number(playlist_get_active(), qpos);
+
+    return TRUE;
+}
+
+gboolean audacious_rc_queue_get_queue_pos(RemoteObject *obj, gint pos, gint *qpos, GError **error) {
+    if (playback_get_playing())
+        *qpos = playlist_get_queue_position_number(playlist_get_active(), pos);
+
+    return TRUE;
+}
+
+gboolean audacious_rc_playqueue_is_queued(RemoteObject *obj, gint pos, gboolean *is_queued, GError **error) {
+    *is_queued = playlist_is_position_queued(playlist_get_active(), pos);
+    return TRUE;
+}
+
+
+
+/* In Progress */
+static void call_add_url(GList *list, gpointer *data) {
+        playlist_add_url(playlist_get_active(), list->data);
+}
+
+gboolean audacious_rc_playlist_add(RemoteObject *obj, gpointer list, GError **error) {
+    g_list_foreach((GList *)list, (GFunc)call_add_url, NULL);
+    return TRUE;
+}
+
+gboolean audacious_rc_playlist_enqueue_to_temp(RemoteObject *obj, char *list, gint num, gboolean enqueue, GError **error) {
+    return TRUE;
+}
+
+gboolean audacious_rc_playlist_ins_url_string(RemoteObject *obj, gchar *url, gint *pos, GError **error) {
+    if (url && strlen(url)) {
+        playlist_ins_url(playlist_get_active(), url, *pos);
+    }
+    return TRUE;
+}
+
+
+/********************************************************************************/
+
 DBusGProxy *audacious_get_dbus_proxy(void)
 {
     DBusGConnection *connection = NULL;
--- a/src/audacious/objects.xml	Sun Oct 28 21:37:05 2007 +0100
+++ b/src/audacious/objects.xml	Mon Oct 29 22:21:42 2007 +0900
@@ -56,37 +56,42 @@
     CMD_PLAYLIST_GET_TUPLE_DATA
     CMD_IS_ADVANCE
     CMD_TOGGLE_ADVANCE
+    CMD_SHOW_PREFS_BOX
+    CMD_SHOW_ABOUT_BOX
+    CMD_SHOW_JTF_BOX
+
+    New:
+    CMD_PLAY_PAUSE
+    CMD_ACTIVATE
+    CMD_GET_SKIN
+    CMD_SET_SKIN
+    CMD_GET_INFO
+    CMD_TOGGLE_AOT
+    CMD_GET_PLAYQUEUE_LENGTH
+    CMD_PLAYQUEUE_ADD
+    CMD_PLAYQUEUE_REMOVE
+    CMD_PLAYQUEUE_CLEAR
+    CMD_PLAYQUEUE_GET_LPOS //CHANGED: get list position by queue position
+    CMD_PLAYQUEUE_GET_QPOS //CHANGED: get queue position by list postion
+    CMD_PLAYQUEUE_IS_QUEUED
+
+
+    In Progress:
+    CMD_PLAYLIST_INS_URL_STRING
+    CMD_PLAYLIST_ADD
+    CMD_PLAYLIST_ENQUEUE_TO_TEMP
 
 
     Remaining:
-    CMD_PLAYLIST_ADD
-    CMD_GET_SKIN
-    CMD_SET_SKIN
-    CMD_GET_INFO
-    CMD_GET_EQ_DATA
-    CMD_SET_EQ_DATA
-    CMD_SHOW_PREFS_BOX
-    CMD_TOGGLE_AOT
-    CMD_SHOW_ABOUT_BOX
+    CMD_PLAYLIST_INS //unnecessary?
+    CMD_GET_EQ_DATA //obsolete
+    CMD_SET_EQ_DATA //obsolete
     CMD_GET_EQ
     CMD_GET_EQ_PREAMP
     CMD_GET_EQ_BAND
     CMD_SET_EQ
     CMD_SET_EQ_PREAMP
     CMD_SET_EQ_BAND
-    CMD_PLAYLIST_INS_URL_STRING
-    CMD_PLAYLIST_INS
-    CMD_PLAY_PAUSE
-    CMD_PLAYQUEUE_ADD
-    CMD_GET_PLAYQUEUE_LENGTH
-    CMD_PLAYQUEUE_REMOVE
-    CMD_ACTIVATE
-    CMD_SHOW_JTF_BOX
-    CMD_PLAYQUEUE_CLEAR
-    CMD_PLAYQUEUE_IS_QUEUED
-    CMD_PLAYQUEUE_GET_POS
-    CMD_PLAYQUEUE_GET_QPOS
-    CMD_PLAYLIST_ENQUEUE_TO_TEMP
 -->
 
 <node name="/">
@@ -358,5 +363,107 @@
         <method name="ToggleShuffle">
             <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
         </method>
+
+        <!-- Show preferences window -->
+        <method name="ShowPrefsBox">
+            <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
+        </method>
+
+        <!-- Show about window -->
+        <method name="ShowAboutBox">
+            <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
+        </method>
+
+        <!-- Show jump to file window -->
+        <method name="ShowJtfBox">
+            <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
+        </method>
+
+        <!-- Either play or pause -->
+        <method name="PlayPause">
+            <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
+        </method>
+
+        <!-- Activate -->
+        <method name="Activate">
+            <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
+        </method>
+
+        <!-- Playqueue get playlist pos -->
+        <method name="QueueGetListPos">
+            <arg type="u" name="qpos"/>
+            <arg type="u" direction="out" name="pos"/>
+        </method>
+
+        <!-- Playqueue get playqueue pos -->
+        <method name="QueueGetQueuePos">
+            <arg type="u" name="pos"/>
+            <arg type="u" direction="out" name="qpos"/>
+        </method>
+
+        <!-- Get skin -->
+        <method name="GetSkin">
+            <!-- Return filename of desired song -->
+            <arg type="s" direction="out" name="skin"/>
+        </method>
+
+        <!-- Set skin -->
+        <method name="SetSkin">
+            <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
+            <!-- Return filename of desired song -->
+            <arg type="s" name="skin"/>
+        </method>
+
+        <!-- Get Info -->
+        <method name="GetInfo">
+            <arg type="i" direction="out" name="rate"/>
+            <arg type="i" direction="out" name="freq"/>
+            <arg type="i" direction="out" name="nch"/>
+        </method>
+
+        <method name="ToggleAot">
+            <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
+            <arg type="b" name="ontop"/>
+        </method>
+
+        <method name="GetPlayqueueLength">
+            <arg type="i" direction="out" name="length"/>
+        </method>
+
+        <method name="PlaylistInsUrlString">
+            <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
+            <arg type="s" name="url"/>
+            <arg type="i" name="pos"/>
+        </method>
+
+        <method name="PlaylistAdd">
+            <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
+            <arg type="s" name="list"/>
+        </method>
+
+        <method name="PlayqueueAdd">
+            <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
+            <arg type="i" name="pos"/>
+        </method>
+
+        <method name="PlayqueueRemove">
+            <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
+            <arg type="i" name="pos"/>
+        </method>
+
+        <method name="PlayqueueClear">
+            <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
+        </method>
+
+        <method name="PlayqueueIsQueued">
+            <arg type="i" name="pos"/>
+            <arg type="b" direction="out" name="is_queued"/>
+        </method>
+
+        <method name="PlaylistEnqueueToTemp">
+            <annotation name="org.freedesktop.DBus.GLib.NoReply" value=""/>
+            <arg type="s" name="url"/>
+        </method>
+
     </interface>
 </node>
--- a/src/audacious/playlist.c	Sun Oct 28 21:37:05 2007 +0100
+++ b/src/audacious/playlist.c	Mon Oct 29 22:21:42 2007 +0900
@@ -1368,7 +1368,7 @@
 playlist_is_position_queued(Playlist *playlist, guint pos)
 {
     PlaylistEntry *entry;
-    GList *tmp;
+    GList *tmp = NULL;
 
     PLAYLIST_LOCK(playlist);
     entry = g_list_nth_data(playlist->entries, pos);
--- a/src/audtool/Makefile	Sun Oct 28 21:37:05 2007 +0100
+++ b/src/audtool/Makefile	Mon Oct 29 22:21:42 2007 +0900
@@ -5,6 +5,7 @@
        audtool_handlers_playlist.c	\
        audtool_handlers_playqueue.c	\
        audtool_handlers_vitals.c	\
+       audtool_handlers_test.c	\
        audtool_report.c
 
 include ../../buildsys.mk
--- a/src/audtool/audtool.h	Sun Oct 28 21:37:05 2007 +0100
+++ b/src/audtool/audtool.h	Mon Oct 29 22:21:42 2007 +0900
@@ -87,8 +87,8 @@
 extern void playqueue_add(gint, gchar **);
 extern void playqueue_remove(gint, gchar **);
 extern void playqueue_is_queued(gint, gchar **);
-extern void playqueue_get_position(gint, gchar **);
-extern void playqueue_get_qposition(gint, gchar **);
+extern void playqueue_get_queue_position(gint, gchar **);
+extern void playqueue_get_list_position(gint, gchar **);
 extern void playqueue_display(gint, gchar **);
 extern void playqueue_length(gint, gchar **);
 extern void playqueue_clear(gint, gchar **);
@@ -108,8 +108,17 @@
 extern void show_preferences_window(gint, gchar **);
 extern void show_jtf_window(gint, gchar **);
 extern void shutdown_audacious_server(gint, gchar **);
+extern void show_about_window(gint, gchar **);
 
 extern void audtool_report(const gchar *str, ...);
 extern void audtool_whine(const gchar *str, ...);
 
+/* test suite */
+extern void test_activate(gint argc, gchar **argv);
+extern void test_enqueue_to_temp(gint argc, gchar **argv);
+extern void test_toggle_aot(gint argc, gchar **argv);
+extern void test_get_skin(gint argc, gchar **argv);
+extern void test_set_skin(gint argc, gchar **argv);
+extern void test_get_info(gint argc, gchar **argv);
+
 #endif
--- a/src/audtool/audtool_handlers_general.c	Sun Oct 28 21:37:05 2007 +0100
+++ b/src/audtool/audtool_handlers_general.c	Mon Oct 29 22:21:42 2007 +0900
@@ -128,6 +128,11 @@
 	audacious_remote_show_prefs_box(dbus_proxy);
 }
 
+void show_about_window(gint argc, gchar **argv)
+{
+	audacious_remote_show_about_box(dbus_proxy);
+}
+
 void show_jtf_window(gint argc, gchar **argv)
 {
 	audacious_remote_show_jtf_box(dbus_proxy);
--- a/src/audtool/audtool_handlers_playqueue.c	Sun Oct 28 21:37:05 2007 +0100
+++ b/src/audtool/audtool_handlers_playqueue.c	Mon Oct 29 22:21:42 2007 +0900
@@ -101,11 +101,15 @@
 		audtool_whine("invalid playlist position %d", i);
 		return;
 	}
-
-	exit(!(audacious_remote_playqueue_is_queued(dbus_proxy, i - 1)));
+    if(audacious_remote_playqueue_is_queued(dbus_proxy, i - 1)) {
+        audtool_report("OK");
+        exit(0);
+    }
+    else
+        exit(1);
 }
 
-void playqueue_get_position(gint argc, gchar **argv)
+void playqueue_get_queue_position(gint argc, gchar **argv)
 {
 	gint i, pos;
 
@@ -124,7 +128,7 @@
 		return;
 	}
 
-	pos = audacious_remote_get_playqueue_position(dbus_proxy, i - 1) + 1;
+	pos = audacious_remote_get_playqueue_queue_position(dbus_proxy, i - 1) + 1;
 
 	if (pos < 1)
 		return;
@@ -132,7 +136,7 @@
 	audtool_report("%d", pos);
 }
 
-void playqueue_get_qposition(gint argc, gchar **argv)
+void playqueue_get_list_position(gint argc, gchar **argv)
 {
 	gint i, pos;
 
@@ -151,7 +155,7 @@
 		return;
 	}
 
-	pos = audacious_remote_get_playqueue_queue_position(dbus_proxy, i - 1) + 1;
+	pos = audacious_remote_get_playqueue_list_position(dbus_proxy, i - 1) + 1;
 
 	if (pos < 1)
 		return;
@@ -174,7 +178,7 @@
 
 	for (ii = 0; ii < i; ii++)
 	{
-		position = audacious_remote_get_playqueue_queue_position(dbus_proxy, ii);
+		position = audacious_remote_get_playqueue_list_position(dbus_proxy, ii);
 		songname = audacious_remote_get_playlist_title(dbus_proxy, position);
 		frames = audacious_remote_get_playlist_time(dbus_proxy, position);
 		length = frames / 1000;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audtool/audtool_handlers_test.c	Mon Oct 29 22:21:42 2007 +0900
@@ -0,0 +1,460 @@
+/*
+ * Audtool2
+ * Copyright (c) 2007 Audacious development team
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <mowgli.h>
+#include <locale.h>
+#include "libaudclient/audctrl.h"
+#include "audtool.h"
+
+void test_activate(gint argc, gchar **argv)
+{
+    audacious_remote_activate(dbus_proxy);
+}
+
+void test_enqueue_to_temp(gint argc, gchar **argv)
+{
+    gint playpos;
+
+	if (argc < 2)
+	{
+		audtool_whine("invalid parameters for %s.", argv[0]);
+		audtool_whine("syntax: %s <position>", argv[0]);
+		return;
+	}
+
+	playpos = atoi(argv[1]);
+
+	if (playpos < 1 || playpos > audacious_remote_get_playlist_length(dbus_proxy))
+	{
+		audtool_whine("invalid playlist position %d", playpos);
+		return;
+	}
+
+    audacious_remote_get_playqueue_queue_position(dbus_proxy, playpos - 1); // xxx playpos - 1?
+}
+
+void test_toggle_aot(gint argc, gchar **argv)
+{
+    gboolean ontop;
+
+	if (argc < 2)
+	{
+		audtool_whine("invalid parameters for %s.", argv[0]);
+		audtool_whine("syntax: %s <boolean>", argv[0]);
+		return;
+	}
+
+	ontop = (gboolean)atoi(argv[1]);
+    printf("ontop = %d\n", ontop);
+    audacious_remote_toggle_aot(dbus_proxy, ontop);
+}
+
+void test_get_skin(gint argc, gchar **argv)
+{
+    gchar *skin = NULL;
+    skin = audacious_remote_get_skin(dbus_proxy);
+    printf("skin = %s\n", skin);
+    g_free(skin);
+}
+
+void test_set_skin(gint argc, gchar **argv)
+{
+	if (argc < 2)
+	{
+		audtool_whine("invalid parameters for %s.", argv[0]);
+		audtool_whine("syntax: %s <skin>", argv[0]);
+		return;
+	}
+    printf("argc = %d\n", argc);
+    printf("skin = %p\n", argv[1]);
+
+
+    if(!argv[1] || !strcmp(argv[1], ""))
+       return;
+
+    audacious_remote_set_skin(dbus_proxy, argv[1]);
+}
+
+void test_get_info(gint argc, gchar **argv)
+{
+    gint rate, freq, nch;
+
+    audacious_remote_get_info(dbus_proxy, &rate, &freq, &nch);
+    printf("rate = %d freq = %d nch = %d\n", rate, freq, nch);
+}
+
+
+
+
+#if 0
+void playlist_reverse(gint argc, gchar **argv)
+{
+	audacious_remote_playlist_prev(dbus_proxy);
+}
+
+void playlist_advance(gint argc, gchar **argv)
+{
+	audacious_remote_playlist_next(dbus_proxy);
+}
+
+void playlist_add_url_string(gint argc, gchar **argv)
+{
+	if (argc < 2)
+	{
+		audtool_whine("invalid parameters for %s.", argv[0]);
+		audtool_whine("syntax: %s <url>", argv[0]);
+		return;
+	}
+
+	audacious_remote_playlist_add_url_string(dbus_proxy, argv[1]);
+}
+
+void playlist_delete(gint argc, gchar **argv)
+{
+	gint playpos;
+
+	if (argc < 2)
+	{
+		audtool_whine("invalid parameters for %s.", argv[0]);
+		audtool_whine("syntax: %s <position>", argv[0]);
+		return;
+	}
+
+	playpos = atoi(argv[1]);
+
+	if (playpos < 1 || playpos > audacious_remote_get_playlist_length(dbus_proxy))
+	{
+		audtool_whine("invalid playlist position %d", playpos);
+		return;
+	}
+
+	audacious_remote_playlist_delete(dbus_proxy, playpos - 1);
+}
+
+void playlist_length(gint argc, gchar **argv)
+{
+	gint i;
+
+	i = audacious_remote_get_playlist_length(dbus_proxy);
+
+	audtool_report("%d", i);
+}
+
+void playlist_song(gint argc, gchar **argv)
+{
+	gint playpos;
+	gchar *song;
+
+	if (argc < 2)
+	{
+		audtool_whine("invalid parameters for %s.", argv[0]);
+		audtool_whine("syntax: %s <position>", argv[0]);
+		return;
+	}
+
+	playpos = atoi(argv[1]);
+
+	if (playpos < 1 || playpos > audacious_remote_get_playlist_length(dbus_proxy))
+	{
+		audtool_whine("invalid playlist position %d", playpos);
+		return;
+	}
+
+	song = audacious_remote_get_playlist_title(dbus_proxy, playpos - 1);
+
+	audtool_report("%s", song);
+}
+
+
+void playlist_song_length(gint argc, gchar **argv)
+{
+	gint playpos, frames, length;
+
+	if (argc < 2)
+	{
+		audtool_whine("invalid parameters for %s.", argv[0]);
+		audtool_whine("syntax: %s <position>", argv[0]);
+		return;
+	}
+
+	playpos = atoi(argv[1]);
+
+	if (playpos < 1 || playpos > audacious_remote_get_playlist_length(dbus_proxy))
+	{
+		audtool_whine("invalid playlist position %d", playpos);
+		return;
+	}
+
+	frames = audacious_remote_get_playlist_time(dbus_proxy, playpos - 1);
+	length = frames / 1000;
+
+	audtool_report("%d:%.2d", length / 60, length % 60);
+}
+
+void playlist_song_length_seconds(gint argc, gchar **argv)
+{
+	gint playpos, frames, length;
+
+	if (argc < 2)
+	{
+		audtool_whine("invalid parameters for %s.", argv[0]);
+		audtool_whine("syntax: %s <position>", argv[0]);
+		return;
+	}
+
+	playpos = atoi(argv[1]);
+
+	if (playpos < 1 || playpos > audacious_remote_get_playlist_length(dbus_proxy))
+	{
+		audtool_whine("invalid playlist position %d", playpos);
+		return;
+	}
+
+	frames = audacious_remote_get_playlist_time(dbus_proxy, playpos - 1);
+	length = frames / 1000;
+
+	audtool_report("%d", length);
+}
+
+void playlist_song_length_frames(gint argc, gchar **argv)
+{
+	gint playpos, frames;
+
+	if (argc < 2)
+	{
+		audtool_whine("invalid parameters for %s.", argv[0]);
+		audtool_whine("syntax: %s <position>", argv[0]);
+		return;
+	}
+
+	playpos = atoi(argv[1]);
+
+	if (playpos < 1 || playpos > audacious_remote_get_playlist_length(dbus_proxy))
+	{
+		audtool_whine("invalid playlist position %d", playpos);
+		return;
+	}
+
+	frames = audacious_remote_get_playlist_time(dbus_proxy, playpos - 1);
+
+	audtool_report("%d", frames);
+}
+
+void playlist_display(gint argc, gchar **argv)
+{
+	gint i, ii, frames, length, total;
+	gchar *songname;
+	gchar *fmt = NULL, *p;
+	gint column;
+
+	i = audacious_remote_get_playlist_length(dbus_proxy);
+
+	audtool_report("%d track%s.", i, i != 1 ? "s" : "");
+
+	total = 0;
+
+	for (ii = 0; ii < i; ii++)
+	{
+		songname = audacious_remote_get_playlist_title(dbus_proxy, ii);
+		frames = audacious_remote_get_playlist_time(dbus_proxy, ii);
+		length = frames / 1000;
+		total += length;
+
+		/* adjust width for multi byte characters */
+		column = 60;
+		if(songname){
+			p = songname;
+			while(*p){
+				gint stride;
+				stride = g_utf8_next_char(p) - p;
+				if(g_unichar_iswide(g_utf8_get_char(p))
+#if ( (GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION >= 12) )
+				   || g_unichar_iswide_cjk(g_utf8_get_char(p))
+#endif
+                                ){
+					column += (stride - 2);
+				}
+				else {
+					column += (stride - 1);
+				}
+				p = g_utf8_next_char(p);
+			}
+
+		}
+
+		fmt = g_strdup_printf("%%4d | %%-%ds | %%d:%%.2d", column);
+		audtool_report(fmt, ii + 1, songname, length / 60, length % 60);
+		g_free(fmt);
+	}
+
+	audtool_report("Total length: %d:%.2d", total / 60, total % 60);
+}
+
+void playlist_position(gint argc, gchar **argv)
+{
+	gint i;
+
+	i = audacious_remote_get_playlist_pos(dbus_proxy);
+
+	audtool_report("%d", i + 1);
+}
+
+void playlist_song_filename(gint argc, gchar **argv)
+{
+	gint i;
+
+	if (argc < 2)
+	{
+		audtool_whine("invalid parameters for %s.", argv[0]);
+		audtool_whine("syntax: %s <position>", argv[0]);
+		return;
+	}
+
+	i = atoi(argv[1]);
+
+	if (i < 1 || i > audacious_remote_get_playlist_length(dbus_proxy))
+	{
+		audtool_whine("invalid playlist position %d", i);
+		return;
+	}
+
+	audtool_report("%s", audacious_remote_get_playlist_file(dbus_proxy, i - 1));
+}
+
+void playlist_jump(gint argc, gchar **argv)
+{
+	gint i;
+
+	if (argc < 2)
+	{
+		audtool_whine("invalid parameters for %s.", argv[0]);
+		audtool_whine("syntax: %s <position>", argv[0]);
+		return;
+	}
+
+	i = atoi(argv[1]);
+
+	if (i < 1 || i > audacious_remote_get_playlist_length(dbus_proxy))
+	{
+		audtool_whine("invalid playlist position %d", i);
+		return;
+	}
+
+	audacious_remote_set_playlist_pos(dbus_proxy, i - 1);
+}
+
+void playlist_clear(gint argc, gchar **argv)
+{
+	audacious_remote_playlist_clear(dbus_proxy);
+}
+
+void playlist_repeat_status(gint argc, gchar **argv)
+{
+	if (audacious_remote_is_repeat(dbus_proxy))
+	{
+		audtool_report("on");
+		return;
+	}
+	else
+	{
+		audtool_report("off");
+		return;
+	}
+}
+
+void playlist_repeat_toggle(gint argc, gchar **argv)
+{
+	audacious_remote_toggle_repeat(dbus_proxy);
+}
+
+void playlist_shuffle_status(gint argc, gchar **argv)
+{
+	if (audacious_remote_is_shuffle(dbus_proxy))
+	{
+		audtool_report("on");
+		return;
+	}
+	else
+	{
+		audtool_report("off");
+		return;
+	}
+}
+
+void playlist_shuffle_toggle(gint argc, gchar **argv)
+{
+	audacious_remote_toggle_shuffle(dbus_proxy);
+}
+
+void playlist_tuple_field_data(gint argc, gchar **argv)
+{
+	gint i;
+	gpointer data;
+
+	if (argc < 3)
+	{
+		audtool_whine("invalid parameters for %s.", argv[0]);
+		audtool_whine("syntax: %s <fieldname> <position>", argv[0]);
+		audtool_whine("  - fieldname example choices: performer, album_name,");
+		audtool_whine("      track_name, track_number, year, date, genre, comment,");
+		audtool_whine("      file_name, file_ext, file_path, length, formatter,");
+		audtool_whine("      custom, mtime");
+		return;
+	}
+
+	i = atoi(argv[2]);
+
+	if (i < 1 || i > audacious_remote_get_playlist_length(dbus_proxy))
+	{
+		audtool_whine("invalid playlist position %d", i);
+		return;
+	}
+
+	if (!(data = audacious_get_tuple_field_data(dbus_proxy, argv[1], i - 1)))
+	{
+		return;
+	}
+	
+	if (!g_ascii_strcasecmp(argv[1], "track_number") || !g_ascii_strcasecmp(argv[1], "year") || !g_ascii_strcasecmp(argv[1], "length") || !g_ascii_strcasecmp(argv[1], "mtime"))
+	{
+		if (*(gint *)data > 0)
+		{
+			audtool_report("%d", *(gint *)data);
+		}
+		return;
+	}
+
+	audtool_report("%s", (gchar *)data);
+}
+#endif
--- a/src/audtool/audtool_main.c	Sun Oct 28 21:37:05 2007 +0100
+++ b/src/audtool/audtool_main.c	Mon Oct 29 22:21:42 2007 +0900
@@ -77,8 +77,8 @@
 	{"playqueue-add", playqueue_add, "adds a song to the playqueue", 1},
 	{"playqueue-remove", playqueue_remove, "removes a song from the playqueue", 1},
 	{"playqueue-is-queued", playqueue_is_queued, "returns OK if a song is queued", 1},
-	{"playqueue-get-position", playqueue_get_position, "returns the queue position of a song in the playlist", 1},
-	{"playqueue-get-qposition", playqueue_get_qposition, "returns the playlist position of a song in the queue", 1},
+	{"playqueue-get-queue-position", playqueue_get_queue_position, "returns the playqueue position of a song in the given poition in the playlist", 1},
+	{"playqueue-get-list-position", playqueue_get_list_position, "returns the playlist position of a song in the given position in the playqueue", 1},
 	{"playqueue-length", playqueue_length, "returns the length of the playqueue", 0},
 	{"playqueue-display", playqueue_display, "returns a list of currently-queued songs", 0},
 	{"playqueue-clear", playqueue_clear, "clears the playqueue", 0},
@@ -100,12 +100,23 @@
 	{"mainwin-show", mainwin_show, "shows/hides the main window", 1},
 	{"playlist-show", playlist_show, "shows/hides the playlist window", 1},
 	{"equalizer-show", equalizer_show, "shows/hides the equalizer window", 1},
-	{"preferences", show_preferences_window, "shows/hides the preferences window", 0},
+	{"preferences", show_preferences_window, "shows the preferences window", 0},
+	{"about", show_about_window, "shows the about window", 0},
 	{"jumptofile", show_jtf_window, "shows the jump to file window", 0},
 	{"shutdown", shutdown_audacious_server, "shuts down audacious", 0},
 	{"<sep>", NULL, "Help system", 0},
 	{"list-handlers", get_handlers_list, "shows handlers list", 0},
 	{"help", get_handlers_list, "shows handlers list", 0},
+
+    /* test suite */
+	{"<sep>", NULL, "Test suite", 0},
+	{"activate", test_activate, "activate", 0},
+	{"playlist-enqueue-to-temp", test_enqueue_to_temp, "enqueue_to_temp", 1},
+	{"toggle-aot", test_toggle_aot, "specify allways on top or not", 1}, // xxx need to be improved.
+    {"get-skin", test_get_skin, "get skin", 0},
+    {"set-skin", test_set_skin, "set skin", 1},
+    {"get-info", test_get_info, "get info", 0},
+
 	{NULL, NULL, NULL, 0}
 };
 
--- a/src/libaudclient/audctrl.c	Sun Oct 28 21:37:05 2007 +0100
+++ b/src/libaudclient/audctrl.c	Mon Oct 29 22:21:42 2007 +0900
@@ -21,6 +21,7 @@
 
 #include <stdlib.h>
 #include <glib.h>
+#include <string.h>
 #include <dbus/dbus-glib.h>
 #include "audacious/dbus.h"
 #include "audacious/dbus-client-bindings.h"
@@ -37,9 +38,29 @@
  *
  * Sends a playlist to audacious.
  **/
-void audacious_remote_playlist(DBusGProxy *proxy, gchar **list, gint num,
-                               gboolean enqueue) {
-//XXX
+void audacious_remote_playlist(DBusGProxy *proxy, gchar **list, gint num, gboolean enqueue) {
+    GList *glist = NULL;
+    gchar **data = list;
+
+    g_return_if_fail(list != NULL);
+    g_return_if_fail(num > 0);
+
+    if (!enqueue)
+        audacious_remote_playlist_clear(proxy);
+
+    // construct a GList
+    while(data) {
+        glist = g_list_append(glist, (gpointer)data);
+        data++;
+    }
+
+    org_atheme_audacious_playlist_add(proxy, (gpointer)glist, &error);
+
+    g_list_free(glist);
+    glist = NULL;
+
+    if (!enqueue)
+        audacious_remote_play(proxy);
 }
 
 /**
@@ -64,7 +85,7 @@
 void audacious_remote_playlist_add(DBusGProxy *proxy, GList *list) {
 	GList *iter;
 	for (iter = list; iter != NULL; iter = g_list_next(iter))
-		org_atheme_audacious_add(proxy, iter->data, &error);
+		org_atheme_audacious_playlist_add(proxy, iter->data, &error);
 	g_clear_error(&error);
 }
 
@@ -76,7 +97,8 @@
  * Deletes a playlist entry.
  **/
 void audacious_remote_playlist_delete(DBusGProxy *proxy, guint pos) {
-//XXX
+    org_atheme_audacious_delete(proxy, pos, &error);
+    g_clear_error(&error);
 }
 
 /**
@@ -340,8 +362,10 @@
  * Return value: A path to the currently selected skin.
  **/
 gchar *audacious_remote_get_skin(DBusGProxy *proxy) {
-//XXX
-    return NULL;
+    gchar *skin = NULL;
+    org_atheme_audacious_get_skin (proxy, &skin, &error); // xxx
+    g_clear_error(&error);
+    return skin;
 }
 
 /**
@@ -352,7 +376,8 @@
  * Tells audacious to start using the skinfile provided.
  **/
 void audacious_remote_set_skin(DBusGProxy *proxy, gchar *skinfile) {
-//XXX
+    org_atheme_audacious_set_skin(proxy, skinfile, &error);
+	g_clear_error(&error);
 }
 
 /**
@@ -506,7 +531,19 @@
  * Tells audacious to show the preferences pane.
  **/
 void audacious_remote_show_prefs_box(DBusGProxy *proxy) {
-//XXX
+    org_atheme_audacious_show_prefs_box(proxy, &error);
+    g_clear_error(&error);
+}
+
+/**
+ * audacious_remote_show_about_box:
+ * @proxy: DBus proxy for audacious
+ *
+ * Tells audacious to show the about box.
+ **/
+void audacious_remote_show_about_box(DBusGProxy *proxy) {
+    org_atheme_audacious_show_about_box(proxy, &error);
+    g_clear_error(&error);
 }
 
 /**
@@ -517,7 +554,8 @@
  * Tells audacious to toggle the always-on-top feature.
  **/
 void audacious_remote_toggle_aot(DBusGProxy *proxy, gboolean ontop) {
-//XXX
+    org_atheme_audacious_toggle_aot(proxy, ontop, &error);
+	g_clear_error(&error);
 }
 
 /**
@@ -733,7 +771,7 @@
  * Tells audacious to either play or pause.
  **/
 void audacious_remote_play_pause(DBusGProxy *proxy) {
-//XXX
+    org_atheme_audacious_play_pause(proxy, &error);
 }
 
 /**
@@ -746,7 +784,8 @@
  **/
 void audacious_remote_playlist_ins_url_string(DBusGProxy *proxy,
                                               gchar *string, guint pos) {
-//XXX
+    org_atheme_audacious_playlist_ins_url_string (proxy, string, pos, &error);
+    g_clear_error(&error);
 }
 
 /**
@@ -757,7 +796,8 @@
  * Tells audacious to add a playlist entry to the playqueue.
  **/
 void audacious_remote_playqueue_add(DBusGProxy *proxy, guint pos) {
-//XXX
+    org_atheme_audacious_playqueue_add (proxy, pos, &error);
+    g_clear_error(&error);
 }
 
 /**
@@ -768,7 +808,8 @@
  * Tells audacious to remove a playlist entry from the playqueue.
  **/
 void audacious_remote_playqueue_remove(DBusGProxy *proxy, guint pos) {
-//XXX
+    org_atheme_audacious_playqueue_remove (proxy, pos, &error);
+    g_clear_error(&error);
 }
 
 /**
@@ -820,7 +861,8 @@
  * Tells audacious to display the main window and become the selected window.
  **/
 void audacious_remote_activate(DBusGProxy *proxy) {
-//XXX
+    org_atheme_audacious_activate(proxy, &error);
+    g_clear_error(&error);
 }
 
 /**
@@ -830,7 +872,8 @@
  * Tells audacious to show the Jump-to-File pane.
  **/
 void audacious_remote_show_jtf_box(DBusGProxy *proxy) {
-//XXX
+    org_atheme_audacious_show_jtf_box(proxy, &error);
+    g_clear_error(&error);
 }
 
 /**
@@ -840,7 +883,8 @@
  * Tells audacious to clear the playqueue.
  **/
 void audacious_remote_playqueue_clear(DBusGProxy *proxy) {
-//XXX
+    org_atheme_audacious_playqueue_clear(proxy, &error);
+    g_clear_error(&error);
 }
 
 /**
@@ -853,22 +897,10 @@
  * Return value: TRUE if yes, FALSE otherwise.
  **/
 gboolean audacious_remote_playqueue_is_queued(DBusGProxy *proxy, guint pos) {
-//XXX
-    return FALSE;
-}
-
-/**
- * audacious_remote_get_playqueue_position:
- * @proxy: DBus proxy for audacious
- * @pos: Position to check queue for.
- *
- * Queries audacious about what the playqueue position is for a playlist entry.
- *
- * Return value: TRUE if yes, FALSE otherwise.
- **/
-gint audacious_remote_get_playqueue_position(DBusGProxy *proxy, guint pos) {
-//XXX
-    return 0;
+    gboolean is_queued;
+    org_atheme_audacious_playqueue_is_queued (proxy, pos, &is_queued, &error);
+    g_clear_error(&error);
+    return is_queued;
 }
 
 /**
@@ -876,14 +908,31 @@
  * @proxy: DBus proxy for audacious
  * @pos: Position to check queue for.
  *
+ * Queries audacious about what the playqueue position is for a playlist entry.
+ *
+ * Return value: the playqueue position for a playlist entry
+ **/
+gint audacious_remote_get_playqueue_queue_position(DBusGProxy *proxy, guint pos) {
+    guint qpos = 0;
+    org_atheme_audacious_queue_get_queue_pos (proxy, pos, &qpos, &error);
+    g_clear_error(&error);
+    return qpos;
+}
+
+/**
+ * audacious_remote_get_playqueue_list_position:
+ * @proxy: DBus proxy for audacious
+ * @pos: Position to check queue for.
+ *
  * Queries audacious about what the playlist position is for a playqueue entry.
  *
- * Return value: TRUE if yes, FALSE otherwise.
+ * Return value: the playlist position for a playqueue entry
  **/
-gint audacious_remote_get_playqueue_queue_position(DBusGProxy *proxy,
-                                                   guint pos) {
-//XXX
-    return 0;
+gint audacious_remote_get_playqueue_list_position(DBusGProxy *proxy, guint qpos) {
+    guint pos = 0;
+    org_atheme_audacious_queue_get_list_pos (proxy, qpos, &pos, &error);
+    g_clear_error(&error);
+    return pos;
 }
 
 /**
@@ -895,7 +944,8 @@
  **/
 void audacious_remote_playlist_enqueue_to_temp(DBusGProxy *proxy,
                                                gchar *string) {
-//XXX
+    org_atheme_audacious_playlist_enqueue_to_temp(proxy, string, &error);
+	g_clear_error(&error);
 }
 
 /**
@@ -911,5 +961,7 @@
 gchar *audacious_get_tuple_field_data(DBusGProxy *proxy, gchar *field,
                                       guint pos) {
 //XXX
+	g_clear_error(&error);
     return NULL;
 }
+
--- a/src/libaudclient/audctrl.h	Sun Oct 28 21:37:05 2007 +0100
+++ b/src/libaudclient/audctrl.h	Mon Oct 29 22:21:42 2007 +0900
@@ -106,9 +106,8 @@
     void audacious_remote_show_jtf_box(DBusGProxy *proxy);
     void audacious_remote_playqueue_clear(DBusGProxy *proxy);
     gboolean audacious_remote_playqueue_is_queued(DBusGProxy *proxy, guint pos);
-    gint audacious_remote_get_playqueue_position(DBusGProxy *proxy, guint pos);
-    gint audacious_remote_get_playqueue_queue_position(DBusGProxy *proxy,
-                                                       guint pos);
+    gint audacious_remote_get_playqueue_list_position(DBusGProxy *proxy, guint qpos);
+    gint audacious_remote_get_playqueue_queue_position(DBusGProxy *proxy, guint pos);
 
 /* Added in Audacious 1.2 */
     void audacious_set_session_uri(DBusGProxy *proxy, gchar *uri);
@@ -120,6 +119,8 @@
                                                    gchar *string);
     gchar *audacious_get_tuple_field_data(DBusGProxy *proxy, gchar *field,
                                           guint pos);
+/* Added in Audacious 1.4 */
+    void audacious_remote_show_about_box(DBusGProxy *proxy);
 
 #ifdef __cplusplus
 };