changeset 1644:a556e7ff1871 trunk

[svn] - keep filepopup code in the core for now - add README noting that this code sucks - still a ways to go
author nenolod
date Thu, 07 Sep 2006 20:27:46 -0700
parents 1a525bd78cf0
children 67f6cfc251de
files ChangeLog Plugins/UserInterface/wa2gui/Makefile Plugins/UserInterface/wa2gui/README Plugins/UserInterface/wa2gui/equalizer.c Plugins/UserInterface/wa2gui/equalizer.h Plugins/UserInterface/wa2gui/filepopup.c Plugins/UserInterface/wa2gui/filepopup.h Plugins/UserInterface/wa2gui/mainwin.c Plugins/UserInterface/wa2gui/mainwin.h Plugins/UserInterface/wa2gui/playlist.c Plugins/UserInterface/wa2gui/playlist.h Plugins/UserInterface/wa2gui/ui_playlist.h Plugins/UserInterface/wa2gui/widgets/Makefile Plugins/UserInterface/wa2gui/widgets/eq_graph.c Plugins/UserInterface/wa2gui/widgets/eq_graph.h Plugins/UserInterface/wa2gui/widgets/eq_slider.c Plugins/UserInterface/wa2gui/widgets/eq_slider.h Plugins/UserInterface/wa2gui/widgets/hslider.c Plugins/UserInterface/wa2gui/widgets/hslider.h Plugins/UserInterface/wa2gui/widgets/menurow.c Plugins/UserInterface/wa2gui/widgets/menurow.h Plugins/UserInterface/wa2gui/widgets/monostereo.c Plugins/UserInterface/wa2gui/widgets/monostereo.h Plugins/UserInterface/wa2gui/widgets/number.c Plugins/UserInterface/wa2gui/widgets/number.h Plugins/UserInterface/wa2gui/widgets/pbutton.c Plugins/UserInterface/wa2gui/widgets/pbutton.h Plugins/UserInterface/wa2gui/widgets/playlist_list.c Plugins/UserInterface/wa2gui/widgets/playlist_list.h Plugins/UserInterface/wa2gui/widgets/playlist_slider.c Plugins/UserInterface/wa2gui/widgets/playlist_slider.h Plugins/UserInterface/wa2gui/widgets/playstatus.c Plugins/UserInterface/wa2gui/widgets/playstatus.h Plugins/UserInterface/wa2gui/widgets/sbutton.c Plugins/UserInterface/wa2gui/widgets/sbutton.h Plugins/UserInterface/wa2gui/widgets/skin.c Plugins/UserInterface/wa2gui/widgets/skin.h Plugins/UserInterface/wa2gui/widgets/svis.c Plugins/UserInterface/wa2gui/widgets/svis.h Plugins/UserInterface/wa2gui/widgets/tbutton.c Plugins/UserInterface/wa2gui/widgets/tbutton.h Plugins/UserInterface/wa2gui/widgets/textbox.c Plugins/UserInterface/wa2gui/widgets/textbox.h Plugins/UserInterface/wa2gui/widgets/vis.c Plugins/UserInterface/wa2gui/widgets/vis.h Plugins/UserInterface/wa2gui/widgets/widget.c Plugins/UserInterface/wa2gui/widgets/widget.h Plugins/UserInterface/wa2gui/widgets/widgetcore.h
diffstat 48 files changed, 6557 insertions(+), 676 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Sep 07 19:57:27 2006 -0700
+++ b/ChangeLog	Thu Sep 07 20:27:46 2006 -0700
@@ -1,3 +1,11 @@
+2006-09-08 02:57:27 +0000  William Pitcock <nenolod@nenolod.net>
+  revision [2217]
+  - copy the WA2GUI code into a Plugin shell
+  
+
+  Changes:        Modified:
+
+
 2006-09-08 01:33:19 +0000  William Pitcock <nenolod@nenolod.net>
   revision [2215]
   - use gdk_drawable_get_size() instead
--- a/Plugins/UserInterface/wa2gui/Makefile	Thu Sep 07 19:57:27 2006 -0700
+++ b/Plugins/UserInterface/wa2gui/Makefile	Thu Sep 07 20:27:46 2006 -0700
@@ -1,14 +1,16 @@
 include ../../../mk/rules.mk
 include ../../../mk/init.mk
 
-OBJECTIVE_LIBS = libwa2_gui$(SHARED_SUFFIX)
+OBJECTIVE_LIBS = libwa2gui$(SHARED_SUFFIX)
+
+SUBDIRS = widgets
 
 noinst_HEADERS = coreaudio.h
 
 LIBDIR = $(plugindir)/$(USERINTERFACE_PLUGIN_DIR)
 
 LIBADD = $(GTK_LIBS)
-SOURCES = mainwin.c equalizer.c playlist.c filepopup.c wa2gui.c
+SOURCES = mainwin.c equalizer.c playlist.c wa2gui.c
 
 OBJECTS = ${SOURCES:.c=.o}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/README	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,9 @@
+This is the XMMS/BMP WA2GUI implementation.
+
+It is broken on everything other than X11, so don't expect it to work on your platform.
+Thanks!
+
+If you want to fix or rewrite it, be our guest!
+
+Toodles now.
+  - audacious team
--- a/Plugins/UserInterface/wa2gui/equalizer.c	Thu Sep 07 19:57:27 2006 -0700
+++ b/Plugins/UserInterface/wa2gui/equalizer.c	Thu Sep 07 20:27:46 2006 -0700
@@ -27,6 +27,7 @@
 #endif
 
 #include "equalizer.h"
+#include "playlist.h"
 
 #include <glib.h>
 #include <glib/gi18n.h>
@@ -35,21 +36,20 @@
 #include <math.h>
 #include <string.h>
 
-#include "platform/smartinclude.h"
-#include "widgets/widgetcore.h"
-#include "dock.h"
-#include "hints.h"
-#include "input.h"
-#include "main.h"
-#include "playlist.h"
-#include "ui_playlist.h"
-#include "util.h"
-#include "output.h"
+#include "audacious/platform/smartinclude.h"
+#include "audacious/widgets/widgetcore.h"
+#include "audacious/dock.h"
+#include "audacious/hints.h"
+#include "audacious/input.h"
+#include "audacious/main.h"
+#include "audacious/playlist.h"
+#include "audacious/util.h"
+#include "audacious/output.h"
 
 #include "libaudacious/rcfile.h"
 #include "libaudacious/vfs.h"
 
-#include "images/audacious_eq.xpm"
+#include "audacious/images/audacious_eq.xpm"
 
 enum PresetViewCols {
     PRESET_VIEW_COL_NAME,
--- a/Plugins/UserInterface/wa2gui/equalizer.h	Thu Sep 07 19:57:27 2006 -0700
+++ b/Plugins/UserInterface/wa2gui/equalizer.h	Thu Sep 07 20:27:46 2006 -0700
@@ -25,7 +25,7 @@
 #include <glib.h>
 #include <gtk/gtk.h>
 
-#include "widgets/widgetcore.h"
+#include "audacious/widgets/widgetcore.h"
 
 #define EQUALIZER_HEIGHT         (gint)(cfg.equalizer_shaded ? 14 : 116)
 #define EQUALIZER_WIDTH          (gint)275
--- a/Plugins/UserInterface/wa2gui/filepopup.c	Thu Sep 07 19:57:27 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,512 +0,0 @@
-/*
- * Audacious: A cross-platform multimedia player
- * Copyright (c) 2006 William Pitcock, Tony Vroon, George Averill,
- *                    Giacomo Lozito, Derek Pomery and Yoshiki Yazawa.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <gtk/gtk.h>
-#include <glade/glade.h>
-#include <string.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "glade.h"
-
-#include "plugin.h"
-#include "pluginenum.h"
-#include "input.h"
-#include "effect.h"
-#include "general.h"
-#include "output.h"
-#include "visualization.h"
-
-#include "main.h"
-#include "urldecode.h"
-#include "util.h"
-#include "dnd.h"
-#include "libaudacious/configdb.h"
-#include "libaudacious/titlestring.h"
-
-#include "playlist.h"
-
-#include "mainwin.h"
-#include "ui_playlist.h"
-#include "skinwin.h"
-#include "build_stamp.h"
-#include "ui_fileinfo.h"
-#include "ui_playlist.h"
-
-GtkWidget *fileinfo_win;
-GtkWidget *filepopup_win;
-GdkPixbuf *filepopup_pixbuf;
-
-static void
-fileinfo_entry_set_text(const char *entry, const char *text)
-{
-	GladeXML *xml = g_object_get_data(G_OBJECT(fileinfo_win), "glade-xml");
-	GtkWidget *widget = glade_xml_get_widget(xml, entry);
-
-	if (xml == NULL || widget == NULL)
-		return;
-
-	gtk_entry_set_text(GTK_ENTRY(widget), text);
-}
-
-static void
-fileinfo_entry_set_text_free(const char *entry, char *text)
-{
-	GladeXML *xml = g_object_get_data(G_OBJECT(fileinfo_win), "glade-xml");
-	GtkWidget *widget = glade_xml_get_widget(xml, entry);
-
-	if (xml == NULL || widget == NULL)
-		return;
-
-	gtk_entry_set_text(GTK_ENTRY(widget), text);
-
-	g_free(text);
-}
-
-static void
-fileinfo_entry_set_image(const char *entry, const char *text)
-{
-	GladeXML *xml = g_object_get_data(G_OBJECT(fileinfo_win), "glade-xml");
-	GtkWidget *widget = glade_xml_get_widget(xml, entry);
-	GdkPixbuf *pixbuf;
-
-	if (xml == NULL || widget == NULL)
-		return;
-
-	pixbuf = gdk_pixbuf_new_from_file(text, NULL);
-
-	if (pixbuf == NULL)
-		return;
-
-	if (gdk_pixbuf_get_height(GDK_PIXBUF(pixbuf)) > 150)
-	{
-		GdkPixbuf *pixbuf2 = gdk_pixbuf_scale_simple(GDK_PIXBUF(pixbuf), 150, 150, GDK_INTERP_BILINEAR);
-		g_object_unref(G_OBJECT(pixbuf));
-		pixbuf = pixbuf2;
-	}
-
-	gtk_image_set_from_pixbuf(GTK_IMAGE(widget), GDK_PIXBUF(pixbuf));
-	g_object_unref(G_OBJECT(pixbuf));
-}
-
-static void
-filepopup_entry_set_text(const char *entry, const char *text)
-{
-	GladeXML *xml = g_object_get_data(G_OBJECT(filepopup_win), "glade-xml");
-	GtkWidget *widget = glade_xml_get_widget(xml, entry);
-
-	if (xml == NULL || widget == NULL)
-		return;
-
-	gtk_label_set_text(GTK_LABEL(widget), text);
-}
-
-static void
-filepopup_entry_set_image(const char *entry, const char *text)
-{
-	GladeXML *xml = g_object_get_data(G_OBJECT(filepopup_win), "glade-xml");
-	GtkWidget *widget = glade_xml_get_widget(xml, entry);
-	GdkPixbuf *pixbuf;
-
-	if (xml == NULL || widget == NULL)
-		return;
-
-	pixbuf = gdk_pixbuf_new_from_file(text, NULL);
-
-	if (pixbuf == NULL)
-		return;
-
-	if (gdk_pixbuf_get_height(GDK_PIXBUF(pixbuf)) > 150)
-	{
-		GdkPixbuf *pixbuf2 = gdk_pixbuf_scale_simple(GDK_PIXBUF(pixbuf), 150, 150, GDK_INTERP_BILINEAR);
-		g_object_unref(G_OBJECT(pixbuf));
-		pixbuf = pixbuf2;
-	}
-
-	gtk_image_set_from_pixbuf(GTK_IMAGE(widget), GDK_PIXBUF(pixbuf));
-	g_object_unref(G_OBJECT(pixbuf));
-}
-
-static void
-filepopup_entry_set_text_free(const char *entry, char *text)
-{
-	GladeXML *xml = g_object_get_data(G_OBJECT(filepopup_win), "glade-xml");
-	GtkWidget *widget = glade_xml_get_widget(xml, entry);
-
-	if (xml == NULL || widget == NULL)
-		return;
-
-	gtk_label_set_text(GTK_LABEL(widget), text);
-
-	g_free(text);
-}
-
-static gboolean
-filepopup_pointer_check_iter(gpointer unused)
-{
-	gint x, y, pos;
-	TitleInput *tuple;
-	static gint prev_x = 0, prev_y = 0, ctr = 0, prev_pos = -1;
-	gboolean skip = FALSE;
-	GdkWindow *win;
-
-	win = gdk_window_at_pointer(NULL, NULL);
-	gdk_window_get_pointer(GDK_WINDOW(playlistwin->window), &x, &y, NULL);
-	pos = playlist_list_get_playlist_position(playlistwin_list, x, y);
-
-	if (win == NULL
-		|| cfg.show_filepopup_for_tuple == FALSE
-		|| playlistwin_list->pl_tooltips == FALSE
-		|| pos != prev_pos
-		|| win != GDK_WINDOW(playlistwin->window)
-		|| playlistwin_is_shaded())
-	{
-		prev_pos = pos;
-		ctr = 0;
-                if ( filepopup_win->window != NULL &&
-                     gdk_window_is_viewable(GDK_WINDOW(filepopup_win->window)) )
-                  filepopup_hide(NULL);
-		return TRUE;
-	}
-
-	if (prev_x == x && prev_y == y)
-		ctr++;
-	else
-	{
-		ctr = 0;
-		prev_x = x;
-		prev_y = y;
-		filepopup_hide(NULL);
-		return TRUE;
-	}
-
-	if (filepopup_win->window == NULL)
-		skip = TRUE;
-
-        if (ctr >= 20 && (skip == TRUE || gdk_window_is_viewable(GDK_WINDOW(filepopup_win->window)) != TRUE))
-        {
-		if (pos == -1)
-  		{
-			filepopup_hide(NULL);
-			return TRUE;
-	    	}
-
-		prev_pos = pos;
-
-		tuple = playlist_get_tuple(pos);
-		filepopup_show_for_tuple(tuple);
-	}
-
-	return TRUE;
-}
-
-void fileinfo_hide(gpointer unused)
-{
-	gtk_widget_hide(fileinfo_win);
-
-	/* Clear it out. */
-	fileinfo_entry_set_text("entry_title", "");
-	fileinfo_entry_set_text("entry_artist", "");
-	fileinfo_entry_set_text("entry_album", "");
-	fileinfo_entry_set_text("entry_comment", "");
-	fileinfo_entry_set_text("entry_genre", "");
-	fileinfo_entry_set_text("entry_year", "");
-	fileinfo_entry_set_text("entry_track", "");
-	fileinfo_entry_set_text("entry_location", "");
-
-	fileinfo_entry_set_image("image_artwork", DATA_DIR "/images/audio.png");
-}
-
-void filepopup_hide(gpointer unused)
-{
-	gtk_widget_hide(filepopup_win);
-
-	filepopup_entry_set_text("label_title", "");
-	filepopup_entry_set_text("label_artist", "");
-	filepopup_entry_set_text("label_album", "");
-	filepopup_entry_set_text("label_genre", "");
-	filepopup_entry_set_text("label_track", "");
-	filepopup_entry_set_text("label_year", "");
-	filepopup_entry_set_text("label_length", "");
-
-	filepopup_entry_set_image("image_artwork", DATA_DIR "/images/audio.png");
-
-	gtk_window_resize(GTK_WINDOW(filepopup_win), 1, 1);
-}
-
-void
-create_fileinfo_window(void)
-{
-	const gchar *glade_file = DATA_DIR "/glade/fileinfo.glade";
-	GladeXML *xml;
-	GtkWidget *widget;
-
-	xml = glade_xml_new_or_die(_("Track Information Window"), glade_file, NULL, NULL);
-
-	glade_xml_signal_autoconnect(xml);
-
-	fileinfo_win = glade_xml_get_widget(xml, "fileinfo_win");
-	g_object_set_data(G_OBJECT(fileinfo_win), "glade-xml", xml);
-	gtk_window_set_transient_for(GTK_WINDOW(fileinfo_win), GTK_WINDOW(mainwin));
-
-	widget = glade_xml_get_widget(xml, "image_artwork");
-	gtk_image_set_from_file(GTK_IMAGE(widget), DATA_DIR "/images/audio.png");
-
-	widget = glade_xml_get_widget(xml, "btn_close");
-	g_signal_connect(G_OBJECT(widget), "clicked", (GCallback) fileinfo_hide, NULL);
-}
-
-void
-create_filepopup_window(void)
-{
-	const gchar *glade_file = DATA_DIR "/glade/fileinfo_popup.glade";
-	GladeXML *xml;
-	GtkWidget *widget;
-
-	xml = glade_xml_new_or_die(_("Track Information Popup"), glade_file, NULL, NULL);
-
-	glade_xml_signal_autoconnect(xml);
-
-	filepopup_win = glade_xml_get_widget(xml, "win_pl_popup");
-	g_object_set_data(G_OBJECT(filepopup_win), "glade-xml", xml);
-	gtk_window_set_transient_for(GTK_WINDOW(filepopup_win), GTK_WINDOW(mainwin));
-
-	widget = glade_xml_get_widget(xml, "image_artwork");
-	gtk_image_set_from_file(GTK_IMAGE(widget), DATA_DIR "/images/audio.png");
-
-	g_timeout_add(50, filepopup_pointer_check_iter, NULL);
-}
-
-void
-fileinfo_show_for_tuple(TitleInput *tuple)
-{
-	gchar *tmp = NULL;
-
-	if (tuple == NULL)
-		return;
-
-	gtk_widget_realize(fileinfo_win);
-
-	fileinfo_entry_set_text("entry_title", tuple->track_name);
-	fileinfo_entry_set_text("entry_artist", tuple->performer);
-	fileinfo_entry_set_text("entry_album", tuple->album_name);
-	fileinfo_entry_set_text("entry_comment", tuple->comment);
-	fileinfo_entry_set_text("entry_genre", tuple->genre);
-
-	tmp = g_strdup_printf("%s/%s", tuple->file_path, tuple->file_name);
-	if(tmp){
-		fileinfo_entry_set_text_free("entry_location", str_to_utf8(tmp));
-		g_free(tmp);
-		tmp = NULL;
-	}
-
-	if (tuple->year != 0)
-		fileinfo_entry_set_text_free("entry_year", g_strdup_printf("%d", tuple->year));
-
-	if (tuple->track_number != 0)
-		fileinfo_entry_set_text_free("entry_track", g_strdup_printf("%d", tuple->track_number));
-
-	tmp = fileinfo_recursive_get_image(tuple->file_path, 0);
-	
-	if(tmp)
-	{
-		fileinfo_entry_set_image("image_artwork", tmp);
-		g_free(tmp);
-	}
-	
-	gtk_widget_show(fileinfo_win);
-}
-
-static gboolean
-cover_name_filter(const gchar *name, const gchar *filter, const gboolean ret_on_empty)
-{
-	gboolean result = FALSE;
-	gchar **splitted;
-	gchar *current;
-	gchar *lname;
-	gint i;
-
-	if (!filter || strlen(filter) == 0) {
-		return ret_on_empty;
-	}
-
-	splitted = g_strsplit(filter, ",", 0);
-
-	lname = g_strdup(name);
-	g_strdown(lname);
-
-	for (i = 0; !result && (current = splitted[i]); i++) {
-		gchar *stripped = g_strstrip(g_strdup(current));
-		g_strdown(stripped);
-
-		result = result || strstr(lname, stripped);
-
-		g_free(stripped);
-	}
-
-	g_free(lname);
-	g_strfreev(splitted);
-
-	return result;
-}
-
-/* Check wether it's an image we want */
-static gboolean
-is_front_cover_image(const gchar *name)
-{
-	char *ext;
-
-	ext = strrchr(name, '.');
-	if (!ext) {
-		/* No file extension */
-		return FALSE;
-	}
-
-	if (g_strcasecmp(ext, ".jpg") != 0 &&
-	    g_strcasecmp(ext, ".jpeg") != 0 &&
-	    g_strcasecmp(ext, ".png") != 0) {
-		/* No recognized file extension */
-		return FALSE;
-	}
-
-	return cover_name_filter(name, cfg.cover_name_include, TRUE) &&
-	       !cover_name_filter(name, cfg.cover_name_exclude, FALSE);
-}
-
-gchar*
-fileinfo_recursive_get_image(const gchar* path, gint depth)
-{
-	GDir *d;
-
-	if (cfg.recurse_for_cover && depth > cfg.recurse_for_cover_depth)
-		return NULL;
-	
-	d = g_dir_open(path, 0, NULL);
-
-	if (d)
-	{	
-		const gchar *f = g_dir_read_name(d);
-		
-		while (f)
-		{
-			gchar *newpath = g_strdup_printf("%s/%s", path, f);
-
-			if (is_front_cover_image(f))
-			{
-				/* We found a suitable file in the current
-				 * directory, use that. The string will be
-				 * freed by the caller */
-				g_dir_close(d);
-				return newpath;
-			}
-			else
-			{
-				f = g_dir_read_name(d);
-				if (cfg.recurse_for_cover)
-				{
-					/* File/directory wasn't suitable, try and recurse into it.
-					 * This should either return a filename for a image file, 
-					 * or NULL if there was no suitable file, or 'f' wasn't a dir.
-					 */
-					gchar *tmp = fileinfo_recursive_get_image(newpath, depth+1);
-					
-					if(tmp)
-					{
-						g_free(newpath);
-						g_dir_close(d);
-						return tmp;
-					}
-				}
-			}
-		}
-		
-		g_dir_close(d);
-	}
-	
-	return NULL;
-}
-
-void
-filepopup_show_for_tuple(TitleInput *tuple)
-{
-	gchar *tmp;
-	gint x, y, x_off = 3, y_off = 3, h, w;
-
-	if (tuple == NULL)
-		return;
-
-	gtk_widget_realize(filepopup_win);
-
-	filepopup_entry_set_text("label_title", tuple->track_name);
-	filepopup_entry_set_text("label_artist", tuple->performer);
-	filepopup_entry_set_text("label_album", tuple->album_name);
-	filepopup_entry_set_text("label_genre", tuple->genre);
-
-	if (tuple->length != -1)
-		filepopup_entry_set_text_free("label_length", g_strdup_printf("%d:%02d", tuple->length / 60000, (tuple->length / 1000) % 60));
-
-	if (tuple->year != 0)
-		filepopup_entry_set_text_free("label_year", g_strdup_printf("%d", tuple->year));
-
-	if (tuple->track_number != 0)
-		filepopup_entry_set_text_free("label_track", g_strdup_printf("%d", tuple->track_number));
-
-	tmp = fileinfo_recursive_get_image(tuple->file_path, 0);
-	
-	if(tmp)
-	{
-		filepopup_entry_set_image("image_artwork", tmp);
-		g_free(tmp);
-	}
-	
-	gdk_window_get_pointer(NULL, &x, &y, NULL);
-	gtk_window_get_size(GTK_WINDOW(filepopup_win), &w, &h);
-	if (gdk_screen_width()-(w+3) < x) x_off = (w*-1)-3;
-	if (gdk_screen_height()-(h+3) < y) y_off = (h*-1)-3;
-	gtk_window_move(GTK_WINDOW(filepopup_win), x + x_off, y + y_off);
-
-	gtk_widget_show(filepopup_win);
-}
-
-void
-fileinfo_show_for_path(gchar *path)
-{
-	TitleInput *tuple = input_get_song_tuple(path);
-
-	if (tuple == NULL)
-		return input_file_info_box(path);
-
-	fileinfo_show_for_tuple(tuple);
-
-	bmp_title_input_free(tuple);
-	tuple = NULL;
-}
--- a/Plugins/UserInterface/wa2gui/filepopup.h	Thu Sep 07 19:57:27 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * Audacious: A cross-platform multimedia player
- * Copyright (c) 2006 William Pitcock, Tony Vroon, George Averill,
- *                    Giacomo Lozito, Derek Pomery and Yoshiki Yazawa.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef _UI_FILEINFO_H_
-#define _UI_FILEINFO_H_
-
-void create_fileinfo_window(void);
-void create_filepopup_window(void);
-void fileinfo_show_for_tuple(TitleInput *tuple);
-void filepopup_show_for_tuple(TitleInput *tuple);
-gchar* fileinfo_recursive_get_image(const gchar* path, gint depth);
-void fileinfo_show_for_path(gchar *path);
-
-void filepopup_hide(gpointer unused);
-
-#endif
--- a/Plugins/UserInterface/wa2gui/mainwin.c	Thu Sep 07 19:57:27 2006 -0700
+++ b/Plugins/UserInterface/wa2gui/mainwin.c	Thu Sep 07 20:27:46 2006 -0700
@@ -34,7 +34,7 @@
 #include <gtk/gtkmessagedialog.h>
 
 /* GDK including */
-#include "platform/smartinclude.h"
+#include "audacious/platform/smartinclude.h"
 
 #include <math.h>
 #include <stdlib.h>
@@ -42,31 +42,32 @@
 
 #include <X11/Xlib.h>
 
-#include "widgets/widgetcore.h"
+#include "audacious/widgets/widgetcore.h"
 #include "mainwin.h"
-#include "pixmaps.h"
-
-#include "main.h"
-
-#include "controlsocket.h"
-#include "pluginenum.h"
-
-#include "credits.h"
-#include "dnd.h"
-#include "dock.h"
+#include "audacious/pixmaps.h"
+
+#include "audacious/main.h"
+
+#include "audacious/controlsocket.h"
+#include "audacious/pluginenum.h"
+
+#include "audacious/credits.h"
+#include "audacious/dnd.h"
+#include "audacious/dock.h"
+#include "audacious/hints.h"
+#include "audacious/input.h"
+#include "audacious/prefswin.h"
+#include "audacious/skinwin.h"
+#include "audacious/genevent.h"
+#include "audacious/playback.h"
+#include "audacious/playlist.h"
+#include "audacious/urldecode.h"
+#include "audacious/util.h"
+#include "audacious/visualization.h"
+#include "libaudacious/configdb.h"
+
 #include "equalizer.h"
-#include "hints.h"
-#include "input.h"
-#include "ui_playlist.h"
-#include "prefswin.h"
-#include "skinwin.h"
-#include "genevent.h"
-#include "playback.h"
 #include "playlist.h"
-#include "urldecode.h"
-#include "util.h"
-#include "visualization.h"
-#include "libaudacious/configdb.h"
 
 static GTimeVal cb_time; /* click delay for tristate is defined by TRISTATE_THRESHOLD */
 
--- a/Plugins/UserInterface/wa2gui/mainwin.h	Thu Sep 07 19:57:27 2006 -0700
+++ b/Plugins/UserInterface/wa2gui/mainwin.h	Thu Sep 07 20:27:46 2006 -0700
@@ -24,7 +24,7 @@
 
 #include <gtk/gtk.h>
 
