changeset 4712:6584bba8de63

I don't think those files belong to legacy ui...
author Tomasz Mon <desowin@gmail.com>
date Tue, 08 Jul 2008 16:36:50 +0200
parents a33facf19590
children 22c9b76bef40
files src/audacious/Makefile src/audacious/legacy/ui_about.c src/audacious/legacy/ui_albumart.c src/audacious/legacy/ui_credits.c src/audacious/legacy/ui_credits.h src/audacious/legacy/ui_fileinfo.c src/audacious/legacy/ui_fileinfo.h src/audacious/legacy/ui_jumptotrack.c src/audacious/legacy/ui_jumptotrack_cache.c src/audacious/legacy/ui_jumptotrack_cache.h src/audacious/legacy/ui_urlopener.c src/audacious/legacy/ui_urlopener.h src/audacious/pluginenum.c src/audacious/ui_about.c src/audacious/ui_albumart.c src/audacious/ui_credits.c src/audacious/ui_credits.h src/audacious/ui_fileinfo.c src/audacious/ui_fileinfo.h src/audacious/ui_fileinfopopup.c src/audacious/ui_jumptotrack.c src/audacious/ui_jumptotrack_cache.c src/audacious/ui_jumptotrack_cache.h src/audacious/ui_legacy.c src/audacious/ui_urlopener.c src/audacious/ui_urlopener.h
diffstat 26 files changed, 3202 insertions(+), 3216 deletions(-) [+]
line wrap: on
line diff
--- a/src/audacious/Makefile	Tue Jul 08 15:35:48 2008 +0200
+++ b/src/audacious/Makefile	Tue Jul 08 16:36:50 2008 +0200
@@ -54,15 +54,15 @@
        visualization.c							\
        volumecontrol.c							\
        sync-menu.c								\
-       legacy/ui_about.c						\
-       legacy/ui_albumart.c						\
-       legacy/ui_credits.c						\
+       ui_about.c						\
+       ui_albumart.c						\
+       ui_credits.c						\
        legacy/ui_dock.c							\
        legacy/ui_equalizer.c					\
-       legacy/ui_fileinfo.c						\
+       ui_fileinfo.c						\
        legacy/ui_hints.c						\
-       legacy/ui_jumptotrack.c					\
-       legacy/ui_jumptotrack_cache.c			\
+       ui_jumptotrack.c					\
+       ui_jumptotrack_cache.c			\
        legacy/ui_main.c							\
        legacy/ui_main_evlisteners.c				\
        legacy/ui_manager.c						\
@@ -85,7 +85,7 @@
        legacy/ui_skinned_playlist_slider.c		\
        legacy/ui_skinned_playlist.c				\
        legacy/ui_skinselector.c					\
-       legacy/ui_urlopener.c					\
+       ui_urlopener.c					\
 
 ifeq ($(USE_DBUS),yes)
 SRCS += dbus.c
--- a/src/audacious/legacy/ui_about.c	Tue Jul 08 15:35:48 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,212 +0,0 @@
-/*
- *  Audacious - Cross-platform multimedia player
- *  Copyright (C) 2005-2007  Audacious development team
- *
- *  Based on BMP:
- *  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; under version 3 of the License.
- *
- *  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, see <http://www.gnu.org/licenses>.
- *
- *  The Audacious team does not consider modular code linking to
- *  Audacious or using our public API to be a derived work.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include "ui_credits.h"
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <gtk/gtk.h>
-
-#include "platform/smartinclude.h"
-
-static GtkWidget *about_window = NULL;
-static GdkPixbuf *about_pixbuf = NULL;
-static GdkPixmap *mask_pixmap_window1 = NULL,
-        *mask_pixmap_window2 = NULL;
-static GdkBitmap *mask_bitmap_window1 = NULL,
-        *mask_bitmap_window2 = NULL;
-
-static const gchar *audacious_brief = N_("<big><b>Audacious %s</b></big>\n\n"
-			"Copyright (C) 2005-2008 Audacious Development Team");
-    
-static gboolean
-on_about_window_expose(GtkWidget *widget, GdkEventExpose *expose, gpointer data)
-{
-	g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE);
-
-	gdk_window_set_back_pixmap(GDK_WINDOW(widget->window), mask_pixmap_window2, 0);
-	gdk_window_clear(GDK_WINDOW(widget->window));
-
-	return FALSE;
-}
-
-static gboolean
-on_about_window_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data)
-{
-	g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE);
-
-	if (event->keyval == GDK_Escape)
-	{      
-		gtk_widget_hide(widget);
-	}
-
-	return FALSE;
-}
-
-static gboolean
-on_close_button_clicked (GtkWidget *widget, gpointer data)
-{
-	g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE);
-
-	gtk_widget_hide(about_window);
-
-	return FALSE;
-}
-
-static gboolean
-on_credits_button_clicked (GtkWidget *widget, gpointer data)
-{
-	g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE);
-
-	show_credits_window();
-
-	return FALSE;
-}
-
-void
-show_about_window(void)
-{
-    GtkWidget *about_fixedbox;
-    GtkWidget *close_button;
-    GtkWidget *credits_button , *credits_button_hbox, *credits_button_image, *credits_button_label;
-    GtkWidget *brief_label;
-    gchar *filename = DATA_DIR G_DIR_SEPARATOR_S "images" G_DIR_SEPARATOR_S "about-logo.png";
-    gchar *text;
-    PangoAttrList *brief_label_attrs;
-    PangoAttribute *brief_label_foreground;
-
-    if (about_window != NULL)
-    {
-        gtk_window_present(GTK_WINDOW(about_window));
-        return;
-    }
-
-    about_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
-    g_signal_connect(about_window, "destroy",
-                     G_CALLBACK(gtk_widget_destroyed), &about_window);
-
-    gtk_widget_realize(about_window);
-
-    about_pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
-
-    gtk_widget_set_size_request(GTK_WIDGET (about_window),
-                   gdk_pixbuf_get_width (about_pixbuf),
-                   gdk_pixbuf_get_height (about_pixbuf));
-
-    gtk_widget_set_app_paintable(about_window, TRUE);
-    gtk_window_set_title(GTK_WINDOW(about_window), _("About Audacious"));
-    gtk_window_set_position(GTK_WINDOW(about_window), GTK_WIN_POS_CENTER);
-    gtk_window_set_resizable(GTK_WINDOW(about_window), FALSE);
-    gtk_window_set_decorated(GTK_WINDOW(about_window), FALSE);
-
-    gdk_pixbuf_render_pixmap_and_mask(about_pixbuf,
-                     &mask_pixmap_window1,
-                     &mask_bitmap_window1,
-                     0);
-
-    gdk_pixbuf_render_pixmap_and_mask(about_pixbuf,
-                     &mask_pixmap_window2,
-                     &mask_bitmap_window2,
-                     128);
-
-    gtk_widget_add_events(about_window, GDK_ALL_EVENTS_MASK);
-
-    g_signal_connect(about_window, "expose-event",
-	G_CALLBACK(on_about_window_expose), &about_window);
-
-    g_signal_connect(about_window, "key-press-event",
-	G_CALLBACK(on_about_window_key_press), &about_window);
-
-    gtk_widget_shape_combine_mask(GTK_WIDGET(about_window), mask_bitmap_window2, 0, 0);
-
-    /* GtkFixed hasn't got its GdkWindow, this means that it can be used to
-       display widgets while the logo below will be displayed anyway;
-       however fixed positions are not that great, cause the button sizes may (will)
-       vary depending on the gtk style used, so it's not possible to center
-       them unless a fixed width and heigth is forced (and this may bring to cutted
-       text if someone, i.e., uses a big font for gtk widgets);
-       other types of container most likely have their GdkWindow, this simply
-       means that the logo must be drawn on the container widget, instead of the
-       window; otherwise, it won't be displayed correctly */
-    about_fixedbox = gtk_fixed_new();
-    gtk_container_add( GTK_CONTAINER(about_window) , about_fixedbox );
-
-    close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
-
-    g_signal_connect(close_button, "clicked",
-	G_CALLBACK(on_close_button_clicked), NULL);
-
-    gtk_fixed_put( GTK_FIXED(about_fixedbox) , close_button , 375 , 220 );
-    gtk_widget_set_size_request( close_button , 100 , -1 );
-
-    credits_button = gtk_button_new();
-    credits_button_hbox = gtk_hbox_new( FALSE , 0 );
-    credits_button_image = gtk_image_new_from_stock( GTK_STOCK_DIALOG_INFO , GTK_ICON_SIZE_BUTTON );
-    gtk_misc_set_alignment( GTK_MISC(credits_button_image) , 1 , 0.5 );
-    credits_button_label = gtk_label_new( _("Credits") );
-    gtk_misc_set_alignment( GTK_MISC(credits_button_label) , 0 , 0.5 );
-    gtk_box_pack_start( GTK_BOX(credits_button_hbox) , credits_button_image ,
-                        TRUE , TRUE , 2 );
-    gtk_box_pack_start( GTK_BOX(credits_button_hbox) , credits_button_label ,
-                        TRUE , TRUE , 2 );
-    gtk_container_add( GTK_CONTAINER(credits_button) , credits_button_hbox );
-
-    g_signal_connect(credits_button, "clicked",
-	G_CALLBACK(on_credits_button_clicked), NULL);
-
-    gtk_fixed_put( GTK_FIXED(about_fixedbox) , credits_button , 25 , 220 );
-    gtk_widget_set_size_request( credits_button , 100 , -1 );
-
-    brief_label = gtk_label_new(NULL);
-    text = g_strdup_printf(_(audacious_brief), VERSION);
-
-    brief_label_foreground = pango_attr_foreground_new(0, 0, 0);
-    brief_label_attrs = pango_attr_list_new();
-    pango_attr_list_insert(brief_label_attrs, brief_label_foreground);
-
-    gtk_label_set_markup(GTK_LABEL(brief_label), text);
-    gtk_label_set_justify(GTK_LABEL(brief_label), GTK_JUSTIFY_CENTER);
-    gtk_label_set_attributes(GTK_LABEL(brief_label), brief_label_attrs);
-    g_free(text);
-
-    gtk_fixed_put(GTK_FIXED(about_fixedbox), brief_label, 20, 145);
-    gtk_widget_set_size_request( brief_label , 460 , -1 );
-
-    gtk_widget_show_all(about_window);
-    gtk_window_present(GTK_WINDOW(about_window));
-}
-
-void
-hide_about_window(void)
-{
-    g_return_if_fail(about_window);
-    gtk_widget_hide(GTK_WIDGET(about_window));
-}
--- a/src/audacious/legacy/ui_albumart.c	Tue Jul 08 15:35:48 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,195 +0,0 @@
-/*
- * Audacious: A cross-platform multimedia player
- * Copyright (c) 2007 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; under version 3 of the License.
- *
- * 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, see <http://www.gnu.org/licenses>.
- *
- * The Audacious team does not consider modular code linking to
- * Audacious or using our public API to be a derived work.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <gtk/gtk.h>
-#include <string.h>
-
-#include "ui_fileinfopopup.h"
-#include "main.h"
-#include "ui_main.h"
-#include "playlist.h"
-#include "playback.h"
-
-static gboolean
-has_front_cover_extension(const gchar *name)
-{
-	char *ext;
-
-	ext = strrchr(name, '.');
-	if (!ext) {
-		/* No file extension */
-		return FALSE;
-	}
-
-	return g_strcasecmp(ext, ".jpg") == 0 ||
-	       g_strcasecmp(ext, ".jpeg") == 0 ||
-	       g_strcasecmp(ext, ".png") == 0;
-}
-
-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 *imgfile)
-{
-	return cover_name_filter(imgfile, cfg.cover_name_include, TRUE) &&
-	       !cover_name_filter(imgfile, cfg.cover_name_exclude, FALSE);
-}
-
-static gboolean
-is_file_image(const gchar *imgfile, const gchar *file_name)
-{
-	char *imgfile_ext, *file_name_ext;
-	size_t imgfile_len, file_name_len;
-
-	imgfile_ext = strrchr(imgfile, '.');
-	if (!imgfile_ext) {
-		/* No file extension */
-		return FALSE;
-	}
-
-	file_name_ext = strrchr(file_name, '.');
-	if (!file_name_ext) {
-		/* No file extension */
-		return FALSE;
-	}
-
-	imgfile_len = (imgfile_ext - imgfile);
-	file_name_len = (file_name_ext - file_name);
-
-	if (imgfile_len == file_name_len) {
-		return (g_ascii_strncasecmp(imgfile, file_name, imgfile_len) == 0);
-	} else {
-		return FALSE;
-	}
-}
-
-gchar*
-fileinfo_recursive_get_image(const gchar* path,
-	const gchar* file_name, 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;
-
-		if (cfg.use_file_cover && file_name) {
-			/* Look for images matching file name */
-			while((f = g_dir_read_name(d))) { 
-				gchar *newpath = g_strconcat(path, "/", f, NULL);
-
-				if (!g_file_test(newpath, G_FILE_TEST_IS_DIR) &&
-				    has_front_cover_extension(f) &&
-				    is_file_image(f, file_name)) {
-					g_dir_close(d);
-					return newpath;
-				}
-
-				g_free(newpath);
-			}
-			g_dir_rewind(d);
-		}
-		
-		/* Search for files using filter */
-		while ((f = g_dir_read_name(d))) {
-			gchar *newpath = g_strconcat(path, "/", f, NULL);
-
-			if (!g_file_test(newpath, G_FILE_TEST_IS_DIR) &&
-			    has_front_cover_extension(f) &&
-			    is_front_cover_image(f)) {
-				g_dir_close(d);
-				return newpath;
-			}
-
-			g_free(newpath);
-		}
-		g_dir_rewind(d);
-
-		/* checks whether recursive or not. */
-		if (!cfg.recurse_for_cover) {
-			g_dir_close(d);
-			return NULL;
-		}
-
-		/* Descend into directories recursively. */
-		while ((f = g_dir_read_name(d))) {
-			gchar *newpath = g_strconcat(path, "/", f, NULL);
-			
-			if(g_file_test(newpath, G_FILE_TEST_IS_DIR)) {
-				gchar *tmp = fileinfo_recursive_get_image(newpath,
-					NULL, depth + 1);
-				if(tmp) {
-					g_free(newpath);
-					g_dir_close(d);
-					return tmp;
-				}
-			}
-
-			g_free(newpath);
-		}
-
-		g_dir_close(d);
-	}
-
-	return NULL;
-}
--- a/src/audacious/legacy/ui_credits.c	Tue Jul 08 15:35:48 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,434 +0,0 @@
-/*  Audacious - Cross-platform multimedia player
- *  Copyright (C) 2005-2007  Audacious Team
- *
- *  Based on BMP:
- *  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; under version 3 of the License.
- *
- *  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, see <http://www.gnu.org/licenses>.
- *
- *  The Audacious team does not consider modular code linking to
- *  Audacious or using our public API to be a derived work.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include "ui_credits.h"
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <gtk/gtk.h>
-
-#include "audacious_logo.xpm"
-
-
-enum {
-    COL_LEFT,
-    COL_RIGHT,
-    N_COLS
-};
-
-
-static const gchar *audacious_brief =
-    N_("<big><b>Audacious %s</b></big>\n"
-       "A skinned multimedia player for many platforms.\n"
-       "\n"
-       "Copyright (C) 2005-2008 Audacious Development Team\n");
-
-static const gchar *credit_text[] = {
-    N_("Audacious core developers:"),
-    "George Averill",
-    "Daniel Barkalow",
-    "Christian Birchinger",
-    "Daniel Bradshaw",
-    "Adam Cecile",
-    "Michael Färber",
-    "Matti Hämäläinen",
-    "Troels Bang Jensen",
-    "Giacomo Lozito",
-    "Cristi Măgherușan",
-    "Tomasz Moń",
-    "William Pitcock",
-    "Derek Pomery",
-    "Jonathan Schleifer",
-    "Ben Tucker",
-    "Tony Vroon",
-    "Yoshiki Yazawa",
-    "Eugene Zagidullin",
-    NULL,
-
-    N_("Graphics:"),
-    "George Averill",
-    "Stephan Sokolow",
-    NULL,
-
-    N_("Default skin:"),
-    "George Averill",
-    "Michael Färber",
-    "William Pitcock",
-    NULL,
-
-    N_("Plugin development:"),
-    "Kiyoshi Aman",
-    "Luca Barbato",
-    "Daniel Barkalow",
-    "Michael Färber",
-    "Shay Green",
-    "Matti Hämäläinen",
-    "Sascha Hlusiak",
-    "Giacomo Lozito",
-    "Cristi Măgherușan",
-    "Tomasz Moń",
-    "William Pitcock",
-    "Derek Pomery",
-    "Jonathan Schleifer",
-    "Tony Vroon",
-    "Yoshiki Yazawa",
-    NULL,
-
-    N_("Patch authors:"),
-    "Massimo Cavalleri",
-    "Stefano D'Angelo",
-    "Laszlo Dvornik",
-    "Ralf Ertzinger",
-    "Mike Frysinger",
-    "Mark Glines",
-    "Teru KAMOGASHIRA",
-    "Chris Kehler",
-    "Alex Maclean",
-    "Michael Hanselmann",
-    "Joseph Jezak",
-    "Henrik Johansson",
-    "Rodrigo Martins de Matos Ventura",
-    "Diego Pettenò",
-    "Kazuki Shimura",
-    "Valentine Sinitsyn",
-    "Johan Tavelin",
-    "Tim Yamin",
-    "Ivan N. Zlatev",
-    NULL,
-
-    N_("0.1.x developers:"),
-    "William Pitcock",
-    "Mohammed Sameer",
-    "Tony Vroon",
-    NULL,
-
-    N_("BMP Developers:"),
-    "Artem Baguinski",
-    "Edward Brocklesby",
-    "Chong Kai Xiong",
-    "Milosz Derezynski",
-    "David Lau",
-    "Ole Andre Vadla Ravnaas",
-    "Michiel Sikkes",
-    "Andrei Badea",
-    "Peter Behroozi",
-    "Bernard Blackham",
-    "Oliver Blin",
-    "Tomas Bzatek",
-    "Liviu Danicel",
-    "Jon Dowland",
-    "Artur Frysiak",
-    "Sebastian Kapfer",
-    "Lukas Koberstein",
-    "Dan Korostelev",
-    "Jolan Luff",
-    "Michael Marineau",
-    "Tim-Philipp Muller",
-    "Julien Portalier",
-    "Andrew Ruder",
-    "Olivier Samyn",
-    "Martijn Vernooij",
-    NULL,
-
-    NULL
-};
-
-static const gchar *translators[] = {
-    N_("Brazilian Portuguese:"),
-    "Fábio Antunes",
-    "Philipi Pinto",
-    NULL,
-    N_("Breton:"),
-    "Thierry Vignaud",
-    NULL,
-    N_("Bulgarian:"),
-    "Andrew Ivanov",
-    NULL,
-    N_("Catalan:"),
-    "Ernest Adrogu",
-    NULL,
-    N_("Croatian:"),
-    "Marin Glibic",
-    NULL,
-    N_("Czech:"),
-    "Petr Pisar",
-    NULL,
-    N_("Dutch:"),
-    "Laurens Buhler",
-    "Tony Vroon",
-    NULL,
-    N_("Estonian:"),
-    "Ivar Smolin",
-    NULL,
-    N_("Finnish:"),
-    "Pauli Virtanen",
-    "Matti Hämäläinen",
-    NULL,
-    N_("French:"),
-    "Adam Cecile",
-    "Stanislas Zeller",
-    "Stany Henry",
-    NULL,
-    N_("German:"),
-    "Michael Färber",
-    "Michael Hanselmann",
-    "Matthias Debus",
-    NULL,
-    N_("Georgian:"),
-    "George Machitidze",
-    NULL,
-    N_("Greek:"),
-    "Kouzinopoulos Haris",
-    "Stavros Giannouris",
-    "Stathis Kamperis",
-    NULL,
-    N_("Hindi:"),
-    "Dhananjaya Sharma",
-    NULL,
-    N_("Hungarian:"),
-    "Laszlo Dvornik",
-    NULL,
-    N_("Italian:"),
-    "Alessio D'Ascanio",
-    "Diego Pettenò",
-    NULL,
-    N_("Japanese:"),
-    "Dai",
-    NULL,
-    N_("Korean:"),
-    "DongCheon Park",
-    NULL,
-    N_("Lithuanian:"),
-    "Rimas Kudelis",
-    NULL,
-    N_("Macedonian:"),
-    "Arangel Angov",
-    NULL,
-    N_("Polish:"),
-    "Wojciech Myrda",
-    NULL,
-    N_("Romanian:"),
-    "Daniel Patriche",
-    "Cristi Măgherușan",
-    NULL,
-    N_("Russian:"),
-    "Alexandr Orlov",
-    NULL,
-    N_("Serbian (Latin):"),
-    "Strahinja Kustudić",
-    NULL,
-    N_("Serbian (Cyrillic):"),
-    "Strahinja Kustudić",
-    NULL,
-    N_("Simplified Chinese:"),
-    "Yang Zhang",
-    NULL,
-    N_("Slovak:"),
-    "Andrej Herceg",
-    NULL,
-    N_("Spanish:"),
-    "Gustavo D. Vranjes",
-    NULL,
-    N_("Swedish:"),
-    "Martin Persenius",
-    NULL,
-    N_("Traditional Chinese:"),
-    "Cheng-Wei Chien",
-    "Sylecn Song",
-    "Yang Zhang",
-    NULL,
-    N_("Turkish:"),
-    "Murat Şenel",
-    "Eren Turkay",
-    NULL,
-    N_("Ukrainian:"),
-    "Mykola Lynnyk",
-    NULL,
-    N_("Welsh:"),
-    "Edward Brocklesby",
-    "William Pitcock",
-    NULL,
-
-    NULL
-};
-
-
-static GtkWidget *
-generate_credit_list(const gchar * text[], gboolean sec_space)
-{
-    GtkWidget *scrollwin;
-    GtkWidget *treeview;
-    GtkListStore *list_store;
-    GtkTreeIter iter;
-    GtkTreeViewColumn *column;
-    GtkCellRenderer *renderer;
-    const gchar *const *item;
-
-    list_store = gtk_list_store_new(N_COLS, G_TYPE_STRING, G_TYPE_STRING);
-
-    item = text;
-
-    while (*item) {
-        gtk_list_store_append(list_store, &iter);
-        gtk_list_store_set(list_store, &iter,
-                           COL_LEFT, _(item[0]), COL_RIGHT, _(item[1]), -1);
-        item += 2;
-
-        while (*item) {
-            gtk_list_store_append(list_store, &iter);
-            gtk_list_store_set(list_store, &iter,
-                               COL_LEFT, "", COL_RIGHT, _(*item++), -1);
-        }
-
-        ++item;
-
-        if (*item && sec_space) {
-            gtk_list_store_append(list_store, &iter);
-            gtk_list_store_set(list_store, &iter,
-                               COL_LEFT, "", COL_RIGHT, "", -1);
-        }
-    }
-
-    treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store));
-    gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(treeview), FALSE);
-    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
-    gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
-        GTK_SELECTION_NONE);
-
-    renderer = gtk_cell_renderer_text_new();
-    g_object_set(renderer, "xalign", 1.0, NULL);
-    column = gtk_tree_view_column_new_with_attributes("Left", renderer,
-                                                      "text", COL_LEFT, NULL);
-    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
-
-    renderer = gtk_cell_renderer_text_new();
-    g_object_set(renderer, "xalign", 0.0, NULL);
-    column = gtk_tree_view_column_new_with_attributes("Right", renderer,
-                                                      "text", COL_RIGHT,
-                                                      NULL);
-    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
-
-    scrollwin = gtk_scrolled_window_new(NULL, NULL);
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
-                                   GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
-    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin), GTK_SHADOW_IN);
-    gtk_container_add(GTK_CONTAINER(scrollwin), treeview);
-    gtk_container_set_border_width(GTK_CONTAINER(scrollwin), 10);
-
-    gtk_widget_show_all(scrollwin);
-
-    return scrollwin;
-}
-
-void
-show_credits_window(void)
-{
-    static GtkWidget *about_window = NULL;
-
-    GdkPixbuf *logo_pixbuf;
-    GtkWidget *about_vbox;
-    GtkWidget *about_credits_logo_box, *about_credits_logo_frame;
-    GtkWidget *about_credits_logo;
-    GtkWidget *about_notebook;
-    GtkWidget *list;
-    GtkWidget *bbox, *close_btn;
-    GtkWidget *label;
-    gchar *text;
-
-    if (about_window)
-        return;
-
-    about_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    gtk_window_set_type_hint(GTK_WINDOW(about_window),
-                             GDK_WINDOW_TYPE_HINT_DIALOG);
-
-    gtk_window_set_default_size(GTK_WINDOW(about_window), -1, 512);
-    gtk_window_set_title(GTK_WINDOW(about_window), _("About Audacious"));
-    gtk_window_set_position(GTK_WINDOW(about_window), GTK_WIN_POS_CENTER);
-    gtk_window_set_resizable(GTK_WINDOW(about_window), TRUE);
-    gtk_container_set_border_width(GTK_CONTAINER(about_window), 10);
-
-    g_signal_connect(about_window, "destroy",
-                     G_CALLBACK(gtk_widget_destroyed), &about_window);
-
-    gtk_widget_realize(about_window);
-
-    about_vbox = gtk_vbox_new(FALSE, 5);
-    gtk_container_add(GTK_CONTAINER(about_window), about_vbox);
-
-    logo_pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)audacious_logo_xpm);
-
-    about_credits_logo_box = gtk_hbox_new(TRUE, 0);
-    gtk_box_pack_start(GTK_BOX(about_vbox), about_credits_logo_box,
-                       FALSE, FALSE, 0);
-
-    about_credits_logo_frame = gtk_frame_new(NULL);
-    gtk_frame_set_shadow_type(GTK_FRAME(about_credits_logo_frame),
-                              GTK_SHADOW_ETCHED_OUT);
-    gtk_box_pack_start(GTK_BOX(about_credits_logo_box),
-                       about_credits_logo_frame, FALSE, FALSE, 0);
-
-    about_credits_logo = gtk_image_new_from_pixbuf(logo_pixbuf);
-    gtk_container_add(GTK_CONTAINER(about_credits_logo_frame),
-                      about_credits_logo);
-    g_object_unref(logo_pixbuf);
-
-    label = gtk_label_new(NULL);
-    text = g_strdup_printf(_(audacious_brief), VERSION);
-    gtk_label_set_markup(GTK_LABEL(label), text);
-    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
-    g_free(text);
-
-    gtk_box_pack_start(GTK_BOX(about_vbox), label, FALSE, FALSE, 0);
-
-    about_notebook = gtk_notebook_new();
-    gtk_box_pack_start(GTK_BOX(about_vbox), about_notebook, TRUE, TRUE, 0);
-
-    list = generate_credit_list(credit_text, TRUE);
-    gtk_notebook_append_page(GTK_NOTEBOOK(about_notebook), list,
-                             gtk_label_new(_("Credits")));
-
-    list = generate_credit_list(translators, FALSE);
-    gtk_notebook_append_page(GTK_NOTEBOOK(about_notebook), list,
-                             gtk_label_new(_("Translators")));
-
-    bbox = gtk_hbutton_box_new();
-    gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
-    gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
-    gtk_box_pack_start(GTK_BOX(about_vbox), bbox, FALSE, FALSE, 0);
-
-    close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
-    g_signal_connect_swapped(close_btn, "clicked",
-                             G_CALLBACK(gtk_widget_destroy), about_window);
-    GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
-    gtk_box_pack_start(GTK_BOX(bbox), close_btn, TRUE, TRUE, 0);
-    gtk_widget_grab_default(close_btn);
-
-    gtk_widget_show_all(about_window);
-}
--- a/src/audacious/legacy/ui_credits.h	Tue Jul 08 15:35:48 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-
-#ifndef AUDACIOUS_UI_CREDITS_H
-#define AUDACIOUS_UI_CREDITS_H
-
-void show_about_window(void);
-void hide_about_window(void);
-void show_credits_window(void);
-
-#endif /* AUDACIOUS_UI_CREDITS_H */
--- a/src/audacious/legacy/ui_fileinfo.c	Tue Jul 08 15:35:48 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1019 +0,0 @@
-/*
- * Audacious: A cross-platform multimedia player
- * Copyright (c) 2006 William Pitcock, Tony Vroon, George Averill,
- *                    Giacomo Lozito, Derek Pomery and Yoshiki Yazawa.
- * Copyright (c) 2008 Eugene Zagidullin
- *
- * 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; under version 3 of the License.
- *
- * 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, see <http://www.gnu.org/licenses>.
- *
- * The Audacious team does not consider modular code linking to
- * Audacious or using our public API to be a derived work.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <gtk/gtk.h>
-#include <string.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "plugin.h"
-#include "pluginenum.h"
-#include "input.h"
-#include "effect.h"
-#include "strings.h"
-#include "general.h"
-#include "output.h"
-#include "visualization.h"
-
-#include "main.h"
-#include "util.h"
-#include "dnd.h"
-#include "tuple.h"
-#include "vfs.h"
-
-#include "playlist.h"
-
-#include "ui_main.h"
-#include "ui_playlist.h"
-#include "build_stamp.h"
-#include "ui_fileinfo.h"
-#include "ui_playlist.h"
-
-#define G_FREE_CLEAR(a) if(a != NULL) { g_free(a); a = NULL; }
-#define STATUS_TIMEOUT 3*1000
-
-GtkWidget *fileinfo_win = NULL;
-
-GtkWidget *entry_location;
-GtkWidget *entry_title;
-GtkWidget *entry_artist;
-GtkWidget *entry_album;
-GtkWidget *entry_comment;
-GtkWidget *entry_year;
-GtkWidget *entry_track;
-GtkWidget *entry_genre;
-
-GtkWidget *image_artwork;
-
-GtkWidget *image_fileicon;
-GtkWidget *label_format_name;
-GtkWidget *label_quality;
-GtkWidget *label_bitrate;
-GtkWidget *btn_apply;
-GtkWidget *label_mini_status;
-GtkWidget *arrow_rawdata;
-GtkWidget *treeview_rawdata;
-
-enum {
-    RAWDATA_KEY,
-    RAWDATA_VALUE,
-    RAWDATA_N_COLS
-};
-
-static gchar *current_file = NULL;
-static InputPlugin *current_ip = NULL;
-static gboolean something_changed = FALSE;
-
-/* stolen from Audacious 1.4 vorbis plugin. --nenolod */
-static const gchar *genre_table[] = {
-    N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"),
-    N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"),
-    N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"),
-    N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"),
-    N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"),
-    N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"),
-    N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"),
-    N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"),
-    N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"),
-    N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("AlternRock"),
-    N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"),
-    N_("Meditative"), N_("Instrumental Pop"),
-    N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"),
-    N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"),
-    N_("Pop-Folk"), N_("Eurodance"), N_("Dream"),
-    N_("Southern Rock"), N_("Comedy"), N_("Cult"),
-    N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"),
-    N_("Pop/Funk"), N_("Jungle"), N_("Native American"),
-    N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"),
-    N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"),
-    N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"),
-    N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"),
-    N_("Folk/Rock"), N_("National Folk"), N_("Swing"),
-    N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"),
-    N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"),
-    N_("Gothic Rock"), N_("Progressive Rock"),
-    N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"),
-    N_("Big Band"), N_("Chorus"), N_("Easy Listening"),
-    N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"),
-    N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"),
-    N_("Booty Bass"), N_("Primus"), N_("Porn Groove"),
-    N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"),
-    N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"),
-    N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"),
-    N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"),
-    N_("Euro-House"), N_("Dance Hall"), N_("Goa"),
-    N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"),
-    N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"),
-    N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"),
-    N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"),
-    N_("Contemporary Christian"), N_("Christian Rock"),
-    N_("Merengue"), N_("Salsa"), N_("Thrash Metal"),
-    N_("Anime"), N_("JPop"), N_("Synthpop")
-};
-
-static GList *genre_list = NULL;
-
-static void
-fileinfo_entry_set_text(GtkWidget *widget, const char *text)
-{
-    if (widget == NULL)
-        return;
-
-    gtk_entry_set_text(GTK_ENTRY(widget), text != NULL ? text : "");
-}
-
-static void
-set_entry_str_from_field(GtkWidget *widget, Tuple *tuple, gint fieldn, gboolean editable)
-{
-    gchar *text;
-
-    if(widget != NULL) {
-        text = (gchar*)tuple_get_string(tuple, fieldn, NULL);
-        gtk_entry_set_text(GTK_ENTRY(widget), text != NULL ? text : "");
-        gtk_editable_set_editable(GTK_EDITABLE(widget), editable);
-    }
-}
-
-static void
-set_entry_int_from_field(GtkWidget *widget, Tuple *tuple, gint fieldn, gboolean editable)
-{
-    gchar *text;
-
-    if(widget == NULL) return;
-
-    if(tuple_get_value_type(tuple, fieldn, NULL) == TUPLE_INT) {
-        text = g_strdup_printf("%d", tuple_get_int(tuple, fieldn, NULL));
-        gtk_entry_set_text(GTK_ENTRY(widget), text);
-        gtk_editable_set_editable(GTK_EDITABLE(widget), editable);
-        g_free(text);
-    } else {
-        gtk_entry_set_text(GTK_ENTRY(widget), "");
-        gtk_editable_set_editable(GTK_EDITABLE(widget), editable);
-    }
-}
-
-static void
-set_field_str_from_entry(Tuple *tuple, gint fieldn, GtkWidget *widget)
-{
-    if(widget == NULL) return;
-    tuple_associate_string(tuple, fieldn, NULL, gtk_entry_get_text(GTK_ENTRY(widget)));
-}
-
-static void
-set_field_int_from_entry(Tuple *tuple, gint fieldn, GtkWidget *widget)
-{
-    gchar *tmp;
-    if(widget == NULL) return;
-
-    tmp = (gchar*)gtk_entry_get_text(GTK_ENTRY(widget));
-    if(*tmp != '\0')
-        tuple_associate_int(tuple, fieldn, NULL, atoi(tmp));
-    else
-        tuple_associate_int(tuple, fieldn, NULL, -1);
-}
-
-static void
-fileinfo_label_set_text(GtkWidget *widget, const char *text)
-{
-    gchar *tmp;
-
-    if (widget == NULL)
-        return;
-
-    if (text) {
-        tmp = g_strdup_printf("<span size=\"small\">%s</span>", text);
-        gtk_label_set_text(GTK_LABEL(widget), tmp);
-        gtk_label_set_use_markup(GTK_LABEL(widget), TRUE);
-        g_free(tmp);
-    } else {
-        gtk_label_set_text(GTK_LABEL(widget), _("<span size=\"small\">n/a</span>"));
-        gtk_label_set_use_markup(GTK_LABEL(widget), TRUE);
-    }
-}
-
-static void
-fileinfo_entry_set_image(GtkWidget *widget, const char *text)
-{
-    GdkPixbuf *pixbuf;
-    int width, height;
-    double aspect;
-    GdkPixbuf *pixbuf2;
-
-    if (widget == NULL)
-        return;
-
-    pixbuf = gdk_pixbuf_new_from_file(text, NULL);
-
-    if (pixbuf == NULL)
-        return;
-
-    width  = gdk_pixbuf_get_width(GDK_PIXBUF(pixbuf));
-    height = gdk_pixbuf_get_height(GDK_PIXBUF(pixbuf));
-
-    if (strcmp(DATA_DIR "/images/audio.png", text)) {
-        if (width == 0)
-            width = 1;
-        aspect = (double)height / (double)width;
-
-        if (aspect > 1.0) {
-            height = (int)(cfg.filepopup_pixelsize * aspect);
-            width = cfg.filepopup_pixelsize;
-        } else {
-            height = cfg.filepopup_pixelsize;
-            width = (int)(cfg.filepopup_pixelsize / aspect);
-        }
-
-        pixbuf2 = gdk_pixbuf_scale_simple(GDK_PIXBUF(pixbuf), width, height, 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
-fileinfo_hide(gpointer unused)
-{
-    if(GTK_WIDGET_VISIBLE(fileinfo_win)) 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(gtk_bin_get_child(GTK_BIN(entry_genre)), "");
-    fileinfo_entry_set_text(entry_year, "");
-    fileinfo_entry_set_text(entry_track, "");
-    fileinfo_entry_set_text(entry_location, "");
-
-    fileinfo_label_set_text(label_format_name, NULL);
-    fileinfo_label_set_text(label_quality, NULL);
-    fileinfo_label_set_text(label_bitrate, NULL);
-    
-    if (label_mini_status != NULL) {
-        gtk_label_set_text(GTK_LABEL(label_mini_status), "<span size=\"small\"></span>");
-        gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE);
-    }
-    
-    something_changed = FALSE;
-    gtk_widget_set_sensitive(btn_apply, FALSE);
-
-    current_ip = NULL;
-    G_FREE_CLEAR(current_file);
-
-    fileinfo_entry_set_image(image_artwork, DATA_DIR "/images/audio.png");
-}
-
-static void
-entry_changed (GtkEditable *editable, gpointer user_data)
-{
-    if(current_file != NULL && current_ip != NULL && current_ip->update_song_tuple != NULL) {
-        something_changed = TRUE;
-        gtk_widget_set_sensitive(btn_apply, TRUE);
-    }
-}
-
-static gboolean
-ministatus_timeout_proc (gpointer data)
-{
-    GtkLabel *status = GTK_LABEL(data);
-    gtk_label_set_text(status, "<span size=\"small\"></span>");
-    gtk_label_set_use_markup(status, TRUE);
-
-    return FALSE;
-}
-
-static void
-ministatus_display_message(gchar *text)
-{
-    if(label_mini_status != NULL) {
-        gchar *tmp = g_strdup_printf("<span size=\"small\">%s</span>", text);
-        gtk_label_set_text(GTK_LABEL(label_mini_status), tmp);
-        g_free(tmp);
-        gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE);
-        g_timeout_add (STATUS_TIMEOUT, (GSourceFunc) ministatus_timeout_proc, (gpointer) label_mini_status);
-    }
-}
-
-static void
-message_update_successfull()
-{
-    ministatus_display_message(_("Metadata updated successfully"));
-}
-
-static void
-message_update_failed()
-{
-    ministatus_display_message(_("Metadata updating failed"));
-}
-
-static void
-fileinfo_update_tuple(gpointer data)
-{
-    Tuple *tuple;
-    VFSFile *fd;
-
-    if (current_file != NULL && current_ip != NULL && current_ip->update_song_tuple != NULL && something_changed) {
-        tuple = tuple_new();
-        fd = vfs_fopen(current_file, "r+b");
-
-        if (fd != NULL) {
-            set_field_str_from_entry(tuple, FIELD_TITLE, entry_title);
-            set_field_str_from_entry(tuple, FIELD_ARTIST, entry_artist);
-            set_field_str_from_entry(tuple, FIELD_ALBUM, entry_album);
-            set_field_str_from_entry(tuple, FIELD_COMMENT, entry_comment);
-            set_field_str_from_entry(tuple, FIELD_GENRE, gtk_bin_get_child(GTK_BIN(entry_genre)));
-
-            set_field_int_from_entry(tuple, FIELD_YEAR, entry_year);
-            set_field_int_from_entry(tuple, FIELD_TRACK_NUMBER, entry_track);
-
-            plugin_set_current((Plugin *)current_ip);
-            if (current_ip->update_song_tuple(tuple, fd)) {
-                message_update_successfull();
-                something_changed = FALSE;
-                gtk_widget_set_sensitive(btn_apply, FALSE);
-            } else
-                message_update_failed();
-
-            vfs_fclose(fd);
-
-        } else
-            message_update_failed();
-
-        mowgli_object_unref(tuple);
-    }
-}
-
-/**
- * Looks up an icon from a NULL-terminated list of icon names.
- *
- * size: the requested size
- * name: the default name
- * ... : a NULL-terminated list of alternates
- */
-GdkPixbuf *
-themed_icon_lookup(gint size, const gchar *name, ...)
-{
-    GtkIconTheme *icon_theme;
-    GdkPixbuf *pixbuf;
-    GError *error = NULL;
-    gchar *n;
-    va_list par;
-
-    icon_theme = gtk_icon_theme_get_default ();
-    pixbuf = gtk_icon_theme_load_icon (icon_theme, name, size, 0, &error);
-
-    if (pixbuf != NULL)
-        return pixbuf;
-    
-    if (error != NULL)
-        g_error_free(error);
-
-    /* fallback */
-    va_start(par, name);
-    while((n = (gchar*)va_arg(par, gchar *)) != NULL) {
-        error = NULL;
-        pixbuf = gtk_icon_theme_load_icon (icon_theme, n, size, 0, &error);
-
-        if (pixbuf) {
-            va_end(par);
-            return pixbuf;
-        }
-
-        if (error != NULL)
-            g_error_free(error);
-    }
-    
-    return NULL;
-}
-
-/**
- * Intelligently looks up an icon for a mimetype. Supports
- * HIDEOUSLY BROKEN gnome icon naming scheme too.
- *
- * size     : the requested size
- * mime_type: the mime type.
- */
-GdkPixbuf *
-mime_icon_lookup(gint size, const gchar *mime_type) /* smart icon resolving routine :) */
-{
-    gchar *mime_as_is;         /* audio-x-mp3            */
-    gchar *mime_gnome;         /* gnome-mime-audio-x-mp3 */
-    gchar *mime_generic;       /* audio-x-generic */
-    gchar *mime_gnome_generic; /* gnome-mime-audio */
-
-    GdkPixbuf *icon = NULL;
-
-    gchar **s = g_strsplit(mime_type, "/", 2);
-    if(s[1] != NULL) {
-        mime_as_is         = g_strdup_printf("%s-%s", s[0], s[1]);
-        mime_gnome         = g_strdup_printf("gnome-mime-%s-%s", s[0], s[1]);
-        mime_generic       = g_strdup_printf("%s-x-generic", s[0]);
-        mime_gnome_generic = g_strdup_printf("gnome-mime-%s", s[0]);
-        icon = themed_icon_lookup(size, mime_as_is, mime_gnome, mime_generic, mime_gnome_generic, s[0], NULL); /* s[0] is category */
-        g_free(mime_gnome_generic);
-        g_free(mime_generic);
-        g_free(mime_gnome);
-        g_free(mime_as_is);
-    }
-    g_strfreev(s);
-
-    return icon;
-}
-
-void
-create_fileinfo_window(void)
-{
-    GtkWidget *hbox;
-    GtkWidget *hbox_status_and_bbox;
-    GtkWidget *vbox0;
-    GtkWidget *vbox1;
-    GtkWidget *vbox2;
-    GtkWidget *vbox3;
-    GtkWidget *label_title;
-    GtkWidget *label_artist;
-    GtkWidget *label_album;
-    GtkWidget *label_comment;
-    GtkWidget *label_genre;
-    GtkWidget *label_year;
-    GtkWidget *label_track;
-    GtkWidget *label_location;
-    GtkWidget *label_general;
-    GtkWidget *label_format;
-    GtkWidget *label_quality_label;
-    GtkWidget *label_bitrate_label;
-    GtkWidget *codec_hbox;
-    GtkWidget *codec_table;
-    GtkWidget *table1;
-    GtkWidget *bbox_close;
-    GtkWidget *btn_close;
-    GtkWidget *alignment;
-    GtkWidget *separator;
-    GtkWidget *scrolledwindow;
-    GtkTreeViewColumn *column;
-    GtkCellRenderer *renderer;
-    gint i;
-
-    fileinfo_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    gtk_container_set_border_width(GTK_CONTAINER(fileinfo_win), 6);
-    gtk_window_set_title(GTK_WINDOW(fileinfo_win), _("Track Information"));
-    gtk_window_set_position(GTK_WINDOW(fileinfo_win), GTK_WIN_POS_CENTER);
-    gtk_window_set_resizable(GTK_WINDOW(fileinfo_win), FALSE);
-    gtk_window_set_type_hint(GTK_WINDOW(fileinfo_win), GDK_WINDOW_TYPE_HINT_DIALOG);
-    gtk_window_set_transient_for(GTK_WINDOW(fileinfo_win), GTK_WINDOW(mainwin));
-
-    vbox0 = gtk_vbox_new(FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(fileinfo_win), vbox0);
-
-    hbox = gtk_hbox_new(FALSE, 6);
-    gtk_box_pack_start(GTK_BOX(vbox0), hbox, TRUE, TRUE, 0);
-
-    image_artwork = gtk_image_new();
-    gtk_box_pack_start(GTK_BOX(hbox), image_artwork, FALSE, FALSE, 0);
-    gtk_misc_set_alignment(GTK_MISC(image_artwork), 0.5, 0);
-    gtk_image_set_from_file(GTK_IMAGE(image_artwork), DATA_DIR "/images/audio.png");
-    separator = gtk_vseparator_new();
-    gtk_box_pack_start(GTK_BOX(hbox), separator, FALSE, FALSE, 0);
-
-    vbox1 = gtk_vbox_new(FALSE, 0);
-    gtk_box_pack_start(GTK_BOX(hbox), vbox1, TRUE, TRUE, 0);
-
-    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
-    gtk_box_pack_start(GTK_BOX(vbox1), alignment, TRUE, TRUE, 0);
-
-    vbox2 = gtk_vbox_new(FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(alignment), vbox2);
-
-    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
-    gtk_box_pack_start(GTK_BOX(vbox1), alignment, TRUE, TRUE, 0);
-
-    vbox3 = gtk_vbox_new(FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(alignment), vbox3);
-    
-    label_general = gtk_label_new(_("<span size=\"small\">General</span>"));
-    gtk_box_pack_start (GTK_BOX (vbox2), label_general, FALSE, FALSE, 0);
-    gtk_label_set_use_markup(GTK_LABEL(label_general), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_general), 0, 0.5);
-    
-    alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
-    gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 0, 0);
-    gtk_box_pack_start (GTK_BOX (vbox2), alignment, FALSE, FALSE, 0);
-
-    codec_hbox = gtk_hbox_new(FALSE, 6);
-    gtk_container_add (GTK_CONTAINER(alignment), codec_hbox);
-
-    image_fileicon = gtk_image_new_from_stock (GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG);
-    gtk_box_pack_start (GTK_BOX (codec_hbox), image_fileicon, FALSE, FALSE, 0);
-    
-    codec_table = gtk_table_new(3, 2, FALSE);
-    gtk_table_set_row_spacings (GTK_TABLE(codec_table), 6);
-    gtk_table_set_col_spacings (GTK_TABLE(codec_table), 12);
-    gtk_box_pack_start (GTK_BOX (codec_hbox), codec_table, FALSE, FALSE, 0);
-
-    label_format = gtk_label_new(_("<span size=\"small\">Format:</span>"));
-    gtk_label_set_use_markup(GTK_LABEL(label_format), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_format), 0, 0.5);
-    label_quality_label = gtk_label_new(_("<span size=\"small\">Quality:</span>"));
-    gtk_label_set_use_markup(GTK_LABEL(label_quality_label), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_quality_label), 0, 0.5);
-    label_bitrate_label = gtk_label_new(_("<span size=\"small\">Bitrate:</span>"));
-    gtk_label_set_use_markup(GTK_LABEL(label_bitrate_label), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_bitrate_label), 0, 0.5);
-
-    label_format_name = gtk_label_new(_("<span size=\"small\">n/a</span>"));
-    gtk_label_set_use_markup(GTK_LABEL(label_format_name), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_format_name), 0, 0.5);
-    label_quality = gtk_label_new(_("<span size=\"small\">n/a</span>"));
-    gtk_label_set_use_markup(GTK_LABEL(label_quality), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_quality), 0, 0.5);
-    label_bitrate = gtk_label_new(_("<span size=\"small\">n/a</span>"));
-    gtk_label_set_use_markup(GTK_LABEL(label_bitrate), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_bitrate), 0, 0.5);
-    
-    gtk_table_attach(GTK_TABLE(codec_table), label_format, 0, 1, 0, 1,
-                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                     (GtkAttachOptions) (0), 0, 0);
-    gtk_table_attach(GTK_TABLE(codec_table), label_format_name, 1, 2, 0, 1,
-                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                     (GtkAttachOptions) (0), 0, 0);
-    gtk_table_attach(GTK_TABLE(codec_table), label_quality_label, 0, 1, 1, 2,
-                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                     (GtkAttachOptions) (0), 0, 0);
-    gtk_table_attach(GTK_TABLE(codec_table), label_quality, 1, 2, 1, 2,
-                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                     (GtkAttachOptions) (0), 0, 0);
-    gtk_table_attach(GTK_TABLE(codec_table), label_bitrate_label, 0, 1, 2, 3,
-                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                     (GtkAttachOptions) (0), 0, 0);
-    gtk_table_attach(GTK_TABLE(codec_table), label_bitrate, 1, 2, 2, 3,
-                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                     (GtkAttachOptions) (0), 0, 0);
-
-    label_title = gtk_label_new(_("<span size=\"small\">Title</span>"));
-    gtk_box_pack_start(GTK_BOX(vbox2), label_title, FALSE, FALSE, 0);
-    gtk_label_set_use_markup(GTK_LABEL(label_title), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_title), 0, 0);
-
-    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
-    gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0);
-    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0);
-    entry_title = gtk_entry_new();
-    gtk_container_add(GTK_CONTAINER(alignment), entry_title);
-    g_signal_connect(G_OBJECT(entry_title), "changed", (GCallback) entry_changed, NULL);
-
-    label_artist = gtk_label_new(_("<span size=\"small\">Artist</span>"));
-    gtk_box_pack_start(GTK_BOX(vbox2), label_artist, FALSE, FALSE, 0);
-    gtk_label_set_use_markup(GTK_LABEL(label_artist), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_artist), 0, 0.5);
-
-    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
-    gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0);
-    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0);
-    entry_artist = gtk_entry_new();
-    gtk_container_add(GTK_CONTAINER(alignment), entry_artist);
-    g_signal_connect(G_OBJECT(entry_artist), "changed", (GCallback) entry_changed, NULL);
-
-    label_album = gtk_label_new(_("<span size=\"small\">Album</span>"));
-    gtk_box_pack_start(GTK_BOX(vbox2), label_album, FALSE, FALSE, 0);
-    gtk_label_set_use_markup(GTK_LABEL(label_album), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_album), 0, 0.5);
-
-    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
-    gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0);
-    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0);
-    entry_album = gtk_entry_new();
-    gtk_container_add(GTK_CONTAINER(alignment), entry_album);
-    g_signal_connect(G_OBJECT(entry_album), "changed", (GCallback) entry_changed, NULL);
-
-    label_comment = gtk_label_new(_("<span size=\"small\">Comment</span>"));
-    gtk_box_pack_start(GTK_BOX(vbox2), label_comment, FALSE, FALSE, 0);
-    gtk_label_set_use_markup(GTK_LABEL(label_comment), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_comment), 0, 0.5);
-
-    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
-    gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0);
-    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0);
-    entry_comment = gtk_entry_new();
-    gtk_container_add (GTK_CONTAINER(alignment), entry_comment);
-    g_signal_connect(G_OBJECT(entry_comment), "changed", (GCallback) entry_changed, NULL);
-
-    label_genre = gtk_label_new(_("<span size=\"small\">Genre</span>"));
-    gtk_box_pack_start(GTK_BOX(vbox2), label_genre, FALSE, FALSE, 0);
-    gtk_label_set_use_markup(GTK_LABEL(label_genre), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_genre), 0, 0.5);
-
-    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
-    gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0);
-    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0);
-    entry_genre = gtk_combo_box_entry_new_text();
-
-    if (!genre_list) {
-        GList *iter;
-
-        for (i = 0; i < G_N_ELEMENTS(genre_table); i++)
-            genre_list = g_list_prepend(genre_list, _(genre_table[i]));
-        genre_list = g_list_sort(genre_list, (GCompareFunc) g_utf8_collate);
-
-        MOWGLI_ITER_FOREACH(iter, genre_list)
-            gtk_combo_box_append_text(GTK_COMBO_BOX(entry_genre), iter->data);
-    }
-
-    gtk_container_add(GTK_CONTAINER(alignment), entry_genre);
-    g_signal_connect(G_OBJECT(entry_genre), "changed", (GCallback) entry_changed, NULL);
-
-    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
-    gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0);
-    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0);
-    table1 = gtk_table_new(2, 2, FALSE);
-    gtk_container_add(GTK_CONTAINER(alignment), table1);
-    gtk_table_set_col_spacings(GTK_TABLE(table1), 6);
-
-    label_year = gtk_label_new(_("<span size=\"small\">Year</span>"));
-    gtk_table_attach(GTK_TABLE(table1), label_year, 0, 1, 0, 1,
-                     (GtkAttachOptions) (GTK_FILL),
-                     (GtkAttachOptions) (0), 0, 0);
-    gtk_label_set_use_markup(GTK_LABEL(label_year), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_year), 0, 0.5);
-
-    entry_year = gtk_entry_new();
-    gtk_table_attach(GTK_TABLE(table1), entry_year, 0, 1, 1, 2,
-                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                     (GtkAttachOptions) (0), 0, 0);
-    g_signal_connect(G_OBJECT(entry_year), "changed", (GCallback) entry_changed, NULL);
-
-    label_track = gtk_label_new(_("<span size=\"small\">Track Number</span>"));
-    gtk_table_attach(GTK_TABLE(table1), label_track, 1, 2, 0, 1,
-                     (GtkAttachOptions) (GTK_FILL),
-                     (GtkAttachOptions) (0), 0, 0);
-    gtk_label_set_use_markup(GTK_LABEL(label_track), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_track), 0, 0.5);
-
-    entry_track = gtk_entry_new();
-    gtk_table_attach(GTK_TABLE(table1), entry_track, 1, 2, 1, 2,
-                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                     (GtkAttachOptions) (0), 0, 0);
-    g_signal_connect(G_OBJECT(entry_track), "changed", (GCallback) entry_changed, NULL);
-
-    label_location = gtk_label_new(_("<span size=\"small\">Location</span>"));
-    gtk_box_pack_start(GTK_BOX(vbox2), label_location, FALSE, FALSE, 0);
-    gtk_label_set_use_markup(GTK_LABEL(label_location), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_location), 0, 0.5);
-
-    alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
-    gtk_box_pack_start (GTK_BOX (vbox2), alignment, FALSE, FALSE, 0);
-    gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 6, 0, 0);
-
-    entry_location = gtk_entry_new();
-    gtk_container_add(GTK_CONTAINER(alignment), entry_location);
-    gtk_editable_set_editable(GTK_EDITABLE(entry_location), FALSE);
-
-    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
-    hbox = gtk_hbox_new(FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(alignment), hbox);
-    gtk_box_pack_start(GTK_BOX(vbox3), alignment, TRUE, TRUE, 0);
-
-    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
-    gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 6, 0, 0);
-    arrow_rawdata = gtk_expander_new(_("<span size=\"small\">Raw Metadata</span>"));
-    gtk_expander_set_use_markup(GTK_EXPANDER(arrow_rawdata), TRUE);
-    gtk_container_add(GTK_CONTAINER(alignment), arrow_rawdata);
-    gtk_box_pack_start(GTK_BOX(hbox), alignment, TRUE, TRUE, 0);
-
-    scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
-    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN);
-    gtk_container_add(GTK_CONTAINER(arrow_rawdata), scrolledwindow);
-
-    treeview_rawdata = gtk_tree_view_new();
-    gtk_container_add(GTK_CONTAINER(scrolledwindow), treeview_rawdata);
-    gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview_rawdata), TRUE);
-    gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview_rawdata), TRUE);
-    gtk_widget_set_size_request(treeview_rawdata, -1, 130);
-
-    column = gtk_tree_view_column_new();
-    gtk_tree_view_column_set_title(column, _("Key"));
-    gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
-    gtk_tree_view_column_set_spacing(column, 4);
-    gtk_tree_view_column_set_resizable(column, FALSE);
-    gtk_tree_view_column_set_fixed_width(column, 50);
-
-    renderer = gtk_cell_renderer_text_new();
-    gtk_tree_view_column_pack_start(column, renderer, FALSE);
-    gtk_tree_view_column_set_attributes(column, renderer,
-                                        "text", RAWDATA_KEY, NULL);
-    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_rawdata), column);
-
-    column = gtk_tree_view_column_new();
-    gtk_tree_view_column_set_title(column, _("Value"));
-    gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
-    gtk_tree_view_column_set_spacing(column, 4);
-    gtk_tree_view_column_set_resizable(column, FALSE);
-    gtk_tree_view_column_set_fixed_width(column, 50);
-
-    renderer = gtk_cell_renderer_text_new();
-    gtk_tree_view_column_pack_start(column, renderer, FALSE);
-    gtk_tree_view_column_set_attributes(column, renderer,
-                                        "text", RAWDATA_VALUE, NULL);
-    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_rawdata), column);
-    
-    hbox_status_and_bbox = gtk_hbox_new(FALSE, 0);
-    gtk_box_pack_start (GTK_BOX (vbox0), hbox_status_and_bbox, FALSE, FALSE, 0);
-
-    label_mini_status = gtk_label_new("<span size=\"small\"></span>");
-    gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label_mini_status), 0, 0.5);
-    gtk_box_pack_start (GTK_BOX (hbox_status_and_bbox), label_mini_status, TRUE, TRUE, 0);
-    
-    bbox_close = gtk_hbutton_box_new();
-    gtk_box_set_spacing(GTK_BOX(bbox_close), 6);
-    gtk_box_pack_start(GTK_BOX(hbox_status_and_bbox), bbox_close, FALSE, FALSE, 0);
-    gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox_close), GTK_BUTTONBOX_END);
-
-    btn_apply = gtk_button_new_from_stock("gtk-save");
-    gtk_container_add(GTK_CONTAINER(bbox_close), btn_apply);
-    g_signal_connect(G_OBJECT(btn_apply), "clicked", (GCallback) fileinfo_update_tuple, NULL);
-    gtk_widget_set_sensitive(btn_apply, FALSE);
-
-    btn_close = gtk_button_new_from_stock("gtk-close");
-    gtk_container_add(GTK_CONTAINER(bbox_close), btn_close);
-    GTK_WIDGET_SET_FLAGS(btn_close, GTK_CAN_DEFAULT);
-    g_signal_connect(G_OBJECT(btn_close), "clicked", (GCallback) fileinfo_hide, NULL);
-
-    gtk_widget_show_all (vbox0);
-}
-
-static void 
-fileinfo_show_for_tuple(Tuple *tuple, gboolean updating_enabled)
-{
-    gchar *tmp = NULL;
-    GdkPixbuf *icon = NULL;
-    GtkTreeIter iter;
-    GtkListStore *store;
-    mowgli_dictionary_iteration_state_t state;
-    TupleValue *tvalue;
-    gint i;
-
-    if (tuple == NULL)
-        return;
-
-    if(!updating_enabled) {
-        current_ip = NULL;
-        G_FREE_CLEAR(current_file);
-    }
-
-    something_changed = FALSE;
-
-    if (fileinfo_win == NULL)
-        create_fileinfo_window();
-
-    if (!GTK_WIDGET_REALIZED(fileinfo_win))
-        gtk_widget_realize(fileinfo_win);
-
-    set_entry_str_from_field(entry_title, tuple, FIELD_TITLE, updating_enabled);
-    set_entry_str_from_field(entry_artist, tuple, FIELD_ARTIST, updating_enabled);
-    set_entry_str_from_field(entry_album, tuple, FIELD_ALBUM, updating_enabled);
-    set_entry_str_from_field(entry_comment, tuple, FIELD_COMMENT, updating_enabled);
-    set_entry_str_from_field(gtk_bin_get_child(GTK_BIN(entry_genre)), tuple, FIELD_GENRE, updating_enabled);
-
-    tmp = g_strdup_printf("%s/%s",
-            tuple_get_string(tuple, FIELD_FILE_PATH, NULL),
-            tuple_get_string(tuple, FIELD_FILE_NAME, NULL));
-
-    if (tmp) {
-        fileinfo_entry_set_text(entry_location, tmp);
-        g_free(tmp);
-    }
-        
-    /* set empty string if field not availaible. --eugene */
-    set_entry_int_from_field(entry_year, tuple, FIELD_YEAR, updating_enabled);
-    set_entry_int_from_field(entry_track, tuple, FIELD_TRACK_NUMBER, updating_enabled);
-
-    fileinfo_label_set_text(label_format_name, tuple_get_string(tuple, FIELD_CODEC, NULL));
-    fileinfo_label_set_text(label_quality, tuple_get_string(tuple, FIELD_QUALITY, NULL));
-
-    if (tuple_get_value_type(tuple, FIELD_BITRATE, NULL) == TUPLE_INT) {
-        tmp = g_strdup_printf(_("%d kb/s"), tuple_get_int(tuple, FIELD_BITRATE, NULL));
-        fileinfo_label_set_text(label_bitrate, tmp);
-        g_free(tmp);
-    } else
-        fileinfo_label_set_text(label_bitrate, NULL);
-
-    tmp = (gchar *)tuple_get_string(tuple, FIELD_MIMETYPE, NULL);
-    icon = mime_icon_lookup(48, tmp ? tmp : "audio/x-generic");
-    if (icon) {
-        if (image_fileicon) gtk_image_set_from_pixbuf (GTK_IMAGE(image_fileicon), icon);
-        g_object_unref(icon);
-    }
-
-    tmp = fileinfo_recursive_get_image(
-            tuple_get_string(tuple, FIELD_FILE_PATH, NULL),
-            tuple_get_string(tuple, FIELD_FILE_NAME, NULL), 0);
-        
-    if (tmp) {
-        fileinfo_entry_set_image(image_artwork, tmp);
-        g_free(tmp);
-    }
-
-    gtk_widget_set_sensitive(btn_apply, FALSE);
-    
-    if (label_mini_status != NULL) {
-        gtk_label_set_text(GTK_LABEL(label_mini_status), "<span size=\"small\"></span>");
-        gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE);
-    }
-
-    store = gtk_list_store_new(RAWDATA_N_COLS, G_TYPE_STRING, G_TYPE_STRING);
-
-    for (i = 0; i < FIELD_LAST; i++) {
-         gchar *key, *value;
-
-         if (!tuple->values[i])
-             continue;
-
-         if (tuple->values[i]->type != TUPLE_INT && tuple->values[i]->value.string)
-             value = g_strdup(tuple->values[i]->value.string);
-         else if (tuple->values[i]->type == TUPLE_INT)
-             value = g_strdup_printf("%d", tuple->values[i]->value.integer);
-         else
-             continue;
-
-         key = g_strdup(tuple_fields[i].name);
-
-         gtk_list_store_append(store, &iter);
-         gtk_list_store_set(store, &iter,
-                            RAWDATA_KEY, key,
-                            RAWDATA_VALUE, value, -1);
-
-         g_free(key);
-         g_free(value);
-    }
-
-    /* non-standard values are stored in a dictionary. */
-    MOWGLI_DICTIONARY_FOREACH(tvalue, &state, tuple->dict) {
-         gchar *key, *value;
-
-         if (tvalue->type != TUPLE_INT && tvalue->value.string)
-             value = g_strdup(tvalue->value.string);
-         else if (tvalue->type == TUPLE_INT)
-             value = g_strdup_printf("%d", tvalue->value.integer);
-         else
-             continue;
-
-         key = g_strdup(state.cur->key);
-
-         gtk_list_store_append(store, &iter);
-         gtk_list_store_set(store, &iter,
-                            RAWDATA_KEY, key,
-                            RAWDATA_VALUE, value, -1);
-
-         g_free(key);
-         g_free(value);
-    }
-
-    gtk_tree_view_set_model(GTK_TREE_VIEW(treeview_rawdata), GTK_TREE_MODEL(store));
-    g_object_unref(store);
-
-    if (!GTK_WIDGET_VISIBLE(fileinfo_win))
-        gtk_widget_show(fileinfo_win);
-}
-
-static void
-fileinfo_show_for_path(gchar *path)
-{
-    Tuple *tuple = input_get_song_tuple(path);
-
-    if (tuple == NULL) {
-         input_file_info_box(path);
-         return;
-    }
-
-    fileinfo_show_for_tuple(tuple, FALSE);
-
-    mowgli_object_unref(tuple);
-}
-
-static void
-fileinfo_show_editor_for_path(gchar *path, InputPlugin *ip)
-{
-    G_FREE_CLEAR(current_file);
-    current_file = g_strdup(path);
-    current_ip = ip;
-
-    Tuple *tuple = input_get_song_tuple(path);
-
-    if (tuple == NULL) {
-        input_file_info_box(path);
-        return;
-    }
-
-    fileinfo_show_for_tuple(tuple, TRUE);
-
-    mowgli_object_unref(tuple);
-}
-
-static void
-ui_fileinfo_show_entry(Playlist *playlist, PlaylistEntry *entry)
-{
-    gchar *path = g_strdup(entry->filename);
-    Tuple *tuple = entry->tuple;
-
-    /* plugin is capable of updating tags. we need to bypass tuple cache. --eugene */
-    /* maybe code cleanup required... */
-    if (entry != NULL &&
-        entry->decoder != NULL &&
-        entry->decoder->update_song_tuple != NULL &&
-        entry->decoder->file_info_box == NULL &&
-        path != NULL && !vfs_is_remote(path))
-    {
-        fileinfo_show_editor_for_path(path, entry->decoder);
-        g_free(path);
-    }
-    else
-    {
-        if (tuple != NULL)
-        {
-            if (entry->decoder != NULL)
-            {
-                if (entry->decoder->file_info_box == NULL)
-                    fileinfo_show_for_tuple(tuple, FALSE);
-                else
-                {
-                    plugin_set_current((Plugin *)(entry->decoder));
-                    entry->decoder->file_info_box(path);
-                }
-            }
-            else
-                fileinfo_show_for_path(path);
-            g_free(path);
-        }
-        else if (path != NULL)
-        {
-            if (entry != NULL &&
-                entry->decoder != NULL &&
-                entry->decoder->file_info_box != NULL)
-            {
-                plugin_set_current((Plugin *)(entry->decoder));
-                entry->decoder->file_info_box(path);
-            }
-            else
-                fileinfo_show_for_path(path);
-            g_free(path);
-        }
-    }
-}
-
-void
-ui_fileinfo_show(Playlist *playlist, guint pos)
-{
-    GList *node = NULL;
-
-    PLAYLIST_LOCK(playlist);
-
-    if ((node = g_list_nth(playlist->entries, pos)))
-        ui_fileinfo_show_entry(playlist, node->data);
-
-    PLAYLIST_UNLOCK(playlist);
-}
-
-void
-ui_fileinfo_show_current(Playlist *playlist)
-{
-    PLAYLIST_LOCK(playlist);
-
-    if (playlist->entries && playlist->position)
-        ui_fileinfo_show_entry(playlist, playlist->position);
-
-    PLAYLIST_UNLOCK(playlist);
-}
--- a/src/audacious/legacy/ui_fileinfo.h	Tue Jul 08 15:35:48 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +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 3 of the License.
- *
- * 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, see <http://www.gnu.org/licenses>.
- */
-
-#ifndef AUDACIOUS_UI_FILEINFO_H
-#define AUDACIOUS_UI_FILEINFO_H
-
-#include "tuple.h"
-#include "plugin.h"
-#include <glib.h>
-
-void create_fileinfo_window(void);
-gchar* fileinfo_recursive_get_image(const gchar* path, const gchar* file_name, gint depth);
-
-void ui_fileinfo_show(Playlist *playlist, guint pos);
-void ui_fileinfo_show_current(Playlist *playlist);
-
-#endif /* AUDACIOUS_UI_FILEINFO_H */
--- a/src/audacious/legacy/ui_jumptotrack.c	Tue Jul 08 15:35:48 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,623 +0,0 @@
-/*  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; under version 3 of the License.
- *
- *  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, see <http://www.gnu.org/licenses>.
- *
- *  The Audacious team does not consider modular code linking to
- *  Audacious or using our public API to be a derived work.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <glib/gprintf.h>
-#include <gtk/gtk.h>
-#include <gtk/gtkmessagedialog.h>
-
-/* GDK including */
-#include "platform/smartinclude.h"
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <sys/types.h>
-
-#if defined(USE_REGEX_ONIGURUMA)
-  #include <onigposix.h>
-#elif defined(USE_REGEX_PCRE)
-  #include <pcreposix.h>
-#else
-  #include <regex.h>
-#endif
-
-#include "ui_main.h"
-#include "icons-stock.h"
-
-#include "actions-mainwin.h"
-
-#include "main.h"
-
-#include "dnd.h"
-#include "input.h"
-#include "playback.h"
-#include "playlist.h"
-#include "pluginenum.h"
-#include "ui_credits.h"
-#include "ui_dock.h"
-#include "ui_equalizer.h"
-#include "ui_fileopener.h"
-#include "ui_manager.h"
-#include "ui_playlist.h"
-#include "ui_preferences.h"
-#include "ui_skinselector.h"
-#include "ui_urlopener.h"
-#include "strings.h"
-#include "util.h"
-#include "visualization.h"
-
-#include "ui_skinned_window.h"
-
-#include "ui_jumptotrack_cache.h"
-
-static GtkWidget *jump_to_track_win = NULL;
-static gulong serial = 0;
-
-static JumpToTrackCache* cache = NULL;
-
-static void
-change_song(guint pos)
-{
-    if (playback_get_playing())
-        playback_stop();
-
-    playlist_set_position(playlist_get_active(), pos);
-    playback_initiate();
-}
-
-void
-ui_jump_to_track_hide(void)
-{
-    g_return_if_fail(jump_to_track_win != NULL);
-    gtk_widget_hide(jump_to_track_win);
-}
-
-static void
-ui_jump_to_track_jump(GtkTreeView * treeview)
-{
-    GtkTreeModel *model;
-    GtkTreeSelection *selection;
-    GtkTreeIter iter;
-    guint pos;
-
-    model = gtk_tree_view_get_model(treeview);
-    selection = gtk_tree_view_get_selection(treeview);
-
-    if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
-        return;
-
-    gtk_tree_model_get(model, &iter, 0, &pos, -1);
-
-    change_song(pos - 1);
-
-    if(cfg.close_jtf_dialog)
-        ui_jump_to_track_hide();
-}
-
-static void
-ui_jump_to_track_toggle_cb(GtkWidget * toggle)
-{
-    cfg.close_jtf_dialog =
-        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle));
-}
-
-static void
-ui_jump_to_track_toggle2_cb(GtkWidget * toggle)
-{
-    cfg.remember_jtf_entry =
-        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle));
-}
-
-static void
-ui_jump_to_track_jump_cb(GtkTreeView * treeview,
-                             gpointer data)
-{
-    ui_jump_to_track_jump(treeview);
-}
-
-static void
-ui_jump_to_track_set_queue_button_label(GtkButton * button,
-                                      guint pos)
-{
-    if (playlist_is_position_queued(playlist_get_active(), pos))
-        gtk_button_set_label(button, _("Un_queue"));
-    else
-        gtk_button_set_label(button, _("_Queue"));
-}
-
-static void
-ui_jump_to_track_queue_cb(GtkButton * button,
-                              gpointer data)
-{
-    GtkTreeView *treeview;
-    GtkTreeModel *model;
-    GtkTreeSelection *selection;
-    GtkTreeIter iter;
-    guint pos;
-
-    treeview = GTK_TREE_VIEW(data);
-    model = gtk_tree_view_get_model(treeview);
-    selection = gtk_tree_view_get_selection(treeview);
-
-    if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
-        return;
-
-    gtk_tree_model_get(model, &iter, 0, &pos, -1);
-
-    playlist_queue_position(playlist_get_active(), (pos - 1));
-
-    ui_jump_to_track_set_queue_button_label(button, (pos - 1));
-}
-
-static void
-ui_jump_to_track_selection_changed_cb(GtkTreeSelection *treesel,
-                                          gpointer data)
-{
-    GtkTreeView *treeview;
-    GtkTreeModel *model;
-    GtkTreeSelection *selection;
-    GtkTreeIter iter;
-    guint pos;
-
-    treeview = gtk_tree_selection_get_tree_view(treesel);
-    model = gtk_tree_view_get_model(treeview);
-    selection = gtk_tree_view_get_selection(treeview);
-
-    if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
-        return;
-
-    gtk_tree_model_get(model, &iter, 0, &pos, -1);
-
-    ui_jump_to_track_set_queue_button_label(GTK_BUTTON(data), (pos - 1));
-}
-
-static gboolean
-ui_jump_to_track_edit_keypress_cb(GtkWidget * object,
-                 GdkEventKey * event,
-                 gpointer data)
-{
-    switch (event->keyval) {
-    case GDK_Return:
-        if (gtk_im_context_filter_keypress (GTK_ENTRY (object)->im_context, event)) {
-            GTK_ENTRY (object)->need_im_reset = TRUE;
-            return TRUE;
-        } else {
-            ui_jump_to_track_jump(GTK_TREE_VIEW(data));
-            return TRUE;
-        }
-    default:
-        return FALSE;
-    }
-}
-
-static gboolean
-ui_jump_to_track_keypress_cb(GtkWidget * object,
-                                 GdkEventKey * event,
-                                 gpointer data)
-{
-    switch (event->keyval) {
-    case GDK_Escape:
-        ui_jump_to_track_hide();
-        return TRUE;
-    case GDK_KP_Enter:
-        ui_jump_to_track_queue_cb(NULL, data);
-        return TRUE;
-    default:
-        return FALSE;
-    };
-
-    return FALSE;
-}
-
-void
-ui_jump_to_track_update(GtkWidget * widget, gpointer user_data)
-{
-    guint row;
-    GList *playlist_glist;
-    gchar *desc_buf = NULL;
-    GtkTreeIter iter;
-    GtkTreeSelection *selection;
-    Playlist *playlist;
-
-    GtkTreeModel *store;
-
-    GtkTreeView *tree = GTK_TREE_VIEW(g_object_get_data(user_data, "treeview"));
-    GtkEntry *edit = g_object_get_data(user_data, "edit");
-
-    if (!jump_to_track_win)
-        return;
-
-    /* clear edit widget */
-    if(edit){
-        gtk_entry_set_text(edit, "");
-    }
-
-    store = gtk_tree_view_get_model(tree);
-    gtk_list_store_clear(GTK_LIST_STORE(store));
-
-    row = 1;
-    playlist = playlist_get_active();
-    for (playlist_glist = playlist->entries; playlist_glist;
-         playlist_glist = g_list_next(playlist_glist)) {
-        PlaylistEntry *entry = PLAYLIST_ENTRY(playlist_glist->data);
-
-        if (entry->title)
-            desc_buf = g_strdup(entry->title);
-        else {
-            gchar *realfn = NULL;
-            realfn = g_filename_from_uri(entry->filename, NULL, NULL);
-            if (strchr(realfn ? realfn : entry->filename, '/'))
-                desc_buf = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1);
-            else
-                desc_buf = str_assert_utf8(realfn ? realfn : entry->filename);
-            g_free(realfn); realfn = NULL;
-        }
-
-        gtk_list_store_append(GTK_LIST_STORE(store), &iter);
-        gtk_list_store_set(GTK_LIST_STORE(store), &iter,
-                           0, row, 1, desc_buf, -1);
-        row++;
-
-        g_free(desc_buf);
-        desc_buf = NULL;
-    }
-
-    gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
-    selection = gtk_tree_view_get_selection(tree);
-    gtk_tree_selection_select_iter(selection, &iter);
-    serial = playlist->serial; // important. --yaz
-}
-
-static void
-ui_jump_to_track_edit_cb(GtkEntry * entry, gpointer user_data)
-{
-    GtkTreeView *treeview = GTK_TREE_VIEW(user_data);
-    GtkTreeSelection *selection;
-    GtkTreeIter iter;
-
-    GtkListStore *store;
-
-    const GArray *search_matches;
-    Playlist *playlist;
-    int i;
-
-    if (cache == NULL) {
-        cache = ui_jump_to_track_cache_new();
-    }
-
-    /* FIXME: Remove the connected signals before clearing
-     * (row-selected will still eventually arrive once) */
-    store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
-    /* detach model from treeview */
-    g_object_ref( store );
-    gtk_tree_view_set_model( GTK_TREE_VIEW(treeview) , NULL );
-
-    gtk_list_store_clear(store);
-
-    playlist = playlist_get_active();
-
-    PLAYLIST_LOCK(playlist);
-
-    search_matches = ui_jump_to_track_cache_search(cache,
-                                                   playlist,
-                                                   gtk_entry_get_text(entry));
-
-    for (i = 0; i < search_matches->len; i++)
-    {
-        JumpToTrackEntry *jttentry = g_array_index(search_matches, JumpToTrackEntry*, i);
-        PlaylistEntry* entry = jttentry->entry;
-        gchar *title = NULL;
-
-        if (entry->title)
-            title = g_strdup(entry->title);
-        else {
-            gchar *realfn = NULL;
-            realfn = g_filename_from_uri(entry->filename, NULL, NULL);
-            if (strchr(realfn ? realfn : entry->filename, '/'))
-                title = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1);
-            else
-                title = str_assert_utf8(realfn ? realfn : entry->filename);
-            g_free(realfn); realfn = NULL;
-        }
-        gtk_list_store_append(store, &iter);
-        gtk_list_store_set(store, &iter, 0, jttentry->playlist_position + 1 , 1, title, -1);
-        g_free(title);
-    }
-
-    PLAYLIST_UNLOCK(playlist);
-
-    /* attach the model again to the treeview */
-    gtk_tree_view_set_model( GTK_TREE_VIEW(treeview) , GTK_TREE_MODEL(store) );
-    g_object_unref( store );
-
-    if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
-        selection = gtk_tree_view_get_selection(treeview);
-        gtk_tree_selection_select_iter(selection, &iter);
-    }
-}
-
-static gboolean
-ui_jump_to_track_fill(gpointer treeview)
-{
-    GList *playlist_glist;
-    Playlist *playlist;
-    gchar *desc_buf = NULL;
-    guint row;
-    GtkTreeIter iter;
-    GtkListStore *jtf_store = (GtkListStore*)gtk_tree_view_get_model( GTK_TREE_VIEW(treeview) );
-
-    /* detach model from treeview before fill */
-    g_object_ref(jtf_store);
-    gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), NULL );
-
-    gtk_list_store_clear(jtf_store);
-
-    row = 1;
-    playlist = playlist_get_active();
-
-    PLAYLIST_LOCK(playlist);
-    for (playlist_glist = playlist->entries; playlist_glist;
-         playlist_glist = g_list_next(playlist_glist)) {
-
-        PlaylistEntry *entry = PLAYLIST_ENTRY(playlist_glist->data);
-
-        if (entry->title)
-            desc_buf = g_strdup(entry->title);
-        else {
-            gchar *realfn = NULL;
-            realfn = g_filename_from_uri(entry->filename, NULL, NULL);
-            if (strchr(realfn ? realfn : entry->filename, '/'))
-                desc_buf = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1);
-            else
-                desc_buf = str_assert_utf8(realfn ? realfn : entry->filename);
-            g_free(realfn); realfn = NULL;
-        }
-
-        gtk_list_store_append(GTK_LIST_STORE(jtf_store), &iter);
-        gtk_list_store_set(GTK_LIST_STORE(jtf_store), &iter,
-                           0, row, 1, desc_buf, -1);
-        row++;
-
-        g_free(desc_buf);
-        desc_buf = NULL;
-    }
-    PLAYLIST_UNLOCK(playlist);
-
-    /* attach liststore to treeview */
-    gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(jtf_store));
-    g_object_unref(jtf_store);
-    serial = playlist->serial;
-    return FALSE;
-}
-
-static gboolean
-watchdog(gpointer storage)
-{
-    GtkWidget *widget;
-    Playlist *playlist = playlist_get_active();
-
-    if(serial == playlist->serial)
-        return TRUE;
-
-    widget = g_object_get_data(storage, "widget");
-    ui_jump_to_track_update(widget, storage);
-    return TRUE;
-}
-
-void
-ui_jump_to_track(void)
-{
-    GtkWidget *scrollwin;
-    GtkWidget *vbox, *bbox, *sep;
-    GtkWidget *toggle, *toggle2;
-    GtkWidget *jump, *queue, *close;
-    GtkWidget *rescan;
-    GtkWidget *search_label, *hbox;
-    static GtkWidget *edit;
-
-    GtkWidget *treeview = NULL;
-    GtkListStore *jtf_store;
-
-    GtkCellRenderer *renderer;
-    GtkTreeViewColumn *column;
-
-    gpointer storage;
-
-    if (jump_to_track_win) {
-        gtk_window_present(GTK_WINDOW(jump_to_track_win));
-
-        if(!cfg.remember_jtf_entry)
-            gtk_entry_set_text(GTK_ENTRY(edit), "");
-
-        gtk_widget_grab_focus(edit);
-        gtk_editable_select_region(GTK_EDITABLE(edit), 0, -1);
-        return;
-    }
-
-    #if defined(USE_REGEX_ONIGURUMA)
-    /* set encoding for Oniguruma regex to UTF-8 */
-    reg_set_encoding( REG_POSIX_ENCODING_UTF8 );
-    onig_set_default_syntax( ONIG_SYNTAX_POSIX_BASIC );
-    #endif
-
-    jump_to_track_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    gtk_window_set_type_hint(GTK_WINDOW(jump_to_track_win),
-                             GDK_WINDOW_TYPE_HINT_DIALOG);
-
-    gtk_window_set_title(GTK_WINDOW(jump_to_track_win), _("Jump to Track"));
-
-    gtk_window_set_position(GTK_WINDOW(jump_to_track_win), GTK_WIN_POS_CENTER);
-    g_signal_connect(jump_to_track_win, "destroy",
-                     G_CALLBACK(gtk_widget_destroyed), &jump_to_track_win);
-
-    gtk_container_border_width(GTK_CONTAINER(jump_to_track_win), 10);
-    gtk_window_set_default_size(GTK_WINDOW(jump_to_track_win), 600, 500);
-
-    vbox = gtk_vbox_new(FALSE, 5);
-    gtk_container_add(GTK_CONTAINER(jump_to_track_win), vbox);
-
-    jtf_store = gtk_list_store_new(2, G_TYPE_UINT, G_TYPE_STRING);
-    treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(jtf_store));
-    g_object_unref(jtf_store);
-
-    gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
-
-    column = gtk_tree_view_column_new();
-    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
-    gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
-
-    renderer = gtk_cell_renderer_text_new();
-    gtk_tree_view_column_pack_start(column, renderer, FALSE);
-    gtk_tree_view_column_set_attributes(column, renderer, "text", 0, NULL);
-    gtk_tree_view_column_set_spacing(column, 4);
-
-    renderer = gtk_cell_renderer_text_new();
-    gtk_tree_view_column_pack_start(column, renderer, FALSE);
-    gtk_tree_view_column_set_attributes(column, renderer, "text", 1, NULL);
-    gtk_tree_view_column_set_spacing(column, 4);
-    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
-
-    gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), 1);
-
-    g_signal_connect(treeview, "row-activated",
-                     G_CALLBACK(ui_jump_to_track_jump), NULL);
-
-    hbox = gtk_hbox_new(FALSE, 3);
-    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
-
-    
-    /* filter box */
-    search_label = gtk_label_new(_("Filter: "));
-    gtk_label_set_markup_with_mnemonic(GTK_LABEL(search_label), _("_Filter:"));
-    gtk_box_pack_start(GTK_BOX(hbox), search_label, FALSE, FALSE, 0);
-
-    edit = gtk_entry_new();
-    gtk_entry_set_editable(GTK_ENTRY(edit), TRUE);
-    gtk_label_set_mnemonic_widget(GTK_LABEL(search_label), edit);
-    g_signal_connect(edit, "changed",
-                     G_CALLBACK(ui_jump_to_track_edit_cb), treeview);
-
-    g_signal_connect(edit, "key_press_event",
-                     G_CALLBACK(ui_jump_to_track_edit_keypress_cb), treeview);
-
-    g_signal_connect(jump_to_track_win, "key_press_event",
-                     G_CALLBACK(ui_jump_to_track_keypress_cb), treeview);
-
-    gtk_box_pack_start(GTK_BOX(hbox), edit, TRUE, TRUE, 3);
-
-    /* remember text entry */
-    toggle2 = gtk_check_button_new_with_label(_("Remember"));
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle2),
-                                 cfg.remember_jtf_entry ? TRUE : FALSE);
-    gtk_box_pack_start(GTK_BOX(hbox), toggle2, FALSE, FALSE, 0);
-    g_signal_connect(toggle2, "clicked",
-                     G_CALLBACK(ui_jump_to_track_toggle2_cb),
-                     toggle2);
-
-    /* clear button */
-    rescan = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
-    gtk_box_pack_start(GTK_BOX(hbox), rescan, FALSE, FALSE, 0);
-
-
-    /* pack to container */
-    storage = g_object_new(G_TYPE_OBJECT, NULL);
-    g_object_set_data(storage, "widget", rescan);
-    g_object_set_data(storage, "treeview", treeview);
-    g_object_set_data(storage, "edit", edit);
-
-    g_signal_connect(rescan, "clicked",
-                     G_CALLBACK(ui_jump_to_track_update), storage);
-
-    GTK_WIDGET_SET_FLAGS(rescan, GTK_CAN_DEFAULT);
-    gtk_widget_grab_default(rescan);
-
-    scrollwin = gtk_scrolled_window_new(NULL, NULL);
-    gtk_container_add(GTK_CONTAINER(scrollwin), treeview);
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
-                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin),
-                                        GTK_SHADOW_IN);
-    gtk_box_pack_start(GTK_BOX(vbox), scrollwin, TRUE, TRUE, 0);
-
-    sep = gtk_hseparator_new();
-    gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
-
-    bbox = gtk_hbutton_box_new();
-    gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
-    gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 4);
-    gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
-
-    /* close dialog toggle */
-    toggle = gtk_check_button_new_with_label(_("Close on Jump"));
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle),
-                                 cfg.close_jtf_dialog ? TRUE : FALSE);
-    gtk_box_pack_start(GTK_BOX(bbox), toggle, FALSE, FALSE, 0);
-    g_signal_connect(toggle, "clicked", 
-                     G_CALLBACK(ui_jump_to_track_toggle_cb),
-                     toggle);
-    
-    queue = gtk_button_new_with_mnemonic(_("_Queue"));
-    gtk_button_set_image(GTK_BUTTON(queue),
-                     gtk_image_new_from_stock(AUD_STOCK_QUEUETOGGLE, GTK_ICON_SIZE_BUTTON));
-    gtk_box_pack_start(GTK_BOX(bbox), queue, FALSE, FALSE, 0);
-    GTK_WIDGET_SET_FLAGS(queue, GTK_CAN_DEFAULT);
-    g_signal_connect(queue, "clicked", 
-                     G_CALLBACK(ui_jump_to_track_queue_cb),
-                     treeview);
-    g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), "changed",
-                     G_CALLBACK(ui_jump_to_track_selection_changed_cb),
-                     queue);
-
-    jump = gtk_button_new_from_stock(GTK_STOCK_JUMP_TO);
-    gtk_box_pack_start(GTK_BOX(bbox), jump, FALSE, FALSE, 0);
-
-    g_signal_connect_swapped(jump, "clicked",
-                             G_CALLBACK(ui_jump_to_track_jump_cb),
-                             treeview);
-
-    GTK_WIDGET_SET_FLAGS(jump, GTK_CAN_DEFAULT);
-    gtk_widget_grab_default(jump);
-
-    close = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
-    gtk_box_pack_start(GTK_BOX(bbox), close, FALSE, FALSE, 0);
-    g_signal_connect_swapped(close, "clicked",
-                             G_CALLBACK(gtk_widget_hide),
-                             jump_to_track_win); // just hide --yaz
-    GTK_WIDGET_SET_FLAGS(close, GTK_CAN_DEFAULT);
-
-    g_timeout_add(100, (GSourceFunc)ui_jump_to_track_fill, treeview);
-    g_timeout_add(500, (GSourceFunc)watchdog, storage);
-
-    gtk_widget_show_all(jump_to_track_win);
-    gtk_widget_grab_focus(edit);
-}
--- a/src/audacious/legacy/ui_jumptotrack_cache.c	Tue Jul 08 15:35:48 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,431 +0,0 @@
-/*  Audacious - Cross-platform multimedia player
- *  Copyright (C) 2008 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; under version 3 of the License.
- *
- *  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, see <http://www.gnu.org/licenses>.
- *
- *  The Audacious team does not consider modular code linking to
- *  Audacious or using our public API to be a derived work.
- */
-
-#include <glib.h>
-#include <string.h>
-#include <assert.h>
-
-#if defined(USE_REGEX_ONIGURUMA)
-  #include <onigposix.h>
-#elif defined(USE_REGEX_PCRE)
-  #include <pcreposix.h>
-#else
-  #include <regex.h>
-#endif
-
-#include "playlist.h"
-#include "strings.h"
-
-#include "ui_jumptotrack_cache.h"
-
-// Struct to keep information about matches from searches.
-typedef struct
-{
-    GArray* track_entries; // JumpToTrackEntry*
-    GArray* normalized_titles; // gchar*
-} KeywordMatches;
-
-/**
- * Creates an regular expression list usable in searches from search keyword.
- *
- * In searches, every regular expression on this list is matched against
- * the search title and if they all match, the title is declared as
- * matching one.
- *
- * Regular expressions in list are formed by splitting the 'keyword' to words
- * by splitting the keyword string with space character.
- */
-static GSList*
-ui_jump_to_track_cache_regex_list_create(const GString* keyword)
-{
-    GSList *regex_list = NULL;
-    gchar **words = NULL;
-    int i = -1;
-    /* Chop the key string into ' '-separated key regex-pattern strings */
-    words = g_strsplit(keyword->str, " ", 0);
-
-    /* create a list of regex using the regex-pattern strings */
-    while ( words[++i] != NULL )
-    {
-        // Ignore empty words.
-        if (words[i][0] == 0) {
-            continue;
-        }
-        regex_t *regex = g_malloc(sizeof(regex_t));
-    #if defined(USE_REGEX_PCRE)
-        if ( regcomp( regex , words[i] , REG_NOSUB | REG_UTF8 ) == 0 )
-    #else
-        if ( regcomp( regex , words[i] , REG_NOSUB ) == 0 )
-    #endif
-            regex_list = g_slist_append( regex_list , regex );
-        else
-            g_free( regex );
-    }
-
-    g_strfreev(words);
-
-    return regex_list;
-}
-
-/**
- * Frees the regular expression list used in searches.
- */
-static void
-ui_jump_to_track_cache_regex_list_free(GSList* regex_list)
-{
-    if ( regex_list != NULL )
-    {
-        GSList* regex_list_tmp = regex_list;
-        while ( regex_list != NULL )
-        {
-            regex_t *regex = regex_list->data;
-            regfree( regex );
-            g_free( regex );
-            regex_list = g_slist_next(regex_list);
-        }
-        g_slist_free( regex_list_tmp );
-    }
-}
-
-/**
- * Checks if 'song' matches all regular expressions in 'regex_list'.
- */
-static gboolean
-ui_jump_to_track_match(const gchar * song, GSList *regex_list)
-{
-    if ( song == NULL )
-        return FALSE;
-
-    for ( ; regex_list ; regex_list = g_slist_next(regex_list) )
-    {
-        regex_t *regex = regex_list->data;
-        if ( regexec( regex , song , 0 , NULL , 0 ) != 0 )
-            return FALSE;
-    }
-
-    return TRUE;
-}
-
-/**
- * Returns all songs that match 'keyword'.
- *
- * Searches are conducted against entries in 'search_space' variable
- * and after the search, search result is added to 'cache'.
- *
- * @param cache The result of this search is added to cache.
- * @param search_space Entries inside which the search is conducted.
- * @param keyword Normalized string for searches.
- */
-static GArray*
-ui_jump_to_track_cache_match_keyword(JumpToTrackCache* cache,
-                                     const KeywordMatches* search_space,
-                                     const GString* keyword)
-{
-    GSList* regex_list = ui_jump_to_track_cache_regex_list_create(keyword);
-    GArray* track_entries = g_array_new(FALSE, FALSE, sizeof(JumpToTrackEntry*));
-    GArray* normalized_titles = g_array_new(FALSE, FALSE, sizeof(gchar*));
-    gboolean match = FALSE;
-    int i = 0;
-
-    for (i = 0; i < search_space->normalized_titles->len; i++)
-    {
-        gchar* title = g_array_index(search_space->normalized_titles, gchar*, i);
-
-        if (regex_list != NULL)
-            match = ui_jump_to_track_match(title, regex_list);
-        else
-            match = TRUE;
-
-        if (match) {
-            JumpToTrackEntry* entry = g_array_index(search_space->track_entries,
-                                                    JumpToTrackEntry*, i);
-            g_array_append_val(track_entries, entry);
-            g_array_append_val(normalized_titles, title);
-        }
-    }
-
-    KeywordMatches* keyword_matches = g_new(KeywordMatches, 1);
-    keyword_matches->track_entries = track_entries;
-    keyword_matches->normalized_titles = normalized_titles;
-
-    g_hash_table_insert(cache->keywords,
-                        GINT_TO_POINTER(g_string_hash(keyword)),
-                        keyword_matches);
-
-    ui_jump_to_track_cache_regex_list_free(regex_list);
-    return track_entries;
-}
-
-/**
- * Normalizes the search string to be more suitable for searches.
- *
- * Basically this does Unicode NFKD normalization to for example match
- * half-width and full-width characters and case folding mainly to match
- * upper- and lowercase letters.
- *
- * String returned by this function should be freed manually.
- */
-static gchar *
-normalize_search_string(const gchar* string)
-{
-    gchar* normalized_string = g_utf8_normalize(string, -1, G_NORMALIZE_NFKD);
-    gchar* folded_string = g_utf8_casefold(normalized_string, -1);
-    g_free(normalized_string);
-    return folded_string;
-}
-
-/**
- * Frees the possibly allocated data in KeywordMatches.
- */
-static void
-ui_jump_to_track_cache_free_keywordmatch_data(KeywordMatches* match_entry)
-{
-    int i = 0;
-    assert(match_entry->normalized_titles->len == match_entry->track_entries->len);
-    for (i = 0; i < match_entry->normalized_titles->len; i++)
-    {
-        g_free(g_array_index(match_entry->normalized_titles, gchar*, i));
-        g_free(g_array_index(match_entry->track_entries, PlaylistEntry*, i));
-    }
-}
-
-/**
- * Frees the memory reserved for an search result.
- */
-static void
-ui_jump_to_track_cache_free_cache_entry(gpointer entry)
-{
-    KeywordMatches* match_entry = (KeywordMatches*)entry;
-    g_array_free(match_entry->track_entries, TRUE);
-    g_array_free(match_entry->normalized_titles, TRUE);
-}
-
-/**
- * Creates a new song search cache.
- *
- * Returned value should be freed with ui_jump_to_track_cache_free() function.
- */
-JumpToTrackCache*
-ui_jump_to_track_cache_new()
-{
-    JumpToTrackCache* cache = g_new(JumpToTrackCache, 1);
-    cache->playlist_serial = -1;
-    cache->keywords = g_hash_table_new_full(NULL, NULL, NULL,
-                                            ui_jump_to_track_cache_free_cache_entry);
-    return cache;
-}
-
-/**
- * Clears the search cache.
- */
-static void
-ui_jump_to_track_cache_clear(JumpToTrackCache* cache)
-{
-    GString* empty_keyword = g_string_new("");
-    gpointer found_keyword = NULL;
-
-    cache->playlist_serial = -1;
-
-    // All normalized titles reside in an empty key "" so we'll free them
-    // first.
-    found_keyword = g_hash_table_lookup(cache->keywords,
-                                        GINT_TO_POINTER(g_string_hash(empty_keyword)));
-    g_string_free(empty_keyword,
-                  TRUE);
-    if (found_keyword != NULL)
-    {
-        KeywordMatches* all_titles = (KeywordMatches*)found_keyword;
-        ui_jump_to_track_cache_free_keywordmatch_data(all_titles);
-    }
-    // Now when all normalized strings are freed, no need to worry about
-    // double frees or memory leaks.
-    g_hash_table_remove_all(cache->keywords);
-}
-
-/**
- * Initializes the search cache if cache is empty or has wrong playlist.
- */
-static void
-ui_jump_to_track_cache_init(JumpToTrackCache* cache,
-                            const Playlist* playlist)
-{
-    if (cache->playlist_serial != playlist->serial)
-    {
-        GList* playlist_entries = NULL;
-        GArray* track_entries = g_array_new(FALSE, FALSE, sizeof(JumpToTrackEntry*));
-        GArray* normalized_titles = g_array_new(FALSE, FALSE, sizeof(gchar*));
-        GString* empty_keyword = g_string_new("");
-        gulong song_index = 0;
-
-        // Reset cache state
-        ui_jump_to_track_cache_clear(cache);
-
-        cache->playlist_serial = playlist->serial;
-
-        // Initialize cache with playlist data
-        for (playlist_entries = playlist->entries;
-             playlist_entries;
-             playlist_entries = g_list_next(playlist_entries))
-        {
-            PlaylistEntry* playlist_entry = PLAYLIST_ENTRY(playlist_entries->data);
-
-            gchar *title = NULL;
-            /*we are matching all the path not just the filename or title*/
-
-            /*
-             * FIXME: The search string should be adapted to the
-             * current display setting, e.g. if the user has set it to
-             * "%p - %t" then build the match string like that too, or
-             * even better, search for each of the tags seperatly.
-             *
-             * In any case the string to match should _never_ contain
-             * something the user can't actually see in the playlist.
-             */
-            if (playlist_entry->title) {
-                title = normalize_search_string(playlist_entry->title);
-            } else {
-                gchar *realfn = NULL;
-                realfn = g_filename_from_uri(playlist_entry->filename, NULL, NULL);
-                gchar *tmp_title = str_assert_utf8(realfn ? realfn : playlist_entry->filename);
-                title = normalize_search_string(tmp_title);
-                g_free(tmp_title);
-                g_free(realfn); realfn = NULL;
-            }
-
-            JumpToTrackEntry* search_entry = g_new(JumpToTrackEntry, 1);
-            search_entry->entry = playlist_entry;
-            search_entry->playlist_position = song_index;
-            g_array_append_val(track_entries, search_entry);
-            g_array_append_val(normalized_titles, title);
-            // We need to manually keep track of the current playlist index.
-            song_index++;
-        }
-        // Finally insert all titles into cache into an empty key "" so that
-        // the matchable data has specified place to be.
-        KeywordMatches* keyword_data = g_new(KeywordMatches, 1);
-        keyword_data->track_entries = track_entries;
-        keyword_data->normalized_titles = normalized_titles;
-        g_hash_table_insert(cache->keywords,
-                            GINT_TO_POINTER(g_string_hash(empty_keyword)),
-                            keyword_data);
-        g_string_free(empty_keyword,
-                      TRUE);
-    }
-}
-
-/**
- * Searches 'keyword' inside 'playlist' by using 'cache' to speed up searching.
- *
- * Searches are basically conducted as follows:
- *
- * Cache is checked if it has the information about right playlist and
- * initialized with playlist data if needed.
- *
- * Keyword is normalized for searching (Unicode NFKD, case folding)
- *
- * Cache is checked if it has keyword and if it has, we can immediately get
- * the search results and return. If not, searching goes as follows:
- *
- * Search for the longest word that is in cache that matches the beginning
- * of keyword and use the cached matches as base for the current search.
- * The shortest word that can be matched against is the empty string "", so
- * there should always be matches in cache.
- *
- * After that conduct the search by splitting keyword into words separated
- * by space and using regular expressions.
- *
- * When the keyword is searched, search result is added to cache to
- * corresponding keyword that can be used as base for new searches.
- *
- * The motivation for caching is that to search word 'some cool song' one
- * has to type following strings that are all searched individually:
- *
- * s
- * so
- * som
- * some
- * some
- * some c
- * some co
- * some coo
- * some cool
- * some cool
- * some cool s
- * some cool so
- * some cool son
- * some cool song
- *
- * If the search results are cached in every phase and the result of
- * the maximum length matching string is used as base for concurrent
- * searches, we can probably get the matches reduced to some hundreds
- * after a few letters typed on playlists with thousands of songs and
- * reduce useless iteration quite a lot.
- *
- * Return: GArray of JumpToTrackEntry*
- */
-const GArray*
-ui_jump_to_track_cache_search(JumpToTrackCache* cache,
-                              const Playlist* playlist,
-                              const gchar* keyword)
-{
-    gchar* normalized_keyword = normalize_search_string(keyword);
-    GString* keyword_string = g_string_new(normalized_keyword);
-    GString* match_string = g_string_new(normalized_keyword);
-    gsize match_string_length = keyword_string->len;
-
-    ui_jump_to_track_cache_init(cache, playlist);
-
-    while (match_string_length >= 0)
-    {
-        gpointer string_ptr =  GINT_TO_POINTER(g_string_hash(match_string));
-        gpointer result_entries = g_hash_table_lookup(cache->keywords,
-                                                      string_ptr);
-        if (result_entries != NULL)
-        {
-            KeywordMatches* matched_entries = (KeywordMatches*)result_entries;
-            // if keyword matches something we have, we'll just return the list
-            // of matches that the keyword has.
-            if (match_string_length == keyword_string->len) {
-                g_string_free(keyword_string, TRUE);
-                g_string_free(match_string, TRUE);
-                g_free(normalized_keyword);
-                return matched_entries->track_entries;
-            }
-
-            // Do normal search by using the result of previous search
-            // as search space.
-            GArray* result = ui_jump_to_track_cache_match_keyword(cache,
-                                                                  matched_entries,
-                                                                  keyword_string);
-            g_string_free(keyword_string, TRUE);
-            g_string_free(match_string, TRUE);
-            g_free(normalized_keyword);
-            return result;
-        }
-        match_string_length--;
-        g_string_set_size(match_string, match_string_length);
-    }
-    // This should never, ever get to this point because there is _always_
-    // the empty string to match against.
-    AUDDBG("One should never get to this point. Something is really wrong with \
-cache->keywords hash table.");
-    assert(FALSE);
-    g_return_val_if_fail(FALSE, (GArray*)-1);
-}
-
--- a/src/audacious/legacy/ui_jumptotrack_cache.h	Tue Jul 08 15:35:48 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*  Audacious - Cross-platform multimedia player
- *  Copyright (C) 2008  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; under version 3 of the License.
- *
- *  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, see <http://www.gnu.org/licenses>.
- *
- *  The Audacious team does not consider modular code linking to
- *  Audacious or using our public API to be a derived work.
- */
-
-#ifndef AUDACIOUS_UI_JUMPTOTRACK_CACHE_H
-#define AUDACIOUS_UI_JUMPTOTRACK_CACHE_H
-
-#include <glib.h>
-
-#include "playlist.h"
-
-typedef struct _JumpToTrackCache JumpToTrackCache;
-typedef struct _JumpToTrackEntry JumpToTrackEntry;
-
-struct _JumpToTrackCache
-{
-    gulong playlist_serial;
-    GHashTable* keywords;
-};
-
-struct _JumpToTrackEntry
-{
-    PlaylistEntry* entry;
-    // We need to manually keep information about current playlist position.
-    gulong playlist_position;
-};
-
-extern JumpToTrackCache* ui_jump_to_track_cache_new(void);
-extern const GArray* ui_jump_to_track_cache_search(JumpToTrackCache* cache, const Playlist* playlist, const gchar* keyword);
-extern void ui_jump_to_track_cache_free(JumpToTrackCache* cache);
-
-#endif /* AUDACIOUS_UI_JUMPTOTRACK_CACHE_H */
--- a/src/audacious/legacy/ui_urlopener.c	Tue Jul 08 15:35:48 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-/*  Audacious - Cross-platform multimedia player
- *  Copyright (C) 2005-2007  Audacious development team
- *
- *  Based on BMP:
- *  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; under version 3 of the License.
- *
- *  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, see <http://www.gnu.org/licenses>.
- *
- *  The Audacious team does not consider modular code linking to
- *  Audacious or using our public API to be a derived work.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#define NEED_GLADE
-#include "util.h"
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <gtk/gtk.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "platform/smartinclude.h"
-#include <errno.h>
-
-#include "input.h"
-#include "main.h"
-#include "playback.h"
-#include "strings.h"
-#include "ui_playlist.h"
-
-#ifdef USE_CHARDET
-#include "../libguess/libguess.h"
-#  ifdef HAVE_UDET
-#    include <libudet_c.h>
-#  endif
-#endif
-
-#define URL_HISTORY_MAX_SIZE 30
-
-static void
-util_add_url_callback(GtkWidget * widget,
-                      GtkEntry * entry)
-{
-    const gchar *text;
-
-    text = gtk_entry_get_text(entry);
-    if (g_list_find_custom(cfg.url_history, text, (GCompareFunc) strcasecmp))
-        return;
-
-    cfg.url_history = g_list_prepend(cfg.url_history, g_strdup(text));
-
-    while (g_list_length(cfg.url_history) > URL_HISTORY_MAX_SIZE) {
-        GList *node = g_list_last(cfg.url_history);
-        g_free(node->data);
-        cfg.url_history = g_list_delete_link(cfg.url_history, node);
-    }
-}
-
-GtkWidget *
-util_add_url_dialog_new(const gchar * caption, GCallback ok_func,
-                        GCallback enqueue_func)
-{
-    GtkWidget *win, *vbox, *bbox, *cancel, *enqueue, *ok, *combo, *entry, 
-              *label;
-    GList *url;
-
-    win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    gtk_window_set_title(GTK_WINDOW(win), _("Add/Open URL Dialog"));
-    gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DIALOG);
-    gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);
-    gtk_window_set_default_size(GTK_WINDOW(win), 400, -1);
-    gtk_container_set_border_width(GTK_CONTAINER(win), 12);
-
-    vbox = gtk_vbox_new(FALSE, 10);
-    gtk_container_add(GTK_CONTAINER(win), vbox);
-
-    label = gtk_label_new(caption);
-    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
-    combo = gtk_combo_box_entry_new_text();
-    gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0);
-
-    entry = gtk_bin_get_child(GTK_BIN(combo));
-    gtk_window_set_focus(GTK_WINDOW(win), entry);
-    gtk_entry_set_text(GTK_ENTRY(entry), "");
-
-    for (url = cfg.url_history; url; url = g_list_next(url))
-        gtk_combo_box_append_text(GTK_COMBO_BOX(combo),
-                                  (const gchar *) url->data);
-
-    g_signal_connect(entry, "activate",
-                     G_CALLBACK(util_add_url_callback),
-                     entry);
-    g_signal_connect(entry, "activate",
-                     G_CALLBACK(ok_func),
-                     entry);
-    g_signal_connect_swapped(entry, "activate",
-                             G_CALLBACK(gtk_widget_destroy),
-                             win);
-
-    bbox = gtk_hbutton_box_new();
-    gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
-    gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
-    gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
-
-    cancel = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
-    gtk_box_pack_start(GTK_BOX(bbox), cancel, FALSE, FALSE, 0);
-    gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(bbox), cancel, TRUE);
-
-    g_signal_connect_swapped(cancel, "clicked",
-                             G_CALLBACK(gtk_widget_destroy),
-                             win);
-
-    enqueue = gtk_button_new_from_stock(GTK_STOCK_ADD);
-    gtk_box_pack_start(GTK_BOX(bbox), enqueue, FALSE, FALSE, 0);
-
-    g_signal_connect(enqueue, "clicked",
-                     G_CALLBACK(util_add_url_callback),
-                     entry);
-    g_signal_connect(enqueue, "clicked",
-                     G_CALLBACK(enqueue_func),
-                     entry);
-    g_signal_connect_swapped(enqueue, "clicked",
-                             G_CALLBACK(gtk_widget_destroy),
-                             win);
-
-    ok = gtk_button_new_from_stock(GTK_STOCK_OPEN);
-    g_signal_connect(ok, "clicked",
-                     G_CALLBACK(util_add_url_callback), entry);
-    g_signal_connect(ok, "clicked",
-                     G_CALLBACK(ok_func), entry);
-    g_signal_connect_swapped(ok, "clicked",
-                             G_CALLBACK(gtk_widget_destroy),
-                             win);
-    gtk_box_pack_start(GTK_BOX(bbox), ok, FALSE, FALSE, 0);
-
-    gtk_widget_show_all(vbox);
-
-    return win;
-}
--- a/src/audacious/legacy/ui_urlopener.h	Tue Jul 08 15:35:48 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*  Audacious - Cross-platform multimedia player
- *  Copyright (C) 2005-2007  Audacious development team
- *
- *  Based on BMP:
- *  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; under version 3 of the License.
- *
- *  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, see <http://www.gnu.org/licenses>.
- *
- *  The Audacious team does not consider modular code linking to
- *  Audacious or using our public API to be a derived work.
- */
-
-#ifndef AUDACIOUS_UI_URLOPENER_H
-#define AUDACIOUS_UI_URLOPENER_H
-
-#ifdef _AUDACIOUS_CORE
-# ifdef HAVE_CONFIG_H
-#  include "config.h"
-# endif
-#endif
-
-#include <glib.h>
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-GtkWidget *util_add_url_dialog_new(const gchar * caption, GCallback ok_func,
-                                   GCallback enqueue_func);
-
-G_END_DECLS
-
-#endif /* AUDACIOUS_UI_URLOPENER_H */
--- a/src/audacious/pluginenum.c	Tue Jul 08 15:35:48 2008 +0200
+++ b/src/audacious/pluginenum.c	Tue Jul 08 16:36:50 2008 +0200
@@ -56,7 +56,7 @@
 #include "volumecontrol.h"
 #include "equalizer_preset.h"
 