-#include "widgets/widgetcore.h"
+#include "audacious/widgets/widgetcore.h"
 
 /* yes, main window size is fixed */
 #define MAINWIN_WIDTH            (gint)275
--- a/Plugins/UserInterface/wa2gui/playlist.c	Thu Sep 07 19:57:27 2006 -0700
+++ b/Plugins/UserInterface/wa2gui/playlist.c	Thu Sep 07 20:27:46 2006 -0700
@@ -22,7 +22,9 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-#include "ui_playlist.h"
+#include "playlist.h"
+#include "equalizer.h"
+#include "mainwin.h"
 
 #include <glib.h>
 #include <glib/gi18n.h>
@@ -31,27 +33,25 @@
 #include <gtk/gtk.h>
 #include <string.h>
 
-#include "platform/smartinclude.h"
+#include "audacious/platform/smartinclude.h"
 
 #include <unistd.h>
 #include <errno.h>
 
 #include "libaudacious/util.h"
 
-#include "dnd.h"
-#include "dock.h"
-#include "equalizer.h"
-#include "hints.h"
-#include "input.h"
-#include "main.h"
-#include "mainwin.h"
-#include "playback.h"
-#include "playlist.h"
-#include "playlist_container.h"
-#include "util.h"
+#include "audacious/dnd.h"
+#include "audacious/dock.h"
+#include "audacious/hints.h"
+#include "audacious/input.h"
+#include "audacious/main.h"
+#include "audacious/playback.h"
+#include "audacious/playlist.h"
+#include "audacious/playlist_container.h"
+#include "audacious/util.h"
 
-#include "pixmaps.h"
-#include "images/audacious_playlist.xpm"
+#include "audacious/pixmaps.h"
+#include "audacious/images/audacious_playlist.xpm"
 
 
 #define ITEM_SEPARATOR {"/-", NULL, NULL, 0, "<Separator>", NULL}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/playlist.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,78 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PLAYLISTWIN_H