-#include "legacy/ui_fileinfo.h"
+#include "ui_fileinfo.h"
 #include "ui_fileinfopopup.h"
 #include "ui_plugin_menu.h"
 #include "ui_preferences.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/ui_about.c	Tue Jul 08 16:36:50 2008 +0200
@@ -0,0 +1,212 @@
+/*
+ *  Audacious - Cross-platform multimedia player
+ *  Copyright (C) 2005-2007  Audacious development team
+ *
+ *  Based on BMP:
+ *  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; under version 3 of the License.
+ *
+ *  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, see <http://www.gnu.org/licenses>.
+ *
+ *  The Audacious team does not consider modular code linking to
+ *  Audacious or using our public API to be a derived work.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "ui_credits.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "platform/smartinclude.h"
+
+static GtkWidget *about_window = NULL;
+static GdkPixbuf *about_pixbuf = NULL;
+static GdkPixmap *mask_pixmap_window1 = NULL,
+        *mask_pixmap_window2 = NULL;
+static GdkBitmap *mask_bitmap_window1 = NULL,
+        *mask_bitmap_window2 = NULL;
+
+static const gchar *audacious_brief = N_("<big><b>Audacious %s</b></big>\n\n"
+			"Copyright (C) 2005-2008 Audacious Development Team");
+    
+static gboolean
+on_about_window_expose(GtkWidget *widget, GdkEventExpose *expose, gpointer data)
+{
+	g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE);
+
+	gdk_window_set_back_pixmap(GDK_WINDOW(widget->window), mask_pixmap_window2, 0);
+	gdk_window_clear(GDK_WINDOW(widget->window));
+
+	return FALSE;
+}
+
+static gboolean
+on_about_window_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+	g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE);
+
+	if (event->keyval == GDK_Escape)
+	{      
+		gtk_widget_hide(widget);
+	}
+
+	return FALSE;
+}
+
+static gboolean
+on_close_button_clicked (GtkWidget *widget, gpointer data)
+{
+	g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE);
+
+	gtk_widget_hide(about_window);
+
+	return FALSE;
+}
+
+static gboolean
+on_credits_button_clicked (GtkWidget *widget, gpointer data)
+{
+	g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE);
+
+	show_credits_window();
+
+	return FALSE;
+}
+
+void
+show_about_window(void)
+{
+    GtkWidget *about_fixedbox;
+    GtkWidget *close_button;
+    GtkWidget *credits_button , *credits_button_hbox, *credits_button_image, *credits_button_label;
+    GtkWidget *brief_label;
+    gchar *filename = DATA_DIR G_DIR_SEPARATOR_S "images" G_DIR_SEPARATOR_S "about-logo.png";
+    gchar *text;
+    PangoAttrList *brief_label_attrs;
+    PangoAttribute *brief_label_foreground;
+
+    if (about_window != NULL)
+    {
+        gtk_window_present(GTK_WINDOW(about_window));
+        return;
+    }
+
+    about_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+    g_signal_connect(about_window, "destroy",
+                     G_CALLBACK(gtk_widget_destroyed), &about_window);
+
+    gtk_widget_realize(about_window);
+
+    about_pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
+
+    gtk_widget_set_size_request(GTK_WIDGET (about_window),
+                   gdk_pixbuf_get_width (about_pixbuf),
+                   gdk_pixbuf_get_height (about_pixbuf));
+
+    gtk_widget_set_app_paintable(about_window, TRUE);
+    gtk_window_set_title(GTK_WINDOW(about_window), _("About Audacious"));
+    gtk_window_set_position(GTK_WINDOW(about_window), GTK_WIN_POS_CENTER);
+    gtk_window_set_resizable(GTK_WINDOW(about_window), FALSE);
+    gtk_window_set_decorated(GTK_WINDOW(about_window), FALSE);
+
+    gdk_pixbuf_render_pixmap_and_mask(about_pixbuf,
+                     &mask_pixmap_window1,
+                     &mask_bitmap_window1,
+                     0);
+
+    gdk_pixbuf_render_pixmap_and_mask(about_pixbuf,
+                     &mask_pixmap_window2,
+                     &mask_bitmap_window2,
+                     128);
+
+    gtk_widget_add_events(about_window, GDK_ALL_EVENTS_MASK);
+
+    g_signal_connect(about_window, "expose-event",
+	G_CALLBACK(on_about_window_expose), &about_window);
+
+    g_signal_connect(about_window, "key-press-event",
+	G_CALLBACK(on_about_window_key_press), &about_window);
+
+    gtk_widget_shape_combine_mask(GTK_WIDGET(about_window), mask_bitmap_window2, 0, 0);
+
+    /* GtkFixed hasn't got its GdkWindow, this means that it can be used to
+       display widgets while the logo below will be displayed anyway;
+       however fixed positions are not that great, cause the button sizes may (will)
+       vary depending on the gtk style used, so it's not possible to center
+       them unless a fixed width and heigth is forced (and this may bring to cutted
+       text if someone, i.e., uses a big font for gtk widgets);
+       other types of container most likely have their GdkWindow, this simply
+       means that the logo must be drawn on the container widget, instead of the
+       window; otherwise, it won't be displayed correctly */
+    about_fixedbox = gtk_fixed_new();
+    gtk_container_add( GTK_CONTAINER(about_window) , about_fixedbox );
+
+    close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+
+    g_signal_connect(close_button, "clicked",
+	G_CALLBACK(on_close_button_clicked), NULL);
+
+    gtk_fixed_put( GTK_FIXED(about_fixedbox) , close_button , 375 , 220 );
+    gtk_widget_set_size_request( close_button , 100 , -1 );
+
+    credits_button = gtk_button_new();
+    credits_button_hbox = gtk_hbox_new( FALSE , 0 );
+    credits_button_image = gtk_image_new_from_stock( GTK_STOCK_DIALOG_INFO , GTK_ICON_SIZE_BUTTON );
+    gtk_misc_set_alignment( GTK_MISC(credits_button_image) , 1 , 0.5 );
+    credits_button_label = gtk_label_new( _("Credits") );
+    gtk_misc_set_alignment( GTK_MISC(credits_button_label) , 0 , 0.5 );
+    gtk_box_pack_start( GTK_BOX(credits_button_hbox) , credits_button_image ,
+                        TRUE , TRUE , 2 );
+    gtk_box_pack_start( GTK_BOX(credits_button_hbox) , credits_button_label ,
+                        TRUE , TRUE , 2 );
+    gtk_container_add( GTK_CONTAINER(credits_button) , credits_button_hbox );
+
+    g_signal_connect(credits_button, "clicked",
+	G_CALLBACK(on_credits_button_clicked), NULL);
+
+    gtk_fixed_put( GTK_FIXED(about_fixedbox) , credits_button , 25 , 220 );
+    gtk_widget_set_size_request( credits_button , 100 , -1 );
+
+    brief_label = gtk_label_new(NULL);
+    text = g_strdup_printf(_(audacious_brief), VERSION);
+
+    brief_label_foreground = pango_attr_foreground_new(0, 0, 0);
+    brief_label_attrs = pango_attr_list_new();
+    pango_attr_list_insert(brief_label_attrs, brief_label_foreground);
+
+    gtk_label_set_markup(GTK_LABEL(brief_label), text);
+    gtk_label_set_justify(GTK_LABEL(brief_label), GTK_JUSTIFY_CENTER);
+    gtk_label_set_attributes(GTK_LABEL(brief_label), brief_label_attrs);
+    g_free(text);
+
+    gtk_fixed_put(GTK_FIXED(about_fixedbox), brief_label, 20, 145);
+    gtk_widget_set_size_request( brief_label , 460 , -1 );
+
+    gtk_widget_show_all(about_window);
+    gtk_window_present(GTK_WINDOW(about_window));
+}
+
+void
+hide_about_window(void)
+{
+    g_return_if_fail(about_window);
+    gtk_widget_hide(GTK_WIDGET(about_window));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/ui_albumart.c	Tue Jul 08 16:36:50 2008 +0200
@@ -0,0 +1,194 @@
+/*
+ * Audacious: A cross-platform multimedia player
+ * Copyright (c) 2007 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; under version 3 of the License.
+ *
+ * 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, see <http://www.gnu.org/licenses>.
+ *
+ * The Audacious team does not consider modular code linking to
+ * Audacious or using our public API to be a derived work.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+#include "ui_fileinfopopup.h"
+#include "main.h"
+#include "playlist.h"
+#include "playback.h"
+
+static gboolean
+has_front_cover_extension(const gchar *name)
+{
+	char *ext;
+
+	ext = strrchr(name, '.');
+	if (!ext) {
+		/* No file extension */
+		return FALSE;
+	}
+
+	return g_strcasecmp(ext, ".jpg") == 0 ||
+	       g_strcasecmp(ext, ".jpeg") == 0 ||
+	       g_strcasecmp(ext, ".png") == 0;
+}
+
+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 *imgfile)
+{
+	return cover_name_filter(imgfile, cfg.cover_name_include, TRUE) &&
+	       !cover_name_filter(imgfile, cfg.cover_name_exclude, FALSE);
+}
+
+static gboolean
+is_file_image(const gchar *imgfile, const gchar *file_name)
+{
+	char *imgfile_ext, *file_name_ext;
+	size_t imgfile_len, file_name_len;
+
+	imgfile_ext = strrchr(imgfile, '.');
+	if (!imgfile_ext) {
+		/* No file extension */
+		return FALSE;
+	}
+
+	file_name_ext = strrchr(file_name, '.');
+	if (!file_name_ext) {
+		/* No file extension */
+		return FALSE;
+	}
+
+	imgfile_len = (imgfile_ext - imgfile);
+	file_name_len = (file_name_ext - file_name);
+
+	if (imgfile_len == file_name_len) {
+		return (g_ascii_strncasecmp(imgfile, file_name, imgfile_len) == 0);
+	} else {
+		return FALSE;
+	}
+}
+
+gchar*
+fileinfo_recursive_get_image(const gchar* path,
+	const gchar* file_name, 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;
+
+		if (cfg.use_file_cover && file_name) {
+			/* Look for images matching file name */
+			while((f = g_dir_read_name(d))) { 
+				gchar *newpath = g_strconcat(path, "/", f, NULL);
+
+				if (!g_file_test(newpath, G_FILE_TEST_IS_DIR) &&
+				    has_front_cover_extension(f) &&
+				    is_file_image(f, file_name)) {
+					g_dir_close(d);
+					return newpath;
+				}
+
+				g_free(newpath);
+			}
+			g_dir_rewind(d);
+		}
+		
+		/* Search for files using filter */
+		while ((f = g_dir_read_name(d))) {
+			gchar *newpath = g_strconcat(path, "/", f, NULL);
+
+			if (!g_file_test(newpath, G_FILE_TEST_IS_DIR) &&
+			    has_front_cover_extension(f) &&
+			    is_front_cover_image(f)) {
+				g_dir_close(d);
+				return newpath;
+			}
+
+			g_free(newpath);
+		}
+		g_dir_rewind(d);
+
+		/* checks whether recursive or not. */
+		if (!cfg.recurse_for_cover) {
+			g_dir_close(d);
+			return NULL;
+		}
+
+		/* Descend into directories recursively. */
+		while ((f = g_dir_read_name(d))) {
+			gchar *newpath = g_strconcat(path, "/", f, NULL);
+			
+			if(g_file_test(newpath, G_FILE_TEST_IS_DIR)) {
+				gchar *tmp = fileinfo_recursive_get_image(newpath,
+					NULL, depth + 1);
+				if(tmp) {
+					g_free(newpath);
+					g_dir_close(d);
+					return tmp;
+				}
+			}
+
+			g_free(newpath);
+		}
+
+		g_dir_close(d);
+	}
+
+	return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/ui_credits.c	Tue Jul 08 16:36:50 2008 +0200
@@ -0,0 +1,434 @@
+/*  Audacious - Cross-platform multimedia player
+ *  Copyright (C) 2005-2007  Audacious Team
+ *
+ *  Based on BMP:
+ *  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; under version 3 of the License.
+ *
+ *  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, see <http://www.gnu.org/licenses>.
+ *
+ *  The Audacious team does not consider modular code linking to
+ *  Audacious or using our public API to be a derived work.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "ui_credits.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "audacious_logo.xpm"
+
+
+enum {
+    COL_LEFT,
+    COL_RIGHT,
+    N_COLS
+};
+
+
+static const gchar *audacious_brief =
+    N_("<big><b>Audacious %s</b></big>\n"
+       "A skinned multimedia player for many platforms.\n"
+       "\n"
+       "Copyright (C) 2005-2008 Audacious Development Team\n");
+
+static const gchar *credit_text[] = {
+    N_("Audacious core developers:"),
+    "George Averill",
+    "Daniel Barkalow",
+    "Christian Birchinger",
+    "Daniel Bradshaw",
+    "Adam Cecile",
+    "Michael Färber",
+    "Matti Hämäläinen",
+    "Troels Bang Jensen",
+    "Giacomo Lozito",
+    "Cristi Măgherușan",
+    "Tomasz Moń",
+    "William Pitcock",
+    "Derek Pomery",
+    "Jonathan Schleifer",
+    "Ben Tucker",
+    "Tony Vroon",
+    "Yoshiki Yazawa",
+    "Eugene Zagidullin",
+    NULL,
+
+    N_("Graphics:"),
+    "George Averill",
+    "Stephan Sokolow",
+    NULL,
+
+    N_("Default skin:"),
+    "George Averill",
+    "Michael Färber",
+    "William Pitcock",
+    NULL,
+
+    N_("Plugin development:"),
+    "Kiyoshi Aman",
+    "Luca Barbato",
+    "Daniel Barkalow",
+    "Michael Färber",
+    "Shay Green",
+    "Matti Hämäläinen",
+    "Sascha Hlusiak",
+    "Giacomo Lozito",
+    "Cristi Măgherușan",
+    "Tomasz Moń",
+    "William Pitcock",
+    "Derek Pomery",
+    "Jonathan Schleifer",
+    "Tony Vroon",
+    "Yoshiki Yazawa",
+    NULL,
+
+    N_("Patch authors:"),
+    "Massimo Cavalleri",
+    "Stefano D'Angelo",
+    "Laszlo Dvornik",
+    "Ralf Ertzinger",
+    "Mike Frysinger",
+    "Mark Glines",
+    "Teru KAMOGASHIRA",
+    "Chris Kehler",
+    "Alex Maclean",
+    "Michael Hanselmann",
+    "Joseph Jezak",
+    "Henrik Johansson",
+    "Rodrigo Martins de Matos Ventura",
+    "Diego Pettenò",
+    "Kazuki Shimura",
+    "Valentine Sinitsyn",
+    "Johan Tavelin",
+    "Tim Yamin",
+    "Ivan N. Zlatev",
+    NULL,
+
+    N_("0.1.x developers:"),
+    "William Pitcock",
+    "Mohammed Sameer",
+    "Tony Vroon",
+    NULL,
+
+    N_("BMP Developers:"),
+    "Artem Baguinski",
+    "Edward Brocklesby",
+    "Chong Kai Xiong",
+    "Milosz Derezynski",
+    "David Lau",
+    "Ole Andre Vadla Ravnaas",
+    "Michiel Sikkes",
+    "Andrei Badea",
+    "Peter Behroozi",
+    "Bernard Blackham",
+    "Oliver Blin",
+    "Tomas Bzatek",
+    "Liviu Danicel",
+    "Jon Dowland",
+    "Artur Frysiak",
+    "Sebastian Kapfer",
+    "Lukas Koberstein",
+    "Dan Korostelev",
+    "Jolan Luff",
+    "Michael Marineau",
+    "Tim-Philipp Muller",
+    "Julien Portalier",
+    "Andrew Ruder",
+    "Olivier Samyn",
+    "Martijn Vernooij",
+    NULL,
+
+    NULL
+};
+
+static const gchar *translators[] = {
+    N_("Brazilian Portuguese:"),
+    "Fábio Antunes",
+    "Philipi Pinto",
+    NULL,
+    N_("Breton:"),
+    "Thierry Vignaud",
+    NULL,
+    N_("Bulgarian:"),
+    "Andrew Ivanov",
+    NULL,
+    N_("Catalan:"),
+    "Ernest Adrogu",
+    NULL,
+    N_("Croatian:"),
+    "Marin Glibic",
+    NULL,
+    N_("Czech:"),
+    "Petr Pisar",
+    NULL,
+    N_("Dutch:"),
+    "Laurens Buhler",
+    "Tony Vroon",
+    NULL,
+    N_("Estonian:"),
+    "Ivar Smolin",
+    NULL,
+    N_("Finnish:"),
+    "Pauli Virtanen",
+    "Matti Hämäläinen",
+    NULL,
+    N_("French:"),
+    "Adam Cecile",
+    "Stanislas Zeller",
+    "Stany Henry",
+    NULL,
+    N_("German:"),
+    "Michael Färber",
+    "Michael Hanselmann",
+    "Matthias Debus",
+    NULL,
+    N_("Georgian:"),
+    "George Machitidze",
+    NULL,
+    N_("Greek:"),
+    "Kouzinopoulos Haris",
+    "Stavros Giannouris",
+    "Stathis Kamperis",
+    NULL,
+    N_("Hindi:"),
+    "Dhananjaya Sharma",
+    NULL,
+    N_("Hungarian:"),
+    "Laszlo Dvornik",
+    NULL,
+    N_("Italian:"),
+    "Alessio D'Ascanio",
+    "Diego Pettenò",
+    NULL,
+    N_("Japanese:"),
+    "Dai",
+    NULL,
+    N_("Korean:"),
+    "DongCheon Park",
+    NULL,
+    N_("Lithuanian:"),
+    "Rimas Kudelis",
+    NULL,
+    N_("Macedonian:"),
+    "Arangel Angov",
+    NULL,
+    N_("Polish:"),
+    "Wojciech Myrda",
+    NULL,
+    N_("Romanian:"),
+    "Daniel Patriche",
+    "Cristi Măgherușan",
+    NULL,
+    N_("Russian:"),
+    "Alexandr Orlov",
+    NULL,
+    N_("Serbian (Latin):"),
+    "Strahinja Kustudić",
+    NULL,
+    N_("Serbian (Cyrillic):"),
+    "Strahinja Kustudić",
+    NULL,
+    N_("Simplified Chinese:"),
+    "Yang Zhang",
+    NULL,
+    N_("Slovak:"),
+    "Andrej Herceg",
+    NULL,
+    N_("Spanish:"),
+    "Gustavo D. Vranjes",
+    NULL,
+    N_("Swedish:"),
+    "Martin Persenius",
+    NULL,
+    N_("Traditional Chinese:"),
+    "Cheng-Wei Chien",
+    "Sylecn Song",
+    "Yang Zhang",
+    NULL,
+    N_("Turkish:"),
+    "Murat Şenel",
+    "Eren Turkay",
+    NULL,
+    N_("Ukrainian:"),
+    "Mykola Lynnyk",
+    NULL,
+    N_("Welsh:"),
+    "Edward Brocklesby",
+    "William Pitcock",
+    NULL,
+
+    NULL
+};
+
+
+static GtkWidget *
+generate_credit_list(const gchar * text[], gboolean sec_space)
+{
+    GtkWidget *scrollwin;
+    GtkWidget *treeview;
+    GtkListStore *list_store;
+    GtkTreeIter iter;
+    GtkTreeViewColumn *column;
+    GtkCellRenderer *renderer;
+    const gchar *const *item;
+
+    list_store = gtk_list_store_new(N_COLS, G_TYPE_STRING, G_TYPE_STRING);
+
+    item = text;
+
+    while (*item) {
+        gtk_list_store_append(list_store, &iter);
+        gtk_list_store_set(list_store, &iter,
+                           COL_LEFT, _(item[0]), COL_RIGHT, _(item[1]), -1);
+        item += 2;
+
+        while (*item) {
+            gtk_list_store_append(list_store, &iter);
+            gtk_list_store_set(list_store, &iter,
+                               COL_LEFT, "", COL_RIGHT, _(*item++), -1);
+        }
+
+        ++item;
+
+        if (*item && sec_space) {
+            gtk_list_store_append(list_store, &iter);
+            gtk_list_store_set(list_store, &iter,
+                               COL_LEFT, "", COL_RIGHT, "", -1);
+        }
+    }
+
+    treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store));
+    gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(treeview), FALSE);
+    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
+    gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
+        GTK_SELECTION_NONE);
+
+    renderer = gtk_cell_renderer_text_new();
+    g_object_set(renderer, "xalign", 1.0, NULL);
+    column = gtk_tree_view_column_new_with_attributes("Left", renderer,
+                                                      "text", COL_LEFT, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+    renderer = gtk_cell_renderer_text_new();
+    g_object_set(renderer, "xalign", 0.0, NULL);
+    column = gtk_tree_view_column_new_with_attributes("Right", renderer,
+                                                      "text", COL_RIGHT,
+                                                      NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+    scrollwin = gtk_scrolled_window_new(NULL, NULL);
+    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
+                                   GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
+    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin), GTK_SHADOW_IN);
+    gtk_container_add(GTK_CONTAINER(scrollwin), treeview);
+    gtk_container_set_border_width(GTK_CONTAINER(scrollwin), 10);
+
+    gtk_widget_show_all(scrollwin);
+
+    return scrollwin;
+}
+
+void
+show_credits_window(void)
+{
+    static GtkWidget *about_window = NULL;
+
+    GdkPixbuf *logo_pixbuf;
+    GtkWidget *about_vbox;
+    GtkWidget *about_credits_logo_box, *about_credits_logo_frame;
+    GtkWidget *about_credits_logo;
+    GtkWidget *about_notebook;
+    GtkWidget *list;
+    GtkWidget *bbox, *close_btn;
+    GtkWidget *label;
+    gchar *text;
+
+    if (about_window)
+        return;
+
+    about_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_type_hint(GTK_WINDOW(about_window),
+                             GDK_WINDOW_TYPE_HINT_DIALOG);
+
+    gtk_window_set_default_size(GTK_WINDOW(about_window), -1, 512);
+    gtk_window_set_title(GTK_WINDOW(about_window), _("About Audacious"));
+    gtk_window_set_position(GTK_WINDOW(about_window), GTK_WIN_POS_CENTER);
+    gtk_window_set_resizable(GTK_WINDOW(about_window), TRUE);
+    gtk_container_set_border_width(GTK_CONTAINER(about_window), 10);
+
+    g_signal_connect(about_window, "destroy",
+                     G_CALLBACK(gtk_widget_destroyed), &about_window);
+
+    gtk_widget_realize(about_window);
+
+    about_vbox = gtk_vbox_new(FALSE, 5);
+    gtk_container_add(GTK_CONTAINER(about_window), about_vbox);
+
+    logo_pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)audacious_logo_xpm);
+
+    about_credits_logo_box = gtk_hbox_new(TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(about_vbox), about_credits_logo_box,
+                       FALSE, FALSE, 0);
+
+    about_credits_logo_frame = gtk_frame_new(NULL);
+    gtk_frame_set_shadow_type(GTK_FRAME(about_credits_logo_frame),
+                              GTK_SHADOW_ETCHED_OUT);
+    gtk_box_pack_start(GTK_BOX(about_credits_logo_box),
+                       about_credits_logo_frame, FALSE, FALSE, 0);
+
+    about_credits_logo = gtk_image_new_from_pixbuf(logo_pixbuf);
+    gtk_container_add(GTK_CONTAINER(about_credits_logo_frame),
+                      about_credits_logo);
+    g_object_unref(logo_pixbuf);
+
+    label = gtk_label_new(NULL);
+    text = g_strdup_printf(_(audacious_brief), VERSION);
+    gtk_label_set_markup(GTK_LABEL(label), text);
+    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
+    g_free(text);
+
+    gtk_box_pack_start(GTK_BOX(about_vbox), label, FALSE, FALSE, 0);
+
+    about_notebook = gtk_notebook_new();
+    gtk_box_pack_start(GTK_BOX(about_vbox), about_notebook, TRUE, TRUE, 0);
+
+    list = generate_credit_list(credit_text, TRUE);
+    gtk_notebook_append_page(GTK_NOTEBOOK(about_notebook), list,
+                             gtk_label_new(_("Credits")));
+
+    list = generate_credit_list(translators, FALSE);
+    gtk_notebook_append_page(GTK_NOTEBOOK(about_notebook), list,
+                             gtk_label_new(_("Translators")));
+
+    bbox = gtk_hbutton_box_new();
+    gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+    gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
+    gtk_box_pack_start(GTK_BOX(about_vbox), bbox, FALSE, FALSE, 0);
+
+    close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+    g_signal_connect_swapped(close_btn, "clicked",
+                             G_CALLBACK(gtk_widget_destroy), about_window);
+    GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
+    gtk_box_pack_start(GTK_BOX(bbox), close_btn, TRUE, TRUE, 0);
+    gtk_widget_grab_default(close_btn);
+
+    gtk_widget_show_all(about_window);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/ui_credits.h	Tue Jul 08 16:36:50 2008 +0200
@@ -0,0 +1,9 @@
+
+#ifndef AUDACIOUS_UI_CREDITS_H
+#define AUDACIOUS_UI_CREDITS_H
+
+void show_about_window(void);
+void hide_about_window(void);
+void show_credits_window(void);
+
+#endif /* AUDACIOUS_UI_CREDITS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/ui_fileinfo.c	Tue Jul 08 16:36:50 2008 +0200
@@ -0,0 +1,1016 @@
+/*
+ * Audacious: A cross-platform multimedia player
+ * Copyright (c) 2006 William Pitcock, Tony Vroon, George Averill,
+ *                    Giacomo Lozito, Derek Pomery and Yoshiki Yazawa.
+ * Copyright (c) 2008 Eugene Zagidullin
+ *
+ * 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; under version 3 of the License.
+ *
+ * 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, see <http://www.gnu.org/licenses>.
+ *
+ * The Audacious team does not consider modular code linking to
+ * Audacious or using our public API to be a derived work.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "plugin.h"
+#include "pluginenum.h"
+#include "input.h"
+#include "effect.h"
+#include "strings.h"
+#include "general.h"
+#include "output.h"
+#include "visualization.h"
+
+#include "main.h"
+#include "util.h"
+#include "dnd.h"
+#include "tuple.h"
+#include "vfs.h"
+
+#include "playlist.h"
+
+#include "build_stamp.h"
+#include "ui_fileinfo.h"
+
+#define G_FREE_CLEAR(a) if(a != NULL) { g_free(a); a = NULL; }
+#define STATUS_TIMEOUT 3*1000
+
+GtkWidget *fileinfo_win = NULL;
+
+GtkWidget *entry_location;
+GtkWidget *entry_title;
+GtkWidget *entry_artist;
+GtkWidget *entry_album;
+GtkWidget *entry_comment;
+GtkWidget *entry_year;
+GtkWidget *entry_track;
+GtkWidget *entry_genre;
+
+GtkWidget *image_artwork;
+
+GtkWidget *image_fileicon;
+GtkWidget *label_format_name;
+GtkWidget *label_quality;
+GtkWidget *label_bitrate;
+GtkWidget *btn_apply;
+GtkWidget *label_mini_status;
+GtkWidget *arrow_rawdata;
+GtkWidget *treeview_rawdata;
+
+enum {
+    RAWDATA_KEY,
+    RAWDATA_VALUE,
+    RAWDATA_N_COLS
+};
+
+static gchar *current_file = NULL;
+static InputPlugin *current_ip = NULL;
+static gboolean something_changed = FALSE;
+
+/* stolen from Audacious 1.4 vorbis plugin. --nenolod */
+static const gchar *genre_table[] = {
+    N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"),
+    N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"),
+    N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"),
+    N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"),
+    N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"),
+    N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"),
+    N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"),
+    N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"),
+    N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"),
+    N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("AlternRock"),
+    N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"),
+    N_("Meditative"), N_("Instrumental Pop"),
+    N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"),
+    N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"),
+    N_("Pop-Folk"), N_("Eurodance"), N_("Dream"),
+    N_("Southern Rock"), N_("Comedy"), N_("Cult"),
+    N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"),
+    N_("Pop/Funk"), N_("Jungle"), N_("Native American"),
+    N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"),
+    N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"),
+    N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"),
+    N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"),
+    N_("Folk/Rock"), N_("National Folk"), N_("Swing"),
+    N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"),
+    N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"),
+    N_("Gothic Rock"), N_("Progressive Rock"),
+    N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"),
+    N_("Big Band"), N_("Chorus"), N_("Easy Listening"),
+    N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"),
+    N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"),
+    N_("Booty Bass"), N_("Primus"), N_("Porn Groove"),
+    N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"),
+    N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"),
+    N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"),
+    N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"),
+    N_("Euro-House"), N_("Dance Hall"), N_("Goa"),
+    N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"),
+    N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"),
+    N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"),
+    N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"),
+    N_("Contemporary Christian"), N_("Christian Rock"),
+    N_("Merengue"), N_("Salsa"), N_("Thrash Metal"),
+    N_("Anime"), N_("JPop"), N_("Synthpop")
+};
+
+static GList *genre_list = NULL;
+
+static void
+fileinfo_entry_set_text(GtkWidget *widget, const char *text)
+{
+    if (widget == NULL)
+        return;
+
+    gtk_entry_set_text(GTK_ENTRY(widget), text != NULL ? text : "");
+}
+
+static void
+set_entry_str_from_field(GtkWidget *widget, Tuple *tuple, gint fieldn, gboolean editable)
+{
+    gchar *text;
+
+    if(widget != NULL) {
+        text = (gchar*)tuple_get_string(tuple, fieldn, NULL);
+        gtk_entry_set_text(GTK_ENTRY(widget), text != NULL ? text : "");
+        gtk_editable_set_editable(GTK_EDITABLE(widget), editable);
+    }
+}
+
+static void
+set_entry_int_from_field(GtkWidget *widget, Tuple *tuple, gint fieldn, gboolean editable)
+{
+    gchar *text;
+
+    if(widget == NULL) return;
+
+    if(tuple_get_value_type(tuple, fieldn, NULL) == TUPLE_INT) {
+        text = g_strdup_printf("%d", tuple_get_int(tuple, fieldn, NULL));
+        gtk_entry_set_text(GTK_ENTRY(widget), text);
+        gtk_editable_set_editable(GTK_EDITABLE(widget), editable);
+        g_free(text);
+    } else {
+        gtk_entry_set_text(GTK_ENTRY(widget), "");
+        gtk_editable_set_editable(GTK_EDITABLE(widget), editable);
+    }
+}
+
+static void
+set_field_str_from_entry(Tuple *tuple, gint fieldn, GtkWidget *widget)
+{
+    if(widget == NULL) return;
+    tuple_associate_string(tuple, fieldn, NULL, gtk_entry_get_text(GTK_ENTRY(widget)));
+}
+
+static void
+set_field_int_from_entry(Tuple *tuple, gint fieldn, GtkWidget *widget)
+{
+    gchar *tmp;
+    if(widget == NULL) return;
+
+    tmp = (gchar*)gtk_entry_get_text(GTK_ENTRY(widget));
+    if(*tmp != '\0')
+        tuple_associate_int(tuple, fieldn, NULL, atoi(tmp));
+    else
+        tuple_associate_int(tuple, fieldn, NULL, -1);
+}
+
+static void
+fileinfo_label_set_text(GtkWidget *widget, const char *text)
+{
+    gchar *tmp;
+
+    if (widget == NULL)
+        return;
+
+    if (text) {
+        tmp = g_strdup_printf("<span size=\"small\">%s</span>", text);
+        gtk_label_set_text(GTK_LABEL(widget), tmp);
+        gtk_label_set_use_markup(GTK_LABEL(widget), TRUE);
+        g_free(tmp);
+    } else {
+        gtk_label_set_text(GTK_LABEL(widget), _("<span size=\"small\">n/a</span>"));
+        gtk_label_set_use_markup(GTK_LABEL(widget), TRUE);
+    }
+}
+
+static void
+fileinfo_entry_set_image(GtkWidget *widget, const char *text)
+{
+    GdkPixbuf *pixbuf;
+    int width, height;
+    double aspect;
+    GdkPixbuf *pixbuf2;
+
+    if (widget == NULL)
+        return;
+
+    pixbuf = gdk_pixbuf_new_from_file(text, NULL);
+
+    if (pixbuf == NULL)
+        return;
+
+    width  = gdk_pixbuf_get_width(GDK_PIXBUF(pixbuf));
+    height = gdk_pixbuf_get_height(GDK_PIXBUF(pixbuf));
+
+    if (strcmp(DATA_DIR "/images/audio.png", text)) {
+        if (width == 0)
+            width = 1;
+        aspect = (double)height / (double)width;
+
+        if (aspect > 1.0) {
+            height = (int)(cfg.filepopup_pixelsize * aspect);
+            width = cfg.filepopup_pixelsize;
+        } else {
+            height = cfg.filepopup_pixelsize;
+            width = (int)(cfg.filepopup_pixelsize / aspect);
+        }
+
+        pixbuf2 = gdk_pixbuf_scale_simple(GDK_PIXBUF(pixbuf), width, height, 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
+fileinfo_hide(gpointer unused)
+{
+    if(GTK_WIDGET_VISIBLE(fileinfo_win)) 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(gtk_bin_get_child(GTK_BIN(entry_genre)), "");
+    fileinfo_entry_set_text(entry_year, "");
+    fileinfo_entry_set_text(entry_track, "");
+    fileinfo_entry_set_text(entry_location, "");
+
+    fileinfo_label_set_text(label_format_name, NULL);
+    fileinfo_label_set_text(label_quality, NULL);
+    fileinfo_label_set_text(label_bitrate, NULL);
+    
+    if (label_mini_status != NULL) {
+        gtk_label_set_text(GTK_LABEL(label_mini_status), "<span size=\"small\"></span>");
+        gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE);
+    }
+    
+    something_changed = FALSE;
+    gtk_widget_set_sensitive(btn_apply, FALSE);
+
+    current_ip = NULL;
+    G_FREE_CLEAR(current_file);
+
+    fileinfo_entry_set_image(image_artwork, DATA_DIR "/images/audio.png");
+}
+
+static void
+entry_changed (GtkEditable *editable, gpointer user_data)
+{
+    if(current_file != NULL && current_ip != NULL && current_ip->update_song_tuple != NULL) {
+        something_changed = TRUE;
+        gtk_widget_set_sensitive(btn_apply, TRUE);
+    }
+}
+
+static gboolean
+ministatus_timeout_proc (gpointer data)
+{
+    GtkLabel *status = GTK_LABEL(data);
+    gtk_label_set_text(status, "<span size=\"small\"></span>");
+    gtk_label_set_use_markup(status, TRUE);
+
+    return FALSE;
+}
+
+static void
+ministatus_display_message(gchar *text)
+{
+    if(label_mini_status != NULL) {
+        gchar *tmp = g_strdup_printf("<span size=\"small\">%s</span>", text);
+        gtk_label_set_text(GTK_LABEL(label_mini_status), tmp);
+        g_free(tmp);
+        gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE);
+        g_timeout_add (STATUS_TIMEOUT, (GSourceFunc) ministatus_timeout_proc, (gpointer) label_mini_status);
+    }
+}
+
+static void
+message_update_successfull()
+{
+    ministatus_display_message(_("Metadata updated successfully"));
+}
+
+static void
+message_update_failed()
+{
+    ministatus_display_message(_("Metadata updating failed"));
+}
+
+static void
+fileinfo_update_tuple(gpointer data)
+{
+    Tuple *tuple;
+    VFSFile *fd;
+
+    if (current_file != NULL && current_ip != NULL && current_ip->update_song_tuple != NULL && something_changed) {
+        tuple = tuple_new();
+        fd = vfs_fopen(current_file, "r+b");
+
+        if (fd != NULL) {
+            set_field_str_from_entry(tuple, FIELD_TITLE, entry_title);
+            set_field_str_from_entry(tuple, FIELD_ARTIST, entry_artist);
+            set_field_str_from_entry(tuple, FIELD_ALBUM, entry_album);
+            set_field_str_from_entry(tuple, FIELD_COMMENT, entry_comment);
+            set_field_str_from_entry(tuple, FIELD_GENRE, gtk_bin_get_child(GTK_BIN(entry_genre)));
+
+            set_field_int_from_entry(tuple, FIELD_YEAR, entry_year);
+            set_field_int_from_entry(tuple, FIELD_TRACK_NUMBER, entry_track);
+
+            plugin_set_current((Plugin *)current_ip);
+            if (current_ip->update_song_tuple(tuple, fd)) {
+                message_update_successfull();
+                something_changed = FALSE;
+                gtk_widget_set_sensitive(btn_apply, FALSE);
+            } else
+                message_update_failed();
+
+            vfs_fclose(fd);
+
+        } else
+            message_update_failed();
+
+        mowgli_object_unref(tuple);
+    }
+}
+
+/**
+ * Looks up an icon from a NULL-terminated list of icon names.
+ *
+ * size: the requested size
+ * name: the default name
+ * ... : a NULL-terminated list of alternates
+ */
+GdkPixbuf *
+themed_icon_lookup(gint size, const gchar *name, ...)
+{
+    GtkIconTheme *icon_theme;
+    GdkPixbuf *pixbuf;
+    GError *error = NULL;
+    gchar *n;
+    va_list par;
+
+    icon_theme = gtk_icon_theme_get_default ();
+    pixbuf = gtk_icon_theme_load_icon (icon_theme, name, size, 0, &error);
+
+    if (pixbuf != NULL)
+        return pixbuf;
+    
+    if (error != NULL)
+        g_error_free(error);
+
+    /* fallback */
+    va_start(par, name);
+    while((n = (gchar*)va_arg(par, gchar *)) != NULL) {
+        error = NULL;
+        pixbuf = gtk_icon_theme_load_icon (icon_theme, n, size, 0, &error);
+
+        if (pixbuf) {
+            va_end(par);
+            return pixbuf;
+        }
+
+        if (error != NULL)
+            g_error_free(error);
+    }
+    
+    return NULL;
+}
+
+/**
+ * Intelligently looks up an icon for a mimetype. Supports
+ * HIDEOUSLY BROKEN gnome icon naming scheme too.
+ *
+ * size     : the requested size
+ * mime_type: the mime type.
+ */
+GdkPixbuf *
+mime_icon_lookup(gint size, const gchar *mime_type) /* smart icon resolving routine :) */
+{
+    gchar *mime_as_is;         /* audio-x-mp3            */
+    gchar *mime_gnome;         /* gnome-mime-audio-x-mp3 */
+    gchar *mime_generic;       /* audio-x-generic */
+    gchar *mime_gnome_generic; /* gnome-mime-audio */
+
+    GdkPixbuf *icon = NULL;
+
+    gchar **s = g_strsplit(mime_type, "/", 2);
+    if(s[1] != NULL) {
+        mime_as_is         = g_strdup_printf("%s-%s", s[0], s[1]);
+        mime_gnome         = g_strdup_printf("gnome-mime-%s-%s", s[0], s[1]);
+        mime_generic       = g_strdup_printf("%s-x-generic", s[0]);
+        mime_gnome_generic = g_strdup_printf("gnome-mime-%s", s[0]);
+        icon = themed_icon_lookup(size, mime_as_is, mime_gnome, mime_generic, mime_gnome_generic, s[0], NULL); /* s[0] is category */
+        g_free(mime_gnome_generic);
+        g_free(mime_generic);
+        g_free(mime_gnome);
+        g_free(mime_as_is);
+    }
+    g_strfreev(s);
+
+    return icon;
+}
+
+void
+create_fileinfo_window(void)
+{
+    GtkWidget *hbox;
+    GtkWidget *hbox_status_and_bbox;
+    GtkWidget *vbox0;
+    GtkWidget *vbox1;
+    GtkWidget *vbox2;
+    GtkWidget *vbox3;
+    GtkWidget *label_title;
+    GtkWidget *label_artist;
+    GtkWidget *label_album;
+    GtkWidget *label_comment;
+    GtkWidget *label_genre;
+    GtkWidget *label_year;
+    GtkWidget *label_track;
+    GtkWidget *label_location;
+    GtkWidget *label_general;
+    GtkWidget *label_format;
+    GtkWidget *label_quality_label;
+    GtkWidget *label_bitrate_label;
+    GtkWidget *codec_hbox;
+    GtkWidget *codec_table;
+    GtkWidget *table1;
+    GtkWidget *bbox_close;
+    GtkWidget *btn_close;
+    GtkWidget *alignment;
+    GtkWidget *separator;
+    GtkWidget *scrolledwindow;
+    GtkTreeViewColumn *column;
+    GtkCellRenderer *renderer;
+    gint i;
+
+    fileinfo_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_container_set_border_width(GTK_CONTAINER(fileinfo_win), 6);
+    gtk_window_set_title(GTK_WINDOW(fileinfo_win), _("Track Information"));
+    gtk_window_set_position(GTK_WINDOW(fileinfo_win), GTK_WIN_POS_CENTER);
+    gtk_window_set_resizable(GTK_WINDOW(fileinfo_win), FALSE);
+    gtk_window_set_type_hint(GTK_WINDOW(fileinfo_win), GDK_WINDOW_TYPE_HINT_DIALOG);
+    gtk_window_set_transient_for(GTK_WINDOW(fileinfo_win), GTK_WINDOW(mainwin));
+
+    vbox0 = gtk_vbox_new(FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(fileinfo_win), vbox0);
+
+    hbox = gtk_hbox_new(FALSE, 6);
+    gtk_box_pack_start(GTK_BOX(vbox0), hbox, TRUE, TRUE, 0);
+
+    image_artwork = gtk_image_new();
+    gtk_box_pack_start(GTK_BOX(hbox), image_artwork, FALSE, FALSE, 0);
+    gtk_misc_set_alignment(GTK_MISC(image_artwork), 0.5, 0);
+    gtk_image_set_from_file(GTK_IMAGE(image_artwork), DATA_DIR "/images/audio.png");
+    separator = gtk_vseparator_new();
+    gtk_box_pack_start(GTK_BOX(hbox), separator, FALSE, FALSE, 0);
+
+    vbox1 = gtk_vbox_new(FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox), vbox1, TRUE, TRUE, 0);
+
+    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
+    gtk_box_pack_start(GTK_BOX(vbox1), alignment, TRUE, TRUE, 0);
+
+    vbox2 = gtk_vbox_new(FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(alignment), vbox2);
+
+    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
+    gtk_box_pack_start(GTK_BOX(vbox1), alignment, TRUE, TRUE, 0);
+
+    vbox3 = gtk_vbox_new(FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(alignment), vbox3);
+    
+    label_general = gtk_label_new(_("<span size=\"small\">General</span>"));
+    gtk_box_pack_start (GTK_BOX (vbox2), label_general, FALSE, FALSE, 0);
+    gtk_label_set_use_markup(GTK_LABEL(label_general), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_general), 0, 0.5);
+    
+    alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
+    gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 0, 0);
+    gtk_box_pack_start (GTK_BOX (vbox2), alignment, FALSE, FALSE, 0);
+
+    codec_hbox = gtk_hbox_new(FALSE, 6);
+    gtk_container_add (GTK_CONTAINER(alignment), codec_hbox);
+
+    image_fileicon = gtk_image_new_from_stock (GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG);
+    gtk_box_pack_start (GTK_BOX (codec_hbox), image_fileicon, FALSE, FALSE, 0);
+    
+    codec_table = gtk_table_new(3, 2, FALSE);
+    gtk_table_set_row_spacings (GTK_TABLE(codec_table), 6);
+    gtk_table_set_col_spacings (GTK_TABLE(codec_table), 12);
+    gtk_box_pack_start (GTK_BOX (codec_hbox), codec_table, FALSE, FALSE, 0);
+
+    label_format = gtk_label_new(_("<span size=\"small\">Format:</span>"));
+    gtk_label_set_use_markup(GTK_LABEL(label_format), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_format), 0, 0.5);
+    label_quality_label = gtk_label_new(_("<span size=\"small\">Quality:</span>"));
+    gtk_label_set_use_markup(GTK_LABEL(label_quality_label), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_quality_label), 0, 0.5);
+    label_bitrate_label = gtk_label_new(_("<span size=\"small\">Bitrate:</span>"));
+    gtk_label_set_use_markup(GTK_LABEL(label_bitrate_label), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_bitrate_label), 0, 0.5);
+
+    label_format_name = gtk_label_new(_("<span size=\"small\">n/a</span>"));
+    gtk_label_set_use_markup(GTK_LABEL(label_format_name), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_format_name), 0, 0.5);
+    label_quality = gtk_label_new(_("<span size=\"small\">n/a</span>"));
+    gtk_label_set_use_markup(GTK_LABEL(label_quality), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_quality), 0, 0.5);
+    label_bitrate = gtk_label_new(_("<span size=\"small\">n/a</span>"));
+    gtk_label_set_use_markup(GTK_LABEL(label_bitrate), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_bitrate), 0, 0.5);
+    
+    gtk_table_attach(GTK_TABLE(codec_table), label_format, 0, 1, 0, 1,
+                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                     (GtkAttachOptions) (0), 0, 0);
+    gtk_table_attach(GTK_TABLE(codec_table), label_format_name, 1, 2, 0, 1,
+                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                     (GtkAttachOptions) (0), 0, 0);
+    gtk_table_attach(GTK_TABLE(codec_table), label_quality_label, 0, 1, 1, 2,
+                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                     (GtkAttachOptions) (0), 0, 0);
+    gtk_table_attach(GTK_TABLE(codec_table), label_quality, 1, 2, 1, 2,
+                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                     (GtkAttachOptions) (0), 0, 0);
+    gtk_table_attach(GTK_TABLE(codec_table), label_bitrate_label, 0, 1, 2, 3,
+                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                     (GtkAttachOptions) (0), 0, 0);
+    gtk_table_attach(GTK_TABLE(codec_table), label_bitrate, 1, 2, 2, 3,
+                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                     (GtkAttachOptions) (0), 0, 0);
+
+    label_title = gtk_label_new(_("<span size=\"small\">Title</span>"));
+    gtk_box_pack_start(GTK_BOX(vbox2), label_title, FALSE, FALSE, 0);
+    gtk_label_set_use_markup(GTK_LABEL(label_title), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_title), 0, 0);
+
+    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
+    gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0);
+    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0);
+    entry_title = gtk_entry_new();
+    gtk_container_add(GTK_CONTAINER(alignment), entry_title);
+    g_signal_connect(G_OBJECT(entry_title), "changed", (GCallback) entry_changed, NULL);
+
+    label_artist = gtk_label_new(_("<span size=\"small\">Artist</span>"));
+    gtk_box_pack_start(GTK_BOX(vbox2), label_artist, FALSE, FALSE, 0);
+    gtk_label_set_use_markup(GTK_LABEL(label_artist), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_artist), 0, 0.5);
+
+    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
+    gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0);
+    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0);
+    entry_artist = gtk_entry_new();
+    gtk_container_add(GTK_CONTAINER(alignment), entry_artist);
+    g_signal_connect(G_OBJECT(entry_artist), "changed", (GCallback) entry_changed, NULL);
+
+    label_album = gtk_label_new(_("<span size=\"small\">Album</span>"));
+    gtk_box_pack_start(GTK_BOX(vbox2), label_album, FALSE, FALSE, 0);
+    gtk_label_set_use_markup(GTK_LABEL(label_album), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_album), 0, 0.5);
+
+    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
+    gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0);
+    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0);
+    entry_album = gtk_entry_new();
+    gtk_container_add(GTK_CONTAINER(alignment), entry_album);
+    g_signal_connect(G_OBJECT(entry_album), "changed", (GCallback) entry_changed, NULL);
+
+    label_comment = gtk_label_new(_("<span size=\"small\">Comment</span>"));
+    gtk_box_pack_start(GTK_BOX(vbox2), label_comment, FALSE, FALSE, 0);
+    gtk_label_set_use_markup(GTK_LABEL(label_comment), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_comment), 0, 0.5);
+
+    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
+    gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0);
+    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0);
+    entry_comment = gtk_entry_new();
+    gtk_container_add (GTK_CONTAINER(alignment), entry_comment);
+    g_signal_connect(G_OBJECT(entry_comment), "changed", (GCallback) entry_changed, NULL);
+
+    label_genre = gtk_label_new(_("<span size=\"small\">Genre</span>"));
+    gtk_box_pack_start(GTK_BOX(vbox2), label_genre, FALSE, FALSE, 0);
+    gtk_label_set_use_markup(GTK_LABEL(label_genre), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_genre), 0, 0.5);
+
+    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
+    gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0);
+    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0);
+    entry_genre = gtk_combo_box_entry_new_text();
+
+    if (!genre_list) {
+        GList *iter;
+
+        for (i = 0; i < G_N_ELEMENTS(genre_table); i++)
+            genre_list = g_list_prepend(genre_list, _(genre_table[i]));
+        genre_list = g_list_sort(genre_list, (GCompareFunc) g_utf8_collate);
+
+        MOWGLI_ITER_FOREACH(iter, genre_list)
+            gtk_combo_box_append_text(GTK_COMBO_BOX(entry_genre), iter->data);
+    }
+
+    gtk_container_add(GTK_CONTAINER(alignment), entry_genre);
+    g_signal_connect(G_OBJECT(entry_genre), "changed", (GCallback) entry_changed, NULL);
+
+    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
+    gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0);
+    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0);
+    table1 = gtk_table_new(2, 2, FALSE);
+    gtk_container_add(GTK_CONTAINER(alignment), table1);
+    gtk_table_set_col_spacings(GTK_TABLE(table1), 6);
+
+    label_year = gtk_label_new(_("<span size=\"small\">Year</span>"));
+    gtk_table_attach(GTK_TABLE(table1), label_year, 0, 1, 0, 1,
+                     (GtkAttachOptions) (GTK_FILL),
+                     (GtkAttachOptions) (0), 0, 0);
+    gtk_label_set_use_markup(GTK_LABEL(label_year), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_year), 0, 0.5);
+
+    entry_year = gtk_entry_new();
+    gtk_table_attach(GTK_TABLE(table1), entry_year, 0, 1, 1, 2,
+                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                     (GtkAttachOptions) (0), 0, 0);
+    g_signal_connect(G_OBJECT(entry_year), "changed", (GCallback) entry_changed, NULL);
+
+    label_track = gtk_label_new(_("<span size=\"small\">Track Number</span>"));
+    gtk_table_attach(GTK_TABLE(table1), label_track, 1, 2, 0, 1,
+                     (GtkAttachOptions) (GTK_FILL),
+                     (GtkAttachOptions) (0), 0, 0);
+    gtk_label_set_use_markup(GTK_LABEL(label_track), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_track), 0, 0.5);
+
+    entry_track = gtk_entry_new();
+    gtk_table_attach(GTK_TABLE(table1), entry_track, 1, 2, 1, 2,
+                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                     (GtkAttachOptions) (0), 0, 0);
+    g_signal_connect(G_OBJECT(entry_track), "changed", (GCallback) entry_changed, NULL);
+
+    label_location = gtk_label_new(_("<span size=\"small\">Location</span>"));
+    gtk_box_pack_start(GTK_BOX(vbox2), label_location, FALSE, FALSE, 0);
+    gtk_label_set_use_markup(GTK_LABEL(label_location), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_location), 0, 0.5);
+
+    alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
+    gtk_box_pack_start (GTK_BOX (vbox2), alignment, FALSE, FALSE, 0);
+    gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 6, 0, 0);
+
+    entry_location = gtk_entry_new();
+    gtk_container_add(GTK_CONTAINER(alignment), entry_location);
+    gtk_editable_set_editable(GTK_EDITABLE(entry_location), FALSE);
+
+    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
+    hbox = gtk_hbox_new(FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(alignment), hbox);
+    gtk_box_pack_start(GTK_BOX(vbox3), alignment, TRUE, TRUE, 0);
+
+    alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
+    gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 6, 0, 0);
+    arrow_rawdata = gtk_expander_new(_("<span size=\"small\">Raw Metadata</span>"));
+    gtk_expander_set_use_markup(GTK_EXPANDER(arrow_rawdata), TRUE);
+    gtk_container_add(GTK_CONTAINER(alignment), arrow_rawdata);
+    gtk_box_pack_start(GTK_BOX(hbox), alignment, TRUE, TRUE, 0);
+
+    scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN);
+    gtk_container_add(GTK_CONTAINER(arrow_rawdata), scrolledwindow);
+
+    treeview_rawdata = gtk_tree_view_new();
+    gtk_container_add(GTK_CONTAINER(scrolledwindow), treeview_rawdata);
+    gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview_rawdata), TRUE);
+    gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview_rawdata), TRUE);
+    gtk_widget_set_size_request(treeview_rawdata, -1, 130);
+
+    column = gtk_tree_view_column_new();
+    gtk_tree_view_column_set_title(column, _("Key"));
+    gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+    gtk_tree_view_column_set_spacing(column, 4);
+    gtk_tree_view_column_set_resizable(column, FALSE);
+    gtk_tree_view_column_set_fixed_width(column, 50);
+
+    renderer = gtk_cell_renderer_text_new();
+    gtk_tree_view_column_pack_start(column, renderer, FALSE);
+    gtk_tree_view_column_set_attributes(column, renderer,
+                                        "text", RAWDATA_KEY, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_rawdata), column);
+
+    column = gtk_tree_view_column_new();
+    gtk_tree_view_column_set_title(column, _("Value"));
+    gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+    gtk_tree_view_column_set_spacing(column, 4);
+    gtk_tree_view_column_set_resizable(column, FALSE);
+    gtk_tree_view_column_set_fixed_width(column, 50);
+
+    renderer = gtk_cell_renderer_text_new();
+    gtk_tree_view_column_pack_start(column, renderer, FALSE);
+    gtk_tree_view_column_set_attributes(column, renderer,
+                                        "text", RAWDATA_VALUE, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_rawdata), column);
+    
+    hbox_status_and_bbox = gtk_hbox_new(FALSE, 0);
+    gtk_box_pack_start (GTK_BOX (vbox0), hbox_status_and_bbox, FALSE, FALSE, 0);
+
+    label_mini_status = gtk_label_new("<span size=\"small\"></span>");
+    gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label_mini_status), 0, 0.5);
+    gtk_box_pack_start (GTK_BOX (hbox_status_and_bbox), label_mini_status, TRUE, TRUE, 0);
+    
+    bbox_close = gtk_hbutton_box_new();
+    gtk_box_set_spacing(GTK_BOX(bbox_close), 6);
+    gtk_box_pack_start(GTK_BOX(hbox_status_and_bbox), bbox_close, FALSE, FALSE, 0);
+    gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox_close), GTK_BUTTONBOX_END);
+
+    btn_apply = gtk_button_new_from_stock("gtk-save");
+    gtk_container_add(GTK_CONTAINER(bbox_close), btn_apply);
+    g_signal_connect(G_OBJECT(btn_apply), "clicked", (GCallback) fileinfo_update_tuple, NULL);
+    gtk_widget_set_sensitive(btn_apply, FALSE);
+
+    btn_close = gtk_button_new_from_stock("gtk-close");
+    gtk_container_add(GTK_CONTAINER(bbox_close), btn_close);
+    GTK_WIDGET_SET_FLAGS(btn_close, GTK_CAN_DEFAULT);
+    g_signal_connect(G_OBJECT(btn_close), "clicked", (GCallback) fileinfo_hide, NULL);
+
+    gtk_widget_show_all (vbox0);
+}
+
+static void 
+fileinfo_show_for_tuple(Tuple *tuple, gboolean updating_enabled)
+{
+    gchar *tmp = NULL;
+    GdkPixbuf *icon = NULL;
+    GtkTreeIter iter;
+    GtkListStore *store;
+    mowgli_dictionary_iteration_state_t state;
+    TupleValue *tvalue;
+    gint i;
+
+    if (tuple == NULL)
+        return;
+
+    if(!updating_enabled) {
+        current_ip = NULL;
+        G_FREE_CLEAR(current_file);
+    }
+
+    something_changed = FALSE;
+
+    if (fileinfo_win == NULL)
+        create_fileinfo_window();
+
+    if (!GTK_WIDGET_REALIZED(fileinfo_win))
+        gtk_widget_realize(fileinfo_win);
+
+    set_entry_str_from_field(entry_title, tuple, FIELD_TITLE, updating_enabled);
+    set_entry_str_from_field(entry_artist, tuple, FIELD_ARTIST, updating_enabled);
+    set_entry_str_from_field(entry_album, tuple, FIELD_ALBUM, updating_enabled);
+    set_entry_str_from_field(entry_comment, tuple, FIELD_COMMENT, updating_enabled);
+    set_entry_str_from_field(gtk_bin_get_child(GTK_BIN(entry_genre)), tuple, FIELD_GENRE, updating_enabled);
+
+    tmp = g_strdup_printf("%s/%s",
+            tuple_get_string(tuple, FIELD_FILE_PATH, NULL),
+            tuple_get_string(tuple, FIELD_FILE_NAME, NULL));
+
+    if (tmp) {
+        fileinfo_entry_set_text(entry_location, tmp);
+        g_free(tmp);
+    }
+        
+    /* set empty string if field not availaible. --eugene */
+    set_entry_int_from_field(entry_year, tuple, FIELD_YEAR, updating_enabled);
+    set_entry_int_from_field(entry_track, tuple, FIELD_TRACK_NUMBER, updating_enabled);
+
+    fileinfo_label_set_text(label_format_name, tuple_get_string(tuple, FIELD_CODEC, NULL));
+    fileinfo_label_set_text(label_quality, tuple_get_string(tuple, FIELD_QUALITY, NULL));
+
+    if (tuple_get_value_type(tuple, FIELD_BITRATE, NULL) == TUPLE_INT) {
+        tmp = g_strdup_printf(_("%d kb/s"), tuple_get_int(tuple, FIELD_BITRATE, NULL));
+        fileinfo_label_set_text(label_bitrate, tmp);
+        g_free(tmp);
+    } else
+        fileinfo_label_set_text(label_bitrate, NULL);
+
+    tmp = (gchar *)tuple_get_string(tuple, FIELD_MIMETYPE, NULL);
+    icon = mime_icon_lookup(48, tmp ? tmp : "audio/x-generic");
+    if (icon) {
+        if (image_fileicon) gtk_image_set_from_pixbuf (GTK_IMAGE(image_fileicon), icon);
+        g_object_unref(icon);
+    }
+
+    tmp = fileinfo_recursive_get_image(
+            tuple_get_string(tuple, FIELD_FILE_PATH, NULL),
+            tuple_get_string(tuple, FIELD_FILE_NAME, NULL), 0);
+        
+    if (tmp) {
+        fileinfo_entry_set_image(image_artwork, tmp);
+        g_free(tmp);
+    }
+
+    gtk_widget_set_sensitive(btn_apply, FALSE);
+    
+    if (label_mini_status != NULL) {
+        gtk_label_set_text(GTK_LABEL(label_mini_status), "<span size=\"small\"></span>");
+        gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE);
+    }
+
+    store = gtk_list_store_new(RAWDATA_N_COLS, G_TYPE_STRING, G_TYPE_STRING);
+
+    for (i = 0; i < FIELD_LAST; i++) {
+         gchar *key, *value;
+
+         if (!tuple->values[i])
+             continue;
+
+         if (tuple->values[i]->type != TUPLE_INT && tuple->values[i]->value.string)
+             value = g_strdup(tuple->values[i]->value.string);
+         else if (tuple->values[i]->type == TUPLE_INT)
+             value = g_strdup_printf("%d", tuple->values[i]->value.integer);
+         else
+             continue;
+
+         key = g_strdup(tuple_fields[i].name);
+
+         gtk_list_store_append(store, &iter);
+         gtk_list_store_set(store, &iter,
+                            RAWDATA_KEY, key,
+                            RAWDATA_VALUE, value, -1);
+
+         g_free(key);
+         g_free(value);
+    }
+
+    /* non-standard values are stored in a dictionary. */
+    MOWGLI_DICTIONARY_FOREACH(tvalue, &state, tuple->dict) {
+         gchar *key, *value;
+
+         if (tvalue->type != TUPLE_INT && tvalue->value.string)
+             value = g_strdup(tvalue->value.string);
+         else if (tvalue->type == TUPLE_INT)
+             value = g_strdup_printf("%d", tvalue->value.integer);
+         else
+             continue;
+
+         key = g_strdup(state.cur->key);
+
+         gtk_list_store_append(store, &iter);
+         gtk_list_store_set(store, &iter,
+                            RAWDATA_KEY, key,
+                            RAWDATA_VALUE, value, -1);
+
+         g_free(key);
+         g_free(value);
+    }
+
+    gtk_tree_view_set_model(GTK_TREE_VIEW(treeview_rawdata), GTK_TREE_MODEL(store));
+    g_object_unref(store);
+
+    if (!GTK_WIDGET_VISIBLE(fileinfo_win))
+        gtk_widget_show(fileinfo_win);
+}
+
+static void
+fileinfo_show_for_path(gchar *path)
+{
+    Tuple *tuple = input_get_song_tuple(path);
+
+    if (tuple == NULL) {
+         input_file_info_box(path);
+         return;
+    }
+
+    fileinfo_show_for_tuple(tuple, FALSE);
+
+    mowgli_object_unref(tuple);
+}
+
+static void
+fileinfo_show_editor_for_path(gchar *path, InputPlugin *ip)
+{
+    G_FREE_CLEAR(current_file);
+    current_file = g_strdup(path);
+    current_ip = ip;
+
+    Tuple *tuple = input_get_song_tuple(path);
+
+    if (tuple == NULL) {
+        input_file_info_box(path);
+        return;
+    }
+
+    fileinfo_show_for_tuple(tuple, TRUE);
+
+    mowgli_object_unref(tuple);
+}
+
+static void
+ui_fileinfo_show_entry(Playlist *playlist, PlaylistEntry *entry)
+{
+    gchar *path = g_strdup(entry->filename);
+    Tuple *tuple = entry->tuple;
+
+    /* plugin is capable of updating tags. we need to bypass tuple cache. --eugene */
+    /* maybe code cleanup required... */
+    if (entry != NULL &&
+        entry->decoder != NULL &&
+        entry->decoder->update_song_tuple != NULL &&
+        entry->decoder->file_info_box == NULL &&
+        path != NULL && !vfs_is_remote(path))
+    {
+        fileinfo_show_editor_for_path(path, entry->decoder);
+        g_free(path);
+    }
+    else
+    {
+        if (tuple != NULL)
+        {
+            if (entry->decoder != NULL)
+            {
+                if (entry->decoder->file_info_box == NULL)
+                    fileinfo_show_for_tuple(tuple, FALSE);
+                else
+                {
+                    plugin_set_current((Plugin *)(entry->decoder));
+                    entry->decoder->file_info_box(path);
+                }
+            }
+            else
+                fileinfo_show_for_path(path);
+            g_free(path);
+        }
+        else if (path != NULL)
+        {
+            if (entry != NULL &&
+                entry->decoder != NULL &&
+                entry->decoder->file_info_box != NULL)
+            {
+                plugin_set_current((Plugin *)(entry->decoder));
+                entry->decoder->file_info_box(path);
+            }
+            else
+                fileinfo_show_for_path(path);
+            g_free(path);
+        }
+    }
+}
+
+void
+ui_fileinfo_show(Playlist *playlist, guint pos)
+{
+    GList *node = NULL;
+
+    PLAYLIST_LOCK(playlist);
+
+    if ((node = g_list_nth(playlist->entries, pos)))
+        ui_fileinfo_show_entry(playlist, node->data);
+
+    PLAYLIST_UNLOCK(playlist);
+}
+
+void
+ui_fileinfo_show_current(Playlist *playlist)
+{
+    PLAYLIST_LOCK(playlist);
+
+    if (playlist->entries && playlist->position)
+        ui_fileinfo_show_entry(playlist, playlist->position);
+
+    PLAYLIST_UNLOCK(playlist);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/ui_fileinfo.h	Tue Jul 08 16:36:50 2008 +0200
@@ -0,0 +1,32 @@
+/*
+ * 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 3 of the License.
+ *
+ * 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, see <http://www.gnu.org/licenses>.
+ */
+
+#ifndef AUDACIOUS_UI_FILEINFO_H
+#define AUDACIOUS_UI_FILEINFO_H
+
+#include "tuple.h"
+#include "plugin.h"
+#include <glib.h>
+
+void create_fileinfo_window(void);
+gchar* fileinfo_recursive_get_image(const gchar* path, const gchar* file_name, gint depth);
+
+void ui_fileinfo_show(Playlist *playlist, guint pos);
+void ui_fileinfo_show_current(Playlist *playlist);
+
+#endif /* AUDACIOUS_UI_FILEINFO_H */
--- a/src/audacious/ui_fileinfopopup.c	Tue Jul 08 15:35:48 2008 +0200
+++ b/src/audacious/ui_fileinfopopup.c	Tue Jul 08 16:36:50 2008 +0200
@@ -33,7 +33,7 @@
 #include "playback.h"
 #include "strings.h"
 #include "ui_fileinfopopup.h"
-#include "legacy/ui_fileinfo.h"
+#include "ui_fileinfo.h"
 
 static void
 filepopup_entry_set_text(GtkWidget *filepopup_win, const gchar *entry_name,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/ui_jumptotrack.c	Tue Jul 08 16:36:50 2008 +0200
@@ -0,0 +1,614 @@
+/*  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; under version 3 of the License.
+ *
+ *  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, see <http://www.gnu.org/licenses>.
+ *
+ *  The Audacious team does not consider modular code linking to
+ *  Audacious or using our public API to be a derived work.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gprintf.h>
+#include <gtk/gtk.h>
+#include <gtk/gtkmessagedialog.h>
+
+/* GDK including */
+#include "platform/smartinclude.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+
+#if defined(USE_REGEX_ONIGURUMA)
+  #include <onigposix.h>
+#elif defined(USE_REGEX_PCRE)
+  #include <pcreposix.h>
+#else
+  #include <regex.h>
+#endif
+
+#include "icons-stock.h"
+
+#include "actions-mainwin.h"
+
+#include "main.h"
+
+#include "dnd.h"
+#include "input.h"
+#include "playback.h"
+#include "playlist.h"
+#include "pluginenum.h"
+#include "ui_credits.h"
+#include "ui_fileopener.h"
+#include "ui_preferences.h"
+#include "strings.h"
+#include "util.h"
+#include "visualization.h"
+
+#include "ui_jumptotrack_cache.h"
+
+static GtkWidget *jump_to_track_win = NULL;
+static gulong serial = 0;
+
+static JumpToTrackCache* cache = NULL;
+
+static void
+change_song(guint pos)
+{
+    if (playback_get_playing())
+        playback_stop();
+
+    playlist_set_position(playlist_get_active(), pos);
+    playback_initiate();
+}
+
+void
+ui_jump_to_track_hide(void)
+{
+    g_return_if_fail(jump_to_track_win != NULL);
+    gtk_widget_hide(jump_to_track_win);
+}
+
+static void
+ui_jump_to_track_jump(GtkTreeView * treeview)
+{
+    GtkTreeModel *model;
+    GtkTreeSelection *selection;
+    GtkTreeIter iter;
+    guint pos;
+
+    model = gtk_tree_view_get_model(treeview);
+    selection = gtk_tree_view_get_selection(treeview);
+
+    if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
+        return;
+
+    gtk_tree_model_get(model, &iter, 0, &pos, -1);
+
+    change_song(pos - 1);
+
+    if(cfg.close_jtf_dialog)
+        ui_jump_to_track_hide();
+}
+
+static void
+ui_jump_to_track_toggle_cb(GtkWidget * toggle)
+{
+    cfg.close_jtf_dialog =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle));
+}
+
+static void
+ui_jump_to_track_toggle2_cb(GtkWidget * toggle)
+{
+    cfg.remember_jtf_entry =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle));
+}
+
+static void
+ui_jump_to_track_jump_cb(GtkTreeView * treeview,
+                             gpointer data)
+{
+    ui_jump_to_track_jump(treeview);
+}
+
+static void
+ui_jump_to_track_set_queue_button_label(GtkButton * button,
+                                      guint pos)
+{
+    if (playlist_is_position_queued(playlist_get_active(), pos))
+        gtk_button_set_label(button, _("Un_queue"));
+    else
+        gtk_button_set_label(button, _("_Queue"));
+}
+
+static void
+ui_jump_to_track_queue_cb(GtkButton * button,
+                              gpointer data)
+{
+    GtkTreeView *treeview;
+    GtkTreeModel *model;
+    GtkTreeSelection *selection;
+    GtkTreeIter iter;
+    guint pos;
+
+    treeview = GTK_TREE_VIEW(data);
+    model = gtk_tree_view_get_model(treeview);
+    selection = gtk_tree_view_get_selection(treeview);
+
+    if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
+        return;
+
+    gtk_tree_model_get(model, &iter, 0, &pos, -1);
+
+    playlist_queue_position(playlist_get_active(), (pos - 1));
+
+    ui_jump_to_track_set_queue_button_label(button, (pos - 1));
+}
+
+static void
+ui_jump_to_track_selection_changed_cb(GtkTreeSelection *treesel,
+                                          gpointer data)
+{
+    GtkTreeView *treeview;
+    GtkTreeModel *model;
+    GtkTreeSelection *selection;
+    GtkTreeIter iter;
+    guint pos;
+
+    treeview = gtk_tree_selection_get_tree_view(treesel);
+    model = gtk_tree_view_get_model(treeview);
+    selection = gtk_tree_view_get_selection(treeview);
+
+    if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
+        return;
+
+    gtk_tree_model_get(model, &iter, 0, &pos, -1);
+
+    ui_jump_to_track_set_queue_button_label(GTK_BUTTON(data), (pos - 1));
+}
+
+static gboolean
+ui_jump_to_track_edit_keypress_cb(GtkWidget * object,
+                 GdkEventKey * event,
+                 gpointer data)
+{
+    switch (event->keyval) {
+    case GDK_Return:
+        if (gtk_im_context_filter_keypress (GTK_ENTRY (object)->im_context, event)) {
+            GTK_ENTRY (object)->need_im_reset = TRUE;
+            return TRUE;
+        } else {
+            ui_jump_to_track_jump(GTK_TREE_VIEW(data));
+            return TRUE;
+        }
+    default:
+        return FALSE;
+    }
+}
+
+static gboolean
+ui_jump_to_track_keypress_cb(GtkWidget * object,
+                                 GdkEventKey * event,
+                                 gpointer data)
+{
+    switch (event->keyval) {
+    case GDK_Escape:
+        ui_jump_to_track_hide();
+        return TRUE;
+    case GDK_KP_Enter:
+        ui_jump_to_track_queue_cb(NULL, data);
+        return TRUE;
+    default:
+        return FALSE;
+    };
+
+    return FALSE;
+}
+
+void
+ui_jump_to_track_update(GtkWidget * widget, gpointer user_data)
+{
+    guint row;
+    GList *playlist_glist;
+    gchar *desc_buf = NULL;
+    GtkTreeIter iter;
+    GtkTreeSelection *selection;
+    Playlist *playlist;
+
+    GtkTreeModel *store;
+
+    GtkTreeView *tree = GTK_TREE_VIEW(g_object_get_data(user_data, "treeview"));
+    GtkEntry *edit = g_object_get_data(user_data, "edit");
+
+    if (!jump_to_track_win)
+        return;
+
+    /* clear edit widget */
+    if(edit){
+        gtk_entry_set_text(edit, "");
+    }
+
+    store = gtk_tree_view_get_model(tree);
+    gtk_list_store_clear(GTK_LIST_STORE(store));
+
+    row = 1;
+    playlist = playlist_get_active();
+    for (playlist_glist = playlist->entries; playlist_glist;
+         playlist_glist = g_list_next(playlist_glist)) {
+        PlaylistEntry *entry = PLAYLIST_ENTRY(playlist_glist->data);
+
+        if (entry->title)
+            desc_buf = g_strdup(entry->title);
+        else {
+            gchar *realfn = NULL;
+            realfn = g_filename_from_uri(entry->filename, NULL, NULL);
+            if (strchr(realfn ? realfn : entry->filename, '/'))
+                desc_buf = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1);
+            else
+                desc_buf = str_assert_utf8(realfn ? realfn : entry->filename);
+            g_free(realfn); realfn = NULL;
+        }
+
+        gtk_list_store_append(GTK_LIST_STORE(store), &iter);
+        gtk_list_store_set(GTK_LIST_STORE(store), &iter,
+                           0, row, 1, desc_buf, -1);
+        row++;
+
+        g_free(desc_buf);
+        desc_buf = NULL;
+    }
+
+    gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
+    selection = gtk_tree_view_get_selection(tree);
+    gtk_tree_selection_select_iter(selection, &iter);
+    serial = playlist->serial; // important. --yaz
+}
+
+static void
+ui_jump_to_track_edit_cb(GtkEntry * entry, gpointer user_data)
+{
+    GtkTreeView *treeview = GTK_TREE_VIEW(user_data);
+    GtkTreeSelection *selection;
+    GtkTreeIter iter;
+
+    GtkListStore *store;
+
+    const GArray *search_matches;
+    Playlist *playlist;
+    int i;
+
+    if (cache == NULL) {
+        cache = ui_jump_to_track_cache_new();
+    }
+
+    /* FIXME: Remove the connected signals before clearing
+     * (row-selected will still eventually arrive once) */
+    store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
+    /* detach model from treeview */
+    g_object_ref( store );
+    gtk_tree_view_set_model( GTK_TREE_VIEW(treeview) , NULL );
+
+    gtk_list_store_clear(store);
+
+    playlist = playlist_get_active();
+
+    PLAYLIST_LOCK(playlist);
+
+    search_matches = ui_jump_to_track_cache_search(cache,
+                                                   playlist,
+                                                   gtk_entry_get_text(entry));
+
+    for (i = 0; i < search_matches->len; i++)
+    {
+        JumpToTrackEntry *jttentry = g_array_index(search_matches, JumpToTrackEntry*, i);
+        PlaylistEntry* entry = jttentry->entry;
+        gchar *title = NULL;
+
+        if (entry->title)
+            title = g_strdup(entry->title);
+        else {
+            gchar *realfn = NULL;
+            realfn = g_filename_from_uri(entry->filename, NULL, NULL);
+            if (strchr(realfn ? realfn : entry->filename, '/'))
+                title = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1);
+            else
+                title = str_assert_utf8(realfn ? realfn : entry->filename);
+            g_free(realfn); realfn = NULL;
+        }
+        gtk_list_store_append(store, &iter);
+        gtk_list_store_set(store, &iter, 0, jttentry->playlist_position + 1 , 1, title, -1);
+        g_free(title);
+    }
+
+    PLAYLIST_UNLOCK(playlist);
+
+    /* attach the model again to the treeview */
+    gtk_tree_view_set_model( GTK_TREE_VIEW(treeview) , GTK_TREE_MODEL(store) );
+    g_object_unref( store );
+
+    if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
+        selection = gtk_tree_view_get_selection(treeview);
+        gtk_tree_selection_select_iter(selection, &iter);
+    }
+}
+
+static gboolean
+ui_jump_to_track_fill(gpointer treeview)
+{
+    GList *playlist_glist;
+    Playlist *playlist;
+    gchar *desc_buf = NULL;
+    guint row;
+    GtkTreeIter iter;
+    GtkListStore *jtf_store = (GtkListStore*)gtk_tree_view_get_model( GTK_TREE_VIEW(treeview) );
+
+    /* detach model from treeview before fill */
+    g_object_ref(jtf_store);
+    gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), NULL );
+
+    gtk_list_store_clear(jtf_store);
+
+    row = 1;
+    playlist = playlist_get_active();
+
+    PLAYLIST_LOCK(playlist);
+    for (playlist_glist = playlist->entries; playlist_glist;
+         playlist_glist = g_list_next(playlist_glist)) {
+
+        PlaylistEntry *entry = PLAYLIST_ENTRY(playlist_glist->data);
+
+        if (entry->title)
+            desc_buf = g_strdup(entry->title);
+        else {
+            gchar *realfn = NULL;
+            realfn = g_filename_from_uri(entry->filename, NULL, NULL);
+            if (strchr(realfn ? realfn : entry->filename, '/'))
+                desc_buf = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1);
+            else
+                desc_buf = str_assert_utf8(realfn ? realfn : entry->filename);
+            g_free(realfn); realfn = NULL;
+        }
+
+        gtk_list_store_append(GTK_LIST_STORE(jtf_store), &iter);
+        gtk_list_store_set(GTK_LIST_STORE(jtf_store), &iter,
+                           0, row, 1, desc_buf, -1);
+        row++;
+
+        g_free(desc_buf);
+        desc_buf = NULL;
+    }
+    PLAYLIST_UNLOCK(playlist);
+
+    /* attach liststore to treeview */
+    gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(jtf_store));
+    g_object_unref(jtf_store);
+    serial = playlist->serial;
+    return FALSE;
+}
+
+static gboolean
+watchdog(gpointer storage)
+{
+    GtkWidget *widget;
+    Playlist *playlist = playlist_get_active();
+
+    if(serial == playlist->serial)
+        return TRUE;
+
+    widget = g_object_get_data(storage, "widget");
+    ui_jump_to_track_update(widget, storage);
+    return TRUE;
+}
+
+void
+ui_jump_to_track(void)
+{
+    GtkWidget *scrollwin;
+    GtkWidget *vbox, *bbox, *sep;
+    GtkWidget *toggle, *toggle2;
+    GtkWidget *jump, *queue, *close;
+    GtkWidget *rescan;
+    GtkWidget *search_label, *hbox;
+    static GtkWidget *edit;
+
+    GtkWidget *treeview = NULL;
+    GtkListStore *jtf_store;
+
+    GtkCellRenderer *renderer;
+    GtkTreeViewColumn *column;
+
+    gpointer storage;
+
+    if (jump_to_track_win) {
+        gtk_window_present(GTK_WINDOW(jump_to_track_win));
+
+        if(!cfg.remember_jtf_entry)
+            gtk_entry_set_text(GTK_ENTRY(edit), "");
+
+        gtk_widget_grab_focus(edit);
+        gtk_editable_select_region(GTK_EDITABLE(edit), 0, -1);
+        return;
+    }
+
+    #if defined(USE_REGEX_ONIGURUMA)
+    /* set encoding for Oniguruma regex to UTF-8 */
+    reg_set_encoding( REG_POSIX_ENCODING_UTF8 );
+    onig_set_default_syntax( ONIG_SYNTAX_POSIX_BASIC );
+    #endif
+
+    jump_to_track_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_type_hint(GTK_WINDOW(jump_to_track_win),
+                             GDK_WINDOW_TYPE_HINT_DIALOG);
+
+    gtk_window_set_title(GTK_WINDOW(jump_to_track_win), _("Jump to Track"));
+
+    gtk_window_set_position(GTK_WINDOW(jump_to_track_win), GTK_WIN_POS_CENTER);
+    g_signal_connect(jump_to_track_win, "destroy",
+                     G_CALLBACK(gtk_widget_destroyed), &jump_to_track_win);
+
+    gtk_container_border_width(GTK_CONTAINER(jump_to_track_win), 10);
+    gtk_window_set_default_size(GTK_WINDOW(jump_to_track_win), 600, 500);
+
+    vbox = gtk_vbox_new(FALSE, 5);
+    gtk_container_add(GTK_CONTAINER(jump_to_track_win), vbox);
+
+    jtf_store = gtk_list_store_new(2, G_TYPE_UINT, G_TYPE_STRING);
+    treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(jtf_store));
+    g_object_unref(jtf_store);
+
+    gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
+
+    column = gtk_tree_view_column_new();
+    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
+    gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+
+    renderer = gtk_cell_renderer_text_new();
+    gtk_tree_view_column_pack_start(column, renderer, FALSE);
+    gtk_tree_view_column_set_attributes(column, renderer, "text", 0, NULL);
+    gtk_tree_view_column_set_spacing(column, 4);
+
+    renderer = gtk_cell_renderer_text_new();
+    gtk_tree_view_column_pack_start(column, renderer, FALSE);
+    gtk_tree_view_column_set_attributes(column, renderer, "text", 1, NULL);
+    gtk_tree_view_column_set_spacing(column, 4);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+    gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), 1);
+
+    g_signal_connect(treeview, "row-activated",
+                     G_CALLBACK(ui_jump_to_track_jump), NULL);
+
+    hbox = gtk_hbox_new(FALSE, 3);
+    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
+
+    
+    /* filter box */
+    search_label = gtk_label_new(_("Filter: "));
+    gtk_label_set_markup_with_mnemonic(GTK_LABEL(search_label), _("_Filter:"));
+    gtk_box_pack_start(GTK_BOX(hbox), search_label, FALSE, FALSE, 0);
+
+    edit = gtk_entry_new();
+    gtk_entry_set_editable(GTK_ENTRY(edit), TRUE);
+    gtk_label_set_mnemonic_widget(GTK_LABEL(search_label), edit);
+    g_signal_connect(edit, "changed",
+                     G_CALLBACK(ui_jump_to_track_edit_cb), treeview);
+
+    g_signal_connect(edit, "key_press_event",
+                     G_CALLBACK(ui_jump_to_track_edit_keypress_cb), treeview);
+
+    g_signal_connect(jump_to_track_win, "key_press_event",
+                     G_CALLBACK(ui_jump_to_track_keypress_cb), treeview);
+
+    gtk_box_pack_start(GTK_BOX(hbox), edit, TRUE, TRUE, 3);
+
+    /* remember text entry */
+    toggle2 = gtk_check_button_new_with_label(_("Remember"));
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle2),
+                                 cfg.remember_jtf_entry ? TRUE : FALSE);
+    gtk_box_pack_start(GTK_BOX(hbox), toggle2, FALSE, FALSE, 0);
+    g_signal_connect(toggle2, "clicked",
+                     G_CALLBACK(ui_jump_to_track_toggle2_cb),
+                     toggle2);
+
+    /* clear button */
+    rescan = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
+    gtk_box_pack_start(GTK_BOX(hbox), rescan, FALSE, FALSE, 0);
+
+
+    /* pack to container */
+    storage = g_object_new(G_TYPE_OBJECT, NULL);
+    g_object_set_data(storage, "widget", rescan);
+    g_object_set_data(storage, "treeview", treeview);
+    g_object_set_data(storage, "edit", edit);
+
+    g_signal_connect(rescan, "clicked",
+                     G_CALLBACK(ui_jump_to_track_update), storage);
+
+    GTK_WIDGET_SET_FLAGS(rescan, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default(rescan);
+
+    scrollwin = gtk_scrolled_window_new(NULL, NULL);
+    gtk_container_add(GTK_CONTAINER(scrollwin), treeview);
+    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
+                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin),
+                                        GTK_SHADOW_IN);
+    gtk_box_pack_start(GTK_BOX(vbox), scrollwin, TRUE, TRUE, 0);
+
+    sep = gtk_hseparator_new();
+    gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
+
+    bbox = gtk_hbutton_box_new();
+    gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+    gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 4);
+    gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
+
+    /* close dialog toggle */
+    toggle = gtk_check_button_new_with_label(_("Close on Jump"));
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle),
+                                 cfg.close_jtf_dialog ? TRUE : FALSE);
+    gtk_box_pack_start(GTK_BOX(bbox), toggle, FALSE, FALSE, 0);
+    g_signal_connect(toggle, "clicked", 
+                     G_CALLBACK(ui_jump_to_track_toggle_cb),
+                     toggle);
+    
+    queue = gtk_button_new_with_mnemonic(_("_Queue"));
+    gtk_button_set_image(GTK_BUTTON(queue),
+                     gtk_image_new_from_stock(AUD_STOCK_QUEUETOGGLE, GTK_ICON_SIZE_BUTTON));
+    gtk_box_pack_start(GTK_BOX(bbox), queue, FALSE, FALSE, 0);
+    GTK_WIDGET_SET_FLAGS(queue, GTK_CAN_DEFAULT);
+    g_signal_connect(queue, "clicked", 
+                     G_CALLBACK(ui_jump_to_track_queue_cb),
+                     treeview);
+    g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), "changed",
+                     G_CALLBACK(ui_jump_to_track_selection_changed_cb),
+                     queue);
+
+    jump = gtk_button_new_from_stock(GTK_STOCK_JUMP_TO);
+    gtk_box_pack_start(GTK_BOX(bbox), jump, FALSE, FALSE, 0);
+
+    g_signal_connect_swapped(jump, "clicked",
+                             G_CALLBACK(ui_jump_to_track_jump_cb),
+                             treeview);
+
+    GTK_WIDGET_SET_FLAGS(jump, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default(jump);
+
+    close = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+    gtk_box_pack_start(GTK_BOX(bbox), close, FALSE, FALSE, 0);
+    g_signal_connect_swapped(close, "clicked",
+                             G_CALLBACK(gtk_widget_hide),
+                             jump_to_track_win); // just hide --yaz
+    GTK_WIDGET_SET_FLAGS(close, GTK_CAN_DEFAULT);
+
+    g_timeout_add(100, (GSourceFunc)ui_jump_to_track_fill, treeview);
+    g_timeout_add(500, (GSourceFunc)watchdog, storage);
+
+    gtk_widget_show_all(jump_to_track_win);
+    gtk_widget_grab_focus(edit);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/ui_jumptotrack_cache.c	Tue Jul 08 16:36:50 2008 +0200
@@ -0,0 +1,431 @@
+/*  Audacious - Cross-platform multimedia player
+ *  Copyright (C) 2008 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; under version 3 of the License.
+ *
+ *  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, see <http://www.gnu.org/licenses>.
+ *
+ *  The Audacious team does not consider modular code linking to
+ *  Audacious or using our public API to be a derived work.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <assert.h>
+
+#if defined(USE_REGEX_ONIGURUMA)
+  #include <onigposix.h>
+#elif defined(USE_REGEX_PCRE)
+  #include <pcreposix.h>
+#else
+  #include <regex.h>
+#endif
+
+#include "playlist.h"
+#include "strings.h"
+
+#include "ui_jumptotrack_cache.h"
+
+// Struct to keep information about matches from searches.
+typedef struct
+{
+    GArray* track_entries; // JumpToTrackEntry*
+    GArray* normalized_titles; // gchar*
+} KeywordMatches;
+
+/**
+ * Creates an regular expression list usable in searches from search keyword.
+ *
+ * In searches, every regular expression on this list is matched against
+ * the search title and if they all match, the title is declared as
+ * matching one.
+ *
+ * Regular expressions in list are formed by splitting the 'keyword' to words
+ * by splitting the keyword string with space character.
+ */
+static GSList*
+ui_jump_to_track_cache_regex_list_create(const GString* keyword)
+{
+    GSList *regex_list = NULL;
+    gchar **words = NULL;
+    int i = -1;
+    /* Chop the key string into ' '-separated key regex-pattern strings */
+    words = g_strsplit(keyword->str, " ", 0);
+
+    /* create a list of regex using the regex-pattern strings */
+    while ( words[++i] != NULL )
+    {
+        // Ignore empty words.
+        if (words[i][0] == 0) {
+            continue;
+        }
+        regex_t *regex = g_malloc(sizeof(regex_t));
+    #if defined(USE_REGEX_PCRE)
+        if ( regcomp( regex , words[i] , REG_NOSUB | REG_UTF8 ) == 0 )
+    #else
+        if ( regcomp( regex , words[i] , REG_NOSUB ) == 0 )
+    #endif
+            regex_list = g_slist_append( regex_list , regex );
+        else
+            g_free( regex );
+    }
+
+    g_strfreev(words);
+
+    return regex_list;
+}
+
+/**
+ * Frees the regular expression list used in searches.
+ */
+static void
+ui_jump_to_track_cache_regex_list_free(GSList* regex_list)
+{
+    if ( regex_list != NULL )
+    {
+        GSList* regex_list_tmp = regex_list;
+        while ( regex_list != NULL )
+        {
+            regex_t *regex = regex_list->data;
+            regfree( regex );
+            g_free( regex );
+            regex_list = g_slist_next(regex_list);
+        }
+        g_slist_free( regex_list_tmp );
+    }
+}
+
+/**
+ * Checks if 'song' matches all regular expressions in 'regex_list'.
+ */
+static gboolean
+ui_jump_to_track_match(const gchar * song, GSList *regex_list)
+{
+    if ( song == NULL )
+        return FALSE;
+
+    for ( ; regex_list ; regex_list = g_slist_next(regex_list) )
+    {
+        regex_t *regex = regex_list->data;
+        if ( regexec( regex , song , 0 , NULL , 0 ) != 0 )
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+/**
+ * Returns all songs that match 'keyword'.
+ *
+ * Searches are conducted against entries in 'search_space' variable
+ * and after the search, search result is added to 'cache'.
+ *
+ * @param cache The result of this search is added to cache.
+ * @param search_space Entries inside which the search is conducted.
+ * @param keyword Normalized string for searches.
+ */
+static GArray*
+ui_jump_to_track_cache_match_keyword(JumpToTrackCache* cache,
+                                     const KeywordMatches* search_space,
+                                     const GString* keyword)
+{
+    GSList* regex_list = ui_jump_to_track_cache_regex_list_create(keyword);
+    GArray* track_entries = g_array_new(FALSE, FALSE, sizeof(JumpToTrackEntry*));
+    GArray* normalized_titles = g_array_new(FALSE, FALSE, sizeof(gchar*));
+    gboolean match = FALSE;
+    int i = 0;
+
+    for (i = 0; i < search_space->normalized_titles->len; i++)
+    {
+        gchar* title = g_array_index(search_space->normalized_titles, gchar*, i);
+
+        if (regex_list != NULL)
+            match = ui_jump_to_track_match(title, regex_list);
+        else
+            match = TRUE;
+
+        if (match) {
+            JumpToTrackEntry* entry = g_array_index(search_space->track_entries,
+                                                    JumpToTrackEntry*, i);
+            g_array_append_val(track_entries, entry);
+            g_array_append_val(normalized_titles, title);
+        }
+    }
+
+    KeywordMatches* keyword_matches = g_new(KeywordMatches, 1);
+    keyword_matches->track_entries = track_entries;
+    keyword_matches->normalized_titles = normalized_titles;
+
+    g_hash_table_insert(cache->keywords,
+                        GINT_TO_POINTER(g_string_hash(keyword)),
+                        keyword_matches);
+
+    ui_jump_to_track_cache_regex_list_free(regex_list);
+    return track_entries;
+}
+
+/**
+ * Normalizes the search string to be more suitable for searches.
+ *
+ * Basically this does Unicode NFKD normalization to for example match
+ * half-width and full-width characters and case folding mainly to match
+ * upper- and lowercase letters.
+ *
+ * String returned by this function should be freed manually.
+ */
+static gchar *
+normalize_search_string(const gchar* string)
+{
+    gchar* normalized_string = g_utf8_normalize(string, -1, G_NORMALIZE_NFKD);
+    gchar* folded_string = g_utf8_casefold(normalized_string, -1);
+    g_free(normalized_string);
+    return folded_string;
+}
+
+/**
+ * Frees the possibly allocated data in KeywordMatches.
+ */
+static void
+ui_jump_to_track_cache_free_keywordmatch_data(KeywordMatches* match_entry)
+{
+    int i = 0;
+    assert(match_entry->normalized_titles->len == match_entry->track_entries->len);
+    for (i = 0; i < match_entry->normalized_titles->len; i++)
+    {
+        g_free(g_array_index(match_entry->normalized_titles, gchar*, i));
+        g_free(g_array_index(match_entry->track_entries, PlaylistEntry*, i));
+    }
+}
+
+/**
+ * Frees the memory reserved for an search result.
+ */
+static void
+ui_jump_to_track_cache_free_cache_entry(gpointer entry)
+{
+    KeywordMatches* match_entry = (KeywordMatches*)entry;
+    g_array_free(match_entry->track_entries, TRUE);
+    g_array_free(match_entry->normalized_titles, TRUE);
+}
+
+/**
+ * Creates a new song search cache.
+ *
+ * Returned value should be freed with ui_jump_to_track_cache_free() function.
+ */
+JumpToTrackCache*
+ui_jump_to_track_cache_new()
+{
+    JumpToTrackCache* cache = g_new(JumpToTrackCache, 1);
+    cache->playlist_serial = -1;
+    cache->keywords = g_hash_table_new_full(NULL, NULL, NULL,
+                                            ui_jump_to_track_cache_free_cache_entry);
+    return cache;
+}
+
+/**
+ * Clears the search cache.
+ */
+static void
+ui_jump_to_track_cache_clear(JumpToTrackCache* cache)
+{
+    GString* empty_keyword = g_string_new("");
+    gpointer found_keyword = NULL;
+
+    cache->playlist_serial = -1;
+
+    // All normalized titles reside in an empty key "" so we'll free them
+    // first.
+    found_keyword = g_hash_table_lookup(cache->keywords,
+                                        GINT_TO_POINTER(g_string_hash(empty_keyword)));
+    g_string_free(empty_keyword,
+                  TRUE);
+    if (found_keyword != NULL)
+    {
+        KeywordMatches* all_titles = (KeywordMatches*)found_keyword;
+        ui_jump_to_track_cache_free_keywordmatch_data(all_titles);
+    }
+    // Now when all normalized strings are freed, no need to worry about
+    // double frees or memory leaks.
+    g_hash_table_remove_all(cache->keywords);
+}
+
+/**
+ * Initializes the search cache if cache is empty or has wrong playlist.
+ */
+static void
+ui_jump_to_track_cache_init(JumpToTrackCache* cache,
+                            const Playlist* playlist)
+{
+    if (cache->playlist_serial != playlist->serial)
+    {
+        GList* playlist_entries = NULL;
+        GArray* track_entries = g_array_new(FALSE, FALSE, sizeof(JumpToTrackEntry*));
+        GArray* normalized_titles = g_array_new(FALSE, FALSE, sizeof(gchar*));
+        GString* empty_keyword = g_string_new("");
+        gulong song_index = 0;
+
+        // Reset cache state
+        ui_jump_to_track_cache_clear(cache);
+
+        cache->playlist_serial = playlist->serial;
+
+        // Initialize cache with playlist data
+        for (playlist_entries = playlist->entries;
+             playlist_entries;
+             playlist_entries = g_list_next(playlist_entries))
+        {
+            PlaylistEntry* playlist_entry = PLAYLIST_ENTRY(playlist_entries->data);
+
+            gchar *title = NULL;
+            /*we are matching all the path not just the filename or title*/
+
+            /*
+             * FIXME: The search string should be adapted to the
+             * current display setting, e.g. if the user has set it to
+             * "%p - %t" then build the match string like that too, or
+             * even better, search for each of the tags seperatly.
+             *
+             * In any case the string to match should _never_ contain
+             * something the user can't actually see in the playlist.
+             */
+            if (playlist_entry->title) {
+                title = normalize_search_string(playlist_entry->title);
+            } else {
+                gchar *realfn = NULL;
+                realfn = g_filename_from_uri(playlist_entry->filename, NULL, NULL);
+                gchar *tmp_title = str_assert_utf8(realfn ? realfn : playlist_entry->filename);
+                title = normalize_search_string(tmp_title);
+                g_free(tmp_title);
+                g_free(realfn); realfn = NULL;
+            }
+
+            JumpToTrackEntry* search_entry = g_new(JumpToTrackEntry, 1);
+            search_entry->entry = playlist_entry;
+            search_entry->playlist_position = song_index;
+            g_array_append_val(track_entries, search_entry);
+            g_array_append_val(normalized_titles, title);
+            // We need to manually keep track of the current playlist index.
+            song_index++;
+        }
+        // Finally insert all titles into cache into an empty key "" so that
+        // the matchable data has specified place to be.
+        KeywordMatches* keyword_data = g_new(KeywordMatches, 1);
+        keyword_data->track_entries = track_entries;
+        keyword_data->normalized_titles = normalized_titles;
+        g_hash_table_insert(cache->keywords,
+                            GINT_TO_POINTER(g_string_hash(empty_keyword)),
+                            keyword_data);
+        g_string_free(empty_keyword,
+                      TRUE);
+    }
+}
+
+/**
+ * Searches 'keyword' inside 'playlist' by using 'cache' to speed up searching.
+ *
+ * Searches are basically conducted as follows:
+ *
+ * Cache is checked if it has the information about right playlist and
+ * initialized with playlist data if needed.
+ *
+ * Keyword is normalized for searching (Unicode NFKD, case folding)
+ *
+ * Cache is checked if it has keyword and if it has, we can immediately get
+ * the search results and return. If not, searching goes as follows:
+ *
+ * Search for the longest word that is in cache that matches the beginning
+ * of keyword and use the cached matches as base for the current search.
+ * The shortest word that can be matched against is the empty string "", so
+ * there should always be matches in cache.
+ *
+ * After that conduct the search by splitting keyword into words separated
+ * by space and using regular expressions.
+ *
+ * When the keyword is searched, search result is added to cache to
+ * corresponding keyword that can be used as base for new searches.
+ *
+ * The motivation for caching is that to search word 'some cool song' one
+ * has to type following strings that are all searched individually:
+ *
+ * s
+ * so
+ * som
+ * some
+ * some
+ * some c
+ * some co
+ * some coo
+ * some cool
+ * some cool
+ * some cool s
+ * some cool so
+ * some cool son
+ * some cool song
+ *
+ * If the search results are cached in every phase and the result of
+ * the maximum length matching string is used as base for concurrent
+ * searches, we can probably get the matches reduced to some hundreds
+ * after a few letters typed on playlists with thousands of songs and
+ * reduce useless iteration quite a lot.
+ *
+ * Return: GArray of JumpToTrackEntry*
+ */
+const GArray*
+ui_jump_to_track_cache_search(JumpToTrackCache* cache,
+                              const Playlist* playlist,
+                              const gchar* keyword)
+{
+    gchar* normalized_keyword = normalize_search_string(keyword);
+    GString* keyword_string = g_string_new(normalized_keyword);
+    GString* match_string = g_string_new(normalized_keyword);
+    gsize match_string_length = keyword_string->len;
+
+    ui_jump_to_track_cache_init(cache, playlist);
+
+    while (match_string_length >= 0)
+    {
+        gpointer string_ptr =  GINT_TO_POINTER(g_string_hash(match_string));
+        gpointer result_entries = g_hash_table_lookup(cache->keywords,
+                                                      string_ptr);
+        if (result_entries != NULL)
+        {
+            KeywordMatches* matched_entries = (KeywordMatches*)result_entries;
+            // if keyword matches something we have, we'll just return the list
+            // of matches that the keyword has.
+            if (match_string_length == keyword_string->len) {
+                g_string_free(keyword_string, TRUE);
+                g_string_free(match_string, TRUE);
+                g_free(normalized_keyword);
+                return matched_entries->track_entries;
+            }
+
+            // Do normal search by using the result of previous search
+            // as search space.
+            GArray* result = ui_jump_to_track_cache_match_keyword(cache,
+                                                                  matched_entries,
+                                                                  keyword_string);
+            g_string_free(keyword_string, TRUE);
+            g_string_free(match_string, TRUE);
+            g_free(normalized_keyword);
+            return result;
+        }
+        match_string_length--;
+        g_string_set_size(match_string, match_string_length);
+    }
+    // This should never, ever get to this point because there is _always_
+    // the empty string to match against.
+    AUDDBG("One should never get to this point. Something is really wrong with \
+cache->keywords hash table.");
+    assert(FALSE);
+    g_return_val_if_fail(FALSE, (GArray*)-1);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/ui_jumptotrack_cache.h	Tue Jul 08 16:36:50 2008 +0200
@@ -0,0 +1,47 @@
+/*  Audacious - Cross-platform multimedia player
+ *  Copyright (C) 2008  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; under version 3 of the License.
+ *
+ *  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, see <http://www.gnu.org/licenses>.
+ *
+ *  The Audacious team does not consider modular code linking to
+ *  Audacious or using our public API to be a derived work.
+ */
+
+#ifndef AUDACIOUS_UI_JUMPTOTRACK_CACHE_H
+#define AUDACIOUS_UI_JUMPTOTRACK_CACHE_H
+
+#include <glib.h>
+
+#include "playlist.h"
+
+typedef struct _JumpToTrackCache JumpToTrackCache;
+typedef struct _JumpToTrackEntry JumpToTrackEntry;
+
+struct _JumpToTrackCache
+{
+    gulong playlist_serial;
+    GHashTable* keywords;
+};
+
+struct _JumpToTrackEntry
+{
+    PlaylistEntry* entry;
+    // We need to manually keep information about current playlist position.
+    gulong playlist_position;
+};
+
+extern JumpToTrackCache* ui_jump_to_track_cache_new(void);
+extern const GArray* ui_jump_to_track_cache_search(JumpToTrackCache* cache, const Playlist* playlist, const gchar* keyword);
+extern void ui_jump_to_track_cache_free(JumpToTrackCache* cache);
+
+#endif /* AUDACIOUS_UI_JUMPTOTRACK_CACHE_H */
--- a/src/audacious/ui_legacy.c	Tue Jul 08 15:35:48 2008 +0200
+++ b/src/audacious/ui_legacy.c	Tue Jul 08 16:36:50 2008 +0200
@@ -66,7 +66,7 @@
 #include "signals.h"
 #include "legacy/ui_skin.h"
 #include "legacy/ui_equalizer.h"
-#include "legacy/ui_fileinfo.h"
+#include "ui_fileinfo.h"
 #include "legacy/ui_hints.h"
 #include "legacy/ui_main.h"
 #include "legacy/ui_manager.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/ui_urlopener.c	Tue Jul 08 16:36:50 2008 +0200
@@ -0,0 +1,158 @@
+/*  Audacious - Cross-platform multimedia player
+ *  Copyright (C) 2005-2007  Audacious development team
+ *
+ *  Based on BMP:
+ *  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; under version 3 of the License.
+ *
+ *  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, see <http://www.gnu.org/licenses>.
+ *
+ *  The Audacious team does not consider modular code linking to
+ *  Audacious or using our public API to be a derived work.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#define NEED_GLADE
+#include "util.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "platform/smartinclude.h"
+#include <errno.h>
+
+#include "input.h"
+#include "main.h"
+#include "playback.h"
+#include "strings.h"
+
+#ifdef USE_CHARDET
+#include "../libguess/libguess.h"
+#  ifdef HAVE_UDET
+#    include <libudet_c.h>
+#  endif
+#endif
+
+#define URL_HISTORY_MAX_SIZE 30
+
+static void
+util_add_url_callback(GtkWidget * widget,
+                      GtkEntry * entry)
+{
+    const gchar *text;
+
+    text = gtk_entry_get_text(entry);
+    if (g_list_find_custom(cfg.url_history, text, (GCompareFunc) strcasecmp))
+        return;
+
+    cfg.url_history = g_list_prepend(cfg.url_history, g_strdup(text));
+
+    while (g_list_length(cfg.url_history) > URL_HISTORY_MAX_SIZE) {
+        GList *node = g_list_last(cfg.url_history);
+        g_free(node->data);
+        cfg.url_history = g_list_delete_link(cfg.url_history, node);
+    }
+}
+
+GtkWidget *
+util_add_url_dialog_new(const gchar * caption, GCallback ok_func,
+                        GCallback enqueue_func)
+{
+    GtkWidget *win, *vbox, *bbox, *cancel, *enqueue, *ok, *combo, *entry, 
+              *label;
+    GList *url;
+
+    win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_title(GTK_WINDOW(win), _("Add/Open URL Dialog"));
+    gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DIALOG);
+    gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);
+    gtk_window_set_default_size(GTK_WINDOW(win), 400, -1);
+    gtk_container_set_border_width(GTK_CONTAINER(win), 12);
+
+    vbox = gtk_vbox_new(FALSE, 10);
+    gtk_container_add(GTK_CONTAINER(win), vbox);
+
+    label = gtk_label_new(caption);
+    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+
+    combo = gtk_combo_box_entry_new_text();
+    gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0);
+
+    entry = gtk_bin_get_child(GTK_BIN(combo));
+    gtk_window_set_focus(GTK_WINDOW(win), entry);
+    gtk_entry_set_text(GTK_ENTRY(entry), "");
+
+    for (url = cfg.url_history; url; url = g_list_next(url))
+        gtk_combo_box_append_text(GTK_COMBO_BOX(combo),
+                                  (const gchar *) url->data);
+
+    g_signal_connect(entry, "activate",
+                     G_CALLBACK(util_add_url_callback),
+                     entry);
+    g_signal_connect(entry, "activate",
+                     G_CALLBACK(ok_func),
+                     entry);
+    g_signal_connect_swapped(entry, "activate",
+                             G_CALLBACK(gtk_widget_destroy),
+                             win);
+
+    bbox = gtk_hbutton_box_new();
+    gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+    gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
+    gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
+
+    cancel = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+    gtk_box_pack_start(GTK_BOX(bbox), cancel, FALSE, FALSE, 0);
+    gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(bbox), cancel, TRUE);
+
+    g_signal_connect_swapped(cancel, "clicked",
+                             G_CALLBACK(gtk_widget_destroy),
+                             win);
+
+    enqueue = gtk_button_new_from_stock(GTK_STOCK_ADD);
+    gtk_box_pack_start(GTK_BOX(bbox), enqueue, FALSE, FALSE, 0);
+
+    g_signal_connect(enqueue, "clicked",
+                     G_CALLBACK(util_add_url_callback),
+                     entry);
+    g_signal_connect(enqueue, "clicked",
+                     G_CALLBACK(enqueue_func),
+                     entry);
+    g_signal_connect_swapped(enqueue, "clicked",
+                             G_CALLBACK(gtk_widget_destroy),
+                             win);
+
+    ok = gtk_button_new_from_stock(GTK_STOCK_OPEN);
+    g_signal_connect(ok, "clicked",
+                     G_CALLBACK(util_add_url_callback), entry);
+    g_signal_connect(ok, "clicked",
+                     G_CALLBACK(ok_func), entry);
+    g_signal_connect_swapped(ok, "clicked",
+                             G_CALLBACK(gtk_widget_destroy),
+                             win);
+    gtk_box_pack_start(GTK_BOX(bbox), ok, FALSE, FALSE, 0);
+
+    gtk_widget_show_all(vbox);
+
+    return win;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/ui_urlopener.h	Tue Jul 08 16:36:50 2008 +0200
@@ -0,0 +1,45 @@
+/*  Audacious - Cross-platform multimedia player
+ *  Copyright (C) 2005-2007  Audacious development team
+ *
+ *  Based on BMP:
+ *  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; under version 3 of the License.
+ *
+ *  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, see <http://www.gnu.org/licenses>.
+ *
+ *  The Audacious team does not consider modular code linking to
+ *  Audacious or using our public API to be a derived work.
+ */
+
+#ifndef AUDACIOUS_UI_URLOPENER_H
+#define AUDACIOUS_UI_URLOPENER_H
+
+#ifdef _AUDACIOUS_CORE
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+#endif
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+GtkWidget *util_add_url_dialog_new(const gchar * caption, GCallback ok_func,
+                                   GCallback enqueue_func);
+
+G_END_DECLS
+
+#endif /* AUDACIOUS_UI_URLOPENER_H */