+#define PLAYLISTWIN_H
+
+#include <glib.h>
+
+#include "mainwin.h"
+#include "audacious/widgets/widgetcore.h"
+
+#define PLAYLISTWIN_FRAME_TOP_HEIGHT    20
+#define PLAYLISTWIN_FRAME_BOTTOM_HEIGHT 38
+#define PLAYLISTWIN_FRAME_LEFT_WIDTH    12
+#define PLAYLISTWIN_FRAME_RIGHT_WIDTH   19
+
+#define PLAYLISTWIN_MIN_WIDTH           MAINWIN_WIDTH
+#define PLAYLISTWIN_MIN_HEIGHT          MAINWIN_HEIGHT
+#define PLAYLISTWIN_WIDTH_SNAP          25
+#define PLAYLISTWIN_HEIGHT_SNAP         29
+#define PLAYLISTWIN_SHADED_HEIGHT       MAINWIN_SHADED_HEIGHT
+#define PLAYLISTWIN_WIDTH               cfg.playlist_width
+#define PLAYLISTWIN_HEIGHT \
+    (cfg.playlist_shaded ? PLAYLISTWIN_SHADED_HEIGHT : cfg.playlist_height)
+
+#define PLAYLISTWIN_DEFAULT_WIDTH       275
+#define PLAYLISTWIN_DEFAULT_HEIGHT      232
+#define PLAYLISTWIN_DEFAULT_POS_X       295
+#define PLAYLISTWIN_DEFAULT_POS_Y       20
+
+#define PLAYLISTWIN_DEFAULT_FONT        "Sans Bold 8"
+
+gboolean playlistwin_is_shaded(void);
+void playlistwin_update_list(void);
+gboolean playlistwin_item_visible(gint index);
+gint playlistwin_get_toprow(void);
+void playlistwin_set_toprow(gint top);
+void playlistwin_set_shade_menu_cb(gboolean shaded);
+void playlistwin_set_shade(gboolean shaded);
+void playlistwin_shade_toggle(void);
+void playlistwin_create(void);
+void draw_playlist_window(gboolean force);
+void playlistwin_hide_timer(void);
+void playlistwin_set_time(gint time, gint length, TimerMode mode);
+void playlistwin_show(void);
+void playlistwin_hide(void);
+void playlistwin_set_back_pixmap(void);
+void playlistwin_scroll(gint num);
+void playlistwin_scroll_up_pushed(void);
+void playlistwin_scroll_down_pushed(void);
+void playlistwin_select_playlist_to_load(const gchar * default_filename);
+
+extern GtkWidget *playlistwin;
+extern PlayList_List *playlistwin_list;
+
+extern PButton *playlistwin_shade, *playlistwin_close;
+
+extern gboolean playlistwin_focus;
+
+#endif
--- a/Plugins/UserInterface/wa2gui/ui_playlist.h	Thu Sep 07 19:57:27 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*  BMP - Cross-platform multimedia player
- *  Copyright (C) 2003-2004  BMP development team.
- *
- *  Based on XMMS:
- *  Copyright (C) 1998-2003  XMMS development team.
- *
- *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef PLAYLISTWIN_H
-#define PLAYLISTWIN_H
-
-#include <glib.h>
-
-#include "mainwin.h"
-#include "widgets/widgetcore.h"
-
-#define PLAYLISTWIN_FRAME_TOP_HEIGHT    20
-#define PLAYLISTWIN_FRAME_BOTTOM_HEIGHT 38
-#define PLAYLISTWIN_FRAME_LEFT_WIDTH    12
-#define PLAYLISTWIN_FRAME_RIGHT_WIDTH   19
-
-#define PLAYLISTWIN_MIN_WIDTH           MAINWIN_WIDTH
-#define PLAYLISTWIN_MIN_HEIGHT          MAINWIN_HEIGHT
-#define PLAYLISTWIN_WIDTH_SNAP          25
-#define PLAYLISTWIN_HEIGHT_SNAP         29
-#define PLAYLISTWIN_SHADED_HEIGHT       MAINWIN_SHADED_HEIGHT
-#define PLAYLISTWIN_WIDTH               cfg.playlist_width
-#define PLAYLISTWIN_HEIGHT \
-    (cfg.playlist_shaded ? PLAYLISTWIN_SHADED_HEIGHT : cfg.playlist_height)
-
-#define PLAYLISTWIN_DEFAULT_WIDTH       275
-#define PLAYLISTWIN_DEFAULT_HEIGHT      232
-#define PLAYLISTWIN_DEFAULT_POS_X       295
-#define PLAYLISTWIN_DEFAULT_POS_Y       20
-
-#define PLAYLISTWIN_DEFAULT_FONT        "Sans Bold 8"
-
-gboolean playlistwin_is_shaded(void);
-void playlistwin_update_list(void);
-gboolean playlistwin_item_visible(gint index);
-gint playlistwin_get_toprow(void);
-void playlistwin_set_toprow(gint top);
-void playlistwin_set_shade_menu_cb(gboolean shaded);
-void playlistwin_set_shade(gboolean shaded);
-void playlistwin_shade_toggle(void);
-void playlistwin_create(void);
-void draw_playlist_window(gboolean force);
-void playlistwin_hide_timer(void);
-void playlistwin_set_time(gint time, gint length, TimerMode mode);
-void playlistwin_show(void);
-void playlistwin_hide(void);
-void playlistwin_set_back_pixmap(void);
-void playlistwin_scroll(gint num);
-void playlistwin_scroll_up_pushed(void);
-void playlistwin_scroll_down_pushed(void);
-void playlistwin_select_playlist_to_load(const gchar * default_filename);
-
-extern GtkWidget *playlistwin;
-extern PlayList_List *playlistwin_list;
-
-extern PButton *playlistwin_shade, *playlistwin_close;
-
-extern gboolean playlistwin_focus;
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/Makefile	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,39 @@
+include ../../../../mk/rules.mk
+include ../../../../mk/init.mk
+
+OBJECTIVE_LIBS_NOINST = libwidgets.a
+
+LDFLAGS += -Wl,-export-dynamic
+
+CFLAGS += \
+	$(GTK_CFLAGS)      \
+	$(LIBGLADE_CFLAGS) \
+	$(BEEP_DEFINES)    \
+	$(ARCH_DEFINES)    \
+	-I..		\
+	-I../../../..    \
+	-I../../..	   \
+	-I../../../../intl \
+
+SOURCES = \
+	widget.c \
+	sbutton.c \
+	pbutton.c \
+	tbutton.c \
+	textbox.c \
+	hslider.c \
+	menurow.c \
+	monostereo.c \
+	vis.c \
+	svis.c \
+	number.c \
+	playstatus.c \
+	playlist_list.c \
+	playlist_slider.c \
+	eq_graph.c \
+	eq_slider.c \
+	skin.c
+
+OBJECTS = ${SOURCES:.c=.o}
+
+include ../../../../mk/objective.mk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/eq_graph.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,149 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+
+#include "audacious/main.h"
+#include "skin.h"
+
+void
+init_spline(gfloat * x, gfloat * y, gint n, gfloat * y2)
+{
+    gint i, k;
+    gfloat p, qn, sig, un, *u;
+
+    u = (gfloat *) g_malloc(n * sizeof(gfloat));
+
+    y2[0] = u[0] = 0.0;
+
+    for (i = 1; i < n - 1; i++) {
+        sig = ((gfloat) x[i] - x[i - 1]) / ((gfloat) x[i + 1] - x[i - 1]);
+        p = sig * y2[i - 1] + 2.0;
+        y2[i] = (sig - 1.0) / p;
+        u[i] =
+            (((gfloat) y[i + 1] - y[i]) / (x[i + 1] - x[i])) -
+            (((gfloat) y[i] - y[i - 1]) / (x[i] - x[i - 1]));
+        u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p;
+    }
+    qn = un = 0.0;
+
+    y2[n - 1] = (un - qn * u[n - 2]) / (qn * y2[n - 2] + 1.0);
+    for (k = n - 2; k >= 0; k--)
+        y2[k] = y2[k] * y2[k + 1] + u[k];
+    g_free(u);
+}
+
+gfloat
+eval_spline(gfloat xa[], gfloat ya[], gfloat y2a[], gint n, gfloat x)
+{
+    gint klo, khi, k;
+    gfloat h, b, a;
+
+    klo = 0;
+    khi = n - 1;
+    while (khi - klo > 1) {
+        k = (khi + klo) >> 1;
+        if (xa[k] > x)
+            khi = k;
+        else
+            klo = k;
+    }
+    h = xa[khi] - xa[klo];
+    a = (xa[khi] - x) / h;
+    b = (x - xa[klo]) / h;
+    return (a * ya[klo] + b * ya[khi] +
+            ((a * a * a - a) * y2a[klo] +
+             (b * b * b - b) * y2a[khi]) * (h * h) / 6.0);
+}
+
+void
+eqgraph_draw(Widget * w)
+{
+    EqGraph *eg = (EqGraph *) w;
+    GdkPixmap *obj;
+    GdkColor col;
+    guint32 cols[19];
+    gint i, y, ymin, ymax, py = 0;
+    gfloat x[] = { 0, 11, 23, 35, 47, 59, 71, 83, 97, 109 }, yf[10];
+
+    /*
+     * This avoids the init_spline() function to be inlined.
+     * Inlining the function caused troubles when compiling with
+     * `-O' (at least on FreeBSD).
+     */
+    void (*__init_spline) (gfloat *, gfloat *, gint, gfloat *) = init_spline;
+
+    obj = eg->eg_widget.parent;
+    skin_draw_pixmap(bmp_active_skin, obj, eg->eg_widget.gc, SKIN_EQMAIN,
+                     0, 294, eg->eg_widget.x, eg->eg_widget.y,
+                     eg->eg_widget.width, eg->eg_widget.height);
+    skin_draw_pixmap(bmp_active_skin, obj, eg->eg_widget.gc, SKIN_EQMAIN,
+                     0, 314, eg->eg_widget.x,
+                     eg->eg_widget.y + 9 +
+                     ((cfg.equalizer_preamp * 9) / 20),
+                     eg->eg_widget.width, 1);
+
+    skin_get_eq_spline_colors(bmp_active_skin, cols);
+
+    __init_spline(x, cfg.equalizer_bands, 10, yf);
+    for (i = 0; i < 109; i++) {
+        y = 9 -
+            (gint) ((eval_spline(x, cfg.equalizer_bands, yf, 10, i) *
+                     9.0) / 20.0);
+        if (y < 0)
+            y = 0;
+        if (y > 18)
+            y = 18;
+        if (!i)
+            py = y;
+        if (y < py) {
+            ymin = y;
+            ymax = py;
+        }
+        else {
+            ymin = py;
+            ymax = y;
+        }
+        py = y;
+        for (y = ymin; y <= ymax; y++) {
+            col.pixel = cols[y];
+            gdk_gc_set_foreground(eg->eg_widget.gc, &col);
+            gdk_draw_point(obj, eg->eg_widget.gc, eg->eg_widget.x + i + 2,
+                           eg->eg_widget.y + y);
+        }
+    }
+}
+
+EqGraph *
+create_eqgraph(GList ** wlist, GdkPixmap * parent, GdkGC * gc, gint x, gint y)
+{
+    EqGraph *eg;
+
+    eg = g_new0(EqGraph, 1);
+    widget_init(&eg->eg_widget, parent, gc, x, y, 113, 19, TRUE);
+    eg->eg_widget.draw = eqgraph_draw;
+
+    widget_list_add(wlist, WIDGET(eg));
+
+    return eg;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/eq_graph.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,44 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef EQ_GRAPH_H
+#define EQ_GRAPH_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "widget.h"
+
+#define EQ_GRAPH(x)  ((EqGraph *)(x))
+struct _EqGraph {
+    Widget eg_widget;
+};
+
+typedef struct _EqGraph EqGraph;
+
+EqGraph *create_eqgraph(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+                        gint x, gint y);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/eq_slider.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,235 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include "equalizer.h"
+#include "mainwin.h"
+#include "skin.h"
+
+void
+eqslider_set_position(EqSlider * es,
+                      gfloat pos)
+{
+    es->es_position = 25 - (gint) ((pos * 25.0) / 20.0);
+
+    if (es->es_position < 0)
+        es->es_position = 0;
+
+    if (es->es_position > 50)
+        es->es_position = 50;
+
+    if (es->es_position >= 24 && es->es_position <= 26)
+        es->es_position = 25;
+
+    widget_draw(WIDGET(es));
+}
+
+gfloat
+eqslider_get_position(EqSlider * es)
+{
+    return 20.0 - (((gfloat) es->es_position * 20.0) / 25.0);
+}
+
+void
+eqslider_draw(Widget * w)
+{
+    EqSlider *es = (EqSlider *) w;
+    GdkPixmap *obj;
+    SkinPixmapId src;
+    gint frame;
+
+    src = SKIN_EQMAIN;
+    obj = es->es_widget.parent;
+
+    frame = 27 - ((es->es_position * 27) / 50);
+    if (frame < 14)
+        skin_draw_pixmap(bmp_active_skin, obj, es->es_widget.gc, src,
+                         (frame * 15) + 13, 164, es->es_widget.x,
+                         es->es_widget.y, es->es_widget.width,
+                         es->es_widget.height);
+    else
+        skin_draw_pixmap(bmp_active_skin, obj, es->es_widget.gc, src,
+                         ((frame - 14) * 15) + 13, 229, es->es_widget.x,
+                         es->es_widget.y, es->es_widget.width,
+                         es->es_widget.height);
+    if (es->es_isdragging)
+        skin_draw_pixmap(bmp_active_skin, obj, es->es_widget.gc, src, 0,
+                         176, es->es_widget.x + 1,
+                         es->es_widget.y + es->es_position, 11, 11);
+    else
+        skin_draw_pixmap(bmp_active_skin, obj, es->es_widget.gc, src, 0,
+                         164, es->es_widget.x + 1,
+                         es->es_widget.y + es->es_position, 11, 11);
+}
+
+void
+eqslider_set_mainwin_text(EqSlider * es)
+{
+    gint band = 0;
+    const gchar *bandname[11] = { N_("PREAMP"), N_("60HZ"), N_("170HZ"),
+        N_("310HZ"), N_("600HZ"), N_("1KHZ"),
+        N_("3KHZ"), N_("6KHZ"), N_("12KHZ"),
+        N_("14KHZ"), N_("16KHZ")
+    };
+    gchar *tmp;
+
+    if (es->es_widget.x > 21)
+        band = ((es->es_widget.x - 78) / 18) + 1;
+
+    tmp =
+        g_strdup_printf("EQ: %s: %+.1f DB", _(bandname[band]),
+                        eqslider_get_position(es));
+    mainwin_lock_info_text(tmp);
+    g_free(tmp);
+}
+
+void
+eqslider_button_press_cb(GtkWidget * w,
+                         GdkEventButton * event,
+                         gpointer data)
+{
+    EqSlider *es = EQ_SLIDER(data);
+    gint y;
+
+    if (widget_contains(&es->es_widget, event->x, event->y)) {
+        if (event->button == 1) {
+            y = event->y - es->es_widget.y;
+            es->es_isdragging = TRUE;
+            if (y >= es->es_position && y < es->es_position + 11)
+                es->es_drag_y = y - es->es_position;
+            else {
+                es->es_position = y - 5;
+                es->es_drag_y = 5;
+                if (es->es_position < 0)
+                    es->es_position = 0;
+                if (es->es_position > 50)
+                    es->es_position = 50;
+                if (es->es_position >= 24 && es->es_position <= 26)
+                    es->es_position = 25;
+                equalizerwin_eq_changed();
+            }
+
+            eqslider_set_mainwin_text(es);
+            widget_draw(WIDGET(es));
+        }
+        if (event->button == 4) {
+            es->es_position -= 2;
+            if (es->es_position < 0)
+                es->es_position = 0;
+            equalizerwin_eq_changed();
+            widget_draw(WIDGET(es));
+        }
+    }
+}
+
+void
+eqslider_mouse_scroll_cb(GtkWidget * w,
+                         GdkEventScroll * event,
+                         gpointer data)
+{
+    EqSlider *es = EQ_SLIDER(data);
+
+    if (!widget_contains(&es->es_widget, event->x, event->y))
+        return;
+
+    if (event->direction == GDK_SCROLL_UP) {
+        es->es_position -= 2;
+
+        if (es->es_position < 0)
+            es->es_position = 0;
+
+        equalizerwin_eq_changed();
+        widget_draw(WIDGET(es));
+    }
+    else {
+        es->es_position += 2;
+
+        if (es->es_position > 50)
+            es->es_position = 50;
+
+        equalizerwin_eq_changed();
+        widget_draw(WIDGET(es));
+    }
+}
+
+void
+eqslider_motion_cb(GtkWidget * w,
+                   GdkEventMotion * event,
+                   gpointer data)
+{
+    EqSlider *es = EQ_SLIDER(data);
+    gint y;
+
+    y = event->y - es->es_widget.y;
+    if (es->es_isdragging) {
+        es->es_position = y - es->es_drag_y;
+        if (es->es_position < 0)
+            es->es_position = 0;
+        if (es->es_position > 50)
+            es->es_position = 50;
+        if (es->es_position >= 24 && es->es_position <= 26)
+            es->es_position = 25;
+        equalizerwin_eq_changed();
+        eqslider_set_mainwin_text(es);
+        widget_draw(WIDGET(es));
+    }
+}
+
+void
+eqslider_button_release_cb(GtkWidget * w,
+                           GdkEventButton * event,
+                           gpointer data)
+{
+    EqSlider *es = EQ_SLIDER(data);
+
+    if (es->es_isdragging) {
+        es->es_isdragging = FALSE;
+        mainwin_release_info_text();
+        widget_draw(WIDGET(es));
+    }
+}
+
+EqSlider *
+create_eqslider(GList ** wlist,
+                GdkPixmap * parent,
+                GdkGC * gc,
+                gint x, gint y)
+{
+    EqSlider *es;
+
+    es = g_new0(EqSlider, 1);
+    widget_init(&es->es_widget, parent, gc, x, y, 14, 63, TRUE);
+    es->es_widget.button_press_cb = eqslider_button_press_cb;
+    es->es_widget.button_release_cb = eqslider_button_release_cb;
+    es->es_widget.motion_cb = eqslider_motion_cb;
+    es->es_widget.draw = eqslider_draw;
+    es->es_widget.mouse_scroll_cb = eqslider_mouse_scroll_cb;
+
+    widget_list_add(wlist, WIDGET(es));
+
+    return es;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/eq_slider.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,49 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef EQ_SLIDER_H
+#define EQ_SLIDER_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "widget.h"
+
+#define EQ_SLIDER(x)  ((EqSlider *)(x))
+struct _EqSlider {
+    Widget es_widget;
+    gint es_position;
+    gboolean es_isdragging;
+    gint es_drag_y;
+};
+
+typedef struct _EqSlider EqSlider;
+
+EqSlider *create_eqslider(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+                          gint x, gint y);
+void eqslider_set_position(EqSlider * es, gfloat pos);
+gfloat eqslider_get_position(EqSlider * es);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/hslider.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,203 @@
+/*  XMMS - Cross-platform multimedia player
+ *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "skin.h"
+
+void
+hslider_set_position(HSlider * hs,
+                     gint pos)
+{
+    if (pos == hs->hs_position || hs->hs_pressed)
+        return;
+
+    hs->hs_position = pos;
+
+    if (hs->hs_frame_cb)
+        hs->hs_frame = hs->hs_frame_cb(hs->hs_position);
+
+    widget_draw(WIDGET(hs));
+}
+
+gint
+hslider_get_position(HSlider * hs)
+{
+    return hs->hs_position;
+}
+
+void
+hslider_draw(Widget * w)
+{
+    HSlider *hs = (HSlider *) w;
+    GdkPixmap *obj;
+
+    obj = hs->hs_widget.parent;
+
+    skin_draw_pixmap(bmp_active_skin, obj, hs->hs_widget.gc,
+                     hs->hs_skin_index, hs->hs_frame_offset,
+                     hs->hs_frame * hs->hs_frame_height, hs->hs_widget.x,
+                     hs->hs_widget.y, hs->hs_widget.width,
+                     hs->hs_widget.height);
+    if (hs->hs_pressed)
+        skin_draw_pixmap(bmp_active_skin, obj, hs->hs_widget.gc,
+                         hs->hs_skin_index, hs->hs_knob_px,
+                         hs->hs_knob_py, hs->hs_widget.x + hs->hs_position,
+                         hs->hs_widget.y +
+                         ((hs->hs_widget.height - hs->hs_knob_height) / 2),
+                         hs->hs_knob_width, hs->hs_knob_height);
+    else
+        skin_draw_pixmap(bmp_active_skin, obj, hs->hs_widget.gc,
+                         hs->hs_skin_index, hs->hs_knob_nx, hs->hs_knob_ny,
+                         hs->hs_widget.x + hs->hs_position,
+                         hs->hs_widget.y +
+                         ((hs->hs_widget.height - hs->hs_knob_height) / 2),
+                         hs->hs_knob_width, hs->hs_knob_height);
+}
+
+void
+hslider_button_press_cb(GtkWidget * w,
+                        GdkEventButton * event,
+                        gpointer data)
+{
+    HSlider *hs = HSLIDER(data);
+    gint x;
+
+    if (event->button != 1)
+        return;
+
+    if (widget_contains(&hs->hs_widget, event->x, event->y)) {
+        x = event->x - hs->hs_widget.x;
+        hs->hs_pressed = TRUE;
+
+        if (x >= hs->hs_position && x < hs->hs_position + hs->hs_knob_width)
+            hs->hs_pressed_x = x - hs->hs_position;
+        else {
+            hs->hs_position = x - (hs->hs_knob_width / 2);
+            hs->hs_pressed_x = hs->hs_knob_width / 2;
+            if (hs->hs_position < hs->hs_min)
+                hs->hs_position = hs->hs_min;
+            if (hs->hs_position > hs->hs_max)
+                hs->hs_position = hs->hs_max;
+            if (hs->hs_frame_cb)
+                hs->hs_frame = hs->hs_frame_cb(hs->hs_position);
+
+        }
+
+        if (hs->hs_motion_cb)
+            hs->hs_motion_cb(hs->hs_position);
+
+        widget_draw(WIDGET(hs));
+    }
+}
+
+void
+hslider_motion_cb(GtkWidget * w, GdkEventMotion * event, gpointer data)
+{
+    HSlider *hs = (HSlider *) data;
+    gint x;
+
+    if (hs->hs_pressed) {
+        if (!hs->hs_widget.visible) {
+            hs->hs_pressed = FALSE;
+            return;
+        }
+
+        x = event->x - hs->hs_widget.x;
+        hs->hs_position = x - hs->hs_pressed_x;
+
+        if (hs->hs_position < hs->hs_min)
+            hs->hs_position = hs->hs_min;
+
+        if (hs->hs_position > hs->hs_max)
+            hs->hs_position = hs->hs_max;
+
+        if (hs->hs_frame_cb)
+            hs->hs_frame = hs->hs_frame_cb(hs->hs_position);
+
+        if (hs->hs_motion_cb)
+            hs->hs_motion_cb(hs->hs_position);
+
+        widget_draw(WIDGET(hs));
+    }
+}
+
+void
+hslider_button_release_cb(GtkWidget * w,
+                          GdkEventButton * event,
+                          gpointer data)
+{
+    HSlider *hs = HSLIDER(data);
+
+    if (hs->hs_pressed) {
+        hs->hs_pressed = FALSE;
+
+        if (hs->hs_release_cb)
+            hs->hs_release_cb(hs->hs_position);
+
+        widget_draw(WIDGET(hs));
+    }
+}
+
+HSlider *
+create_hslider(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+               gint x, gint y, gint w, gint h, gint knx, gint kny,
+               gint kpx, gint kpy, gint kw, gint kh, gint fh,
+               gint fo, gint min, gint max, gint(*fcb) (gint),
+               void (*mcb) (gint), void (*rcb) (gint), SkinPixmapId si)
+{
+    HSlider *hs;
+
+    hs = g_new0(HSlider, 1);
+    widget_init(&hs->hs_widget, parent, gc, x, y, w, h, 1);
+    hs->hs_widget.button_press_cb =
+        (void (*)(GtkWidget *, GdkEventButton *, gpointer))
+        hslider_button_press_cb;
+    hs->hs_widget.button_release_cb =
+        (void (*)(GtkWidget *, GdkEventButton *, gpointer))
+        hslider_button_release_cb;
+    hs->hs_widget.motion_cb =
+        (void (*)(GtkWidget *, GdkEventMotion *, gpointer))
+        hslider_motion_cb;
+    hs->hs_widget.draw = hslider_draw;
+    hs->hs_knob_nx = knx;
+    hs->hs_knob_ny = kny;
+    hs->hs_knob_px = kpx;
+    hs->hs_knob_py = kpy;
+    hs->hs_knob_width = kw;
+    hs->hs_knob_height = kh;
+    hs->hs_frame_height = fh;
+    hs->hs_frame_offset = fo;
+    hs->hs_min = min;
+    hs->hs_position = min;
+    hs->hs_max = max;
+    hs->hs_frame_cb = fcb;
+    hs->hs_motion_cb = mcb;
+    hs->hs_release_cb = rcb;
+    if (hs->hs_frame_cb)
+        hs->hs_frame = hs->hs_frame_cb(0);
+    hs->hs_skin_index = si;
+
+    widget_list_add(wlist, WIDGET(hs));
+
+    return hs;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/hslider.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,59 @@
+/*  XMMS - Cross-platform multimedia player
+ *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef HSLIDER_H
+#define HSLIDER_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "skin.h"
+#include "widget.h"
+
+#define HSLIDER(x)  ((HSlider *)(x))
+struct _HSlider {
+    Widget hs_widget;
+    gint hs_frame, hs_frame_offset, hs_frame_height, hs_min, hs_max;
+    gint hs_knob_nx, hs_knob_ny, hs_knob_px, hs_knob_py;
+    gint hs_knob_width, hs_knob_height;
+    gint hs_position;
+    gboolean hs_pressed;
+    gint hs_pressed_x, hs_pressed_y;
+     gint(*hs_frame_cb) (gint);
+    void (*hs_motion_cb) (gint);
+    void (*hs_release_cb) (gint);
+    SkinPixmapId hs_skin_index;
+};
+
+typedef struct _HSlider HSlider;
+
+HSlider *create_hslider(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+                        gint x, gint y, gint w, gint h, gint knx, gint kny,
+                        gint kpx, gint kpy, gint kw, gint kh, gint fh,
+                        gint fo, gint min, gint max, gint(*fcb) (gint),
+                        void (*mcb) (gint), void (*rcb) (gint),
+                        SkinPixmapId si);
+
+void hslider_set_position(HSlider * hs, gint pos);
+gint hslider_get_position(HSlider * hs);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/menurow.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,186 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "audacious/main.h"
+#include "menurow.h"
+#include "widget.h"
+
+void
+menurow_draw(Widget * widget)
+{
+    MenuRow *mr = MENU_ROW(widget);
+
+    GdkPixmap *obj = mr->mr_widget.parent;
+
+    if (mr->mr_selected == MENUROW_NONE) {
+        if (cfg.always_show_cb || mr->mr_bpushed)
+            skin_draw_pixmap(bmp_active_skin, obj,
+                             mr->mr_widget.gc,
+                             mr->mr_skin_index,
+                             mr->mr_nx, mr->mr_ny,
+                             mr->mr_widget.x, mr->mr_widget.y, 8, 43);
+        else
+            skin_draw_pixmap(bmp_active_skin, obj,
+                             mr->mr_widget.gc,
+                             mr->mr_skin_index,
+                             mr->mr_nx + 8, mr->mr_ny,
+                             mr->mr_widget.x, mr->mr_widget.y, 8, 43);
+    }
+    else {
+        skin_draw_pixmap(bmp_active_skin, obj,
+                         mr->mr_widget.gc,
+                         mr->mr_skin_index,
+                         mr->mr_sx + ((mr->mr_selected - 1) * 8),
+                         mr->mr_sy, mr->mr_widget.x, mr->mr_widget.y, 8, 43);
+    }
+    if (cfg.always_show_cb || mr->mr_bpushed) {
+        if (mr->mr_always_selected)
+            skin_draw_pixmap(bmp_active_skin, obj,
+                             mr->mr_widget.gc,
+                             mr->mr_skin_index,
+                             mr->mr_sx + 8, mr->mr_sy + 10,
+                             mr->mr_widget.x, mr->mr_widget.y + 10, 8, 8);
+        if (mr->mr_doublesize_selected)
+            skin_draw_pixmap(bmp_active_skin, obj,
+                             mr->mr_widget.gc,
+                             mr->mr_skin_index,
+                             mr->mr_sx + 24, mr->mr_sy + 26,
+                             mr->mr_widget.x, mr->mr_widget.y + 26, 8, 8);
+    }
+
+}
+
+MenuRowItem
+menurow_find_selected(MenuRow * mr, gint x, gint y)
+{
+    MenuRowItem ret = MENUROW_NONE;
+
+    x -= mr->mr_widget.x;
+    y -= mr->mr_widget.y;
+    if (x > 0 && x < 8) {
+        if (y >= 0 && y <= 10)
+            ret = MENUROW_OPTIONS;
+        if (y >= 10 && y <= 17)
+            ret = MENUROW_ALWAYS;
+        if (y >= 18 && y <= 25)
+            ret = MENUROW_FILEINFOBOX;
+        if (y >= 26 && y <= 33)
+            ret = MENUROW_DOUBLESIZE;
+        if (y >= 34 && y <= 42)
+            ret = MENUROW_VISUALIZATION;
+    }
+    return ret;
+}
+
+void
+menurow_button_press(GtkWidget * widget,
+                     GdkEventButton * event,
+                     gpointer data)
+{
+    MenuRow *mr = MENU_ROW(data);
+
+    if (event->button != 1)
+        return;
+
+    if (widget_contains(&mr->mr_widget, event->x, event->y)) {
+        mr->mr_bpushed = TRUE;
+        mr->mr_selected = menurow_find_selected(mr, event->x, event->y);
+
+        widget_draw(WIDGET(mr));
+
+        if (mr->mr_change_callback)
+            mr->mr_change_callback(mr->mr_selected);
+    }
+}
+
+void
+menurow_motion(GtkWidget * widget,
+               GdkEventMotion * event,
+               gpointer data)
+{
+    MenuRow *mr = MENU_ROW(data);
+
+    if (mr->mr_bpushed) {
+        mr->mr_selected = menurow_find_selected(mr, event->x, event->y);
+
+        widget_draw(WIDGET(mr));
+
+        if (mr->mr_change_callback)
+            mr->mr_change_callback(mr->mr_selected);
+    }
+}
+
+void
+menurow_button_release(GtkWidget * widget,
+                       GdkEventButton * event,
+                       gpointer data)
+{
+    MenuRow *mr = MENU_ROW(data);
+
+    if (mr->mr_bpushed) {
+        mr->mr_bpushed = FALSE;
+
+        if (mr->mr_selected == MENUROW_ALWAYS)
+            mr->mr_always_selected = !mr->mr_always_selected;
+
+        if (mr->mr_selected == MENUROW_DOUBLESIZE)
+            mr->mr_doublesize_selected = !mr->mr_doublesize_selected;
+
+        if ((int)(mr->mr_selected) != -1 && mr->mr_release_callback)
+            mr->mr_release_callback(mr->mr_selected);
+
+        mr->mr_selected = MENUROW_NONE;
+
+        widget_draw(WIDGET(mr));
+    }
+}
+
+MenuRow *
+create_menurow(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+               gint x, gint y, gint nx, gint ny, gint sx, gint sy,
+               void (*ccb) (MenuRowItem),
+               void (*rcb) (MenuRowItem), SkinPixmapId si)
+{
+    MenuRow *mr;
+
+    mr = g_new0(MenuRow, 1);
+    widget_init(&mr->mr_widget, parent, gc, x, y, 8, 43, 1);
+    mr->mr_widget.draw = menurow_draw;
+    mr->mr_widget.button_press_cb = menurow_button_press;
+    mr->mr_widget.motion_cb = menurow_motion;
+    mr->mr_widget.button_release_cb = menurow_button_release;
+    mr->mr_nx = nx;
+    mr->mr_ny = ny;
+    mr->mr_sx = sx;
+    mr->mr_sy = sy;
+    mr->mr_selected = MENUROW_NONE;
+    mr->mr_change_callback = ccb;
+    mr->mr_release_callback = rcb;
+    mr->mr_skin_index = si;
+
+    widget_list_add(wlist, WIDGET(mr));
+    return mr;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/menurow.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,61 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef MENUROW_H
+#define	MENUROW_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "skin.h"
+#include "widget.h"
+
+typedef enum {
+    MENUROW_NONE, MENUROW_OPTIONS, MENUROW_ALWAYS, MENUROW_FILEINFOBOX,
+    MENUROW_DOUBLESIZE, MENUROW_VISUALIZATION
+} MenuRowItem;
+
+#define MENU_ROW(x)  ((MenuRow *)(x))
+struct _MenuRow {
+    Widget mr_widget;
+    gint mr_nx, mr_ny;
+    gint mr_sx, mr_sy;
+    MenuRowItem mr_selected;
+    gboolean mr_bpushed;
+    gboolean mr_always_selected;
+    gboolean mr_doublesize_selected;
+    void (*mr_change_callback) (MenuRowItem);
+    void (*mr_release_callback) (MenuRowItem);
+    SkinPixmapId mr_skin_index;
+};
+
+typedef struct _MenuRow MenuRow;
+
+MenuRow *create_menurow(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+                        gint x, gint y, gint nx, gint ny, gint sx, gint sy,
+                        void (*ccb) (MenuRowItem),
+                        void (*rcb) (MenuRowItem), SkinPixmapId si);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/monostereo.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,93 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "skin.h"
+#include "widget.h"
+
+void
+monostereo_draw(Widget * widget)
+{
+    MonoStereo *ms = (MonoStereo *) widget;
+    GdkPixmap *obj;
+
+    obj = ms->ms_widget.parent;
+
+    switch (ms->ms_num_channels) {
+    case 0:
+        skin_draw_pixmap(bmp_active_skin, obj, ms->ms_widget.gc,
+                         ms->ms_skin_index, 29, 12,
+                         ms->ms_widget.x, ms->ms_widget.y, 27, 12);
+        skin_draw_pixmap(bmp_active_skin, obj, ms->ms_widget.gc,
+                         ms->ms_skin_index, 0, 12,
+                         ms->ms_widget.x + 27, ms->ms_widget.y, 29, 12);
+        break;
+    case 1:
+        skin_draw_pixmap(bmp_active_skin, obj, ms->ms_widget.gc,
+                         ms->ms_skin_index, 29, 0,
+                         ms->ms_widget.x, ms->ms_widget.y, 27, 12);
+        skin_draw_pixmap(bmp_active_skin, obj, ms->ms_widget.gc,
+                         ms->ms_skin_index, 0, 12,
+                         ms->ms_widget.x + 27, ms->ms_widget.y, 29, 12);
+        break;
+    case 2:
+        skin_draw_pixmap(bmp_active_skin, obj, ms->ms_widget.gc,
+                         ms->ms_skin_index, 29, 12,
+                         ms->ms_widget.x, ms->ms_widget.y, 27, 12);
+        skin_draw_pixmap(bmp_active_skin, obj, ms->ms_widget.gc,
+                         ms->ms_skin_index, 0, 0,
+                         ms->ms_widget.x + 27, ms->ms_widget.y, 29, 12);
+        break;
+    }
+}
+
+void
+monostereo_set_num_channels(MonoStereo * ms,
+                            gint nch)
+{
+    if (!ms)
+        return;
+
+    ms->ms_num_channels = nch;
+    widget_draw(WIDGET(ms));
+}
+
+MonoStereo *
+create_monostereo(GList ** wlist,
+                  GdkPixmap * parent,
+                  GdkGC * gc,
+                  gint x, gint y, 
+                  SkinPixmapId si)
+{
+    MonoStereo *ms;
+
+    ms = g_new0(MonoStereo, 1);
+    widget_init(&ms->ms_widget, parent, gc, x, y, 56, 12, 1);
+    ms->ms_widget.draw = monostereo_draw;
+    ms->ms_skin_index = si;
+
+    widget_list_add(wlist, WIDGET(ms));
+    return ms;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/monostereo.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,48 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef MONOSTEREO_H
+#define MONOSTEREO_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "skin.h"
+#include "widget.h"
+
+#define MONO_STEREO(x)  ((MonoStereo *)(x))
+struct _MonoStereo {
+    Widget ms_widget;
+    gint ms_num_channels;
+    SkinPixmapId ms_skin_index;
+};
+
+typedef struct _MonoStereo MonoStereo;
+
+MonoStereo *create_monostereo(GList ** wlist, GdkPixmap * parent,
+                              GdkGC * gc, gint x, gint y, SkinPixmapId si);
+void monostereo_set_num_channels(MonoStereo * ms, gint nch);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/number.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,75 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "skin.h"
+
+void
+number_set_number(Number * nu,
+                  gint number)
+{
+    if (number == nu->nu_number)
+        return;
+
+    nu->nu_number = number;
+    widget_draw(WIDGET(nu));
+}
+
+void
+number_draw(Widget * w)
+{
+    Number *nu = NUMBER(w);
+    GdkPixmap *obj;
+
+    obj = nu->nu_widget.parent;
+
+    if (nu->nu_number <= 11)
+        skin_draw_pixmap(bmp_active_skin, obj, nu->nu_widget.gc,
+                         nu->nu_skin_index, nu->nu_number * 9, 0,
+                         nu->nu_widget.x, nu->nu_widget.y, 9, 13);
+    else
+        skin_draw_pixmap(bmp_active_skin, obj, nu->nu_widget.gc,
+                         nu->nu_skin_index, 90, 0, nu->nu_widget.x,
+                         nu->nu_widget.y, 9, 13);
+}
+
+Number *
+create_number(GList ** wlist,
+              GdkPixmap * parent,
+              GdkGC * gc,
+              gint x, gint y,
+              SkinPixmapId si)
+{
+    Number *nu;
+
+    nu = g_new0(Number, 1);
+    widget_init(&nu->nu_widget, parent, gc, x, y, 9, 13, 1);
+    nu->nu_widget.draw = number_draw;
+    nu->nu_number = 10;
+    nu->nu_skin_index = si;
+
+    widget_list_add(wlist, WIDGET(nu));
+    return nu;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/number.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,48 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef NUMBER_H
+#define NUMBER_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "widget.h"
+#include "skin.h"
+
+#define NUMBER(x) ((Number *)(x))
+struct _Number {
+    Widget nu_widget;
+    gint nu_number;
+    SkinPixmapId nu_skin_index;
+};
+
+typedef struct _Number Number;
+
+void number_set_number(Number * nu, gint number);
+Number *create_number(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+                      gint x, gint y, SkinPixmapId si);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/pbutton.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,194 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include "skin.h"
+#include "widget.h"
+
+void
+pbutton_draw(PButton * button)
+{
+    GdkPixmap *obj;
+
+    if (button->pb_allow_draw) {
+        obj = button->pb_widget.parent;
+
+        if (button->pb_pressed && button->pb_inside) {
+            skin_draw_pixmap(bmp_active_skin, obj,
+                             button->pb_widget.gc,
+                             button->pb_skin_index2, button->pb_px,
+                             button->pb_py, button->pb_widget.x,
+                             button->pb_widget.y,
+                             button->pb_widget.width,
+                             button->pb_widget.height);
+        }
+        else {
+            skin_draw_pixmap(bmp_active_skin, obj,
+                             button->pb_widget.gc,
+                             button->pb_skin_index1,
+                             button->pb_nx, button->pb_ny,
+                             button->pb_widget.x, button->pb_widget.y,
+                             button->pb_widget.width,
+                             button->pb_widget.height);
+        }
+    }
+}
+
+void
+pbutton_button_press_cb(GtkWidget * widget,
+                        GdkEventButton * event,
+                        PButton * button)
+{
+    if (event->button != 1)
+        return;
+
+    if (widget_contains(&button->pb_widget, event->x, event->y)) {
+        button->pb_pressed = 1;
+        button->pb_inside = 1;
+        widget_draw(WIDGET(button));
+        if (button->pb_push_cb)
+            button->pb_push_cb();
+    }
+}
+
+void
+pbutton_button_release_cb(GtkWidget * widget,
+                          GdkEventButton * event,
+                          PButton * button)
+{
+    if (event->button != 1)
+        return;
+    if (button->pb_inside && button->pb_pressed) {
+        button->pb_inside = 0;
+        widget_draw(WIDGET(button));
+	if (button->pb_release_cb)
+	    button->pb_release_cb();
+    }
+    if (button->pb_pressed)
+        button->pb_pressed = 0;
+}
+
+void
+pbutton_motion_cb(GtkWidget * widget, GdkEventMotion * event,
+                  PButton * button)
+{
+    gint inside;
+
+    if (!button->pb_pressed)
+        return;
+
+    inside = widget_contains(&button->pb_widget, event->x, event->y);
+
+    if (inside != button->pb_inside) {
+        button->pb_inside = inside;
+        widget_draw(WIDGET(button));
+    }
+}
+
+void
+pbutton_set_skin_index(PButton * b, SkinPixmapId si)
+{
+    b->pb_skin_index1 = b->pb_skin_index2 = si;
+}
+
+void
+pbutton_set_skin_index1(PButton * b, SkinPixmapId si)
+{
+    b->pb_skin_index1 = si;
+}
+
+void
+pbutton_set_skin_index2(PButton * b, SkinPixmapId si)
+{
+    b->pb_skin_index2 = si;
+}
+
+void
+pbutton_set_button_data(PButton * b, gint nx, gint ny, gint px, gint py)
+{
+    if (nx > -1)
+        b->pb_nx = nx;
+    if (ny > -1)
+        b->pb_ny = ny;
+    if (px > -1)
+        b->pb_px = px;
+    if (py > -1)
+        b->pb_py = py;
+}
+
+
+PButton *
+create_pbutton_ex(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+                  gint x, gint y, gint w, gint h, gint nx,
+                  gint ny, gint px, gint py, void (*push_cb) (void),
+		  void (*release_cb) (void),
+                  SkinPixmapId si1, SkinPixmapId si2)
+{
+    PButton *b;
+
+    b = g_new0(PButton, 1);
+    widget_init(&b->pb_widget, parent, gc, x, y, w, h, 1);
+    b->pb_widget.button_press_cb =
+        (void (*)(GtkWidget *, GdkEventButton *, gpointer))
+        pbutton_button_press_cb;
+    b->pb_widget.button_release_cb =
+        (void (*)(GtkWidget *, GdkEventButton *, gpointer))
+        pbutton_button_release_cb;
+    b->pb_widget.motion_cb =
+        (void (*)(GtkWidget *, GdkEventMotion *, gpointer))
+        pbutton_motion_cb;
+
+    b->pb_widget.draw = (void (*)(Widget *)) pbutton_draw;
+    b->pb_nx = nx;
+    b->pb_ny = ny;
+    b->pb_px = px;
+    b->pb_py = py;
+    b->pb_push_cb = push_cb;
+    b->pb_release_cb = release_cb;
+    b->pb_skin_index1 = si1;
+    b->pb_skin_index2 = si2;
+    b->pb_allow_draw = TRUE;
+    b->pb_inside = 0;
+    b->pb_pressed = 0;
+    widget_list_add(wlist, WIDGET(b));
+
+    return b;
+}
+
+PButton *
+create_pbutton(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+               gint x, gint y, gint w, gint h, gint nx, gint ny,
+               gint px, gint py, void (*cb) (void), SkinPixmapId si)
+{
+    return create_pbutton_ex(wlist, parent, gc, x, y, w, h, nx, ny, px, py,
+                             NULL, cb, si, si);
+}
+
+void
+free_pbutton(PButton * b)
+{
+    g_free(b);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/pbutton.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,64 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef PBUTTON_H
+#define PBUTTON_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "widget.h"
+#include "skin.h"
+
+#define PBUTTON(x)  ((PButton *)(x))
+struct _PButton {
+    Widget pb_widget;
+    gint pb_nx, pb_ny;
+    gint pb_px, pb_py;
+    gboolean pb_pressed;
+    gboolean pb_inside;
+    gboolean pb_allow_draw;
+    void (*pb_push_cb) (void);
+    void (*pb_release_cb) (void);
+    SkinPixmapId pb_skin_index1, pb_skin_index2;
+};
+
+typedef struct _PButton PButton;
+
+PButton *create_pbutton(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+                        gint x, gint y, gint w, gint h, gint nx, gint ny,
+                        gint px, gint py, void (*push_cb) (void), SkinPixmapId si);
+PButton *create_pbutton_ex(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+                           gint x, gint y, gint w, gint h, gint nx,
+                           gint ny, gint px, gint py, void (*push_cb) (void),
+			   void (*release_cb) (void), SkinPixmapId si1,
+			   SkinPixmapId si2);
+void free_pbutton(PButton * b);
+void pbutton_set_skin_index(PButton * b, SkinPixmapId si);
+void pbutton_set_skin_index1(PButton * b, SkinPixmapId si);
+void pbutton_set_skin_index2(PButton * b, SkinPixmapId si);
+void pbutton_set_button_data(PButton * b, gint nx, gint ny, gint px, gint py);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/playlist_list.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,966 @@
+/*  Audacious - Cross-platform multimedia player
+ *  Copyright (C) 2005-2006  Audacious development team.
+ *
+ *  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/*
+ *  A note about Pango and some funky spacey fonts: Weirdly baselined
+ *  fonts, or fonts with weird ascents or descents _will_ display a
+ *  little bit weird in the playlist widget, but the display engine
+ *  won't make it look too bad, just a little deranged.  I honestly
+ *  don't think it's worth fixing (around...), it doesn't have to be
+ *  perfectly fitting, just the general look has to be ok, which it
+ *  IMHO is.
+ *
+ *  A second note: The numbers aren't perfectly aligned, but in the
+ *  end it looks better when using a single Pango layout for each
+ *  number.
+ */
+
+#include "widgetcore.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "audacious/main.h"
+#include "audacious/input.h"
+#include "audacious/playback.h"
+#include "audacious/playlist.h"
+#include "playlist.h"
+#include "audacious/util.h"
+
+#include "audacious/debug.h"
+
+static PangoFontDescription *playlist_list_font = NULL;
+static gint ascent, descent, width_delta_digit_one;
+static gboolean has_slant;
+static guint padding;
+
+/* FIXME: the following globals should not be needed. */
+static gint width_approx_letters;
+static gint width_colon, width_colon_third;
+static gint width_approx_digits, width_approx_digits_half;
+
+GdkPixmap *rootpix;
+
+void playlist_list_draw(Widget * w);
+
+/* Sort of stolen from XChat, but not really, as theres uses Xlib */
+static void
+shade_gdkimage_generic (GdkVisual *visual, GdkImage *ximg, int bpl, int w, int h, int rm, int gm, int bm, int bg)
+{
+	int x, y;
+	int bgr = (256 - rm) * (bg & visual->red_mask);
+	int bgg = (256 - gm) * (bg & visual->green_mask);
+	int bgb = (256 - bm) * (bg & visual->blue_mask);
+
+	for (x = 0; x < w; x++)
+	{
+		for (y = 0; y < h; y++)
+		{
+			unsigned long pixel = gdk_image_get_pixel (ximg, x, y);
+			int r, g, b;
+
+			r = rm * (pixel & visual->red_mask) + bgr;
+			g = gm * (pixel & visual->green_mask) + bgg;
+			b = bm * (pixel & visual->blue_mask) + bgb;
+
+			gdk_image_put_pixel (ximg, x, y,
+				((r >> 8) & visual->red_mask) |
+				((g >> 8) & visual->green_mask) |
+				((b >> 8) & visual->blue_mask));
+		}
+	}
+}
+
+/* and this is definately mine... -nenolod */
+GdkPixmap *
+shade_pixmap(GdkPixmap *in, gint x, gint y, gint x_offset, gint y_offset, gint w, gint h, GdkColor *shade_color)
+{
+	GdkImage *ximg;
+	GdkPixmap *p = gdk_pixmap_new(in, w, h, -1);
+	GdkGC *gc = gdk_gc_new(p);
+
+        gdk_draw_pixmap(p, gc, in, x, y, 0, 0, w, h);
+
+	gdk_error_trap_push();
+
+	ximg = gdk_drawable_copy_to_image(in, NULL, x, y, 0, 0, w, h);	/* copy */
+
+	gdk_error_trap_pop();
+
+	if (GDK_IS_IMAGE(ximg))
+	{
+		shade_gdkimage_generic(gdk_drawable_get_visual(GDK_WINDOW(playlistwin->window)),
+			ximg, ximg->bpl, w, h, 60, 60, 60, shade_color->pixel);
+
+		gdk_draw_image(p, gc, ximg, 0, 0, x, y, w, h);
+	}
+	else {
+		cfg.playlist_transparent = FALSE;
+	}
+
+	g_object_unref(gc);
+
+	return p;
+}
+
+#ifdef GDK_WINDOWING_X11
+
+#include <gdk/gdkx.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+GdkDrawable *get_transparency_pixmap(void)
+{
+	GdkDrawable *root;
+	XID *pixmaps;
+	GdkAtom prop_type;
+	gint prop_size;
+	GdkPixmap *pixmap;
+	gboolean ret;
+
+	root = gdk_get_default_root_window();
+
+	pixmap = NULL;
+	pixmaps = NULL;
+
+	gdk_error_trap_push();
+
+	ret = gdk_property_get(root, gdk_atom_intern("_XROOTPMAP_ID", TRUE),
+			0, 0, INT_MAX - 3,
+			FALSE,
+			&prop_type, NULL, &prop_size,
+			(guchar **) &pixmaps);
+
+	gdk_error_trap_pop();
+
+	if ((ret == TRUE) && (prop_type == GDK_TARGET_PIXMAP) && (prop_size >= sizeof(XID)) && (pixmaps != NULL))
+	{
+		pixmap = gdk_pixmap_foreign_new_for_display(gdk_drawable_get_display(root),
+			pixmaps[0]);
+
+		if (pixmaps != NULL)
+			g_free(pixmaps);
+	}
+
+	return GDK_DRAWABLE(pixmap);
+}
+
+static GdkFilterReturn
+root_event_cb (GdkXEvent *xev, GdkEventProperty *event, gpointer data)
+{
+        static Atom at = None;
+        XEvent *xevent = (XEvent *)xev;
+
+        if (xevent->type == PropertyNotify)
+        {
+                if (at == None)
+                        at = XInternAtom (xevent->xproperty.display, "_XROOTPMAP_ID", True);
+
+                if (at == xevent->xproperty.atom)
+		{
+                        rootpix = shade_pixmap(get_transparency_pixmap(), 0, 0, 0, 0, gdk_screen_width(), gdk_screen_height(),
+                            skin_get_color(bmp_active_skin, SKIN_PLEDIT_NORMALBG));
+
+			if (cfg.playlist_transparent)
+			{
+				playlistwin_update_list();
+				draw_playlist_window(TRUE);
+			}
+		}
+        }
+
+        return GDK_FILTER_CONTINUE;
+}
+
+#else
+
+GdkPixmap *get_transparency_pixmap(void)
+{
+    return NULL;
+}
+
+#endif
+
+static gboolean
+playlist_list_auto_drag_down_func(gpointer data)
+{
+    PlayList_List *pl = data;
+
+    if (pl->pl_auto_drag_down) {
+        playlist_list_move_down(pl);
+        pl->pl_first++;
+        playlistwin_update_list();
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static gboolean
+playlist_list_auto_drag_up_func(gpointer data)
+{
+    PlayList_List *pl = data;
+
+    if (pl->pl_auto_drag_up) {
+        playlist_list_move_up(pl);
+        pl->pl_first--;
+        playlistwin_update_list();
+        return TRUE;
+
+    }
+    return FALSE;
+}
+
+void
+playlist_list_move_up(PlayList_List * pl)
+{
+    GList *list;
+
+    PLAYLIST_LOCK();
+    if ((list = playlist_get()) == NULL) {
+        PLAYLIST_UNLOCK();
+        return;
+    }
+    if (PLAYLIST_ENTRY(list->data)->selected) {
+        /* We are at the top */
+        PLAYLIST_UNLOCK();
+        return;
+    }
+    while (list) {
+        if (PLAYLIST_ENTRY(list->data)->selected)
+            glist_moveup(list);
+        list = g_list_next(list);
+    }
+    PLAYLIST_UNLOCK();
+    if (pl->pl_prev_selected != -1)
+        pl->pl_prev_selected--;
+    if (pl->pl_prev_min != -1)
+        pl->pl_prev_min--;
+    if (pl->pl_prev_max != -1)
+        pl->pl_prev_max--;
+}
+
+void
+playlist_list_move_down(PlayList_List * pl)
+{
+    GList *list;
+
+    PLAYLIST_LOCK();
+
+    if (!(list = g_list_last(playlist_get()))) {
+        PLAYLIST_UNLOCK();
+        return;
+    }
+
+    if (PLAYLIST_ENTRY(list->data)->selected) {
+        /* We are at the bottom */
+        PLAYLIST_UNLOCK();
+        return;
+    }
+
+    while (list) {
+        if (PLAYLIST_ENTRY(list->data)->selected)
+            glist_movedown(list);
+        list = g_list_previous(list);
+    }
+
+    PLAYLIST_UNLOCK();
+
+    if (pl->pl_prev_selected != -1)
+        pl->pl_prev_selected++;
+    if (pl->pl_prev_min != -1)
+        pl->pl_prev_min++;
+    if (pl->pl_prev_max != -1)
+        pl->pl_prev_max++;
+}
+
+static void
+playlist_list_button_press_cb(GtkWidget * widget,
+                              GdkEventButton * event,
+                              PlayList_List * pl)
+{
+    gint nr, y;
+
+    if (event->button == 1 && pl->pl_fheight &&
+        widget_contains(&pl->pl_widget, event->x, event->y)) {
+
+        y = event->y - pl->pl_widget.y;
+        nr = (y / pl->pl_fheight) + pl->pl_first;
+
+        if (nr >= playlist_get_length())
+            nr = playlist_get_length() - 1;
+
+        if (!(event->state & GDK_CONTROL_MASK))
+            playlist_select_all(FALSE);
+
+        if (event->state & GDK_SHIFT_MASK && pl->pl_prev_selected != -1) {
+            playlist_select_range(pl->pl_prev_selected, nr, TRUE);
+            pl->pl_prev_min = pl->pl_prev_selected;
+            pl->pl_prev_max = nr;
+            pl->pl_drag_pos = nr - pl->pl_first;
+        }
+        else {
+            if (playlist_select_invert(nr)) {
+                if (event->state & GDK_CONTROL_MASK) {
+                    if (pl->pl_prev_min == -1) {
+                        pl->pl_prev_min = pl->pl_prev_selected;
+                        pl->pl_prev_max = pl->pl_prev_selected;
+                    }
+                    if (nr < pl->pl_prev_min)
+                        pl->pl_prev_min = nr;
+                    else if (nr > pl->pl_prev_max)
+                        pl->pl_prev_max = nr;
+                }
+                else
+                    pl->pl_prev_min = -1;
+                pl->pl_prev_selected = nr;
+                pl->pl_drag_pos = nr - pl->pl_first;
+            }
+        }
+        if (event->type == GDK_2BUTTON_PRESS) {
+            /*
+             * Ungrab the pointer to prevent us from
+             * hanging on to it during the sometimes slow
+             * bmp_playback_initiate().
+             */
+            gdk_pointer_ungrab(GDK_CURRENT_TIME);
+            gdk_flush();
+            playlist_set_position(nr);
+            if (!bmp_playback_get_playing())
+                bmp_playback_initiate();
+        }
+
+        pl->pl_dragging = TRUE;
+        playlistwin_update_list();
+    }
+}
+
+gint
+playlist_list_get_playlist_position(PlayList_List * pl,
+                                    gint x,
+                                    gint y)
+{
+    gint iy, length;
+    gint ret;
+
+    if (!widget_contains(WIDGET(pl), x, y) || !pl->pl_fheight)
+        return -1;
+
+    if ((length = playlist_get_length()) == 0)
+        return -1;
+    iy = y - pl->pl_widget.y;
+
+    ret = (iy / pl->pl_fheight) + pl->pl_first;
+
+    if(ret > length-1)
+	    ret = -1;
+
+    return ret;
+}
+
+static void
+playlist_list_motion_cb(GtkWidget * widget,
+                        GdkEventMotion * event,
+                        PlayList_List * pl)
+{
+    gint nr, y, off, i;
+
+    if (pl->pl_dragging) {
+        y = event->y - pl->pl_widget.y;
+        nr = (y / pl->pl_fheight);
+        if (nr < 0) {
+            nr = 0;
+            if (!pl->pl_auto_drag_up) {
+                pl->pl_auto_drag_up = TRUE;
+                pl->pl_auto_drag_up_tag =
+                    gtk_timeout_add(100, playlist_list_auto_drag_up_func, pl);
+            }
+        }
+        else if (pl->pl_auto_drag_up)
+            pl->pl_auto_drag_up = FALSE;
+
+        if (nr >= pl->pl_num_visible) {
+            nr = pl->pl_num_visible - 1;
+            if (!pl->pl_auto_drag_down) {
+                pl->pl_auto_drag_down = TRUE;
+                pl->pl_auto_drag_down_tag =
+                    gtk_timeout_add(100, playlist_list_auto_drag_down_func,
+                                    pl);
+            }
+        }
+        else if (pl->pl_auto_drag_down)
+            pl->pl_auto_drag_down = FALSE;
+
+        off = nr - pl->pl_drag_pos;
+        if (off) {
+            for (i = 0; i < abs(off); i++) {
+                if (off < 0)
+                    playlist_list_move_up(pl);
+                else
+                    playlist_list_move_down(pl);
+
+            }
+            playlistwin_update_list();
+        }
+        pl->pl_drag_pos = nr;
+    }
+}
+
+static void
+playlist_list_button_release_cb(GtkWidget * widget,
+                                GdkEventButton * event,
+                                PlayList_List * pl)
+{
+    pl->pl_dragging = FALSE;
+    pl->pl_auto_drag_down = FALSE;
+    pl->pl_auto_drag_up = FALSE;
+}
+
+static void
+playlist_list_draw_string(PlayList_List * pl,
+                          PangoFontDescription * font,
+                          gint line,
+                          gint width,
+                          const gchar * text,
+                          guint ppos)
+{
+    guint plist_length_int;
+
+    PangoLayout *layout;
+
+    REQUIRE_STATIC_LOCK(playlist);
+
+    if (cfg.show_numbers_in_pl) {
+        gchar *pos_string = g_strdup_printf(cfg.show_separator_in_pl == TRUE ? "%d" : "%d.", ppos);
+        plist_length_int =
+            gint_count_digits(playlist_get_length_nolock()) + !cfg.show_separator_in_pl + 1; /* cf.show_separator_in_pl will be 0 if false */
+
+        padding = plist_length_int;
+        padding = ((padding + 1) * width_approx_digits);
+
+        layout = gtk_widget_create_pango_layout(playlistwin, pos_string);
+        pango_layout_set_font_description(layout, playlist_list_font);
+        pango_layout_set_width(layout, plist_length_int * 100);
+
+        pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
+        gdk_draw_layout(pl->pl_widget.parent, pl->pl_widget.gc,
+                        pl->pl_widget.x +
+                        (width_approx_digits *
+                         (-1 + plist_length_int - strlen(pos_string))) +
+                        (width_approx_digits / 4),
+                        pl->pl_widget.y + (line - 1) * pl->pl_fheight +
+                        ascent + abs(descent), layout);
+        g_free(pos_string);
+        g_object_unref(layout);
+
+        if (!cfg.show_separator_in_pl)
+            padding -= (width_approx_digits * 1.5);
+    }
+    else {
+        padding = 3;
+    }
+
+    width -= padding;
+
+    layout = gtk_widget_create_pango_layout(playlistwin, text);
+
+    pango_layout_set_font_description(layout, playlist_list_font);
+    pango_layout_set_width(layout, width * PANGO_SCALE);
+    pango_layout_set_single_paragraph_mode(layout, TRUE);
+    pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
+    gdk_draw_layout(pl->pl_widget.parent, pl->pl_widget.gc,
+                    pl->pl_widget.x + padding + (width_approx_letters / 4),
+                    pl->pl_widget.y + (line - 1) * pl->pl_fheight +
+                    ascent + abs(descent), layout);
+
+    g_object_unref(layout);
+}
+
+void
+playlist_list_draw(Widget * w)
+{
+    PlayList_List *pl = PLAYLIST_LIST(w);
+    GList *list;
+    GdkGC *gc;
+    GdkPixmap *obj;
+    PangoLayout *layout;
+    gchar *title;
+    gint width, height;
+    gint i, max_first;
+    guint padding, padding_dwidth, padding_plength;
+    guint max_time_len = 0;
+    gfloat queue_tailpadding = 0;
+    gint tpadding; 
+    gsize tpadding_dwidth = 0;
+    gint x, y;
+    guint tail_width;
+    guint tail_len;
+
+    gchar tail[100];
+    gchar queuepos[255];
+    gchar length[40];
+
+    gchar **frags;
+    gchar *frag0;
+
+    gint plw_w, plw_h;
+
+    GdkRectangle *playlist_rect;
+
+    gc = pl->pl_widget.gc;
+
+    width = pl->pl_widget.width;
+    height = pl->pl_widget.height;
+
+    obj = pl->pl_widget.parent;
+
+    gtk_window_get_size(GTK_WINDOW(playlistwin), &plw_w, &plw_h);
+
+    playlist_rect = g_new0(GdkRectangle, 1);
+
+    playlist_rect->x = 0;
+    playlist_rect->y = 0;
+    playlist_rect->width = plw_w - 17;
+    playlist_rect->height = plw_h - 36;
+
+    gdk_gc_set_clip_origin(gc, 31, 58);
+    gdk_gc_set_clip_rectangle(gc, playlist_rect);
+
+    if (cfg.playlist_transparent == FALSE)
+    {
+        gdk_gc_set_foreground(gc,
+                              skin_get_color(bmp_active_skin,
+                                             SKIN_PLEDIT_NORMALBG));
+        gdk_draw_rectangle(obj, gc, TRUE, pl->pl_widget.x, pl->pl_widget.y,
+                              width, height);
+    }
+    else
+    {
+	if (!rootpix)
+           rootpix = shade_pixmap(get_transparency_pixmap(), 0, 0, 0, 0, gdk_screen_width(), gdk_screen_height(), 
+    			    skin_get_color(bmp_active_skin, SKIN_PLEDIT_NORMALBG));
+        gdk_draw_pixmap(obj, gc, rootpix, cfg.playlist_x + pl->pl_widget.x,
+                    cfg.playlist_y + pl->pl_widget.y, pl->pl_widget.x, pl->pl_widget.y,
+                    width, height);
+    }
+
+    if (!playlist_list_font) {
+        g_critical("Couldn't open playlist font");
+        return;
+    }
+
+    pl->pl_fheight = (ascent + abs(descent));
+    pl->pl_num_visible = height / pl->pl_fheight;
+
+    max_first = playlist_get_length() - pl->pl_num_visible;
+    max_first = MAX(max_first, 0);
+
+    pl->pl_first = CLAMP(pl->pl_first, 0, max_first);
+
+    PLAYLIST_LOCK();
+    list = playlist_get();
+    list = g_list_nth(list, pl->pl_first);
+
+    /* It sucks having to run the iteration twice but this is the only
+       way you can reliably get the maximum width so we can get our
+       playlist nice and aligned... -- plasmaroo */
+
+    for (i = pl->pl_first;
+         list && i < pl->pl_first + pl->pl_num_visible;
+         list = g_list_next(list), i++) {
+        PlaylistEntry *entry = list->data;
+
+        if (entry->length != -1)
+        {
+            g_snprintf(length, sizeof(length), "%d:%-2.2d",
+                       entry->length / 60000, (entry->length / 1000) % 60);
+            tpadding_dwidth = MAX(tpadding_dwidth, strlen(length));
+        }
+    }
+
+    /* Reset */
+    list = playlist_get();
+    list = g_list_nth(list, pl->pl_first);
+
+    for (i = pl->pl_first;
+         list && i < pl->pl_first + pl->pl_num_visible;
+         list = g_list_next(list), i++) {
+        gint pos;
+        PlaylistEntry *entry = list->data;
+
+        if (entry->selected) {
+            gdk_gc_set_foreground(gc,
+                                  skin_get_color(bmp_active_skin,
+                                                 SKIN_PLEDIT_SELECTEDBG));
+            gdk_draw_rectangle(obj, gc, TRUE, pl->pl_widget.x,
+                               pl->pl_widget.y +
+                               ((i - pl->pl_first) * pl->pl_fheight),
+                               width, pl->pl_fheight);
+        }
+
+        /* FIXME: entry->title should NEVER be NULL, and there should
+           NEVER be a need to do a UTF-8 conversion. Playlist title
+           strings should be kept properly. */
+
+        if (!entry->title) {
+            gchar *basename = g_path_get_basename(entry->filename);
+            title = filename_to_utf8(basename);
+            g_free(basename);
+        }
+        else
+            title = str_to_utf8(entry->title);
+
+        pos = playlist_get_queue_position(entry);
+
+        tail[0] = 0;
+        queuepos[0] = 0;
+        length[0] = 0;
+
+        if (pos != -1)
+            g_snprintf(queuepos, sizeof(queuepos), "%d", pos + 1);
+
+        if (entry->length != -1)
+        {
+            g_snprintf(length, sizeof(length), "%d:%-2.2d",
+                       entry->length / 60000, (entry->length / 1000) % 60);
+        }
+
+        strncat(tail, length, sizeof(tail));
+        tail_len = strlen(tail);
+
+        max_time_len = MAX(max_time_len, tail_len);
+
+        if (pos != -1 && tpadding_dwidth <= 0)
+            tail_width = width - (width_approx_digits * (strlen(queuepos) + 2.25));
+        else if (pos != -1)
+            tail_width = width - (width_approx_digits * (tpadding_dwidth + strlen(queuepos) + 4));
+        else if (tpadding_dwidth > 0)
+            tail_width = width - (width_approx_digits * (tpadding_dwidth + 2.5));
+        else
+            tail_width = width;
+
+        if (i == playlist_get_position_nolock())
+            gdk_gc_set_foreground(gc,
+                                  skin_get_color(bmp_active_skin,
+                                                 SKIN_PLEDIT_CURRENT));
+        else
+            gdk_gc_set_foreground(gc,
+                                  skin_get_color(bmp_active_skin,
+                                                 SKIN_PLEDIT_NORMAL));
+        playlist_list_draw_string(pl, playlist_list_font,
+                                  i - pl->pl_first, tail_width, title,
+                                  i + 1);
+
+        x = pl->pl_widget.x + width - width_approx_digits * 2;
+        y = pl->pl_widget.y + ((i - pl->pl_first) -
+                               1) * pl->pl_fheight + ascent;
+
+        frags = NULL;
+        frag0 = NULL;
+
+        if ((strlen(tail) > 0) && (tail != NULL)) {
+            frags = g_strsplit(tail, ":", 0);
+            frag0 = g_strconcat(frags[0], ":", NULL);
+
+            layout = gtk_widget_create_pango_layout(playlistwin, frags[1]);
+            pango_layout_set_font_description(layout, playlist_list_font);
+            pango_layout_set_width(layout, tail_len * 100);
+            pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
+            gdk_draw_layout(obj, gc, x - (0.5 * width_approx_digits),
+                            y + abs(descent), layout);
+            g_object_unref(layout);
+
+            layout = gtk_widget_create_pango_layout(playlistwin, frag0);
+            pango_layout_set_font_description(layout, playlist_list_font);
+            pango_layout_set_width(layout, tail_len * 100);
+            pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
+            gdk_draw_layout(obj, gc, x - (0.75 * width_approx_digits),
+                            y + abs(descent), layout);
+            g_object_unref(layout);
+
+            g_free(frag0);
+            g_strfreev(frags);
+        }
+
+        if (pos != -1) {
+
+            /* DON'T remove the commented code yet please     -- Milosz */
+
+            if (tpadding_dwidth > 0)
+                queue_tailpadding = tpadding_dwidth + 1;
+            else
+                queue_tailpadding = -0.75;
+
+            gdk_draw_rectangle(obj, gc, FALSE,
+                               x -
+                               (((queue_tailpadding +
+                                  strlen(queuepos)) *
+                                 width_approx_digits) +
+                                (width_approx_digits / 4)),
+                               y + abs(descent),
+                               (strlen(queuepos)) *
+                               width_approx_digits +
+                               (width_approx_digits / 2),
+                               pl->pl_fheight - 2);
+
+            layout =
+                gtk_widget_create_pango_layout(playlistwin, queuepos);
+            pango_layout_set_font_description(layout, playlist_list_font);
+            pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
+
+            gdk_draw_layout(obj, gc,
+                            x -
+                            ((queue_tailpadding +
+                              strlen(queuepos)) * width_approx_digits) +
+                            (width_approx_digits / 4),
+                            y + abs(descent), layout);
+            g_object_unref(layout);
+        }
+
+        g_free(title);
+    }
+
+
+    /*
+     * Drop target hovering over the playlist, so draw some hint where the
+     * drop will occur.
+     *
+     * This is (currently? unfixably?) broken when dragging files from Qt/KDE apps,
+     * probably due to DnD signaling problems (actually i have no clue).
+     *
+     */
+
+    if (pl->pl_drag_motion) {
+        guint pos, plength, lpadding;
+	gint x, y, plx, ply;
+
+        if (cfg.show_numbers_in_pl) {
+            lpadding = gint_count_digits(playlist_get_length_nolock()) + 1;
+            lpadding = ((lpadding + 1) * width_approx_digits);
+        }
+        else {
+            lpadding = 3;
+        };
+
+        /* We already hold the mutex and have the playlist locked, so call
+           the non-locking function. */
+        plength = playlist_get_length_nolock();
+
+        x = pl->drag_motion_x;
+        y = pl->drag_motion_y;
+
+        plx = pl->pl_widget.x;
+        ply = pl->pl_widget.y;
+
+        if ((x > pl->pl_widget.x) && !(x > pl->pl_widget.width)) {
+
+            if ((y > pl->pl_widget.y)
+                && !(y > (pl->pl_widget.height + ply))) {
+
+                pos = ((y - ((Widget *) pl)->y) / pl->pl_fheight) +
+                    pl->pl_first;
+
+                if (pos > (plength)) {
+                    pos = plength;
+                }
+
+                gdk_gc_set_foreground(gc,
+                                      skin_get_color(bmp_active_skin,
+                                                     SKIN_PLEDIT_CURRENT));
+
+                gdk_draw_line(obj, gc, pl->pl_widget.x,
+			      pl->pl_widget.y + ((pos - pl->pl_first) * pl->pl_fheight),
+                              pl->pl_widget.width + pl->pl_widget.x - 1,
+                              pl->pl_widget.y +
+                              ((pos - pl->pl_first) * pl->pl_fheight));
+            }
+
+        }
+
+        /* When dropping on the borders of the playlist, outside the text area,
+         * files get appended at the end of the list. Show that too.
+         */
+
+        if ((y < ply) || (y > pl->pl_widget.height + ply)) {
+            if ((y >= 0) || (y <= (pl->pl_widget.height + ply))) {
+                pos = plength;
+                gdk_gc_set_foreground(gc,
+                                      skin_get_color(bmp_active_skin,
+                                                     SKIN_PLEDIT_CURRENT));
+
+                gdk_draw_line(obj, gc, pl->pl_widget.x,
+                              pl->pl_widget.y +
+                              ((pos - pl->pl_first) * pl->pl_fheight),
+                              pl->pl_widget.width + pl->pl_widget.x - 1,
+                              pl->pl_widget.y +
+                              ((pos - pl->pl_first) * pl->pl_fheight));
+
+            }
+        }
+    }
+
+    gdk_gc_set_foreground(gc,
+                          skin_get_color(bmp_active_skin,
+                                         SKIN_PLEDIT_NORMAL));
+
+    if (cfg.show_numbers_in_pl) {
+
+        padding_plength = playlist_get_length_nolock();
+
+        if (padding_plength == 0) {
+            padding_dwidth = 0;
+        }
+        else {
+            padding_dwidth = gint_count_digits(playlist_get_length_nolock());
+        }
+
+        padding =
+            (padding_dwidth *
+             width_approx_digits) + width_approx_digits;
+
+
+        /* For italic or oblique fonts we add another half of the
+         * approximate width */
+        if (has_slant)
+            padding += width_approx_digits_half;
+
+        if (cfg.show_separator_in_pl) {
+            gdk_draw_line(obj, gc,
+                          pl->pl_widget.x + padding,
+                          pl->pl_widget.y,
+                          pl->pl_widget.x + padding,
+                          pl->pl_widget.y + pl->pl_widget.height - 1);
+        }
+    }
+
+    if (tpadding_dwidth != 0)
+    {
+        tpadding = (tpadding_dwidth * width_approx_digits) + (width_approx_digits * 1.5);
+
+        if (has_slant)
+            tpadding += width_approx_digits_half;
+
+        if (cfg.show_separator_in_pl) {
+            gdk_draw_line(obj, gc,
+                          pl->pl_widget.x + pl->pl_widget.width - tpadding,
+                          pl->pl_widget.y,
+                          pl->pl_widget.x + pl->pl_widget.width - tpadding,
+                          pl->pl_widget.y + pl->pl_widget.height - 1);
+        }
+    }
+
+    gdk_gc_set_clip_origin(gc, 0, 0);
+    gdk_gc_set_clip_rectangle(gc, NULL);
+
+    PLAYLIST_UNLOCK();
+
+    gdk_flush();
+
+    g_free(playlist_rect);
+}
+
+
+PlayList_List *
+create_playlist_list(GList ** wlist,
+                     GdkPixmap * parent,
+                     GdkGC * gc,
+                     gint x, gint y,
+                     gint w, gint h)
+{
+    PlayList_List *pl;
+
+    pl = g_new0(PlayList_List, 1);
+    widget_init(&pl->pl_widget, parent, gc, x, y, w, h, TRUE);
+
+    pl->pl_widget.button_press_cb =
+        (WidgetButtonPressFunc) playlist_list_button_press_cb;
+    pl->pl_widget.button_release_cb =
+        (WidgetButtonReleaseFunc) playlist_list_button_release_cb;
+    pl->pl_widget.motion_cb = (WidgetMotionFunc) playlist_list_motion_cb;
+    pl->pl_widget.draw = playlist_list_draw;
+
+    pl->pl_prev_selected = -1;
+    pl->pl_prev_min = -1;
+    pl->pl_prev_max = -1;
+
+    widget_list_add(wlist, WIDGET(pl));
+
+#ifdef GDK_WINDOWING_X11
+    gdk_window_set_events (gdk_get_default_root_window(), GDK_PROPERTY_CHANGE_MASK);
+    gdk_window_add_filter (gdk_get_default_root_window(), (GdkFilterFunc)root_event_cb, pl);
+#endif
+
+    return pl;
+}
+
+void
+playlist_list_set_font(const gchar * font)
+{
+
+    /* Welcome to bad hack central 2k3 */
+
+    gchar *font_lower;
+    gint width_temp;
+    gint width_temp_0;
+
+    playlist_list_font = pango_font_description_from_string(font);
+
+    text_get_extents(font,
+                     "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz ",
+                     &width_approx_letters, NULL, &ascent, &descent);
+
+    width_approx_letters = (width_approx_letters / 53);
+
+    /* Experimental: We don't weigh the 1 into total because it's width is almost always
+     * very different from the rest
+     */
+    text_get_extents(font, "023456789", &width_approx_digits, NULL, NULL,
+                     NULL);
+    width_approx_digits = (width_approx_digits / 9);
+
+    /* Precache some often used calculations */
+    width_approx_digits_half = width_approx_digits / 2;
+
+    /* FIXME: We assume that any other number is broader than the "1" */
+    text_get_extents(font, "1", &width_temp, NULL, NULL, NULL);
+    text_get_extents(font, "2", &width_temp_0, NULL, NULL, NULL);
+
+    if (abs(width_temp_0 - width_temp) < 2) {
+        width_delta_digit_one = 0;
+    }
+    else {
+        width_delta_digit_one = ((width_temp_0 - width_temp) / 2) + 2;
+    }
+
+    text_get_extents(font, ":", &width_colon, NULL, NULL, NULL);
+    width_colon_third = width_colon / 4;
+
+    font_lower = g_utf8_strdown(font, strlen(font));
+    /* This doesn't take any i18n into account, but i think there is none with TTF fonts
+     * FIXME: This can probably be retrieved trough Pango too
+     */
+    has_slant = g_strstr_len(font_lower, strlen(font_lower), "oblique")
+        || g_strstr_len(font_lower, strlen(font_lower), "italic");
+
+    g_free(font_lower);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/playlist_list.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,60 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef PLAYLIST_LIST_H
+#define PLAYLIST_LIST_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include "widget.h"
+
+#define PLAYLIST_LIST(x)    ((PlayList_List *)(x))
+struct _PlayList_List {
+    Widget pl_widget;
+    gint pl_first, pl_fheight, pl_prev_selected, pl_prev_min, pl_prev_max;
+    gint pl_num_visible, pl_drag_pos;
+    gboolean pl_dragging, pl_auto_drag_down, pl_auto_drag_up;
+    gint pl_auto_drag_up_tag, pl_auto_drag_down_tag;
+    gboolean pl_drag_motion;
+    gint drag_motion_x, drag_motion_y;
+    gboolean pl_tooltips;
+};
+
+typedef struct _PlayList_List PlayList_List;
+
+PlayList_List *create_playlist_list(GList ** wlist, GdkPixmap * parent,
+                                    GdkGC * gc, gint x, gint y, gint w,
+                                    gint h);
+void playlist_list_move_up(PlayList_List * pl);
+void playlist_list_move_down(PlayList_List * pl);
+int playlist_list_get_playlist_position(PlayList_List * pl, gint x, gint y);
+void playlist_list_set_font(const gchar * font);
+GdkPixmap *rootpix;
+GdkPixmap *shade_pixmap(GdkDrawable *in, gint x, gint y, gint x_offset, gint y_offset, gint w, gint h, GdkColor *shade_color);
+GdkDrawable *get_transparency_pixmap(void);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/playlist_slider.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,168 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+
+#include "audacious/playlist.h"
+#include "playlist.h"
+#include "skin.h"
+#include "widget.h"
+
+void
+playlistslider_draw(Widget * w)
+{
+    PlaylistSlider *ps = (PlaylistSlider *) w;
+    GdkPixmap *obj;
+    gint y, skinx;
+
+    g_return_if_fail(ps != NULL);
+    g_return_if_fail(ps->ps_list != NULL);
+
+    if (playlist_get_length() > ps->ps_list->pl_num_visible)
+        y = (ps->ps_list->pl_first * (ps->ps_widget.height - 19)) /
+            (playlist_get_length() - ps->ps_list->pl_num_visible);
+    else
+        y = 0;
+
+    obj = ps->ps_widget.parent;
+
+    if (ps->ps_back_image) {
+        if (skin_get_id() != ps->ps_skin_id)
+            ps->ps_skin_id = skin_get_id();
+        else if (ps->ps_widget.height == ps->ps_prev_height)
+            gdk_draw_image(obj, ps->ps_widget.gc,
+                           ps->ps_back_image, 0, 0,
+                           ps->ps_widget.x,
+                           ps->ps_widget.y + ps->ps_prev_y, 8, 18);
+        gdk_image_destroy(ps->ps_back_image);
+    }
+
+    ps->ps_prev_y = y;
+    ps->ps_prev_height = ps->ps_widget.height;
+    ps->ps_back_image = gdk_drawable_get_image(obj, ps->ps_widget.x,
+                                               ps->ps_widget.y + y, 8, 18);
+    if (ps->ps_is_draging)
+        skinx = 61;
+    else
+        skinx = 52;
+
+    skin_draw_pixmap(bmp_active_skin, obj, ps->ps_widget.gc, SKIN_PLEDIT,
+                     skinx, 53, ps->ps_widget.x, ps->ps_widget.y + y, 8, 18);
+}
+
+static void
+playlistslider_set_pos(PlaylistSlider * ps, gint y)
+{
+    gint pos;
+
+    y = CLAMP(y, 0, ps->ps_widget.height - 19);
+
+    pos = (y * (playlist_get_length() - ps->ps_list->pl_num_visible)) /
+        (ps->ps_widget.height - 19);
+    playlistwin_set_toprow(pos);
+}
+
+
+void
+playlistslider_button_press_cb(GtkWidget * widget,
+                               GdkEventButton * event, PlaylistSlider * ps)
+{
+    gint y = event->y - ps->ps_widget.y;
+
+    if (!widget_contains(&ps->ps_widget, event->x, event->y))
+        return;
+
+    if (event->button != 1 && event->button != 2)
+        return;
+
+    if ((y >= ps->ps_prev_y && y < ps->ps_prev_y + 18)) {
+        ps->ps_is_draging |= event->button;
+        ps->ps_drag_y = y - ps->ps_prev_y;
+        widget_draw(WIDGET(ps));
+    }
+    else if (event->button == 2) {
+        playlistslider_set_pos(ps, y);
+        ps->ps_is_draging |= event->button;
+        ps->ps_drag_y = 0;
+        widget_draw(WIDGET(ps));
+    }
+    else {
+        gint n = ps->ps_list->pl_num_visible / 2;
+        if (y < ps->ps_prev_y)
+            n *= -1;
+        playlistwin_scroll(n);
+    }
+}
+
+void
+playlistslider_button_release_cb(GtkWidget * widget,
+                                 GdkEventButton * event,
+                                 PlaylistSlider * ps)
+{
+    if (ps->ps_is_draging) {
+        ps->ps_is_draging &= ~event->button;
+        widget_draw(WIDGET(ps));
+    }
+}
+
+void
+playlistslider_motion_cb(GtkWidget * widget, GdkEventMotion * event,
+                         PlaylistSlider * ps)
+{
+    gint y;
+
+    if (!ps->ps_is_draging)
+        return;
+
+    y = event->y - ps->ps_widget.y - ps->ps_drag_y;
+    playlistslider_set_pos(ps, y);
+}
+
+PlaylistSlider *
+create_playlistslider(GList ** wlist, GdkPixmap * parent,
+                      GdkGC * gc, gint x, gint y, gint h,
+                      PlayList_List * list)
+{
+    PlaylistSlider *ps;
+
+    ps = g_new0(PlaylistSlider, 1);
+    widget_init(&ps->ps_widget, parent, gc, x, y, 8, h, 1);
+
+    ps->ps_widget.button_press_cb =
+        (void (*)(GtkWidget *, GdkEventButton *, gpointer))
+        playlistslider_button_press_cb;
+
+    ps->ps_widget.button_release_cb =
+        (void (*)(GtkWidget *, GdkEventButton *, gpointer))
+        playlistslider_button_release_cb;
+
+    ps->ps_widget.motion_cb =
+        (void (*)(GtkWidget *, GdkEventMotion *, gpointer))
+        playlistslider_motion_cb;
+
+    ps->ps_widget.draw = playlistslider_draw;
+    ps->ps_list = list;
+
+    widget_list_add(wlist, WIDGET(ps));
+    return ps;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/playlist_slider.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,51 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef PLAYLIST_SLIDER_H
+#define PLAYLIST_SLIDER_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "playlist_list.h"
+#include "widget.h"
+
+#define PLAYLIST_SLIDER(x)  ((PlayerlistSlider *)(x))
+struct _PlaylistSlider {
+    Widget ps_widget;
+    PlayList_List *ps_list;
+    gboolean ps_is_draging;
+    gint ps_drag_y, ps_prev_y, ps_prev_height;
+    GdkImage *ps_back_image;
+    gint ps_skin_id;
+};
+
+typedef struct _PlaylistSlider PlaylistSlider;
+
+PlaylistSlider *create_playlistslider(GList ** wlist, GdkPixmap * parent,
+                                      GdkGC * gc, gint x, gint y, gint h,
+                                      PlayList_List * list);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/playstatus.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,102 @@
+/*  XMMS - Cross-platform multimedia player
+ *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "skin.h"
+#include "widget.h"
+
+void
+playstatus_draw(Widget * w)
+{
+    PlayStatus *ps = PLAY_STATUS(w);
+    GdkPixmap *obj;
+
+    if (!w)
+        return;
+
+    obj = ps->ps_widget.parent;
+    if (ps->ps_status == STATUS_STOP && ps->ps_status_buffering == TRUE)
+        ps->ps_status_buffering = FALSE;
+    if (ps->ps_status == STATUS_PLAY && ps->ps_status_buffering == TRUE)
+        skin_draw_pixmap(bmp_active_skin, obj, ps->ps_widget.gc,
+                         SKIN_PLAYPAUSE, 39, 0, ps->ps_widget.x,
+                         ps->ps_widget.y, 3, 9);
+    else if (ps->ps_status == STATUS_PLAY)
+        skin_draw_pixmap(bmp_active_skin, obj, ps->ps_widget.gc,
+                         SKIN_PLAYPAUSE, 36, 0, ps->ps_widget.x,
+                         ps->ps_widget.y, 3, 9);
+    else
+        skin_draw_pixmap(bmp_active_skin, obj, ps->ps_widget.gc,
+                         SKIN_PLAYPAUSE, 27, 0, ps->ps_widget.x,
+                         ps->ps_widget.y, 2, 9);
+    switch (ps->ps_status) {
+    case STATUS_STOP:
+        skin_draw_pixmap(bmp_active_skin, obj, ps->ps_widget.gc,
+                         SKIN_PLAYPAUSE, 18, 0,
+                         ps->ps_widget.x + 2, ps->ps_widget.y, 9, 9);
+        break;
+    case STATUS_PAUSE:
+        skin_draw_pixmap(bmp_active_skin, obj, ps->ps_widget.gc,
+                         SKIN_PLAYPAUSE, 9, 0,
+                         ps->ps_widget.x + 2, ps->ps_widget.y, 9, 9);
+        break;
+    case STATUS_PLAY:
+        skin_draw_pixmap(bmp_active_skin, obj, ps->ps_widget.gc,
+                         SKIN_PLAYPAUSE, 1, 0,
+                         ps->ps_widget.x + 3, ps->ps_widget.y, 8, 9);
+        break;
+    }
+}
+
+void
+playstatus_set_status(PlayStatus * ps, PStatus status)
+{
+    if (!ps)
+        return;
+
+    ps->ps_status = status;
+    widget_draw(WIDGET(ps));
+}
+
+void
+playstatus_set_status_buffering(PlayStatus * ps, gboolean status)
+{
+    if (!ps)
+        return;
+
+    ps->ps_status_buffering = status;
+    widget_draw(WIDGET(ps));
+}
+
+PlayStatus *
+create_playstatus(GList ** wlist, GdkPixmap * parent,
+                  GdkGC * gc, gint x, gint y)
+{
+    PlayStatus *ps;
+
+    ps = g_new0(PlayStatus, 1);
+    widget_init(&ps->ps_widget, parent, gc, x, y, 11, 9, TRUE);
+    ps->ps_widget.draw = playstatus_draw;
+
+    widget_list_add(wlist, WIDGET(ps));
+    return ps;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/playstatus.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,46 @@
+/*  XMMS - Cross-platform multimedia player
+ *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef PLAYSTATUS_H
+#define PLAYSTATUS_H
+
+#include "widget.h"
+
+typedef enum {
+    STATUS_STOP, STATUS_PAUSE, STATUS_PLAY
+} PStatus;
+
+#define PLAY_STATUS(x)  ((PlayStatus *)(x))
+struct _PlayStatus {
+    Widget ps_widget;
+    PStatus ps_status;
+    gboolean ps_status_buffering;
+};
+
+typedef struct _PlayStatus PlayStatus;
+
+void playstatus_set_status(PlayStatus * ps, PStatus status);
+void playstatus_set_status_buffering(PlayStatus * ps, gboolean status);
+PlayStatus *create_playstatus(GList ** wlist, GdkPixmap * parent,
+                              GdkGC * gc, gint x, gint y);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/sbutton.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,99 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+void
+sbutton_button_press_cb(GtkWidget * widget,
+                        GdkEventButton * event,
+                        SButton * button)
+{
+    if (event->button != 1)
+        return;
+
+    if (widget_contains(&button->sb_widget, event->x, event->y)) {
+        button->sb_pressed = 1;
+        button->sb_inside = 1;
+    }
+}
+
+void
+sbutton_button_release_cb(GtkWidget * widget, GdkEventButton * event,
+                          SButton * button)
+{
+    if (event->button != 1)
+        return;
+    if (button->sb_inside && button->sb_pressed) {
+        button->sb_inside = 0;
+        if (button->sb_push_cb)
+            button->sb_push_cb();
+    }
+    if (button->sb_pressed)
+        button->sb_pressed = 0;
+}
+
+void
+sbutton_motion_cb(GtkWidget * widget, GdkEventMotion * event,
+                  SButton * button)
+{
+    int inside;
+
+    if (!button->sb_pressed)
+        return;
+
+    inside = widget_contains(&button->sb_widget, event->x, event->y);
+
+    if (inside != button->sb_inside)
+        button->sb_inside = inside;
+}
+
+SButton *
+create_sbutton(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+               gint x, gint y, gint w, gint h, void (*cb) (void))
+{
+    SButton *b;
+
+    b = g_new0(SButton, 1);
+    widget_init(&b->sb_widget, parent, gc, x, y, w, h, 1);
+    b->sb_widget.button_press_cb =
+        (void (*)(GtkWidget *, GdkEventButton *, gpointer))
+        sbutton_button_press_cb;
+    b->sb_widget.button_release_cb =
+        (void (*)(GtkWidget *, GdkEventButton *, gpointer))
+        sbutton_button_release_cb;
+    b->sb_widget.motion_cb =
+        (void (*)(GtkWidget *, GdkEventMotion *, gpointer))
+        sbutton_motion_cb;
+    b->sb_push_cb = cb;
+
+    widget_list_add(wlist, WIDGET(b));
+    return b;
+}
+
+void
+free_sbutton(SButton * b)
+{
+    g_free(b);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/sbutton.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,47 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef SBUTTON_H
+#define SBUTTON_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "widget.h"
+
+#define SBUTTON(x)  ((SButton *)(x))
+struct _SButton {
+    Widget sb_widget;
+    gint sb_pressed, sb_inside;
+    void (*sb_push_cb) (void);
+};
+
+typedef struct _SButton SButton;
+
+SButton *create_sbutton(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+                        gint x, gint y, gint w, gint h, void (*cb) (void));
+void free_sbutton(SButton * b);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/skin.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,1256 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* TODO: enforce default sizes! */
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "widgetcore.h"
+
+#include "mainwin.h"
+#include "equalizer.h"
+#include "playlist.h"
+
+#include "audacious/main.h"
+#include "audacious/skinwin.h"
+#include "audacious/util.h"
+
+#include "audacious/debug.h"
+
+#include "audacious/platform/smartinclude.h"
+
+#define EXTENSION_TARGETS 7
+
+static gchar *ext_targets[EXTENSION_TARGETS] = { "bmp", "xpm", "png", "svg", 
+	"gif", "jpg", "jpeg" };
+
+struct _SkinPixmapIdMapping {
+    SkinPixmapId id;
+    const gchar *name;
+    const gchar *alt_name;
+    gint width, height;
+};
+
+struct _SkinMaskInfo {
+    gint width, height;
+    gchar *inistr;
+};
+
+typedef struct _SkinPixmapIdMapping SkinPixmapIdMapping;
+typedef struct _SkinMaskInfo SkinMaskInfo;
+
+
+Skin *bmp_active_skin = NULL;
+
+static gint skin_current_num;
+
+static SkinMaskInfo skin_mask_info[] = {
+    {275, 116, "Normal"},
+    {275, 16,  "WindowShade"},
+    {275, 116, "Equalizer"},
+    {275, 16,  "EqualizerWS"}
+};
+
+static SkinPixmapIdMapping skin_pixmap_id_map[] = {
+    {SKIN_MAIN, "main", NULL, 0, 0},
+    {SKIN_CBUTTONS, "cbuttons", NULL, 0, 0},
+    {SKIN_SHUFREP, "shufrep", NULL, 0, 0},
+    {SKIN_TEXT, "text", NULL, 0, 0},
+    {SKIN_TITLEBAR, "titlebar", NULL, 0, 0},
+    {SKIN_VOLUME, "volume", NULL, 0, 0},
+    {SKIN_BALANCE, "balance", "volume", 0, 0},
+    {SKIN_MONOSTEREO, "monoster", NULL, 0, 0},
+    {SKIN_PLAYPAUSE, "playpaus", NULL, 0, 0},
+    {SKIN_NUMBERS, "nums_ex", "numbers", 0, 0},
+    {SKIN_POSBAR, "posbar", NULL, 0, 0},
+    {SKIN_EQMAIN, "eqmain", NULL, 0, 0},
+    {SKIN_PLEDIT, "pledit", NULL, 0, 0},
+    {SKIN_EQ_EX, "eq_ex", NULL, 0, 0}
+};
+
+static guint skin_pixmap_id_map_size = G_N_ELEMENTS(skin_pixmap_id_map);
+
+static const guchar skin_default_viscolor[24][3] = {
+    {9, 34, 53},
+    {10, 18, 26},
+    {0, 54, 108},
+    {0, 58, 116},
+    {0, 62, 124},
+    {0, 66, 132},
+    {0, 70, 140},
+    {0, 74, 148},
+    {0, 78, 156},
+    {0, 82, 164},
+    {0, 86, 172},
+    {0, 92, 184},
+    {0, 98, 196},
+    {0, 104, 208},
+    {0, 110, 220},
+    {0, 116, 232},
+    {0, 122, 244},
+    {0, 128, 255},
+    {0, 128, 255},
+    {0, 104, 208},
+    {0, 80, 160},
+    {0, 56, 112},
+    {0, 32, 64},
+    {200, 200, 200}
+};
+
+static GdkBitmap *
+skin_create_transparent_mask(const gchar *,
+                             const gchar *,
+                             const gchar *,
+                             GdkWindow *,
+                             gint, gint);
+
+static void
+skin_setup_masks(Skin * skin);
+
+static void
+skin_set_default_vis_color(Skin * skin);
+
+
+void
+skin_lock(Skin * skin)
+{
+    g_mutex_lock(skin->lock);
+}
+
+void
+skin_unlock(Skin * skin)
+{
+    g_mutex_unlock(skin->lock);
+}
+
+gboolean
+bmp_active_skin_reload(void) 
+{
+    return bmp_active_skin_load(bmp_active_skin->path);	
+}
+
+gboolean
+bmp_active_skin_load(const gchar * path)
+{
+    g_return_val_if_fail(bmp_active_skin != NULL, FALSE);
+
+    memset(&bmp_active_skin->properties, 0, sizeof(SkinProperties));
+
+    if (!skin_load(bmp_active_skin, path))
+        return FALSE;
+
+    skin_setup_masks(bmp_active_skin);
+
+    if (cfg.playlist_transparent)
+    {
+        if (rootpix != NULL)
+            g_object_unref(rootpix);
+
+        rootpix = shade_pixmap(get_transparency_pixmap(), 0, 0, 0, 0, gdk_screen_width(), gdk_screen_height(),
+                               skin_get_color(bmp_active_skin, SKIN_PLEDIT_NORMALBG));
+    }
+
+    draw_main_window(TRUE);
+    draw_playlist_window(TRUE);
+    draw_equalizer_window(TRUE);
+
+    vis_set_window(mainwin_vis, mainwin->window);
+    playlistwin_update_list();
+
+    return TRUE;
+}
+
+void
+skin_pixmap_free(SkinPixmap * p)
+{
+    g_return_if_fail(p != NULL);
+    g_return_if_fail(p->pixmap != NULL);
+
+    g_object_unref(p->pixmap);
+    p->pixmap = NULL;
+}
+
+Skin *
+skin_new(void)
+{
+    Skin *skin;
+    skin = g_new0(Skin, 1);
+    skin->lock = g_mutex_new();
+    return skin;
+}
+
+void
+skin_free(Skin * skin)
+{
+    gint i;
+
+    g_return_if_fail(skin != NULL);
+
+    skin_lock(skin);
+
+    for (i = 0; i < SKIN_PIXMAP_COUNT; i++)
+        skin_pixmap_free(&skin->pixmaps[i]);
+
+    for (i = 0; i < SKIN_PIXMAP_COUNT; i++) {
+        if (skin->masks[i])
+            g_object_unref(skin->masks[i]);
+
+        skin->masks[i] = NULL;
+    }
+
+    skin_set_default_vis_color(skin);
+    skin_unlock(skin);
+}
+
+void
+skin_destroy(Skin * skin)
+{
+    g_return_if_fail(skin != NULL);
+    skin_free(skin);
+    g_mutex_free(skin->lock);
+    g_free(skin);
+}
+
+const SkinPixmapIdMapping *
+skin_pixmap_id_lookup(guint id)
+{
+    guint i;
+
+    for (i = 0; i < skin_pixmap_id_map_size; i++) {
+        if (id == skin_pixmap_id_map[i].id) {
+            return &skin_pixmap_id_map[i];
+        }
+    }
+
+    return NULL;
+}
+
+const gchar *
+skin_pixmap_id_to_name(SkinPixmapId id)
+{
+    guint i;
+
+    for (i = 0; i < skin_pixmap_id_map_size; i++) {
+        if (id == skin_pixmap_id_map[i].id)
+            return skin_pixmap_id_map[i].name;
+    }
+    return NULL;
+}
+
+static void
+skin_set_default_vis_color(Skin * skin)
+{
+    memcpy(skin->vis_color, skin_default_viscolor,
+           sizeof(skin_default_viscolor));
+}
+
+/*
+ * I have rewritten this to take an array of possible targets,
+ * once we find a matching target we now return, instead of loop
+ * recursively. This allows for us to support many possible format
+ * targets for our skinning engine than just the original winamp 
+ * formats.
+ *
+ *    -- nenolod, 16 January 2006
+ */
+gchar *
+skin_pixmap_locate(const gchar * dirname, gchar ** basenames)
+{
+    gchar *filename;
+    gint i;
+
+    for (i = 0; basenames[i]; i++)
+	if (!(filename = find_file_recursively(dirname, basenames[i]))) 
+            g_free(filename);
+        else
+            return filename;
+
+    /* can't find any targets -- sorry */
+    return NULL;
+}
+
+/* FIXME: this function is temporary. It will be removed when the skinning system
+   uses GdkPixbuf in place of GdkPixmap */
+
+static GdkPixmap *
+pixmap_new_from_file(const gchar * filename)
+{
+    GdkPixbuf *pixbuf;
+    GdkPixmap *pixmap;
+    gint width, height;
+
+    if (!(pixbuf = gdk_pixbuf_new_from_file(filename, NULL)))
+        return NULL;
+
+    width = gdk_pixbuf_get_width(pixbuf);
+    height = gdk_pixbuf_get_height(pixbuf);
+
+    if (!(pixmap = gdk_pixmap_new(mainwin->window, width, height,
+                                  gdk_rgb_get_visual()->depth))) {
+        g_object_unref(pixbuf);
+        return NULL;
+    }
+
+    gdk_pixbuf_render_to_drawable(pixbuf, pixmap, mainwin_gc, 0, 0, 0, 0,
+                                  width, height, GDK_RGB_DITHER_MAX, 0, 0);
+    g_object_unref(pixbuf);
+
+    return pixmap;
+}
+
+static gboolean
+skin_load_pixmap_id(Skin * skin, SkinPixmapId id, const gchar * path_p)
+{
+    const gchar *path;
+    gchar *filename;
+    gint width, height;
+    const SkinPixmapIdMapping *pixmap_id_mapping;
+    GdkPixmap *gpm;
+    SkinPixmap *pm = NULL;
+    gchar *basenames[EXTENSION_TARGETS * 2 + 1]; /* alternate basenames */
+    gint i, y;
+
+    g_return_val_if_fail(skin != NULL, FALSE);
+    g_return_val_if_fail(id < SKIN_PIXMAP_COUNT, FALSE);
+
+    pixmap_id_mapping = skin_pixmap_id_lookup(id);
+    g_return_val_if_fail(pixmap_id_mapping != NULL, FALSE);
+
+    memset(&basenames, 0, sizeof(basenames));
+
+    for (i = 0, y = 0; i < EXTENSION_TARGETS; i++, y++)
+    {
+        basenames[y] = g_strdup_printf("%s.%s", pixmap_id_mapping->name,
+			ext_targets[i]);
+
+        if (pixmap_id_mapping->alt_name)
+            basenames[++y] = g_strdup_printf("%s.%s", 
+			pixmap_id_mapping->alt_name, ext_targets[i]);
+    }
+
+    path = path_p ? path_p : skin->path;
+    filename = skin_pixmap_locate(path, basenames);
+
+    for (i = 0; basenames[i] != NULL; i++)
+    {
+         g_free(basenames[i]);
+         basenames[i] = NULL;
+    }
+
+    if (!(gpm = pixmap_new_from_file(filename))) {
+        g_warning("loading of %s failed", filename);
+        g_free(filename);
+        return FALSE;
+    }
+
+    g_free(filename);
+
+    gdk_drawable_get_size(GDK_DRAWABLE(gpm), &width, &height);
+    pm = &skin->pixmaps[id];
+    pm->pixmap = gpm;
+    pm->width = width;
+    pm->height = height;
+    pm->current_width = width;
+    pm->current_height = height;
+
+    return TRUE;
+}
+
+void
+skin_mask_create(Skin * skin,
+                 const gchar * path,
+                 gint id,
+                 GdkWindow * window)
+{
+    skin->masks[id] =
+        skin_create_transparent_mask(path, "region.txt",
+                                     skin_mask_info[id].inistr, window,
+                                     skin_mask_info[id].width,
+                                     skin_mask_info[id].height);
+}
+
+static void
+skin_setup_masks(Skin * skin)
+{
+    GdkBitmap *mask;
+
+    if (cfg.show_wm_decorations)
+        return;
+
+    if (cfg.player_visible) {
+        mask = skin_get_mask(skin, SKIN_MASK_MAIN + cfg.player_shaded);
+        gtk_widget_shape_combine_mask(mainwin, mask, 0, 0);
+    }
+
+    mask = skin_get_mask(skin, SKIN_MASK_EQ + cfg.equalizer_shaded);
+    gtk_widget_shape_combine_mask(equalizerwin, mask, 0, 0);
+}
+
+static GdkBitmap *
+create_default_mask(GdkWindow * parent, gint w, gint h)
+{
+    GdkBitmap *ret;
+    GdkGC *gc;
+    GdkColor pattern;
+
+    ret = gdk_pixmap_new(parent, w, h, 1);
+    gc = gdk_gc_new(ret);
+    pattern.pixel = 1;
+    gdk_gc_set_foreground(gc, &pattern);
+    gdk_draw_rectangle(ret, gc, TRUE, 0, 0, w, h);
+    gdk_gc_destroy(gc);
+
+    return ret;
+}
+
+static void
+skin_query_color(GdkColormap * cm, GdkColor * c)
+{
+#ifdef GDK_WINDOWING_X11
+    XColor xc = { 0,0,0,0,0,0 };
+
+    xc.pixel = c->pixel;
+    XQueryColor(GDK_COLORMAP_XDISPLAY(cm), GDK_COLORMAP_XCOLORMAP(cm), &xc);
+    c->red = xc.red;
+    c->green = xc.green;
+    c->blue = xc.blue;
+#else
+    /* do nothing. see what breaks? */
+#endif
+}
+
+static glong
+skin_calc_luminance(GdkColor * c)
+{
+    return (0.212671 * c->red + 0.715160 * c->green + 0.072169 * c->blue);
+}
+
+static void
+skin_get_textcolors(GdkPixmap * text, GdkColor * bgc, GdkColor * fgc)
+{
+    /*
+     * Try to extract reasonable background and foreground colors
+     * from the font pixmap
+     */
+
+    GdkImage *gi;
+    GdkColormap *cm;
+    gint i;
+
+    g_return_if_fail(text != NULL);
+
+    /* Get the first line of text */
+    gi = gdk_drawable_get_image(text, 0, 0, 152, 6);
+    cm = gdk_window_get_colormap(playlistwin->window);
+    g_return_if_fail(GDK_IS_WINDOW(playlistwin->window));
+
+    for (i = 0; i < 6; i++) {
+        GdkColor c;
+        gint x;
+        glong d, max_d;
+
+        /* Get a pixel from the middle of the space character */
+        bgc[i].pixel = gdk_image_get_pixel(gi, 151, i);
+        skin_query_color(cm, &bgc[i]);
+
+        max_d = 0;
+        for (x = 1; x < 150; x++) {
+            c.pixel = gdk_image_get_pixel(gi, x, i);
+            skin_query_color(cm, &c);
+
+            d = labs(skin_calc_luminance(&c) - skin_calc_luminance(&bgc[i]));
+            if (d > max_d) {
+                memcpy(&fgc[i], &c, sizeof(GdkColor));
+                max_d = d;
+            }
+        }
+    }
+    gdk_image_destroy(gi);
+}
+
+gboolean
+init_skins(const gchar * path)
+{
+    bmp_active_skin = skin_new();
+
+    if (!bmp_active_skin_load(path)) {
+        /* FIXME: Oddly, g_message() causes a crash if path is NULL on
+         * Solaris (see bug #165) */
+        if (path) 
+            g_message("Unable to load skin (%s), trying default...", path);
+
+        /* can't load configured skin, retry with default */
+        if (!bmp_active_skin_load(BMP_DEFAULT_SKIN_PATH)) {
+            g_message("Unable to load default skin (%s)! Giving up.",
+                      BMP_DEFAULT_SKIN_PATH);
+            return FALSE;
+        }
+    }
+
+    if (cfg.random_skin_on_play)
+        skinlist_update();
+
+    return TRUE;
+}
+
+/*
+ * Opens and parses a skin's hints file.
+ * Hints files are somewhat like "scripts" in Winamp3/5.
+ * We'll probably add scripts to it next.
+ */
+void
+skin_parse_hints(Skin * skin, gchar *path_p)
+{
+    gchar *filename, *tmp;
+
+    path_p = path_p ? path_p : skin->path;
+
+    filename = find_file_recursively(path_p, "skin.hints");
+
+    if (filename == NULL)
+        return;
+
+#if 0
+    skin->description = read_ini_string(filename, "skin", "skinDescription");
+#endif
+
+    tmp = read_ini_string(filename, "skin", "mainwinOthertext");
+
+    if (tmp != NULL)
+        skin->properties.mainwin_othertext = atoi(tmp);
+}
+
+static guint
+hex_chars_to_int(gchar hi, gchar lo)
+{
+    /*
+     * Converts a value in the range 0x00-0xFF
+     * to a integer in the range 0-65535
+     */
+    gchar str[3];
+
+    str[0] = hi;
+    str[1] = lo;
+    str[2] = 0;
+
+    return (CLAMP(strtol(str, NULL, 16), 0, 0xFF) << 8);
+}
+
+GdkColor *
+skin_load_color(const gchar * path, const gchar * file,
+                const gchar * section, const gchar * key,
+                gchar * default_hex)
+{
+    gchar *filename, *value;
+    GdkColor *color = NULL;
+
+    filename = find_file_recursively(path, file);
+    if (filename || default_hex) {
+        if (filename) {
+            value = read_ini_string(filename, section, key);
+            if (value == NULL) {
+                value = g_strdup(default_hex);
+            }
+        } else {
+            value = g_strdup(default_hex);
+        }
+        if (value) {
+            gchar *ptr = value;
+            gint len;
+
+            color = g_new0(GdkColor, 1);
+            g_strstrip(value);
+
+            if (value[0] == '#')
+                ptr++;
+            len = strlen(ptr);
+            /*
+             * The handling of incomplete values is done this way
+             * to maximize winamp compatibility
+             */
+            if (len >= 6) {
+                color->red = hex_chars_to_int(*ptr, *(ptr + 1));
+                ptr += 2;
+            }
+            if (len >= 4) {
+                color->green = hex_chars_to_int(*ptr, *(ptr + 1));
+                ptr += 2;
+            }
+            if (len >= 2)
+                color->blue = hex_chars_to_int(*ptr, *(ptr + 1));
+
+            gdk_color_alloc(gdk_window_get_colormap(playlistwin->window),
+                            color);
+            g_free(value);
+        }
+        if (filename)
+            g_free(filename);
+    }
+    return color;
+}
+
+
+
+GdkBitmap *
+skin_create_transparent_mask(const gchar * path,
+                             const gchar * file,
+                             const gchar * section,
+                             GdkWindow * window,
+                             gint width,
+                             gint height)
+{
+    GdkBitmap *mask = NULL;
+    GdkGC *gc = NULL;
+    GdkColor pattern;
+    GdkPoint *gpoints;
+
+    gchar *filename = NULL;
+    gboolean created_mask = FALSE;
+    GArray *num, *point;
+    guint i, j;
+    gint k;
+
+    if (path)
+        filename = find_file_recursively(path, file);
+
+    /* filename will be null if path wasn't set */
+    if (!filename) {
+        return create_default_mask(window, width, height);
+    }
+
+    if ((num = read_ini_array(filename, section, "NumPoints")) == NULL) {
+        g_free(filename);
+        return NULL;
+    }
+
+    if ((point = read_ini_array(filename, section, "PointList")) == NULL) {
+        g_array_free(num, TRUE);
+        g_free(filename);
+        return NULL;
+    }
+
+    mask = gdk_pixmap_new(window, width, height, 1);
+    gc = gdk_gc_new(mask);
+
+    pattern.pixel = 0;
+    gdk_gc_set_foreground(gc, &pattern);
+    gdk_draw_rectangle(mask, gc, TRUE, 0, 0, width, height);
+    pattern.pixel = 1;
+    gdk_gc_set_foreground(gc, &pattern);
+
+    j = 0;
+    for (i = 0; i < num->len; i++) {
+        if ((int)(point->len - j) >= (g_array_index(num, gint, i) * 2)) {
+            created_mask = TRUE;
+            gpoints = g_new(GdkPoint, g_array_index(num, gint, i));
+            for (k = 0; k < g_array_index(num, gint, i); k++) {
+                gpoints[k].x = g_array_index(point, gint, j + k * 2);
+                gpoints[k].y = g_array_index(point, gint, j + k * 2 + 1);
+            }
+            j += k * 2;
+            gdk_draw_polygon(mask, gc, TRUE, gpoints,
+                             g_array_index(num, gint, i));
+            g_free(gpoints);
+        }
+    }
+    g_array_free(num, TRUE);
+    g_array_free(point, TRUE);
+    g_free(filename);
+
+    if (!created_mask)
+        gdk_draw_rectangle(mask, gc, TRUE, 0, 0, width, height);
+
+    gdk_gc_destroy(gc);
+
+    return mask;
+}
+
+void
+skin_load_viscolor(Skin * skin, const gchar * path, const gchar * basename)
+{
+    FILE *file;
+    gint i, c;
+    gchar line[256], *filename;
+    GArray *a;
+
+    g_return_if_fail(skin != NULL);
+    g_return_if_fail(path != NULL);
+    g_return_if_fail(basename != NULL);
+
+    skin_set_default_vis_color(skin);
+
+    filename = find_file_recursively(path, basename);
+    if (!filename)
+        return;
+
+    if (!(file = fopen(filename, "r"))) {
+        g_free(filename);
+        return;
+    }
+
+    g_free(filename);
+
+    for (i = 0; i < 24; i++) {
+        if (fgets(line, 255, file)) {
+            a = string_to_garray(line);
+            if (a->len > 2) {
+                for (c = 0; c < 3; c++)
+                    skin->vis_color[i][c] = g_array_index(a, gint, c);
+            }
+            g_array_free(a, TRUE);
+        }
+        else
+            break;
+    }
+
+    fclose(file);
+}
+
+#if 0
+static void
+skin_numbers_generate_dash(Skin * skin)
+{
+    GdkGC *gc;
+    GdkPixmap *pixmap;
+    SkinPixmap *numbers;
+
+    g_return_if_fail(skin != NULL);
+
+    numbers = &skin->pixmaps[SKIN_NUMBERS];
+    if (!numbers->pixmap || numbers->current_width < 99)
+        return;
+
+    gc = gdk_gc_new(numbers->pixmap);
+    pixmap = gdk_pixmap_new(mainwin->window, 108,
+                            numbers->current_height,
+                            -1);
+
+    skin_draw_pixmap(skin, pixmap, gc, SKIN_NUMBERS, 0, 0, 0, 0, 99, 13);
+    skin_draw_pixmap(skin, pixmap, gc, SKIN_NUMBERS, 90, 0, 99, 0, 9, 13);
+    skin_draw_pixmap(skin, pixmap, gc, SKIN_NUMBERS, 20, 6, 101, 6, 5, 1);
+
+    g_object_unref(numbers->pixmap);
+    g_object_unref(gc);
+
+    numbers->pixmap = pixmap;
+    numbers->current_width = 108;
+}
+#endif
+
+static void
+skin_load_cursor(Skin * skin, const gchar * dirname)
+{
+    const gchar * basename = "normal.cur";
+    gchar * filename = NULL;
+    GdkPixbuf * cursor_pixbuf = NULL;
+    GdkPixbufAnimation * cursor_animated = NULL;
+    GdkCursor * cursor_gdk = NULL;
+    GError * error = NULL;
+ 
+    filename = find_file_recursively(dirname, basename);
+
+    if (filename && cfg.custom_cursors)	{
+    	cursor_animated = gdk_pixbuf_animation_new_from_file(filename, &error);
+        cursor_pixbuf = gdk_pixbuf_animation_get_static_image(cursor_animated);
+        cursor_gdk = gdk_cursor_new_from_pixbuf(gdk_display_get_default(),
+                                                cursor_pixbuf, 0, 0);
+    } else {
+        cursor_gdk = gdk_cursor_new(GDK_LEFT_PTR);
+    }
+
+    gdk_window_set_cursor(mainwin->window, cursor_gdk);
+    gdk_window_set_cursor(playlistwin->window, cursor_gdk);
+    gdk_window_set_cursor(equalizerwin->window, cursor_gdk);
+    gdk_cursor_unref(cursor_gdk);
+}
+
+static void
+skin_load_pixmaps(Skin * skin, const gchar * path)
+{
+    GdkPixmap *text_pm;
+    guint i;
+
+    for (i = 0; i < SKIN_PIXMAP_COUNT; i++)
+        skin_load_pixmap_id(skin, i, path);
+
+    text_pm = skin->pixmaps[SKIN_TEXT].pixmap;
+
+    if (text_pm)
+        skin_get_textcolors(text_pm, skin->textbg, skin->textfg);
+
+#if 0
+    if (skin->pixmaps[SKIN_NUMBERS].pixmap)
+        skin_numbers_generate_dash(skin);
+#endif
+
+    skin->colors[SKIN_PLEDIT_NORMAL] =
+        skin_load_color(path, "pledit.txt", "text", "normal", "#2499ff");
+    skin->colors[SKIN_PLEDIT_CURRENT] =
+        skin_load_color(path, "pledit.txt", "text", "current", "#ffeeff");
+    skin->colors[SKIN_PLEDIT_NORMALBG] =
+        skin_load_color(path, "pledit.txt", "text", "normalbg", "#0a120a");
+    skin->colors[SKIN_PLEDIT_SELECTEDBG] =
+        skin_load_color(path, "pledit.txt", "text", "selectedbg", "#0a124a");
+
+    skin_mask_create(skin, path, SKIN_MASK_MAIN, mainwin->window);
+    skin_mask_create(skin, path, SKIN_MASK_MAIN_SHADE, mainwin->window);
+
+    skin_mask_create(skin, path, SKIN_MASK_EQ, equalizerwin->window);
+    skin_mask_create(skin, path, SKIN_MASK_EQ_SHADE, equalizerwin->window);
+
+    skin_load_viscolor(skin, path, "viscolor.txt");
+}
+
+static gboolean
+skin_load_nolock(Skin * skin, const gchar * path, gboolean force)
+{
+    gchar *cpath;
+
+    g_return_val_if_fail(skin != NULL, FALSE);
+    g_return_val_if_fail(path != NULL, FALSE);
+    REQUIRE_LOCK(skin->lock);
+
+    if (!g_file_test(path, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_DIR))
+	return FALSE;
+   
+    if (!force) {
+        if (skin->path)
+            if (!strcmp(skin->path, path))
+                return FALSE;
+    }
+      
+    skin_current_num++;
+
+    skin->path = g_strdup(path);
+
+    if (!file_is_archive(path)) {
+        skin_load_pixmaps(skin, path);
+        skin_load_cursor(skin, path);
+
+        /* Parse the hints for this skin. */
+        skin_parse_hints(skin, NULL);
+
+        return TRUE;
+    }
+
+    if (!(cpath = archive_decompress(path))) {
+        g_message("Unable to extract skin archive (%s)", path);
+        return FALSE;
+    }
+
+    skin_load_pixmaps(skin, cpath);
+    skin_load_cursor(skin, cpath);
+
+    /* Parse the hints for this skin. */
+    skin_parse_hints(skin, cpath);
+
+    del_directory(cpath);
+    g_free(cpath);
+
+    return TRUE;
+}
+
+void
+skin_install_skin(const gchar * path)
+{
+    gchar *command;
+
+    g_return_if_fail(path != NULL);
+
+    command = g_strdup_printf("cp %s %s", path, bmp_paths[BMP_PATH_USER_SKIN_DIR]);
+    if (system(command)) {
+        g_message("Unable to install skin (%s) into user directory (%s)",
+                  path, bmp_paths[BMP_PATH_USER_SKIN_DIR]);
+    }
+    g_free(command);
+}
+
+
+gboolean
+skin_load(Skin * skin, const gchar * path)
+{
+    gboolean error;
+
+    g_return_val_if_fail(skin != NULL, FALSE);
+
+    if (!path)
+        return FALSE;
+
+    skin_lock(skin);
+    error = skin_load_nolock(skin, path, FALSE);
+    skin_unlock(skin);
+    
+    return error;
+}
+
+gboolean
+skin_reload_forced(void) 
+{
+   gboolean error;
+
+   skin_lock(bmp_active_skin);
+   error = skin_load_nolock(bmp_active_skin, bmp_active_skin->path, TRUE);
+   skin_unlock(bmp_active_skin);
+
+   return error;
+}
+
+void
+skin_reload(Skin * skin)
+{
+    g_return_if_fail(skin != NULL);
+    skin_load_nolock(skin, skin->path, TRUE);
+}
+
+
+static SkinPixmap *
+skin_get_pixmap(Skin * skin, SkinPixmapId map_id)
+{
+    g_return_val_if_fail(skin != NULL, NULL);
+    g_return_val_if_fail(map_id < SKIN_PIXMAP_COUNT, NULL);
+
+    return &skin->pixmaps[map_id];
+}
+
+GdkBitmap *
+skin_get_mask(Skin * skin, SkinMaskId mi)
+{
+    g_return_val_if_fail(skin != NULL, NULL);
+    g_return_val_if_fail(mi < SKIN_PIXMAP_COUNT, NULL);
+
+    return skin->masks[mi];
+}
+
+GdkColor *
+skin_get_color(Skin * skin, SkinColorId color_id)
+{
+    GdkColor *ret = NULL;
+
+    g_return_val_if_fail(skin != NULL, NULL);
+
+    switch (color_id) {
+    case SKIN_TEXTBG:
+        if (skin->pixmaps[SKIN_TEXT].pixmap)
+            ret = skin->textbg;
+        else
+            ret = skin->def_textbg;
+        break;
+    case SKIN_TEXTFG:
+        if (skin->pixmaps[SKIN_TEXT].pixmap)
+            ret = skin->textfg;
+        else
+            ret = skin->def_textfg;
+        break;
+    default:
+        if (color_id < SKIN_COLOR_COUNT)
+            ret = skin->colors[color_id];
+        break;
+    }
+    return ret;
+}
+
+void
+skin_get_viscolor(Skin * skin, guchar vis_color[24][3])
+{
+    gint i;
+
+    g_return_if_fail(skin != NULL);
+
+    for (i = 0; i < 24; i++) {
+        vis_color[i][0] = skin->vis_color[i][0];
+        vis_color[i][1] = skin->vis_color[i][1];
+        vis_color[i][2] = skin->vis_color[i][2];
+    }
+}
+
+gint
+skin_get_id(void)
+{
+    return skin_current_num;
+}
+
+void
+skin_draw_pixmap(Skin * skin, GdkDrawable * drawable, GdkGC * gc,
+                 SkinPixmapId pixmap_id,
+                 gint xsrc, gint ysrc, gint xdest, gint ydest,
+                 gint width, gint height)
+{
+    SkinPixmap *pixmap;
+
+    g_return_if_fail(skin != NULL);
+
+    pixmap = skin_get_pixmap(skin, pixmap_id);
+    g_return_if_fail(pixmap != NULL);
+    g_return_if_fail(pixmap->pixmap != NULL);
+
+    if (xsrc > pixmap->width || ysrc > pixmap->height)
+        return;
+
+    width = MIN(width, pixmap->width - xsrc);
+    height = MIN(height, pixmap->height - ysrc);
+    gdk_draw_pixmap(drawable, gc, pixmap->pixmap, xsrc, ysrc,
+                    xdest, ydest, width, height);
+}
+
+void
+skin_get_eq_spline_colors(Skin * skin, guint32 colors[19])
+{
+    gint i;
+    GdkPixmap *pixmap;
+    GdkImage *img;
+    SkinPixmap *eqmainpm;
+
+    g_return_if_fail(skin != NULL);
+
+    eqmainpm = &skin->pixmaps[SKIN_EQMAIN];
+    if (eqmainpm->pixmap &&
+        eqmainpm->current_width >= 116 && eqmainpm->current_height >= 313)
+        pixmap = eqmainpm->pixmap;
+    else
+        return;
+
+    if (!GDK_IS_DRAWABLE(pixmap))
+        return;
+
+    if (!(img = gdk_drawable_get_image(pixmap, 115, 294, 1, 19)))
+        return;
+
+    for (i = 0; i < 19; i++)
+        colors[i] = gdk_image_get_pixel(img, 0, i);
+
+    gdk_image_destroy(img);
+}
+
+
+static void
+skin_draw_playlistwin_frame_top(Skin * skin,
+                                GdkDrawable * drawable,
+                                GdkGC * gc,
+                                gint width, gint height, gboolean focus)
+{
+    /* The title bar skin consists of 2 sets of 4 images, 1 set
+     * for focused state and the other for unfocused. The 4 images
+     * are: 
+     *
+     * a. right corner (25,20)
+     * b. left corner  (25,20)
+     * c. tiler        (25,20)
+     * d. title        (100,20)
+     * 
+     * min allowed width = 100+25+25 = 150
+     */
+
+    gint i, y, c;
+
+    /* get y offset of the pixmap set to use */
+    if (focus)
+        y = 0;
+    else
+        y = 21;
+
+    /* left corner */
+    skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 0, y, 0, 0, 25, 20);
+
+    /* titlebar title */
+    skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 26, y,
+                     (width - 100) / 2, 0, 100, 20);
+
+    /* titlebar right corner  */
+    skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 153, y,
+                     width - 25, 0, 25, 20);
+
+    /* tile draw the remaining frame */
+
+    /* compute tile count */
+    c = (width - (100 + 25 + 25)) / 25;
+
+    for (i = 0; i < c / 2; i++) {
+        /* left of title */
+        skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 127, y,
+                         25 + i * 25, 0, 25, 20);
+
+        /* right of title */
+        skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 127, y,
+                         (width + 100) / 2 + i * 25, 0, 25, 20);
+    }
+
+    if (c & 1) {
+        /* Odd tile count, so one remaining to draw. Here we split
+         * it into two and draw half on either side of the title */
+        skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 127, y,
+                         ((c / 2) * 25) + 25, 0, 12, 20);
+        skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 127, y,
+                         (width / 2) + ((c / 2) * 25) + 50, 0, 13, 20);
+    }
+}
+
+static void
+skin_draw_playlistwin_frame_bottom(Skin * skin,
+                                   GdkDrawable * drawable,
+                                   GdkGC * gc,
+                                   gint width, gint height, gboolean focus)
+{
+    /* The bottom frame skin consists of 1 set of 4 images. The 4
+     * images are:
+     *
+     * a. left corner with menu buttons (125,38)
+     * b. visualization window (75,38)
+     * c. right corner with play buttons (150,38)
+     * d. frame tile (25,38)
+     * 
+     * (min allowed width = 125+150+25=300
+     */
+
+    gint i, c;
+
+    /* bottom left corner (menu buttons) */
+    skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 0, 72,
+                     0, height - 38, 125, 38);
+
+    c = (width - 275) / 25;
+
+    /* draw visualization window, if width allows */
+    if (c >= 3) {
+        c -= 3;
+        skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 205, 0,
+                         width - (150 + 75), height - 38, 75, 38);
+    }
+
+    /* Bottom right corner (playbuttons etc) */
+    skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT,
+                     126, 72, width - 150, height - 38, 150, 38);
+
+    /* Tile draw the remaining undrawn portions */
+    for (i = 0; i < c; i++)
+        skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 179, 0,
+                         125 + i * 25, height - 38, 25, 38);
+}
+
+static void
+skin_draw_playlistwin_frame_sides(Skin * skin,
+                                  GdkDrawable * drawable,
+                                  GdkGC * gc,
+                                  gint width, gint height, gboolean focus)
+{
+    /* The side frames consist of 2 tile images. 1 for the left, 1 for
+     * the right. 
+     * a. left  (12,29)
+     * b. right (19,29)
+     */
+
+    gint i;
+
+    /* frame sides */
+    for (i = 0; i < (height - (20 + 38)) / 29; i++) {
+        /* left */
+        skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 0, 42,
+                         0, 20 + i * 29, 12, 29);
+
+        /* right */
+        skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 32, 42,
+                         width - 19, 20 + i * 29, 19, 29);
+    }
+}
+
+
+void
+skin_draw_playlistwin_frame(Skin * skin,
+                            GdkDrawable * drawable, GdkGC * gc,
+                            gint width, gint height, gboolean focus)
+{
+    skin_draw_playlistwin_frame_top(skin, drawable, gc, width, height, focus);
+    skin_draw_playlistwin_frame_bottom(skin, drawable, gc, width, height,
+                                       focus);
+    skin_draw_playlistwin_frame_sides(skin, drawable, gc, width, height,
+                                      focus);
+}
+
+
+void
+skin_draw_playlistwin_shaded(Skin * skin,
+                             GdkDrawable * drawable, GdkGC * gc,
+                             gint width, gboolean focus)
+{
+    /* The shade mode titlebar skin consists of 4 images:
+     * a) left corner               offset (72,42) size (25,14)
+     * b) right corner, focused     offset (99,57) size (50,14)
+     * c) right corner, unfocused   offset (99,42) size (50,14)
+     * d) bar tile                  offset (72,57) size (25,14)
+     */
+
+    gint i;
+
+    /* left corner */
+    skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 72, 42, 0, 0, 25, 14);
+
+    /* bar tile */
+    for (i = 0; i < (width - 75) / 25; i++)
+        skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 72, 57,
+                         (i * 25) + 25, 0, 25, 14);
+
+    /* right corner */
+    skin_draw_pixmap(skin, drawable, gc, SKIN_PLEDIT, 99, focus ? 57 : 42,
+                     width - 50, 0, 50, 14);
+}
+
+
+void
+skin_draw_mainwin_titlebar(Skin * skin,
+                           GdkDrawable * drawable, GdkGC * gc,
+                           gboolean shaded, gboolean focus)
+{
+    /* The titlebar skin consists of 2 sets of 2 images, one for for
+     * shaded and the other for unshaded mode, giving a total of 4.
+     * The images are exactly 275x14 pixels, aligned and arranged
+     * vertically on each other in the pixmap in the following order:
+     * 
+     * a) unshaded, focused      offset (27, 0)
+     * b) unshaded, unfocused    offset (27, 15)
+     * c) shaded, focused        offset (27, 29)
+     * d) shaded, unfocused      offset (27, 42)
+     */
+
+    gint y_offset;
+
+    if (shaded) {
+        if (focus)
+            y_offset = 29;
+        else
+            y_offset = 42;
+    }
+    else {
+        if (focus)
+            y_offset = 0;
+        else
+            y_offset = 15;
+    }
+
+    skin_draw_pixmap(skin, drawable, gc, SKIN_TITLEBAR, 27, y_offset,
+                     0, 0, MAINWIN_WIDTH, MAINWIN_TITLEBAR_HEIGHT);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/skin.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,149 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef SKIN_H
+#define SKIN_H
+
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+
+#define BMP_DEFAULT_SKIN_PATH \
+  DATA_DIR G_DIR_SEPARATOR_S "Skins" G_DIR_SEPARATOR_S "Default"
+
+
+typedef enum {
+    SKIN_MAIN = 0,
+    SKIN_CBUTTONS,
+    SKIN_TITLEBAR,
+    SKIN_SHUFREP,
+    SKIN_TEXT,
+    SKIN_VOLUME,
+    SKIN_BALANCE,
+    SKIN_MONOSTEREO,
+    SKIN_PLAYPAUSE,
+    SKIN_NUMBERS,
+    SKIN_POSBAR,
+    SKIN_PLEDIT,
+    SKIN_EQMAIN,
+    SKIN_EQ_EX,
+    SKIN_PIXMAP_COUNT
+} SkinPixmapId;
+
+typedef enum {
+    SKIN_MASK_MAIN = 0,
+    SKIN_MASK_MAIN_SHADE,
+    SKIN_MASK_EQ,
+    SKIN_MASK_EQ_SHADE,
+    SKIN_MASK_COUNT
+} SkinMaskId;
+
+typedef enum {
+    SKIN_PLEDIT_NORMAL = 0,
+    SKIN_PLEDIT_CURRENT,
+    SKIN_PLEDIT_NORMALBG,
+    SKIN_PLEDIT_SELECTEDBG,
+    SKIN_TEXTBG,
+    SKIN_TEXTFG,
+    SKIN_COLOR_COUNT
+} SkinColorId;
+
+typedef struct _SkinProperties {
+	gboolean mainwin_othertext;
+} SkinProperties;
+
+#define SKIN_PIXMAP(x)  ((SkinPixmap *)(x))
+typedef struct _SkinPixmap {
+    GdkPixmap *pixmap;
+    /* GdkPixmap *def_pixmap; */
+
+    /* The real size of the pixmap */
+    gint width, height;
+
+    /* The size of the pixmap from the current skin,
+       which might be smaller */
+    gint current_width, current_height;
+} SkinPixmap;
+
+
+#define SKIN(x)  ((Skin *)(x))
+typedef struct _Skin {
+    GMutex *lock;
+    gchar *path;
+    gchar *def_path;
+    SkinPixmap pixmaps[SKIN_PIXMAP_COUNT];
+    GdkColor textbg[6], def_textbg[6];
+    GdkColor textfg[6], def_textfg[6];
+    GdkColor *colors[SKIN_COLOR_COUNT];
+    guchar vis_color[24][3];
+    GdkBitmap *masks[SKIN_MASK_COUNT];
+    SkinProperties properties;
+} Skin;
+
+extern Skin *bmp_active_skin;
+
+gboolean init_skins(const gchar * path);
+void cleanup_skins(void);
+
+gboolean bmp_active_skin_load(const gchar * path);
+gboolean bmp_active_skin_reload(void);
+
+Skin *skin_new(void);
+gboolean skin_load(Skin * skin, const gchar * path);
+void skin_reload(Skin * skin);
+void skin_free(Skin * skin);
+
+GdkBitmap *skin_get_mask(Skin * skin, SkinMaskId mi);
+GdkColor *skin_get_color(Skin * skin, SkinColorId color_id);
+
+void skin_get_viscolor(Skin * skin, guchar vis_color[24][3]);
+gint skin_get_id(void);
+void skin_draw_pixmap(Skin * skin, GdkDrawable * drawable, GdkGC * gc,
+                      SkinPixmapId pixmap_id,
+                      gint xsrc, gint ysrc, gint xdest, gint ydest,
+                      gint width, gint height);
+void skin_get_eq_spline_colors(Skin * skin, guint32 colors[19]);
+void skin_install_skin(const gchar * path);
+
+void skin_draw_playlistwin_shaded(Skin * skin,
+                                  GdkDrawable * drawable, GdkGC * gc,
+                                  gint width, gboolean focus);
+void skin_draw_playlistwin_frame(Skin * skin,
+                                 GdkDrawable * drawable, GdkGC * gc,
+                                 gint width, gint height, gboolean focus);
+
+void skin_draw_mainwin_titlebar(Skin * skin,
+                                GdkDrawable * drawable, GdkGC * gc,
+                                gboolean shaded, gboolean focus);
+
+
+void skin_parse_hints(Skin * skin, gchar *path_p);
+
+
+gboolean
+skin_reload_forced(void);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/svis.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,204 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <string.h>
+
+#include "audacious/main.h"
+#include "mainwin.h"
+#include "audacious/plugin.h"
+#include "widget.h"
+#include "vis.h"
+
+static gint svis_redraw_delays[] = { 1, 2, 4, 8 };
+
+/* FIXME: Are the svis_scope_colors correct? */
+static guint8 svis_scope_colors[] = { 20, 19, 18, 19, 20 };
+static guint8 svis_vu_normal_colors[] = { 17, 17, 17, 12, 12, 12, 2, 2 };
+
+#define DRAW_DS_PIXEL(ptr,value) \
+	*(ptr) = (value); \
+	*((ptr) + 1) = (value); \
+	*((ptr) + 76) = (value); \
+	*((ptr) + 77) = (value);
+
+#define SVIS_HEIGHT 5
+#define SVIS_WIDTH 38
+
+void
+svis_timeout_func(SVis * svis, guchar * data)
+{
+    static GTimer *timer = NULL;
+    gulong micros = 9999999;
+    gboolean falloff = FALSE;
+    gint i;
+
+    if (!timer) {
+        timer = g_timer_new();
+        g_timer_start(timer);
+    }
+    else {
+        g_timer_elapsed(timer, &micros);
+        if (micros > 14000)
+            g_timer_reset(timer);
+
+    }
+
+    if (cfg.vis_type == INPUT_VIS_ANALYZER) {
+        if (micros > 14000)
+            falloff = TRUE;
+
+        for (i = 0; i < 2; i++) {
+            if (falloff || data) {
+                if (data && data[i] > svis->vs_data[i])
+                    svis->vs_data[i] = data[i];
+                else if (falloff) {
+                    if (svis->vs_data[i] >= 2)
+                        svis->vs_data[i] -= 2;
+                    else
+                        svis->vs_data[i] = 0;
+                }
+            }
+
+        }
+    }
+    else if (data) {
+        for (i = 0; i < 75; i++)
+            svis->vs_data[i] = data[i];
+    }
+
+    if (micros > 14000) {
+        if (!svis->vs_refresh_delay) {
+            svis_draw((Widget *) svis);
+            svis->vs_refresh_delay = svis_redraw_delays[cfg.vis_refresh];
+
+        }
+        svis->vs_refresh_delay--;
+    }
+}
+
+void
+svis_draw(Widget * w)
+{
+    SVis *svis = (SVis *) w;
+    gint x, y, h;
+    guchar svis_color[24][3];
+    guchar rgb_data[SVIS_WIDTH * 2 * SVIS_HEIGHT * 2], *ptr, c;
+    guint32 colors[24];
+    GdkRgbCmap *cmap;
+
+    GDK_THREADS_ENTER();
+
+    skin_get_viscolor(bmp_active_skin, svis_color);
+    for (y = 0; y < 24; y++) {
+        colors[y] =
+            svis_color[y][0] << 16 | svis_color[y][1] << 8 | svis_color[y][2];
+    }
+    cmap = gdk_rgb_cmap_new(colors, 24);
+
+    memset(rgb_data, 0, SVIS_WIDTH * SVIS_HEIGHT);
+    if (cfg.vis_type == VIS_ANALYZER) {
+        switch (cfg.vu_mode) {
+        case VU_NORMAL:
+            for (y = 0; y < 2; y++) {
+                ptr = rgb_data + ((y * 3) * 38);
+                h = (svis->vs_data[y] * 7) / 37;
+                for (x = 0; x < h; x++, ptr += 5) {
+                    c = svis_vu_normal_colors[x];
+                    *(ptr) = c;
+                    *(ptr + 1) = c;
+                    *(ptr + 2) = c;
+                    *(ptr + 38) = c;
+                    *(ptr + 39) = c;
+                    *(ptr + 40) = c;
+                }
+            }
+            break;
+        case VU_SMOOTH:
+            for (y = 0; y < 2; y++) {
+                ptr = rgb_data + ((y * 3) * SVIS_WIDTH);
+                for (x = 0; x < svis->vs_data[y]; x++, ptr++) {
+                    c = 17 - ((x * 15) / 37);
+                    *(ptr) = c;
+                    *(ptr + 38) = c;
+                }
+            }
+            break;
+        }
+    }
+    else if (cfg.vis_type == VIS_SCOPE) {
+        for (x = 0; x < 38; x++) {
+            h = svis->vs_data[x << 1] / 3;
+            ptr = rgb_data + ((4 - h) * 38) + x;
+            *ptr = svis_scope_colors[h];
+        }
+    }
+
+    gdk_draw_indexed_image(mainwin->window, mainwin_gc,
+                           svis->vs_widget.x, svis->vs_widget.y,
+                           svis->vs_widget.width,
+                           svis->vs_widget.height,
+                           GDK_RGB_DITHER_NORMAL, (guchar *) rgb_data,
+                           38, cmap);
+
+    gdk_rgb_cmap_free(cmap);
+    GDK_THREADS_LEAVE();
+}
+
+void
+svis_clear_data(SVis * svis)
+{
+    gint i;
+
+    if (!svis)
+        return;
+
+    for (i = 0; i < 75; i++) {
+        svis->vs_data[i] = (cfg.vis_type == VIS_SCOPE) ? 6 : 0;
+    }
+}
+
+void
+svis_clear(SVis * svis)
+{
+    gdk_window_clear_area(mainwin->window, svis->vs_widget.x,
+                          svis->vs_widget.y, svis->vs_widget.width,
+                          svis->vs_widget.height);
+}
+
+SVis *
+create_svis(GList ** wlist,
+            GdkPixmap * parent, 
+            GdkGC * gc,
+            gint x, gint y)
+{
+    SVis *svis;
+
+    svis = g_new0(SVis, 1);
+    widget_init(&svis->vs_widget, parent, gc, x, y, SVIS_WIDTH, SVIS_HEIGHT,
+                1);
+
+    widget_list_add(wlist, WIDGET(svis));
+    return svis;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/svis.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,52 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef SVIS_H
+#define SVIS_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "svis.h"
+#include "widget.h"
+
+#define SVIS(x)  ((SVis *)(x))
+struct _SVis {
+    Widget vs_widget;
+    gint vs_data[75];
+    gint vs_refresh_delay;
+};
+
+typedef struct _SVis SVis;
+
+void svis_draw(Widget * w);
+void svis_timeout_func(SVis * svis, guchar * data);
+SVis *create_svis(GList ** wlist, GdkPixmap * parent, GdkGC * gc, gint x,
+                  gint y);
+void svis_set_data(SVis * vis, guchar * data);
+void svis_clear_data(SVis * vis);
+void svis_clear(SVis * vis);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/tbutton.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,176 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "widget.h"
+
+void
+tbutton_draw(Widget * w)
+{
+    TButton *button = TBUTTON(w);
+    GdkPixmap *obj;
+
+    obj = button->tb_widget.parent;
+
+    if (button->tb_pressed && button->tb_inside) {
+        if (button->tb_selected) {
+            skin_draw_pixmap(bmp_active_skin, obj,
+                             button->tb_widget.gc,
+                             button->tb_skin_index,
+                             button->tb_psx, button->tb_psy,
+                             button->tb_widget.x, button->tb_widget.y,
+                             button->tb_widget.width,
+                             button->tb_widget.height);
+        }
+        else {
+            skin_draw_pixmap(bmp_active_skin, obj,
+                             button->tb_widget.gc,
+                             button->tb_skin_index,
+                             button->tb_pux, button->tb_puy,
+                             button->tb_widget.x, button->tb_widget.y,
+                             button->tb_widget.width,
+                             button->tb_widget.height);
+        }
+    }
+    else {
+        if (button->tb_selected) {
+            skin_draw_pixmap(bmp_active_skin, obj,
+                             button->tb_widget.gc,
+                             button->tb_skin_index,
+                             button->tb_nsx, button->tb_nsy,
+                             button->tb_widget.x, button->tb_widget.y,
+                             button->tb_widget.width,
+                             button->tb_widget.height);
+        }
+        else {
+            skin_draw_pixmap(bmp_active_skin, obj,
+                             button->tb_widget.gc,
+                             button->tb_skin_index,
+                             button->tb_nux, button->tb_nuy,
+                             button->tb_widget.x, button->tb_widget.y,
+                             button->tb_widget.width,
+                             button->tb_widget.height);
+
+        }
+    }
+}
+
+void
+tbutton_button_press_cb(GtkWidget * widget, GdkEventButton * event,
+                        TButton * button)
+{
+    if (event->button != 1)
+        return;
+
+    if (widget_contains(&button->tb_widget, event->x, event->y)) {
+        button->tb_pressed = 1;
+        button->tb_inside = 1;
+        widget_draw(WIDGET(button));
+    }
+}
+
+void
+tbutton_button_release_cb(GtkWidget * widget, GdkEventButton * event,
+                          TButton * button)
+{
+    if (event->button != 1)
+        return;
+
+    if (button->tb_inside && button->tb_pressed) {
+        button->tb_inside = 0;
+        button->tb_selected = !button->tb_selected;
+
+        widget_draw(WIDGET(button));
+
+        if (button->tb_push_cb)
+            button->tb_push_cb(button->tb_selected);
+    }
+
+    if (button->tb_pressed)
+        button->tb_pressed = 0;
+}
+
+void
+tbutton_motion_cb(GtkWidget * widget, GdkEventMotion * event,
+                  TButton * button)
+{
+    gint inside;
+
+    if (!button->tb_pressed)
+        return;
+    inside = widget_contains(&button->tb_widget, event->x, event->y);
+    if (inside != button->tb_inside) {
+        button->tb_inside = inside;
+        widget_draw(WIDGET(button));
+    }
+}
+
+TButton *
+create_tbutton(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+               gint x, gint y, gint w, gint h, gint nux, gint nuy,
+               gint pux, gint puy, gint nsx, gint nsy, gint psx,
+               gint psy, void (*cb) (gboolean), SkinPixmapId si)
+{
+    TButton *b;
+
+    b = g_new0(TButton, 1);
+    widget_init(&b->tb_widget, parent, gc, x, y, w, h, 1);
+    b->tb_widget.button_press_cb =
+        (void (*)(GtkWidget *, GdkEventButton *, gpointer))
+        tbutton_button_press_cb;
+    b->tb_widget.button_release_cb =
+        (void (*)(GtkWidget *, GdkEventButton *, gpointer))
+        tbutton_button_release_cb;
+    b->tb_widget.motion_cb =
+        (void (*)(GtkWidget *, GdkEventMotion *, gpointer))
+        tbutton_motion_cb;
+    b->tb_widget.draw = tbutton_draw;
+    b->tb_nux = nux;
+    b->tb_nuy = nuy;
+    b->tb_pux = pux;
+    b->tb_puy = puy;
+    b->tb_nsx = nsx;
+    b->tb_nsy = nsy;
+    b->tb_psx = psx;
+    b->tb_psy = psy;
+    b->tb_push_cb = cb;
+    b->tb_skin_index = si;
+
+    widget_list_add(wlist, WIDGET(b));
+    return b;
+}
+
+void
+tbutton_set_toggled(TButton * tb, gboolean toggled)
+{
+    tb->tb_selected = toggled;
+    widget_draw(WIDGET(tb));
+}
+
+void
+free_tbutton(TButton * b)
+{
+    g_free(b);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/tbutton.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,52 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef TBUTTON_H
+#define TBUTTON_H
+
+#include <glib.h>
+
+#include "skin.h"
+#include "widget.h"
+
+#define TBUTTON(x) ((TButton *)(x))
+struct _TButton {
+    Widget tb_widget;
+    gint tb_nux, tb_nuy, tb_pux, tb_puy, tb_nsx, tb_nsy, tb_psx, tb_psy;
+    gint tb_pressed, tb_inside, tb_selected;
+    void (*tb_push_cb) (gboolean);
+    SkinPixmapId tb_skin_index;
+};
+
+typedef struct _TButton TButton;
+
+TButton *create_tbutton(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+                        gint x, gint y, gint w, gint h, gint nux, gint nuy,
+                        gint pux, gint puy, gint nsx, gint nsy, gint psx,
+                        gint psy, void (*cb) (gboolean), SkinPixmapId si);
+void tbutton_set_toggled(TButton * tb, gboolean toggled);
+void free_tbutton(TButton * b);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/textbox.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,579 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkprivate.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "mainwin.h"
+#include "audacious/util.h"
+
+static void textbox_generate_pixmap(TextBox * tb);
+
+static void
+textbox_draw(Widget * w)
+{
+    TextBox *tb = TEXT_BOX(w);
+    gint cw;
+    GdkPixmap *obj;
+    GdkPixmap *src;
+
+    g_return_if_fail(tb != NULL);
+
+    if (tb->tb_text &&
+        (!tb->tb_pixmap_text || strcmp(tb->tb_text, tb->tb_pixmap_text)))
+        textbox_generate_pixmap(tb);
+
+    if (tb->tb_pixmap) {
+        if (skin_get_id() != tb->tb_skin_id) {
+            tb->tb_skin_id = skin_get_id();
+            textbox_generate_pixmap(tb);
+        }
+        obj = tb->tb_widget.parent;
+        src = tb->tb_pixmap;
+
+        cw = tb->tb_pixmap_width - tb->tb_offset;
+        if (cw > tb->tb_widget.width)
+            cw = tb->tb_widget.width;
+        gdk_draw_pixmap(obj, tb->tb_widget.gc, src, tb->tb_offset, 0,
+                        tb->tb_widget.x, tb->tb_widget.y, cw,
+                        tb->tb_widget.height);
+        if (cw < tb->tb_widget.width)
+            gdk_draw_pixmap(obj, tb->tb_widget.gc, src, 0, 0,
+                            tb->tb_widget.x + cw, tb->tb_widget.y,
+                            tb->tb_widget.width - cw, tb->tb_widget.height);
+    }
+}
+
+static gboolean
+textbox_scroll(gpointer data)
+{
+    TextBox *tb = TEXT_BOX(data);
+
+    if (!tb->tb_is_dragging) {
+        tb->tb_offset += 1;
+        if (tb->tb_offset >= tb->tb_pixmap_width)
+            tb->tb_offset -= tb->tb_pixmap_width;
+        widget_draw(WIDGET(tb));
+    }
+
+    return TRUE;
+}
+
+static void
+textbox_button_press(GtkWidget * w, GdkEventButton * event, gpointer data)
+{
+    TextBox *tb = TEXT_BOX(data);
+
+    if (event->button != 1)
+        return;
+    if (widget_contains(&tb->tb_widget, event->x, event->y) &&
+        tb->tb_scroll_allowed &&
+        tb->tb_pixmap_width > tb->tb_widget.width && tb->tb_is_scrollable) {
+        tb->tb_is_dragging = TRUE;
+        tb->tb_drag_off = tb->tb_offset;
+        tb->tb_drag_x = event->x;
+    }
+}
+
+static void
+textbox_motion(GtkWidget * w, GdkEventMotion * event, gpointer data)
+{
+    TextBox *tb = TEXT_BOX(data);
+
+    if (tb->tb_is_dragging) {
+        if (tb->tb_scroll_allowed &&
+            tb->tb_pixmap_width > tb->tb_widget.width) {
+            tb->tb_offset = tb->tb_drag_off - (event->x - tb->tb_drag_x);
+
+            while (tb->tb_offset < 0)
+                tb->tb_offset += tb->tb_pixmap_width;
+
+            while (tb->tb_offset > tb->tb_pixmap_width)
+                tb->tb_offset -= tb->tb_pixmap_width;
+
+            widget_draw(WIDGET(tb));
+        }
+    }
+}
+
+static void
+textbox_button_release(GtkWidget * w, GdkEventButton * event, gpointer data)
+{
+    TextBox *tb = TEXT_BOX(data);
+
+    if (event->button == 1)
+        tb->tb_is_dragging = FALSE;
+}
+
+static gboolean
+textbox_should_scroll(TextBox * tb)
+{
+    g_return_val_if_fail(tb != NULL, FALSE);
+
+    if (!tb->tb_scroll_allowed)
+        return FALSE;
+
+    if (tb->tb_font) {
+        gint width;
+
+        text_get_extents(tb->tb_fontname, tb->tb_text, &width, NULL, NULL,
+                         NULL);
+
+        if (width <= tb->tb_widget.width)
+            return FALSE;
+        else
+            return TRUE;
+    }
+
+    if (g_utf8_strlen(tb->tb_text, -1) * 5 > tb->tb_widget.width)
+        return TRUE;
+
+    return FALSE;
+}
+
+void
+textbox_set_text(TextBox * tb, const gchar * text)
+{
+    g_return_if_fail(tb != NULL);
+    g_return_if_fail(text != NULL);
+
+    widget_lock(WIDGET(tb));
+
+    if (tb->tb_text) {
+        if (!strcmp(text, tb->tb_text)) {
+            widget_unlock(WIDGET(tb));
+            return;
+        }
+        g_free(tb->tb_text);
+    }
+
+    tb->tb_text = str_to_utf8(text);
+
+    widget_unlock(WIDGET(tb));
+    widget_draw(WIDGET(tb));
+}
+
+static void
+textbox_generate_xfont_pixmap(TextBox * tb, const gchar * pixmaptext)
+{
+    gint length, i;
+    GdkGC *gc, *maskgc;
+    GdkColor *c, pattern;
+    GdkBitmap *mask;
+    PangoLayout *layout;
+    gint width;
+
+    g_return_if_fail(tb != NULL);
+    g_return_if_fail(pixmaptext != NULL);
+
+    length = g_utf8_strlen(pixmaptext, -1);
+
+    text_get_extents(tb->tb_fontname, pixmaptext, &width, NULL, NULL, NULL);
+
+    tb->tb_pixmap_width = MAX(width, tb->tb_widget.width);
+    tb->tb_pixmap = gdk_pixmap_new(mainwin->window, tb->tb_pixmap_width,
+                                   tb->tb_widget.height,
+                                   gdk_rgb_get_visual()->depth);
+    gc = tb->tb_widget.gc;
+    c = skin_get_color(bmp_active_skin, SKIN_TEXTBG);
+    for (i = 0; i < tb->tb_widget.height; i++) {
+        gdk_gc_set_foreground(gc, &c[6 * i / tb->tb_widget.height]);
+        gdk_draw_line(tb->tb_pixmap, gc, 0, i, tb->tb_pixmap_width, i);
+    }
+
+    mask = gdk_pixmap_new(mainwin->window, tb->tb_pixmap_width,
+                          tb->tb_widget.height, 1);
+    maskgc = gdk_gc_new(mask);
+    pattern.pixel = 0;
+    gdk_gc_set_foreground(maskgc, &pattern);
+
+    gdk_draw_rectangle(mask, maskgc, TRUE, 0, 0,
+                       tb->tb_pixmap_width, tb->tb_widget.height);
+    pattern.pixel = 1;
+    gdk_gc_set_foreground(maskgc, &pattern);
+
+    gdk_gc_set_foreground(gc, skin_get_color(bmp_active_skin, SKIN_TEXTFG));
+
+    layout = gtk_widget_create_pango_layout(mainwin, pixmaptext);
+    pango_layout_set_font_description(layout, tb->tb_font);
+
+    gdk_draw_layout(tb->tb_pixmap, gc, 0, (tb->tb_font_descent / 2), layout);
+    g_object_unref(layout);
+
+    g_object_unref(maskgc);
+
+    gdk_gc_set_clip_mask(gc, mask);
+    c = skin_get_color(bmp_active_skin, SKIN_TEXTFG);
+    for (i = 0; i < tb->tb_widget.height; i++) {
+        gdk_gc_set_foreground(gc, &c[6 * i / tb->tb_widget.height]);
+        gdk_draw_line(tb->tb_pixmap, gc, 0, i, tb->tb_pixmap_width, i);
+    }
+    g_object_unref(mask);
+    gdk_gc_set_clip_mask(gc, NULL);
+}
+
+static void
+textbox_handle_special_char(gchar c, gint * x, gint * y)
+{
+    switch (c) {
+    case '"':
+        *x = 130;
+        *y = 0;
+        break;
+    case '\r':
+        *x = 50;
+        *y = 6;
+        break;
+    case ':':
+    case ';':
+        *x = 60;
+        *y = 6;
+        break;
+    case '(':
+        *x = 65;
+        *y = 6;
+        break;
+    case ')':
+        *x = 70;
+        *y = 6;
+        break;
+    case '-':
+        *x = 75;
+        *y = 6;
+        break;
+    case '`':
+    case '\'':
+        *x = 80;
+        *y = 6;
+        break;
+    case '!':
+        *x = 85;
+        *y = 6;
+        break;
+    case '_':
+        *x = 90;
+        *y = 6;
+        break;
+    case '+':
+        *x = 95;
+        *y = 6;
+        break;
+    case '\\':
+        *x = 100;
+        *y = 6;
+        break;
+    case '/':
+        *x = 105;
+        *y = 6;
+        break;
+    case '[':
+        *x = 110;
+        *y = 6;
+        break;
+    case ']':
+        *x = 115;
+        *y = 6;
+        break;
+    case '^':
+        *x = 120;
+        *y = 6;
+        break;
+    case '&':
+        *x = 125;
+        *y = 6;
+        break;
+    case '%':
+        *x = 130;
+        *y = 6;
+        break;
+    case '.':
+    case ',':
+        *x = 135;
+        *y = 6;
+        break;
+    case '=':
+        *x = 140;
+        *y = 6;
+        break;
+    case '$':
+        *x = 145;
+        *y = 6;
+        break;
+    case '#':
+        *x = 150;
+        *y = 6;
+        break;
+    case 'å':
+    case 'Å':
+        *x = 0;
+        *y = 12;
+        break;
+    case 'ö':
+    case 'Ö':
+        *x = 5;
+        *y = 12;
+        break;
+    case 'ä':
+    case 'Ä':
+        *x = 10;
+        *y = 12;
+        break;
+    case 'ü':
+    case 'Ü':
+        *x = 100;
+        *y = 0;
+        break;
+    case '?':
+        *x = 15;
+        *y = 12;
+        break;
+    case '*':
+        *x = 20;
+        *y = 12;
+        break;
+    default:
+        *x = 145;
+        *y = 0;
+        break;
+    }
+}
+
+static void
+textbox_generate_pixmap(TextBox * tb)
+{
+    gint length, i, x, y, wl;
+    gchar *pixmaptext;
+    GdkGC *gc;
+
+    g_return_if_fail(tb != NULL);
+
+    if (tb->tb_pixmap) {
+        g_object_unref(tb->tb_pixmap);
+        tb->tb_pixmap = NULL;
+    }
+
+    /*
+     * Don't reset the offset if only text after the last '(' has
+     * changed.  This is a hack to avoid visual noice on vbr files
+     * where we guess the length.
+     */
+    if (!(tb->tb_pixmap_text && strrchr(tb->tb_text, '(') &&
+          !strncmp(tb->tb_pixmap_text, tb->tb_text,
+                   strrchr(tb->tb_text, '(') - tb->tb_text)))
+        tb->tb_offset = 0;
+
+    g_free(tb->tb_pixmap_text);
+    tb->tb_pixmap_text = g_strdup(tb->tb_text);
+
+    /*
+     * wl is the number of (partial) letters visible. Only makes
+     * sense when using skinned font.
+     */
+
+    wl = tb->tb_widget.width / 5;
+    if (wl * 5 != tb->tb_widget.width)
+        wl++;
+
+    length = g_utf8_strlen(tb->tb_text, -1);
+
+    tb->tb_is_scrollable = FALSE;
+
+    if (textbox_should_scroll(tb)) {
+        tb->tb_is_scrollable = TRUE;
+        pixmaptext = g_strconcat(tb->tb_pixmap_text, "  ***  ", NULL);
+        length += 7;
+    }
+    else if (!tb->tb_font && length <= wl) {
+        gint pad = wl - length;
+        gchar *padchars = g_strnfill(pad, ' ');
+
+        pixmaptext = g_strconcat(tb->tb_pixmap_text, padchars, NULL);
+        g_free(padchars);
+        length += pad;
+    }
+    else
+        pixmaptext = g_strdup(tb->tb_pixmap_text);
+
+
+    if (tb->tb_is_scrollable) {
+        if (tb->tb_scroll_enabled && !tb->tb_timeout_tag) {
+            gint tag;
+            tag = TEXTBOX_SCROLL_SMOOTH_TIMEOUT;
+            tb->tb_timeout_tag = gtk_timeout_add(tag, textbox_scroll, tb);
+        }
+    }
+    else {
+        if (tb->tb_timeout_tag) {
+            gtk_timeout_remove(tb->tb_timeout_tag);
+            tb->tb_timeout_tag = 0;
+        }
+        tb->tb_offset = 0;
+    }
+
+    if (tb->tb_font) {
+        textbox_generate_xfont_pixmap(tb, pixmaptext);
+        g_free(pixmaptext);
+        return;
+    }
+
+    tb->tb_pixmap_width = length * 5;
+    tb->tb_pixmap = gdk_pixmap_new(mainwin->window,
+                                   tb->tb_pixmap_width, 6,
+                                   gdk_rgb_get_visual()->depth);
+    gc = tb->tb_widget.gc;
+
+    for (i = 0; i < length; i++) {
+        gchar c;
+        x = y = -1;
+        c = toupper(pixmaptext[i]);
+        if (c >= 'A' && c <= 'Z') {
+            x = 5 * (c - 'A');
+            y = 0;
+        }
+        else if (c >= '0' && c <= '9') {
+            x = 5 * (c - '0');
+            y = 6;
+        }
+        else
+            textbox_handle_special_char(c, &x, &y);
+
+        skin_draw_pixmap(bmp_active_skin,
+                         tb->tb_pixmap, gc, tb->tb_skin_index,
+                         x, y, i * 5, 0, 5, 6);
+    }
+    g_free(pixmaptext);
+}
+
+void
+textbox_set_scroll(TextBox * tb, gboolean s)
+{
+    g_return_if_fail(tb != NULL);
+
+    tb->tb_scroll_enabled = s;
+    if (tb->tb_scroll_enabled && tb->tb_is_scrollable
+        && tb->tb_scroll_allowed) {
+        gint tag;
+        tag = TEXTBOX_SCROLL_SMOOTH_TIMEOUT;
+
+	if (tb->tb_timeout_tag)
+        {
+	    gtk_timeout_remove(tb->tb_timeout_tag);
+            tb->tb_timeout_tag = 0;
+	}
+
+        tb->tb_timeout_tag = gtk_timeout_add(tag, textbox_scroll, tb);
+    }
+    else
+    {
+        if (tb->tb_timeout_tag)
+        {
+            gtk_timeout_remove(tb->tb_timeout_tag);
+            tb->tb_timeout_tag = 0;
+        }
+
+        tb->tb_offset = 0;
+        widget_draw(WIDGET(tb));
+    }
+
+}
+
+void
+textbox_set_xfont(TextBox * tb, gboolean use_xfont, const gchar * fontname)
+{
+    gint ascent, descent;
+
+    g_return_if_fail(tb != NULL);
+
+    if (tb->tb_font) {
+        pango_font_description_free(tb->tb_font);
+        tb->tb_font = NULL;
+    }
+
+    tb->tb_widget.y = tb->tb_nominal_y;
+    tb->tb_widget.height = tb->tb_nominal_height;
+
+    /* Make sure the pixmap is regenerated */
+    if (tb->tb_pixmap_text) {
+        g_free(tb->tb_pixmap_text);
+        tb->tb_pixmap_text = NULL;
+    }
+
+    if (!use_xfont || strlen(fontname) == 0)
+        return;
+
+    tb->tb_font = pango_font_description_from_string(fontname);
+    tb->tb_fontname = g_strdup(fontname);
+
+    text_get_extents(fontname,
+                     "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz ",
+                     NULL, NULL, &ascent, &descent);
+    tb->tb_font_ascent = ascent;
+    tb->tb_font_descent = descent;
+
+
+    if (tb->tb_font == NULL)
+        return;
+
+    tb->tb_widget.height = tb->tb_font_ascent;
+    if (tb->tb_widget.height > tb->tb_nominal_height)
+        tb->tb_widget.y -= (tb->tb_widget.height - tb->tb_nominal_height) / 2;
+    else
+        tb->tb_widget.height = tb->tb_nominal_height;
+}
+
+TextBox *
+create_textbox(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+               gint x, gint y, gint w, gboolean allow_scroll, SkinPixmapId si)
+{
+    TextBox *tb;
+
+    tb = g_new0(TextBox, 1);
+    widget_init(&tb->tb_widget, parent, gc, x, y, w, 6, 1);
+    tb->tb_widget.button_press_cb = textbox_button_press;
+    tb->tb_widget.button_release_cb = textbox_button_release;
+    tb->tb_widget.motion_cb = textbox_motion;
+    tb->tb_widget.draw = textbox_draw;
+    tb->tb_scroll_allowed = allow_scroll;
+    tb->tb_scroll_enabled = TRUE;
+    tb->tb_skin_index = si;
+    tb->tb_nominal_y = y;
+    tb->tb_nominal_height = tb->tb_widget.height;
+    widget_list_add(wlist, WIDGET(tb));
+    tb->tb_timeout_tag = 0;
+    return tb;
+}
+
+void
+textbox_free(TextBox * tb)
+{
+    g_return_if_fail(tb != NULL);
+
+    if (tb->tb_pixmap)
+        g_object_unref(tb->tb_pixmap);
+    g_free(tb->tb_text);
+    g_free(tb);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/textbox.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,68 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef TEXTBOX_H
+#define	TEXTBOX_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <pango/pango.h>
+
+#include "skin.h"
+#include "widget.h"
+
+#define	TEXTBOX_SCROLL_TIMEOUT	       200
+#define TEXTBOX_SCROLL_SMOOTH_TIMEOUT  30
+
+#define TEXT_BOX(x)  ((TextBox *)(x))
+struct _TextBox {
+    Widget tb_widget;
+    GdkPixmap *tb_pixmap;
+    gchar *tb_text, *tb_pixmap_text;
+    gint tb_pixmap_width;
+    gint tb_offset;
+    gboolean tb_scroll_allowed, tb_scroll_enabled;
+    gboolean tb_is_scrollable, tb_is_dragging;
+    gint tb_timeout_tag, tb_drag_x, tb_drag_off;
+    gint tb_nominal_y, tb_nominal_height;
+    gint tb_skin_id;
+    SkinPixmapId tb_skin_index;
+    PangoFontDescription *tb_font;
+    gint tb_font_ascent, tb_font_descent;
+    gchar *tb_fontname;
+};
+
+typedef struct _TextBox TextBox;
+
+void textbox_set_text(TextBox * tb, const gchar * text);
+void textbox_set_scroll(TextBox * tb, gboolean s);
+TextBox *create_textbox(GList ** wlist, GdkPixmap * parent, GdkGC * gc,
+                        gint x, gint y, gint w, gboolean allow_scroll,
+                        SkinPixmapId si);
+void textbox_set_xfont(TextBox * tb, gboolean use_xfont,
+                       const gchar * fontname);
+void textbox_free(TextBox * tb);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/vis.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,291 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <string.h>
+
+#include "audacious/main.h"
+#include "skin.h"
+#include "widget.h"
+
+static const gfloat vis_afalloff_speeds[] = { 0.34, 0.5, 1.0, 1.3, 1.6 };
+static const gfloat vis_pfalloff_speeds[] = { 1.2, 1.3, 1.4, 1.5, 1.6 };
+static const gint vis_redraw_delays[] = { 1, 2, 4, 8 };
+static const guint8 vis_scope_colors[] =
+    { 21, 21, 20, 20, 19, 19, 18, 19, 19, 20, 20, 21, 21 };
+
+void
+vis_timeout_func(Vis * vis, guchar * data)
+{
+    static GTimer *timer = NULL;
+    gulong micros = 9999999;
+    gboolean falloff = FALSE;
+    gint i;
+
+    if (!timer) {
+        timer = g_timer_new();
+        g_timer_start(timer);
+    }
+    else {
+        g_timer_elapsed(timer, &micros);
+        if (micros > 14000)
+            g_timer_reset(timer);
+
+    }
+
+    if (cfg.vis_type == VIS_ANALYZER) {
+        if (micros > 14000)
+            falloff = TRUE;
+        if (data || falloff) {
+            for (i = 0; i < 75; i++) {
+                if (data && data[i] > vis->vs_data[i]) {
+                    vis->vs_data[i] = data[i];
+                    if (vis->vs_data[i] > vis->vs_peak[i]) {
+                        vis->vs_peak[i] = vis->vs_data[i];
+                        vis->vs_peak_speed[i] = 0.01;
+
+                    }
+                    else if (vis->vs_peak[i] > 0.0) {
+                        vis->vs_peak[i] -= vis->vs_peak_speed[i];
+                        vis->vs_peak_speed[i] *=
+                            vis_pfalloff_speeds[cfg.peaks_falloff];
+                        if (vis->vs_peak[i] < vis->vs_data[i])
+                            vis->vs_peak[i] = vis->vs_data[i];
+                        if (vis->vs_peak[i] < 0.0)
+                            vis->vs_peak[i] = 0.0;
+                    }
+                }
+                else if (falloff) {
+                    if (vis->vs_data[i] > 0.0) {
+                        vis->vs_data[i] -=
+                            vis_afalloff_speeds[cfg.analyzer_falloff];
+                        if (vis->vs_data[i] < 0.0)
+                            vis->vs_data[i] = 0.0;
+                    }
+                    if (vis->vs_peak[i] > 0.0) {
+                        vis->vs_peak[i] -= vis->vs_peak_speed[i];
+                        vis->vs_peak_speed[i] *=
+                            vis_pfalloff_speeds[cfg.peaks_falloff];
+                        if (vis->vs_peak[i] < vis->vs_data[i])
+                            vis->vs_peak[i] = vis->vs_data[i];
+                        if (vis->vs_peak[i] < 0.0)
+                            vis->vs_peak[i] = 0.0;
+                    }
+                }
+            }
+        }
+    }
+    else if (data) {
+        for (i = 0; i < 75; i++)
+            vis->vs_data[i] = data[i];
+    }
+
+    if (micros > 14000) {
+        if (!vis->vs_refresh_delay) {
+            vis_draw((Widget *) vis);
+            vis->vs_refresh_delay = vis_redraw_delays[cfg.vis_refresh];
+
+        }
+        vis->vs_refresh_delay--;
+    }
+}
+
+void
+vis_draw(Widget * w)
+{
+    Vis *vis = (Vis *) w;
+    gint x, y, h = 0, h2;
+    guchar vis_color[24][3];
+    guchar rgb_data[152 * 32], *ptr, c;
+    guint32 colors[24];
+    GdkRgbCmap *cmap;
+
+    if (!vis->vs_widget.visible)
+        return;
+
+    skin_get_viscolor(bmp_active_skin, vis_color);
+    for (y = 0; y < 24; y++) {
+        colors[y] =
+            vis_color[y][0] << 16 | vis_color[y][1] << 8 | vis_color[y][2];
+    }
+    cmap = gdk_rgb_cmap_new(colors, 24);
+
+    memset(rgb_data, 0, 76 * 16);
+    for (y = 1; y < 16; y += 2) {
+        ptr = rgb_data + (y * 76);
+        for (x = 0; x < 76; x += 2, ptr += 2)
+            *ptr = 1;
+    }
+    if (cfg.vis_type == VIS_ANALYZER) {
+        for (x = 0; x < 75; x++) {
+            if (cfg.analyzer_type == ANALYZER_BARS && (x % 4) == 0)
+                h = vis->vs_data[x >> 2];
+            else if (cfg.analyzer_type == ANALYZER_LINES)
+                h = vis->vs_data[x];
+            if (h && (cfg.analyzer_type == ANALYZER_LINES ||
+                      (x % 4) != 3)) {
+                ptr = rgb_data + ((16 - h) * 76) + x;
+                switch (cfg.analyzer_mode) {
+                case ANALYZER_NORMAL:
+                    for (y = 0; y < h; y++, ptr += 76)
+                        *ptr = 18 - h + y;
+                    break;
+                case ANALYZER_FIRE:
+                    for (y = 0; y < h; y++, ptr += 76)
+                        *ptr = y + 2;
+                    break;
+                case ANALYZER_VLINES:
+                    for (y = 0; y < h; y++, ptr += 76)
+                        *ptr = 18 - h;
+                    break;
+                }
+            }
+        }
+        if (cfg.analyzer_peaks) {
+            for (x = 0; x < 75; x++) {
+                if (cfg.analyzer_type == ANALYZER_BARS && (x % 4) == 0)
+                    h = vis->vs_peak[x >> 2];
+                else if (cfg.analyzer_type == ANALYZER_LINES)
+                    h = vis->vs_peak[x];
+                if (h
+                    && (cfg.analyzer_type == ANALYZER_LINES
+                        || (x % 4) != 3))
+                    rgb_data[(16 - h) * 76 + x] = 23;
+            }
+        }
+    }
+    else if (cfg.vis_type == VIS_SCOPE) {
+        for (x = 0; x < 75; x++) {
+            switch (cfg.scope_mode) {
+            case SCOPE_DOT:
+                h = vis->vs_data[x];
+                ptr = rgb_data + ((15 - h) * 76) + x;
+                *ptr = vis_scope_colors[h];
+                break;
+            case SCOPE_LINE:
+                if (x != 74) {
+                    h = 15 - vis->vs_data[x];
+                    h2 = 15 - vis->vs_data[x + 1];
+                    if (h > h2) {
+                        y = h;
+                        h = h2;
+                        h2 = y;
+                    }
+                    ptr = rgb_data + (h * 76) + x;
+                    for (y = h; y <= h2; y++, ptr += 76)
+                        *ptr = vis_scope_colors[y - 3];
+
+                }
+                else {
+                    h = 15 - vis->vs_data[x];
+                    ptr = rgb_data + (h * 76) + x;
+                    *ptr = vis_scope_colors[h];
+                }
+                break;
+            case SCOPE_SOLID:
+                h = 15 - vis->vs_data[x];
+                h2 = 9;
+                c = vis_scope_colors[(gint) vis->vs_data[x]];
+                if (h > h2) {
+                    y = h;
+                    h = h2;
+                    h2 = y;
+                }
+                ptr = rgb_data + (h * 76) + x;
+                for (y = h; y <= h2; y++, ptr += 76)
+                    *ptr = c;
+                break;
+            }
+        }
+    }
+
+    /* FIXME: The check "shouldn't" be neccessary? */
+    /*	if (GTK_IS_WINDOW(vis->vs_window)) { */
+    GDK_THREADS_ENTER();
+    gdk_draw_indexed_image(vis->vs_window, vis->vs_widget.gc,
+                           vis->vs_widget.x, vis->vs_widget.y,
+                           vis->vs_widget.width, vis->vs_widget.height,
+                           GDK_RGB_DITHER_NORMAL, (guchar *) rgb_data,
+                           76, cmap);
+    GDK_THREADS_LEAVE();
+    /*	} else {
+        vis->vs_window = mainwin->window;
+        GDK_THREADS_ENTER();
+        gdk_draw_indexed_image(vis->vs_window, vis->vs_widget.gc,
+        vis->vs_widget.x, vis->vs_widget.y,
+        vis->vs_widget.width, vis->vs_widget.height,
+        GDK_RGB_DITHER_NORMAL, (guchar *) rgb_data,
+        76, cmap);
+        GDK_THREADS_LEAVE();
+        }
+    */
+
+    gdk_rgb_cmap_free(cmap);
+}
+
+void
+vis_clear_data(Vis * vis)
+{
+    gint i;
+
+    if (!vis)
+        return;
+
+    for (i = 0; i < 75; i++) {
+        vis->vs_data[i] = (cfg.vis_type == VIS_SCOPE) ? 6 : 0;
+        vis->vs_peak[i] = 0;
+    }
+}
+
+void
+vis_clear(Vis * vis)
+{
+    gdk_window_clear_area(vis->vs_window, vis->vs_widget.x,
+                          vis->vs_widget.y, vis->vs_widget.width,
+                          vis->vs_widget.height);
+}
+
+void
+vis_set_window(Vis * vis, GdkWindow * window)
+{
+    vis->vs_window = window;
+}
+
+Vis *
+create_vis(GList ** wlist,
+           GdkPixmap * parent,
+           GdkWindow * window,
+           GdkGC * gc,
+           gint x, gint y,
+           gint width)
+{
+    Vis *vis;
+
+    vis = g_new0(Vis, 1);
+
+    widget_init(&vis->vs_widget, parent, gc, x, y, width, 16, 1);
+    widget_list_add(wlist, WIDGET(vis));
+
+    return vis;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/vis.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,82 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef VIS_H
+#define VIS_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "widget.h"
+
+typedef enum {
+    VIS_ANALYZER, VIS_SCOPE, VIS_OFF
+} VisType;
+
+typedef enum {
+    ANALYZER_NORMAL, ANALYZER_FIRE, ANALYZER_VLINES
+} AnalyzerMode;
+
+typedef enum {
+    ANALYZER_LINES, ANALYZER_BARS
+} AnalyzerType;
+
+typedef enum {
+    SCOPE_DOT, SCOPE_LINE, SCOPE_SOLID
+} ScopeMode;
+
+typedef enum {
+    VU_NORMAL, VU_SMOOTH
+} VUMode;
+
+typedef enum {
+    REFRESH_FULL, REFRESH_HALF, REFRESH_QUARTER, REFRESH_EIGTH
+} RefreshRate;
+
+typedef enum {
+    FALLOFF_SLOWEST, FALLOFF_SLOW, FALLOFF_MEDIUM, FALLOFF_FAST,
+    FALLOFF_FASTEST
+} FalloffSpeed;
+
+#define VIS(x)  ((Vis *)(x))
+struct _Vis {
+    Widget vs_widget;
+    GdkWindow *vs_window;
+    gfloat vs_data[75], vs_peak[75], vs_peak_speed[75];
+    gint vs_refresh_delay;
+};
+
+typedef struct _Vis Vis;
+
+void vis_draw(Widget * w);
+
+Vis *create_vis(GList ** wlist, GdkPixmap * parent, GdkWindow * window,
+                GdkGC * gc, gint x, gint y, gint width);
+void vis_timeout_func(Vis * vis, guchar * data);
+void vis_clear_data(Vis * vis);
+void vis_clear(Vis * vis);
+void vis_set_window(Vis * vis, GdkWindow * window);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/widget.c	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,263 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetcore.h"
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "audacious/debug.h"
+
+
+void
+widget_init(Widget * widget, GdkPixmap * parent, GdkGC * gc,
+            gint x, gint y, gint width, gint height, gint visible)
+{
+    widget->parent = parent;
+    widget->gc = gc;
+    widget_set_position(widget, x, y);
+    widget_set_size(widget, width, height);
+    widget->visible = visible;
+    widget->redraw = TRUE;
+    widget->mutex = g_mutex_new();
+}
+
+void
+widget_set_position(Widget * widget, gint x, gint y)
+{
+    widget->x = x;
+    widget->y = y;
+    widget_queue_redraw(widget);
+}
+
+void
+widget_set_size(Widget * widget, gint width, gint height)
+{
+    widget->width = width;
+    widget->height = height;
+    widget_queue_redraw(widget);
+}
+
+void
+widget_queue_redraw(Widget * widget)
+{
+    widget->redraw = TRUE;
+}
+
+gboolean
+widget_contains(Widget * widget, gint x, gint y)
+{
+    return (widget->visible &&
+            x >= widget->x && 
+            y >= widget->y && 
+            x <  widget->x + widget->width && 
+            y <  widget->y + widget->height);
+}
+
+void
+widget_show(Widget * widget)
+{
+    if (!widget)
+        return;
+
+    widget->visible = TRUE;
+    widget_draw(widget);
+}
+
+void
+widget_hide(Widget * widget)
+{
+    if (!widget)
+        return;
+
+    widget->visible = FALSE;
+}
+
+gboolean
+widget_is_visible(Widget * widget)
+{
+    if (!widget)
+        return FALSE;
+
+    return widget->visible;
+}
+
+void
+widget_resize(Widget * widget, gint width, gint height)
+{
+    widget_set_size(widget, width, height);
+}
+
+void
+widget_move(Widget * widget, gint x, gint y)
+{
+    widget_lock(widget);
+    widget_set_position(widget, x, y);
+    widget_unlock(widget);
+}
+
+void
+widget_draw(Widget * widget)
+{
+    widget_lock(widget);
+    WIDGET(widget)->redraw = TRUE;
+    widget_unlock(widget);
+}
+
+void
+widget_draw_quick(Widget * widget)
+{
+    widget_lock(widget);
+    if (WIDGET(widget)->draw != NULL)
+    {
+	WIDGET(widget)->draw(widget);
+        gdk_flush();
+    }
+    widget_unlock(widget);
+}
+
+void
+widget_list_add(GList ** list, Widget * widget)
+{
+    (*list) = g_list_append(*list, widget);
+}
+
+void
+handle_press_cb(GList * widget_list, GtkWidget * widget,
+                GdkEventButton * event)
+{
+    GList *wl;
+
+    for (wl = widget_list; wl; wl = g_list_next(wl)) {
+        if (WIDGET(wl->data)->button_press_cb)
+            WIDGET(wl->data)->button_press_cb(widget, event, wl->data);
+    }
+}
+
+void
+handle_release_cb(GList * widget_list, GtkWidget * widget,
+                  GdkEventButton * event)
+{
+    GList *wl;
+
+    for (wl = widget_list; wl; wl = g_list_next(wl)) {
+        if (WIDGET(wl->data)->button_release_cb)
+            WIDGET(wl->data)->button_release_cb(widget, event, wl->data);
+    }
+}
+
+void
+handle_motion_cb(GList * widget_list, GtkWidget * widget,
+                 GdkEventMotion * event)
+{
+    GList *wl;
+
+    for (wl = widget_list; wl; wl = g_list_next(wl)) {
+        if (WIDGET(wl->data)->motion_cb)
+            WIDGET(wl->data)->motion_cb(widget, event, wl->data);
+    }
+}
+
+void
+handle_scroll_cb(GList * wlist, GtkWidget * widget, GdkEventScroll * event)
+{
+    GList *wl;
+
+    for (wl = wlist; wl; wl = g_list_next(wl)) {
+        if (WIDGET(wl->data)->mouse_scroll_cb)
+            WIDGET(wl->data)->mouse_scroll_cb(widget, event, wl->data);
+    }
+}
+
+void
+widget_list_draw(GList * widget_list, gboolean * redraw, gboolean force)
+{
+    GList *wl;
+    Widget *w;
+
+    *redraw = FALSE;
+    wl = widget_list;
+
+    for (wl = widget_list; wl; wl = g_list_next(wl)) {
+        w = WIDGET(wl->data);
+
+        REQUIRE_LOCK(w->mutex);
+
+        if (!w->draw)
+            continue;
+
+        if (!w->visible)
+            continue;
+
+        if (w->redraw || force) {
+            w->draw(w);
+/*             w->redraw = FALSE; */
+            *redraw = TRUE;
+        }
+    }
+}
+
+void
+widget_list_change_pixmap(GList * widget_list, GdkPixmap * pixmap)
+{
+    GList *wl;
+
+    for (wl = widget_list; wl; wl = g_list_next(wl)) {
+        Widget *widget = wl->data;
+        widget->parent = pixmap;
+        widget_queue_redraw(widget);
+    }
+}
+
+void
+widget_list_clear_redraw(GList * widget_list)
+{
+    GList *wl;
+
+    for (wl = widget_list; wl; wl = g_list_next(wl)) {
+        REQUIRE_LOCK(WIDGET(wl->data)->mutex);
+        WIDGET(wl->data)->redraw = FALSE;
+    }
+}
+
+void
+widget_lock(Widget * widget)
+{
+    g_mutex_lock(WIDGET(widget)->mutex);
+}
+
+void
+widget_unlock(Widget * widget)
+{
+    g_mutex_unlock(WIDGET(widget)->mutex);
+}
+
+void
+widget_list_lock(GList * widget_list)
+{
+    g_list_foreach(widget_list, (GFunc) widget_lock, NULL);
+}
+
+void
+widget_list_unlock(GList * widget_list)
+{
+    g_list_foreach(widget_list, (GFunc) widget_unlock, NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/widget.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,107 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#error Please do not include me directly! Use widgetcore.h instead!
+#endif
+
+#ifndef WIDGET_H
+#define WIDGET_H
+
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+
+typedef struct _Widget Widget;
+
+
+typedef void (*WidgetButtonPressFunc) (GtkWidget *, GdkEventButton *,
+                                       gpointer);
+typedef void (*WidgetButtonReleaseFunc) (GtkWidget *, GdkEventButton *,
+                                         gpointer);
+typedef void (*WidgetMotionFunc) (GtkWidget *, GdkEventMotion *, gpointer);
+typedef void (*WidgetDrawFunc) (Widget *);
+typedef void (*WidgetScrollFunc) (GtkWidget *, GdkEventScroll *, gpointer);
+
+
+#define WIDGET(x)  ((Widget *)(x))
+struct _Widget {
+    GdkPixmap *parent;
+    GdkGC *gc;
+
+    gint x, y;
+    gint width, height;
+
+    gint visible;
+    gboolean redraw;
+
+    GMutex *mutex;
+
+    WidgetButtonPressFunc button_press_cb;
+    WidgetButtonReleaseFunc button_release_cb;
+    WidgetMotionFunc motion_cb;
+    WidgetDrawFunc draw;
+    WidgetScrollFunc mouse_scroll_cb;
+};
+
+
+void widget_init(Widget * widget, GdkPixmap * parent, GdkGC * gc,
+                 gint x, gint y, gint width, gint height, gint visible);
+
+void widget_set_position(Widget * widget, gint x, gint y);
+void widget_set_size(Widget * widget, gint width, gint height);
+void widget_queue_redraw(Widget * widget);
+
+void widget_lock(Widget * widget);
+void widget_unlock(Widget * widget);
+
+gboolean widget_contains(Widget * widget, gint x, gint y);
+
+void widget_show(Widget * widget);
+void widget_hide(Widget * widget);
+gboolean widget_is_visible(Widget * widget);
+
+void widget_resize(Widget * widget, gint width, gint height);
+void widget_move(Widget * widget, gint x, gint y);
+void widget_draw(Widget * widget);
+void widget_draw_quick(Widget * widget);
+
+void handle_press_cb(GList * wlist, GtkWidget * widget,
+                     GdkEventButton * event);
+void handle_release_cb(GList * wlist, GtkWidget * widget,
+                       GdkEventButton * event);
+void handle_motion_cb(GList * wlist, GtkWidget * widget,
+                      GdkEventMotion * event);
+void handle_scroll_cb(GList * wlist, GtkWidget * widget,
+                      GdkEventScroll * event);
+
+void widget_list_add(GList ** list, Widget * widget);
+void widget_list_draw(GList * list, gboolean * redraw, gboolean force);
+void widget_list_change_pixmap(GList * list, GdkPixmap * pixmap);
+void widget_list_clear_redraw(GList * list);
+void widget_list_lock(GList * list);
+void widget_list_unlock(GList * list);
+
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UserInterface/wa2gui/widgets/widgetcore.h	Thu Sep 07 20:27:46 2006 -0700
@@ -0,0 +1,41 @@
+/*
+ * Audacious - a cross-platform multimedia player
+ * Copyright (c) 2006  Audacious development team.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _WIDGETCORE_H_
+#define _WIDGETCORE_H_
+
+#include "tbutton.h"
+#include "eq_graph.h"
+#include "eq_slider.h"
+#include "hslider.h"
+#include "menurow.h"
+#include "monostereo.h"
+#include "number.h"
+#include "pbutton.h"
+#include "playlist_list.h"
+#include "playlist_slider.h"
+#include "playstatus.h"
+#include "sbutton.h"
+#include "skin.h"
+#include "svis.h"
+#include "textbox.h"
+#include "vis.h"
+#include "widget.h"
+
+#endif