/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: prefsdialog.cpp,v 1.18.2.10 2004/10/27 16:59:17 nhart Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

/* This function implements hmw_preferences. It contains a number of
   unprefixed supporting functions.
 */

#include "hxcom.h"
#include "hxwintyp.h"
#include "hxcore.h"

#include <gtk/gtk.h>

#include <stdlib.h>
#include <string.h>

#include "prefsdialog.h"

#include "hxplayer.h"
#include "hxgprefs.h"
#include "hxgvalue.h"
#include "commonapp.h"
#include "mainapp.h"
#include "mimetypes.h"

#include "hxplayer-i18n.h"

/* Helix headers (for clearing clip cache) */
#include "hxcom.h"
#include "hxwintyp.h"
#include "hxplugn.h"
#include "hxcore.h"
#include "hxflche.h"

// As seen in the mac player...
#define BANDWIDTH_10_MBPS    10485800 
#define BANDWIDTH_1_5_MBPS   1544000
#define BANDWIDTH_768_KBPS   786432
#define BANDWIDTH_512_KBPS   524300
#define BANDWIDTH_384_KBPS   393216
#define BANDWIDTH_256_KBPS   262000
#define BANDWIDTH_128_KBPS   131000
#define BANDWIDTH_64_KBPS    65536
#define BANDWIDTH_56_KBPS    57600
#define BANDWIDTH_28_8_KBPS  28800
#define BANDWIDTH_14_4_KBPS  14400

extern "C"
{
    void hpd_configure_rtsp(GtkWidget* widget);
    void hpd_configure_pna(GtkWidget* widget);
    void hpd_media_files_browse(GtkWidget* widget);
    void hpd_web_browser_browse(GtkWidget* widget);
    void hpd_clear_recent_clips(GtkWidget* widget);    
    void hpd_auto_transport_toggled(GtkToggleButton *togglebutton);
    void hpd_empty_clip_cache(GtkWidget *widget);
    void hpd_bandwidth_changed(GtkWidget* max_bandwidth, gpointer);
}

typedef enum
{
    HX_TRANSPORT_RTSP,
    HX_TRANSPORT_PNA
} HXTransportType;

struct _HXPrefsControlInfo;
typedef struct _HXPrefsControlInfo HXPrefsControlInfo;
typedef struct _HXPrefsDialog HXPrefsDialog;

typedef void(*prefs_read_func)(GladeXML* prefs_dialog, const HXPrefsControlInfo* info, const HXPrefsDialog* dialog_info);
typedef void(*prefs_write_func)(GladeXML* prefs_dialog, const HXPrefsControlInfo* info, const HXPrefsDialog* dialog_info);

/* Per-control information */
typedef struct _HXPrefsControlInfo
{
    const gchar* pref_name;
    const gchar* default_value;
    const gchar* widget_name;
    prefs_read_func read_func;
    prefs_write_func write_func;
    
} HXPrefsControlInfo;

/* Per-prefs dialog information */
typedef struct _HXPrefsDialog
{
    HXMainWindow* window; /* Can be NULL if we're being
                             called from the embedded
                             player. */
    HXMimeTypesDialogInfo* mime_types_dialog_info;
    GladeXML* xml;
} HXPrefsDialog;


/* These lang id's are for SMIL, and shouldn't affect
   the whole gettext system. Some id's are commented out in
   the mac player's version of this, so I'm reluctantly leaving them
   commented out here, until someone can tell me why, as it might be
   some US legal thing. */

static const struct
{
    const gchar* lang_code;
    const gchar* lang_name;
} g_lang_id_name_map[] =
{
    { "af",    N_("Afrikaans") },
    { "sq",    N_("Albanian") },
    { "ar",    N_("Arabic") },
    { "ar-dz", N_("Arabic (Algeria)") },
    { "ar-bh", N_("Arabic (Bahrain)") },
    { "ar-eg", N_("Arabic (Egypt)") },
/*  { "ar-iq", N_("Arabic (Iraq)") }, */
    { "ar-jo", N_("Arabic (Jordan)") },
    { "ar-kw", N_("Arabic (Kuwait)") },
    { "ar-lb", N_("Arabic (Lebanon)") },
/*  { "ar-ly", N_("Arabic (Libya)") }, */
    { "ar-ma", N_("Arabic (Morocco)") },
    { "ar-om", N_("Arabic (Oman)") },
    { "ar-qa", N_("Arabic (Qatar)") },
    { "ar-sa", N_("Arabic (Saudi Arabia)") },
/*  { "ar-se", N_("Arabic (Syria)") }, */
    { "ar-tn", N_("Arabic (Tunisia)") },
    { "ar-ae", N_("Arabic (U.A.E.)") },
    { "ar-ye", N_("Arabic (Yemen)") },
    { "hy",    N_("Armenian") },
    { "as",    N_("Assamese") },
    { "az",    N_("Azeri") },
/*  { "az",    N_("Azeri (Cyrillic)") }, */
/*  { "az",    N_("Azeri (Latin)") }, */
    { "eu",    N_("Basque") },
    { "be",    N_("Belarusian") },
    { "bn",    N_("Bengali") },
    { "bg",    N_("Bulgarian") },
    { "ca",    N_("Catalan") },
    { "zh",    N_("Chinese") },
    { "zh-cn", N_("Chinese (China)") },
    { "zh-hk", N_("Chinese (Hong Kong SAR)") },
    { "zh-mo", N_("Chinese (Macau SAR)") },
    { "zh-sg", N_("Chinese (Singapore)") },
    { "zh-tw", N_("Chinese (Taiwan)") },
    { "hr",    N_("Croatian") },
    { "cs",    N_("Czech") },
    { "da",    N_("Danish") },
    { "nl-be", N_("Dutch (Belgium)") },
    { "nl",    N_("Dutch (Netherlands)") },
    { "en",    N_("English") },
    { "en-au", N_("English (Australia)") },
    { "en-bz", N_("English (Belize)") },
    { "en-ca", N_("English (Canada)") },
/*  { "en-cb", N_("English (Caribbean)") XXXSEH: Listed as en in WIN IE 6, but en-cb in Mac IE 5.1? */
    { "en-ie", N_("English (Ireland)") },
    { "en-jm", N_("English (Jamaica)") },
    { "en-nz", N_("English (New Zealand)") },
    { "en-ph", N_("English (Philippines)") },
    { "en-za", N_("English (South Africa)") },
    { "en-tt", N_("English (Trinidad)") },
    { "en-gb", N_("English (United Kingdom)") },
    { "en-us", N_("English (United States)") },
    { "en-zw", N_("English (Zimbabwe)") },
    { "et",    N_("Estonian") },
    { "fo",    N_("Faeroese") },
    { "fa",    N_("Farsi") },
    { "fi",    N_("Finnish") },
    { "fr-be", N_("French (Belgium)") },
    { "fr-ca", N_("French (Canada)") },
    { "fr",    N_("French (France)") },
    { "fr-lu", N_("French (Luxembourg)") },
    { "fr-mc", N_("French (Monaco)") },
    { "fr-ch", N_("French (Switzerland)") },
    { "mk",    N_("FYRO Macedonian") },
    { "ka",    N_("Georgian") },
    { "de-at", N_("German (Austria)") },
    { "de",    N_("German (Germany)") },
    { "de-li", N_("German (Liechtenstein)") },
    { "de-lu", N_("German (Luxembourg)") },
    { "de-ch", N_("German (Switzerland)") },
    { "el",    N_("Greek") },
    { "gu",    N_("Gujarati") },
    { "he",    N_("Hebrew") },
    { "hi",    N_("Hindi") },
    { "hu",    N_("Hungarian") },
    { "is",    N_("Icelandic") },
    { "id",    N_("Indonesian") }, /* Mac IE 5.1 has it as 'in' */
    { "it",    N_("Italian (Italy)") },
    { "it-ch", N_("Italian (Switzerland)") },
    { "ja",    N_("Japanese") },
    { "kn",    N_("Kannada") },
    { "kk",    N_("Kazakh") },
    { "ko",    N_("Korean") },
/*  { "ko-jo", N_("Korean (Johab)") */
    { "lv",    N_("Latvian") },
    { "lt",    N_("Lithuanian") },
    { "ms",    N_("Malay") },
/*  { "ms",    N_("Malay (Brunei)") },
    { "ms",    N_("Malay (Malaysia)")  */
    { "ml",    N_("Malayalam") },
    { "mr",    N_("Marathi") },
    { "ne",    N_("Nepali (India)") },
    { "no",    N_("Norwegian") },
    { "nb-no", N_("Norwegian (Bokmal)") },
    { "nn-no", N_("Norweigan (Nynorsk)") },
    { "or",    N_("Oriya") },
    { "pl",    N_("Polish") },
    { "pt-br", N_("Portuguese (Brazil)") },
    { "pt",    N_("Portuguese (Portugal)") },
    { "pa",    N_("Punjabi") },
    { "ro",    N_("Romanian") },
    { "ru",    N_("Russian") },
    { "sa",    N_("Sanskrit") },
    { "sr",    N_("Serbian") },
/*  { "sr",    N_("Serbian (Cyrillic)") },
    { "sr",    N_("Serbian (Latin)") */
    { "sk",    N_("Slovak") },
    { "sl",    N_("Slovenian") },
    { "es",    N_("Spanish") },
    { "es-ar", N_("Spanish (Argentina)") },
    { "es-bo", N_("Spanish (Bolivia)") },
    { "es-cl", N_("Spanish (Chile)") },
    { "es-co", N_("Spanish (Colombia)") },
    { "es-cr", N_("Spanish (Costa Rica)") },
    { "es-do", N_("Spanish (Dominican Republic)") },
    { "es-ec", N_("Spanish (Ecuador)") },
    { "es-sv", N_("Spanish (El Salvador)") },
    { "es-gt", N_("Spanish (Guatemala)") },
    { "es-hn", N_("Spanish (Honduras)") },
    { "es-mx", N_("Spanish (Mexico)") },
/*  { "es-mn", N_("Spanish (Modern)") */
    { "es-ni", N_("Spanish (Nicaragua)") },
    { "es-pa", N_("Spanish (Panama)") },
    { "es-py", N_("Spanish (Paraguay)") },
    { "es-pe", N_("Spanish (Peru)") },
    { "es-pr", N_("Spanish (Puerto Rico)") },
    { "es-uy", N_("Spanish (Uruguay)") },
    { "es-ve", N_("Spanish (Venezuela)") },
    { "sw",    N_("Swahili") },
    { "sv",    N_("Swedish") },
    { "sv-fi", N_("Swedish (Finland)") },
    { "ta",    N_("Tamil") },
    { "tt",    N_("Tatar") },
    { "te",    N_("Telugu") },
    { "th",    N_("Thai") },
    { "tr",    N_("Turkish") },
    { "uk",    N_("Ukrainian") },
    { "ur",    N_("Urdu") },
    { "uz",    N_("Uzbek") },
/*  { "uz",    N_("Uzbek (Cyrillic)") },
    { "uz",    N_("Uzbek (Latin)") */
    { "vi",    N_("Vietnamese") }    
};

void
hpd_bandwidth_changed(GtkWidget* widget, gpointer)
{
    /* Clamp normal bandwidth to max bandwidth  */
    GtkWidget* toplevel;
    GladeXML* xml;
    GtkWidget* normal_bandwidth;
    GtkWidget* max_bandwidth;
    gint normal_bandwidth_selection;
    gint max_bandwidth_selection;

    toplevel = gtk_widget_get_toplevel(widget);
    xml = (GladeXML*)g_object_get_data(G_OBJECT (toplevel), "hxprefs_xml");
    
    if(xml)
    {
        normal_bandwidth = glade_xml_get_widget(xml, "hpd_normal_bandwidth");
        max_bandwidth = glade_xml_get_widget(xml, "hpd_max_bandwidth");

        max_bandwidth_selection = gtk_option_menu_get_history(GTK_OPTION_MENU(max_bandwidth));
        normal_bandwidth_selection = gtk_option_menu_get_history(GTK_OPTION_MENU(normal_bandwidth));

        if(normal_bandwidth_selection < max_bandwidth_selection)
        {
            if(widget == max_bandwidth)
            {
                gtk_option_menu_set_history(GTK_OPTION_MENU(normal_bandwidth),
                                            max_bandwidth_selection);
            }
            else
            {
                gtk_option_menu_set_history(GTK_OPTION_MENU(max_bandwidth),
                                            normal_bandwidth_selection);
            }                
        }
    }
}

static gint
hpd_compare(gpointer s1, gpointer s2)
{
    return (g_utf8_collate((char*)s1, (char*)s2));
}

static void
hpd_populate_lang_combo(GtkCombo* combo)
{
    guint i;
    GList* items = NULL;
    
    for(i = 0; i < sizeof(g_lang_id_name_map) / sizeof(*g_lang_id_name_map); i++)
    {
        items = g_list_insert_sorted(items, (gpointer)gettext(g_lang_id_name_map[i].lang_name), (GCompareFunc)hpd_compare);
    }

    gtk_combo_set_popdown_strings(GTK_COMBO(combo), items);
}

static const gchar*
hpd_get_lang_code_from_name(const gchar* lang_name)
{
    guint i;
    
    for(i = 0; i < sizeof(g_lang_id_name_map) / sizeof(*g_lang_id_name_map); i++)
    {
        if(strcmp(lang_name, gettext(g_lang_id_name_map[i].lang_name)) == 0)
        {
            return g_lang_id_name_map[i].lang_code;
        }
    }

    return NULL;
}

static const gchar*
hpd_get_lang_name_from_code(const gchar* lang_code)
{
    guint i;
    
    for(i = 0; i < sizeof(g_lang_id_name_map) / sizeof(*g_lang_id_name_map); i++)
    {
        if(strcmp(lang_code, g_lang_id_name_map[i].lang_code) == 0)
        {
            return gettext(g_lang_id_name_map[i].lang_name);
        }
    }

    return NULL;
}


static guint
bandwidth_bytes_per_second_to_option(guint bandwidth)
{
    guint option;
    
    if(bandwidth >= BANDWIDTH_10_MBPS)
    {
        option = 0;
    }
    else if(bandwidth >= BANDWIDTH_1_5_MBPS)
    {
        option = 1;
    }
    else if(bandwidth >= BANDWIDTH_768_KBPS)
    {
        option = 2;
    }
    else if(bandwidth >= BANDWIDTH_512_KBPS)
    {
        option = 3;
    }
    else if(bandwidth >= BANDWIDTH_384_KBPS)
    {
        option = 4;
    }
    else if(bandwidth >= BANDWIDTH_256_KBPS)
    {
        option = 5;
    }
    else if(bandwidth >= BANDWIDTH_128_KBPS)
    {
        option = 6;
    }
    else if(bandwidth >= BANDWIDTH_64_KBPS)
    {
        option = 7;
    }
    else if(bandwidth >= BANDWIDTH_56_KBPS)
    {
        option = 8;
    }
    else if(bandwidth >= BANDWIDTH_28_8_KBPS)
    {
        option = 9;
    }
    else
    {
        option = 10;
    }

    return option;
}

static guint
bandwidth_option_to_bytes_per_second(guint option)
{
    guint bandwidth;
    
    switch(option)
    {
        case 0:
            bandwidth = BANDWIDTH_10_MBPS;
            break;
            
        case 1:
            bandwidth = BANDWIDTH_1_5_MBPS;
            break;

        case 2:
            bandwidth = BANDWIDTH_768_KBPS;
            break;
            
        case 3:
            bandwidth = BANDWIDTH_512_KBPS;
            break;
            
        case 4:
            bandwidth = BANDWIDTH_384_KBPS;
            break;

        case 5:
            bandwidth = BANDWIDTH_256_KBPS;
            break;

        case 6:
            bandwidth = BANDWIDTH_128_KBPS;
            break;

        case 7:
            bandwidth = BANDWIDTH_64_KBPS;
            break;
            
        case 8:
            bandwidth = BANDWIDTH_56_KBPS;
            break;

        case 9:
            bandwidth = BANDWIDTH_28_8_KBPS;

        case 10:
            bandwidth = BANDWIDTH_14_4_KBPS;
            break;
            
        default:
            g_warning("Unknown bandwidth option");
            bandwidth = BANDWIDTH_10_MBPS;
    }

    return bandwidth;
}

static void
prefs_bandwidth_option_menu_read(GladeXML* prefs_dialog,
                                 const HXPrefsControlInfo* info,
                                 const HXPrefsDialog*)
{
    HXEntry* entry;
    HXValue* value;
    guint bandwidth;
    guint bandwidth_option;
    GtkWidget* option_menu;

    option_menu = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(option_menu != NULL);
    
    entry = hx_prefs_get_entry(info->pref_name);
    if(entry)
    {
        value = hx_entry_get_value(entry);
        bandwidth = atoi(hx_value_get_string(value));
    }
    else
    {
        bandwidth = atoi(info->default_value);
    }
    bandwidth_option = bandwidth_bytes_per_second_to_option(bandwidth);
    gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), bandwidth_option);
}

static void
prefs_bandwidth_option_menu_write(GladeXML* prefs_dialog,
                                  const HXPrefsControlInfo* info,
                                  const HXPrefsDialog*)
{
    gchar* str;
    
    guint bandwidth_option;
    guint bandwidth;
    GtkWidget* option_menu;
    HXValue* value;

    option_menu = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(option_menu != NULL);

    bandwidth_option = gtk_option_menu_get_history(GTK_OPTION_MENU(option_menu));
    bandwidth = bandwidth_option_to_bytes_per_second(bandwidth_option);
    str = g_strdup_printf("%d", bandwidth);

    value = hx_value_new(HX_VALUE_STRING);
    hx_value_set_string_nocopy(value, str);
    
    hx_prefs_set_entry(info->pref_name, value);

    g_free(str);
}

static void
prefs_checkbutton_read(GladeXML* prefs_dialog,
                       const HXPrefsControlInfo* info,
                       const HXPrefsDialog*)
{
    HXEntry* entry;
    HXValue* value;
    gboolean checked;
    GtkWidget* checkbutton;

    checkbutton = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(checkbutton != NULL);
    
    entry = hx_prefs_get_entry(info->pref_name);
    if(entry)
    {
        value = hx_entry_get_value(entry);
        checked = atoi(hx_value_get_string(value));
    }
    else
    {
        checked = atoi(info->default_value);
    }

    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), checked);
}

static void
prefs_checkbutton_write_window(GladeXML* prefs_dialog,
                               const HXPrefsControlInfo* info,
                               const HXPrefsDialog* dialog_info)
{
    GtkWidget* checkbutton;
    GValue value;
    gboolean is_active;
        
    checkbutton = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(checkbutton != NULL);

    is_active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton));

    memset(&value, 0, sizeof(value));
    g_value_init(&value, G_TYPE_BOOLEAN);
    g_value_set_boolean(&value, is_active);

    hxwindow_set_property(dialog_info->window, info->pref_name, &value);
    g_value_unset(&value);
}

static void
prefs_checkbutton_read_window(GladeXML* prefs_dialog,
                              const HXPrefsControlInfo* info,
                              const HXPrefsDialog* dialog_info)
{
    gboolean checked;
    GtkWidget* checkbutton;
    GValue value;
    
    checkbutton = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(checkbutton != NULL);

    memset(&value, 0, sizeof(value));
    if(hxwindow_get_property(dialog_info->window, info->pref_name, &value))
    {
        checked = g_value_get_boolean(&value);
    }
    else
    {
        checked = (info->default_value[0] == '1');
    }
    
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), checked);
}

static void
prefs_checkbutton_write(GladeXML* prefs_dialog,
                        const HXPrefsControlInfo* info,
                        const HXPrefsDialog*)
{
    gchar* str;
    
    GtkWidget* checkbutton;
    HXValue* value;
    gboolean is_active;

    checkbutton = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(checkbutton != NULL);

    is_active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton));
    str = g_strdup_printf("%d", is_active? 1: 0);

    value = hx_value_new(HX_VALUE_STRING);
    hx_value_set_string_nocopy(value, str);
    
    hx_prefs_set_entry(info->pref_name, value);

    g_free(str);
}


static void
prefs_entry_read(GladeXML* prefs_dialog,
                 const HXPrefsControlInfo* info,
                 const HXPrefsDialog*)
{
    HXEntry* entry;
    HXValue* value;
    const gchar* str;
    GtkWidget* widget;

    widget = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(widget != NULL);
    
    entry = hx_prefs_get_entry(info->pref_name);
    if(entry)
    {
        value = hx_entry_get_value(entry);
        str = hx_value_get_string(value);
    }
    else
    {
        str = info->default_value;
    }

    gtk_entry_set_text(GTK_ENTRY(widget), str);
}

static void
prefs_entry_write(GladeXML* prefs_dialog,
                  const HXPrefsControlInfo* info,
                  const HXPrefsDialog*)
{
    const gchar* str;
    
    GtkWidget* entry;
    HXValue* value;

    entry = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(entry != NULL);

    str = gtk_entry_get_text(GTK_ENTRY(entry));

    value = hx_value_new(HX_VALUE_STRING);
    hx_value_set_string_nocopy(value, g_strdup(str));
    
    hx_prefs_set_entry(info->pref_name, value);
}

static void
prefs_entry_write_window(GladeXML* prefs_dialog,
                         const HXPrefsControlInfo* info,
                         const HXPrefsDialog* dialog_info)
{
    const gchar* str;
    GtkWidget* entry;
    GValue value;

    entry = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(entry != NULL);

    str = gtk_entry_get_text(GTK_ENTRY(entry));
    if(!str)
    {
        str = info->default_value;
    }
    
    memset(&value, 0, sizeof(value));
    g_value_init(&value, G_TYPE_STRING);
    g_value_set_string(&value, str);

    hxwindow_set_property(dialog_info->window, info->pref_name, &value);
    g_value_unset(&value);
}

static void
prefs_entry_read_window(GladeXML* prefs_dialog,
                        const HXPrefsControlInfo* info,
                        const HXPrefsDialog* dialog_info)
{
    GtkWidget* entry;
    GValue value;
    const gchar* str = NULL;

    entry = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(entry != NULL);

    memset(&value, 0, sizeof(value));
    
    if(hxwindow_get_property(dialog_info->window, info->pref_name, &value))
    {
        str = g_value_get_string(&value);
    }

    if(!str)
    {
        str = info->default_value;
    }
    
    gtk_entry_set_text(GTK_ENTRY(entry), str);
}

static void
prefs_scale_read(GladeXML* prefs_dialog,
                 const HXPrefsControlInfo* info,
                 const HXPrefsDialog*)
{
    HXEntry* entry;
    HXValue* value;
    const gchar* str;
    GtkWidget* widget;
    gint pos;

    widget = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(widget != NULL);
    
    entry = hx_prefs_get_entry(info->pref_name);
    if(entry)
    {
        value = hx_entry_get_value(entry);
        str = hx_value_get_string(value);
        pos = atoi(str);
    }
    else
    {
        pos = atoi(info->default_value);
    }
    
    gtk_range_set_value(GTK_RANGE(widget), (gdouble)pos);
}

static void
prefs_scale_write(GladeXML* prefs_dialog,
                  const HXPrefsControlInfo* info,
                  const HXPrefsDialog*)
{
    gchar* str;
    
    GtkWidget* widget;
    HXValue* value;
    gdouble pos;
    
    widget = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(widget != NULL);

    pos = gtk_range_get_value(GTK_RANGE(widget));
    str = g_strdup_printf("%d", (gint)pos);
    
    value = hx_value_new(HX_VALUE_STRING);
    hx_value_set_string_nocopy(value, g_strdup(str));
    
    hx_prefs_set_entry(info->pref_name, value);
    g_free(str);
}

static void
prefs_sampling_rate_read(GladeXML* prefs_dialog,
                         const HXPrefsControlInfo* info,
                         const HXPrefsDialog*)
{
    HXEntry* entry;
    HXValue* value;
    gboolean checked;
    GtkWidget* checkbutton;

    checkbutton = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(checkbutton != NULL);
    
    entry = hx_prefs_get_entry(info->pref_name);
    if(entry)
    {
        value = hx_entry_get_value(entry);
        checked = strcmp(hx_value_get_string(value), "11025") == 0;
    }
    else
    {
        checked = FALSE;
    }

    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), checked);
}

static void
prefs_sampling_rate_write(GladeXML* prefs_dialog,
                          const HXPrefsControlInfo* info,
                          const HXPrefsDialog*)
{
    GtkWidget* checkbutton;
    HXValue* value;
    gboolean is_active;

    checkbutton = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(checkbutton != NULL);

    is_active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton));

    if(is_active)
    {
        value = hx_value_new(HX_VALUE_STRING);
        hx_value_set_string_nocopy(value, "11025");
        hx_prefs_set_entry(info->pref_name, value);
    }
    else
    {
        hx_prefs_set_entry(info->pref_name, NULL);
    }
}

static void
prefs_bits_per_sample_read(GladeXML* prefs_dialog,
                           const HXPrefsControlInfo* info,
                           const HXPrefsDialog*)
{
    HXEntry* entry;
    HXValue* value;
    gboolean checked;
    GtkWidget* checkbutton;

    checkbutton = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(checkbutton != NULL);
    
    entry = hx_prefs_get_entry(info->pref_name);
    if(entry)
    {
        value = hx_entry_get_value(entry);
        checked = strcmp(hx_value_get_string(value), "8") == 0;
    }
    else
    {
        checked = FALSE;
    }

    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), checked);
}

static void
prefs_bits_per_sample_write(GladeXML* prefs_dialog,
                            const HXPrefsControlInfo* info,
                            const HXPrefsDialog*)
{
    GtkWidget* checkbutton;
    HXValue* value;
    gboolean is_active;

    checkbutton = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(checkbutton != NULL);

    is_active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton));

    if(is_active)
    {
        value = hx_value_new(HX_VALUE_STRING);
        hx_value_set_string_nocopy(value, "8");
        hx_prefs_set_entry(info->pref_name, value);
    }
    else
    {
        hx_prefs_set_entry(info->pref_name, NULL);
    }
}

static void
prefs_content_language_read(GladeXML* prefs_dialog,
                            const HXPrefsControlInfo* info,
                            const HXPrefsDialog*)
{
    HXEntry* entry;
    HXValue* value;
    const gchar* lang_name;
    GtkWidget* widget;
    GtkWidget* entry_widget;

    widget = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(widget != NULL);
    
    entry = hx_prefs_get_entry(info->pref_name);
    if(entry)
    {
        const gchar* lang_code;
        
        value = hx_entry_get_value(entry);
        lang_code = hx_value_get_string(value);        
        lang_name = hpd_get_lang_name_from_code(lang_code);
    }
    else
    {
        lang_name = hpd_get_lang_name_from_code(info->default_value);
    }

    entry_widget = GTK_COMBO(widget)->entry;
    gtk_entry_set_text(GTK_ENTRY(entry_widget), lang_name);
}

static void
prefs_content_language_write(GladeXML* prefs_dialog,
                             const HXPrefsControlInfo* info,
                             const HXPrefsDialog*)
{
    const gchar* lang_name = NULL;
    const gchar* lang_code = NULL;    
    GtkWidget* combo;
    GtkWidget* entry;
    HXValue* value;
    

    combo = glade_xml_get_widget(prefs_dialog, info->widget_name);
    g_return_if_fail(combo != NULL);

    entry = GTK_COMBO(combo)->entry;
    lang_name = gtk_entry_get_text(GTK_ENTRY(entry));
    if(lang_name)
    {
        lang_code = hpd_get_lang_code_from_name(lang_name);
    }

    if(!lang_code)
    {
        lang_code = info->default_value;        
    }
    
    value = hx_value_new(HX_VALUE_STRING);
    hx_value_set_string_nocopy(value, g_strdup(lang_code));    
    hx_prefs_set_entry(info->pref_name, value);    
}

static void
prefs_overdub_caption_read(GladeXML* prefs_dialog,
                           const HXPrefsControlInfo* info,
                           const HXPrefsDialog*)
{
    HXEntry* entry;
    HXValue* value;
    const gchar* str;
    
    entry = hx_prefs_get_entry(info->pref_name);
    if(entry)
    {
        value = hx_entry_get_value(entry);
        str = hx_value_get_string(value);
    }
    else
    {
        str = info->default_value;
    }
    
    if(strcmp(str, "caption") == 0)
    {
        GtkWidget* show_subtitles;
        show_subtitles = glade_xml_get_widget(prefs_dialog, "hpd_show_subtitles");
        g_return_if_fail(show_subtitles != NULL);

        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_subtitles),
                                     TRUE);
    }
    else if(strcmp(str, "overdub") == 0)
    {
        GtkWidget* play_overdub;
        play_overdub = glade_xml_get_widget(prefs_dialog, "hpd_play_overdub_track");
        g_return_if_fail(play_overdub != NULL);
        
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_overdub),
                                     TRUE);
    }
    else
    {
        GtkWidget* no_subtitles_overdub;
        no_subtitles_overdub = glade_xml_get_widget(prefs_dialog, "hpd_no_subtitles_overdub");
        g_return_if_fail(no_subtitles_overdub != NULL);

        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(no_subtitles_overdub),
                                     TRUE);
    }
}

static void
prefs_overdub_caption_write(GladeXML* prefs_dialog,
                            const HXPrefsControlInfo* info,
                            const HXPrefsDialog*)
{
    GtkWidget* no_subtitles_overdub;
    GtkWidget* show_subtitles;
    GtkWidget* play_overdub;
    HXValue* value;
    const gchar* str_value;
    
    no_subtitles_overdub = glade_xml_get_widget(prefs_dialog, "hpd_no_subtitles_overdub");
    g_return_if_fail(no_subtitles_overdub != NULL);

    show_subtitles = glade_xml_get_widget(prefs_dialog, "hpd_show_subtitles");
    g_return_if_fail(show_subtitles != NULL);

    play_overdub = glade_xml_get_widget(prefs_dialog, "hpd_play_overdub_track");
    g_return_if_fail(play_overdub != NULL);

    if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(no_subtitles_overdub)))
    {
        str_value = "none";
    }
    else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(show_subtitles)))
    {
        str_value = "caption";
    }
    else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(play_overdub)))
    {
        str_value = "overdub";        
    }
    else
    {
        str_value = info->default_value;
    }
    
    value = hx_value_new(HX_VALUE_STRING);
    hx_value_set_string_nocopy(value, g_strdup(str_value));
    
    hx_prefs_set_entry(info->pref_name, value);        
}

static void
prefs_auto_transport_read(GladeXML* prefs_dialog,
                          const HXPrefsControlInfo* info,
                          const HXPrefsDialog*)
{
    HXEntry* entry;
    HXValue* value;
    gboolean checked;
    
    entry = hx_prefs_get_entry(info->pref_name);
    if(entry)
    {
        value = hx_entry_get_value(entry);
        checked = atoi(hx_value_get_string(value));
    }
    else
    {
        checked = atoi(info->default_value);
    }
    
    if(checked)
    {
        GtkWidget* auto_transport_on;
        auto_transport_on = glade_xml_get_widget(prefs_dialog, "hpd_auto_transport_on");
        g_return_if_fail(auto_transport_on != NULL);

        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(auto_transport_on),
                                     TRUE);
    }
    else
    {
        GtkWidget* auto_transport_off;
        auto_transport_off = glade_xml_get_widget(prefs_dialog, "hpd_auto_transport_off");
        g_return_if_fail(auto_transport_off != NULL);
        
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(auto_transport_off),
                                     TRUE);
    }
}

static void
prefs_auto_transport_write(GladeXML* prefs_dialog,
                           const HXPrefsControlInfo* info,
                           const HXPrefsDialog*)
{
    GtkWidget* auto_transport_on;
    GtkWidget* auto_transport_off;
    HXValue* value;
    const gchar* str_value;
    
    auto_transport_on = glade_xml_get_widget(prefs_dialog, "hpd_auto_transport_on");
    g_return_if_fail(auto_transport_on != NULL);

    auto_transport_off = glade_xml_get_widget(prefs_dialog, "hpd_auto_transport_off");
    g_return_if_fail(auto_transport_off != NULL);

    if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(auto_transport_off)))
    {
        str_value = "0";
    }
    else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(auto_transport_on)))
    {
        str_value = "1";
    }
    else
    {
        str_value = info->default_value;
    }
    
    value = hx_value_new(HX_VALUE_STRING);
    hx_value_set_string_nocopy(value, g_strdup(str_value));
    
    hx_prefs_set_entry(info->pref_name, value);        
}

/* Prefs for the helix engine */
static const HXPrefsControlInfo g_helix_prefs_map[] = {
//  preference              default        widget                        read                                 write    
    { "Bandwidth",          "10485800",    "hpd_normal_bandwidth",       prefs_bandwidth_option_menu_read,    prefs_bandwidth_option_menu_write    },
    { "MaxBandwidth",       "10485800",    "hpd_max_bandwidth",          prefs_bandwidth_option_menu_read,    prefs_bandwidth_option_menu_write    },
    { "RTSPProxySupport",   "0",           "hpd_rtsp_proxy_support",     prefs_checkbutton_read,              prefs_checkbutton_write              },
    { "RTSPProxyHost",      "",            "hpd_rtsp_proxy_host",        prefs_entry_read,                    prefs_entry_write                    },
    { "RTSPProxyPort",      "554",         "hpd_rtsp_proxy_port",        prefs_entry_read,                    prefs_entry_write                    },
    { "PNAProxySupport",    "0",           "hpd_pna_proxy_support",      prefs_checkbutton_read,              prefs_checkbutton_write              },
    { "PNAProxyHost",       "",            "hpd_pna_proxy_host",         prefs_entry_read,                    prefs_entry_write                    },
    { "PNAProxyPort",       "1090",        "hpd_pna_proxy_port",         prefs_entry_read,                    prefs_entry_write                    },
    { "HTTPProxySupport",   "0",           "hpd_http_proxy_support",     prefs_checkbutton_read,              prefs_checkbutton_write              },
    { "HTTPProxyHost",      "",            "hpd_http_proxy_host",        prefs_entry_read,                    prefs_entry_write                    },
    { "HTTPProxyPort",      "80",          "hpd_http_proxy_port",        prefs_entry_read,                    prefs_entry_write                    },
    { "Quality",            "4",           "hpd_quality",                prefs_scale_read,                    prefs_scale_write                    },
    { "UseOverlay",         "1",           "hpd_use_overlay",            prefs_checkbutton_read,              prefs_checkbutton_write              },
    { "OverlayMode",        "1",           "hpd_use_overlay",            prefs_checkbutton_read,              prefs_checkbutton_write              },
//  { "SoundDriver",        "1" /* oss */, "hpd_sound_driver",           prefs_sound_driver_option_menu_read, prefs_sound_driver_option_menu_write },
//  { "UseUDPPort",         "0",           "hpd_use_udp_port",           prefs_checkbutton_read,              prefs_checkbutton_write              },
//  { "UDPPort",            "7070",        "hpd_udp_port",               prefs_entry_read,                    prefs_entry_write                    },
    { "NoProxyFor",         "",            "hpd_no_proxy_for",           prefs_entry_read,                    prefs_entry_write                    },
    { "PerfPlayEntireClip", "0",           "hpd_perf_play_entire_clip",  prefs_checkbutton_read,              prefs_checkbutton_write              },
    { "BufferedPlayTime",   "10",          "hpd_buffered_play_time",     prefs_entry_read,                    prefs_entry_write                    },
    { "CookiesEnabled",     "1",           "hpd_cookies_enabled",        prefs_checkbutton_read,              prefs_checkbutton_write              },
    { "AllowAuthID",        "0",           "hpd_allow_auth_id",          prefs_checkbutton_read,              prefs_checkbutton_write              },
    { "SendStatistics",     "1",           "hpd_send_statistics",        prefs_checkbutton_read,              prefs_checkbutton_write              },
    { "SamplingRate",       NULL,          "hpd_sampling_rate",          prefs_sampling_rate_read,            prefs_sampling_rate_write            },
    { "BitsPerSample",      NULL,          "hpd_bits_per_sample",        prefs_bits_per_sample_read,          prefs_bits_per_sample_write          },
    { "AutoTransport",      "1",           NULL,                         prefs_auto_transport_read,           prefs_auto_transport_write           },
    { "CacheEnabled",       "1",           "hpd_cache_enabled",          prefs_checkbutton_read,              prefs_checkbutton_write              },
    { "CacheMaxSize",       "4",           "hpd_cache_max_size",         prefs_entry_read,                    prefs_entry_write                    },
    { "ConnectionTimeOut",  "20",          "hpd_connection_time_out",    prefs_entry_read,                    prefs_entry_write                    },
    { "SynchMM",            "1",           "hpd_synch_mm",               prefs_checkbutton_read,              prefs_checkbutton_write              },    
    { "TurboPlay",          "0",           "hpd_turbo_play",             prefs_checkbutton_read,              prefs_checkbutton_write              },

//  No support for automatic proxy configuration    
//     { "RTSPPNMProxyAutoConfig", "0" },
//     { "ProxyAutoConfigURL"     NULL },

//  Other preferences to consider adding to the preferences dialog (some of these are mac/windows only)    
//     { "PreferredBrowser",      "0",   },
//     { "InternalBrowser",       "1",   },
//     { "CookieData",             NULL, },

//     { "CountryID",             "us",  },
//     { "RegionData",            "",    },

};                                         

static const HXPrefsControlInfo g_smil_prefs_map[] = {
//  preference              default  widget                        read                         write    
//  { "useNestedMeta", 
    { "Language",           "en-us", "hpd_content_language_combo", prefs_content_language_read, prefs_content_language_write  },
    { "caption_switch",     "0",     "hpd_caption_switch",         prefs_checkbutton_read,      prefs_checkbutton_write       },
    { "overdub_or_caption", "none",  NULL,                         prefs_overdub_caption_read,  prefs_overdub_caption_write   },
    { "systemAudioDesc",    "0",     "hpd_system_audio_desc",      prefs_checkbutton_read,      prefs_checkbutton_write       },
    { "UseSystemCPU",       "1",     "hpd_use_system_cpu",         prefs_checkbutton_read,      prefs_checkbutton_write       },
    { "UseSystemOS",        "1",     "hpd_use_system_os",          prefs_checkbutton_read,      prefs_checkbutton_write       },
};

/* prefs for the player */
static const HXPrefsControlInfo g_player_prefs_map[] = {
//  preference                default  widget                         read                              write    
    { "EnableRecentUrlsList", "1",     "hpd_enable_recent_urls_list", prefs_checkbutton_read_window,    prefs_checkbutton_write_window    },
    { "MediaFilesPath",       "",      "hpd_media_files_path",        prefs_entry_read_window,          prefs_entry_write_window          },
    { "WebBrowserPath",       "",      "hpd_web_browser_path",        prefs_entry_read_window,          prefs_entry_write_window          },
};

/* RTSP transport prefs */
static const HXPrefsControlInfo g_rtsp_prefs_map[] = {
//  preference                 default  widget                    read                              write    
    { "AttemptRTSPvMulticast", "1",     "htd_attempt_multicast",  prefs_checkbutton_read,           prefs_checkbutton_write           },
    { "AttemptRTSPvUDP",       "1",     "htd_attempt_udp",        prefs_checkbutton_read,           prefs_checkbutton_write           },
    { "AttemptRTSPvTCP",       "1",     "htd_attempt_tcp",        prefs_checkbutton_read,           prefs_checkbutton_write           },
    { "AttemptRTSPvHTTP",      "1",     "htd_attempt_http",       prefs_checkbutton_read,           prefs_checkbutton_write           },
    { "UDPTimeout",            "3000",  "htd_udp_timeout",        prefs_entry_read,                 prefs_entry_write                 },        
    { "TCPTimeout",            "3000",  "htd_tcp_timeout",        prefs_entry_read,                 prefs_entry_write                 },        
    { "MulticastTimeout",      "3000",  "htd_multicast_timeout",  prefs_entry_read,                 prefs_entry_write                 },
};

/* PNA transport prefs */
static const HXPrefsControlInfo g_pna_prefs_map[] = {
//  preference                default   widget                    read                              write    
    { "AttemptPNAvMulticast", "1",      "htd_attempt_multicast",  prefs_checkbutton_read,           prefs_checkbutton_write           },
    { "AttemptPNAvUDP",       "1",      "htd_attempt_udp",        prefs_checkbutton_read,           prefs_checkbutton_write           },
    { "AttemptPNAvTCP",       "1",      "htd_attempt_tcp",        prefs_checkbutton_read,           prefs_checkbutton_write           },
    { "AttemptPNAvHTTP",      "1",      "htd_attempt_http",       prefs_checkbutton_read,           prefs_checkbutton_write           },
    { "UDPTimeout",           "3000",   "htd_udp_timeout",        prefs_entry_read,                 prefs_entry_write                 },        
    { "TCPTimeout",           "3000",   "htd_tcp_timeout",        prefs_entry_read,                 prefs_entry_write                 },        
    { "MulticastTimeout",     "3000",   "htd_multicast_timeout",  prefs_entry_read,                 prefs_entry_write                 },
};

static void
hpd_apply_main_window_preferences(HXMainWindow* window)
{
    GValue value;
    memset(&value, 0, sizeof(value));
    
    if(window)
    {
        hxwindow_get_property(window, "EnableRecentUrlsList", &value);        
        hxwindow_recent_urls_hide(window);
        
        if(g_value_get_boolean(&value))
        {
            hxwindow_recent_urls_show(window);
        }
    }
}

void
hpd_configure_transport(GtkWidget* widget, HXTransportType transport_type)
{
    GtkWidget* toplevel;
    gchar* filename;
    GladeXML* xml;
    GtkWidget* dialog;
    gint response;
    guint i;
    
    toplevel = gtk_widget_get_toplevel(widget);

    filename = hxcommon_locate_file("transport.glade");
    xml = glade_xml_new (filename, NULL, NULL);
    g_free(filename);
    g_return_if_fail(xml != NULL);

    dialog = glade_xml_get_widget(xml, "hxplayer_transport_settings");
    
    gtk_window_set_transient_for (GTK_WINDOW (dialog),
				  GTK_WINDOW (toplevel));    

    /* Update dialog from preferences */
    switch(transport_type)
    {
        case HX_TRANSPORT_RTSP:
            for(i = 0; i < sizeof(g_rtsp_prefs_map) / sizeof(*g_rtsp_prefs_map); i++)
            {
                g_rtsp_prefs_map[i].read_func(xml, &g_rtsp_prefs_map[i], NULL);
            }
            break;

        case HX_TRANSPORT_PNA:
            for(i = 0; i < sizeof(g_pna_prefs_map) / sizeof(*g_pna_prefs_map); i++)
            {
                g_pna_prefs_map[i].read_func(xml, &g_pna_prefs_map[i], NULL);
            }
            break;
        default:
            g_assert_not_reached();
            break;
    }

    do
    {
        response = gtk_dialog_run (GTK_DIALOG (dialog));

        switch(response)
        {
            case GTK_RESPONSE_OK:
            case GTK_RESPONSE_APPLY:
                switch(transport_type)
                {
                    case HX_TRANSPORT_RTSP:
                        for(i = 0; i < sizeof(g_rtsp_prefs_map) / sizeof(*g_rtsp_prefs_map); i++)
                        {
                            g_rtsp_prefs_map[i].write_func(xml, &g_rtsp_prefs_map[i], NULL);
                        }
                        break;

                    case HX_TRANSPORT_PNA:
                        for(i = 0; i < sizeof(g_pna_prefs_map) / sizeof(*g_pna_prefs_map); i++)
                        {
                            g_pna_prefs_map[i].write_func(xml, &g_pna_prefs_map[i], NULL);
                        }
                        break;
                    default:
                        g_assert_not_reached();
                        break;
                }
                break;

            case GTK_RESPONSE_CANCEL:
            default:
                break;
        }
    } while(response != GTK_RESPONSE_OK &&
            response != GTK_RESPONSE_CANCEL &&
            response != GTK_RESPONSE_DELETE_EVENT);

    gtk_widget_destroy (dialog);
    glade_xml_destroy (xml);
}

void
hpd_configure_rtsp(GtkWidget* widget)
{
    hpd_configure_transport(widget, HX_TRANSPORT_RTSP);
}

void
hpd_configure_pna(GtkWidget* widget)
{
    hpd_configure_transport(widget, HX_TRANSPORT_PNA);
}

static void
set_entry_from_file_selection_dialog(GtkWindow* parent,
                                     const gchar* entry_name,
                                     gboolean show_files)
{
    GtkWidget* entry;
    GladeXML* xml;
    const gchar* filename;
    GtkWidget* fs;
    gint fs_response;
    const gchar* select_files = _("Select files");
    
    xml = (GladeXML*)g_object_get_data(G_OBJECT (parent), "hxprefs_xml");
    g_return_if_fail(xml != NULL);

    entry = glade_xml_get_widget(xml, entry_name);
    g_return_if_fail(entry != NULL);

#if GTK_CHECK_VERSION(2, 4, 0)
    GtkFileChooserAction action;
    if(show_files)
    {
        action = GTK_FILE_CHOOSER_ACTION_OPEN;
    }
    else
    {
        action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;        
    }
    
    fs = gtk_file_chooser_dialog_new (select_files,
				      NULL,
				      action,
				      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
				      GTK_STOCK_OPEN, GTK_RESPONSE_OK,
				      NULL);

    gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(fs), TRUE);
#else	
    fs = gtk_file_selection_new (select_files);
    gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(fs));
#endif

    gtk_window_set_transient_for(GTK_WINDOW(fs),
                                 parent);

    fs_response = gtk_dialog_run (GTK_DIALOG (fs));
    gtk_widget_hide (fs);

    if (fs_response == GTK_RESPONSE_OK || fs_response == GTK_RESPONSE_ACCEPT)
    {
#if GTK_CHECK_VERSION(2, 4, 0)
        filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
#else
        filename = gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs));
#endif
    }
    else
    {
        filename = NULL;
    }

    if(filename)
    {
        gtk_entry_set_text(GTK_ENTRY(entry), filename);
    }
}

void
hpd_media_files_browse(GtkWidget* widget)
{
    GtkWidget* toplevel;

    toplevel = gtk_widget_get_toplevel(widget);

    g_assert(GTK_IS_DIALOG(toplevel));
    
    set_entry_from_file_selection_dialog(GTK_WINDOW(toplevel),
                                         "hpd_media_files_path",
                                         FALSE);
}

void
hpd_web_browser_browse(GtkWidget* widget)
{
    GtkWidget* toplevel;

    toplevel = gtk_widget_get_toplevel(widget);

    g_assert(GTK_IS_DIALOG(toplevel));
    
    set_entry_from_file_selection_dialog(GTK_WINDOW(toplevel),
                                         "hpd_web_browser_path",
                                         TRUE);
}

void
hpd_clear_recent_clips(GtkWidget* widget)
{
    HXMainWindow* window;
    GtkWidget* toplevel;

    toplevel = gtk_widget_get_toplevel(widget);    
    window = (HXMainWindow*) g_object_get_data(G_OBJECT (toplevel),
                                               "hxprefs_main_window");

    if(window)
    {
        hxwindow_recent_urls_remove_all(window);
    }
}

void
hpd_auto_transport_toggled(GtkToggleButton *togglebutton)
{
    GtkWidget* toplevel;
    GtkWidget* rtsp_button;
    GtkWidget* pna_button;
    GladeXML* xml;
    gboolean sensitive;

    toplevel = gtk_widget_get_toplevel(GTK_WIDGET(togglebutton));

    xml = (GladeXML*)g_object_get_data(G_OBJECT (toplevel), "hxprefs_xml");
    g_return_if_fail(xml != NULL);

    rtsp_button = glade_xml_get_widget(xml, "hpd_configure_rtsp_button");
    g_return_if_fail(rtsp_button != NULL);

    pna_button = glade_xml_get_widget(xml, "hpd_configure_pna_button");
    g_return_if_fail(pna_button != NULL);


    sensitive = !gtk_toggle_button_get_active(togglebutton);

    gtk_widget_set_sensitive(rtsp_button, sensitive);
    gtk_widget_set_sensitive(pna_button, sensitive);    
}

void
hpd_empty_clip_cache(GtkWidget *widget)
{
    HXMainWindow* window;
    GtkWidget* toplevel;
    GtkWidget* player;
    
    toplevel = gtk_widget_get_toplevel(widget);    
    window = (HXMainWindow*) g_object_get_data(G_OBJECT (toplevel),
                                               "hxprefs_main_window");
    if(window)
    {
        player = hxwindow_get_player(window);

        HX_RESULT retVal;
        IUnknown* pUnkPlayer = NULL;
        IUnknown* pUnkEngine = NULL;
        IUnknown* pUnkHTTP = NULL;
        IHXFileSystemCache* pFileSystemCache = NULL;
        IHXPlugin2Handler* pPlugin2Handler = NULL;
        IHXPlugin* pPlugin = NULL;

        gboolean result;

        result = hx_player_get_unknown(HX_PLAYER(player),
                                       (void**)&pUnkPlayer);
        g_return_if_fail(result != FALSE);

        result = hx_player_get_engine_unknown(HX_PLAYER(player),
                                              (void**)&pUnkEngine);
        g_return_if_fail(result != FALSE);

        retVal = pUnkPlayer->QueryInterface(IID_IHXPlugin2Handler,
                                      (void**)&pPlugin2Handler);

        if(SUCCEEDED(retVal))
        {
            g_assert(pPlugin2Handler != NULL);            
            retVal = pPlugin2Handler->FindPluginUsingStrings( "PluginType",
                                                              "PLUGIN_FILE_SYSTEM",
                                                              "FileProtocol",
                                                              "http",
                                                              NULL,
                                                              NULL,
                                                              pUnkHTTP );
        }

        if(SUCCEEDED(retVal))
        {        
            g_assert(pUnkHTTP != NULL);
            retVal = pUnkHTTP->QueryInterface(IID_IHXPlugin, (void**)&pPlugin);
        }

        if(SUCCEEDED(retVal))
        {        
            g_assert(pPlugin != NULL);
                        
            retVal = pPlugin->InitPlugin(pUnkEngine);

            if(SUCCEEDED(retVal))
            {
                retVal = pPlugin->QueryInterface(IID_IHXFileSystemCache,
                                                 (void**)&pFileSystemCache);
            }
        }

        if(SUCCEEDED(retVal))
        {
            g_assert(pFileSystemCache);

            /* Victory! */
            pFileSystemCache->EmptyCache();
        }
        
        if(pFileSystemCache)
        {
            HX_RELEASE(pFileSystemCache);
        }

        if(pUnkHTTP)
        {
            HX_RELEASE(pUnkHTTP);
        }

        if(pPlugin2Handler)
        {
            HX_RELEASE(pPlugin2Handler);
        }

        g_return_if_fail(SUCCEEDED(retVal));
    }
}

static void
hpd_destroy(GtkWidget* /* widget */,
            HXPrefsDialog* prefs_dlg)
{
    glade_xml_destroy (prefs_dlg->xml);
    
    if(prefs_dlg->mime_types_dialog_info)
    {
        hxplay_mime_types_pane_destroy(prefs_dlg->mime_types_dialog_info);
    }

    g_free(prefs_dlg);
}

static void
hpd_response(GtkWidget* dialog,
             gint response_id,
             HXPrefsDialog* info)
{
    guint i;
    
    switch(response_id)
    {
        case GTK_RESPONSE_OK:
        case GTK_RESPONSE_APPLY:
            for(i = 0; i < sizeof(g_helix_prefs_map) / sizeof(*g_helix_prefs_map); i++)
            {
                g_helix_prefs_map[i].write_func(info->xml, &g_helix_prefs_map[i], info);
            }

            if (info->window)
            {
                /* We're not in embedded player mode */
                for(i = 0; i < sizeof(g_player_prefs_map) / sizeof(*g_player_prefs_map); i++)
                {
                    g_player_prefs_map[i].write_func(info->xml, &g_player_prefs_map[i], info);
                }
            }
            
            for(i = 0; i < sizeof(g_smil_prefs_map) / sizeof(*g_smil_prefs_map); i++)
            {
                g_smil_prefs_map[i].write_func(info->xml, &g_smil_prefs_map[i], info);
            }

            if(info->mime_types_dialog_info)
            {        
                hxplay_mime_types_pane_apply(info->mime_types_dialog_info);
            }

            if(info->window)
            {
                /* Updates main window ui to reflect preference changes */
                hpd_apply_main_window_preferences(info->window);
            }
            break;

        case GTK_RESPONSE_CANCEL:
        default:
            break;
    }
}

GtkDialog*
hxplay_preferences_dialog_new (HXPlayer*  player,
                               HXMainWindow* window)
{
    GladeXML* xml;
    GtkWidget* dialog;
    gchar* filename;
    guint i;
    HXPrefsDialog* dialog_info = NULL;
    
    filename = hxcommon_locate_file("preferences.glade");
    xml = glade_xml_new (filename, NULL, NULL);
    g_free(filename);
    g_return_val_if_fail(xml != NULL, NULL);

    dialog_info = g_new0(HXPrefsDialog, 1);

    dialog = glade_xml_get_widget (xml, "hxplayer_preferences_dialog");

    g_object_set_data(G_OBJECT (dialog), "hxprefs_xml", xml);
    g_object_set_data(G_OBJECT (dialog), "hxprefs_main_window", window);    
    
    /* Populate the languages drop-down combo */
    GtkWidget* lang_combo = glade_xml_get_widget (xml, "hpd_content_language_combo");
    if(lang_combo)
    {
        hpd_populate_lang_combo(GTK_COMBO(lang_combo));
    }

    dialog_info->xml = xml;
    dialog_info->window = window;    
    dialog_info->mime_types_dialog_info = hxplay_mime_types_pane_new (xml, player);    

    /* Update dialog from preferences */
    for(i = 0; i < sizeof(g_helix_prefs_map) / sizeof(*g_helix_prefs_map); i++)
    {
        g_helix_prefs_map[i].read_func(xml, &g_helix_prefs_map[i], dialog_info);
    }

    if(window)
    {
        /* We're not in embedded mode */
        for(i = 0; i < sizeof(g_player_prefs_map) / sizeof(*g_player_prefs_map); i++)
        {
            g_player_prefs_map[i].read_func(xml, &g_player_prefs_map[i], dialog_info);
        }
    }
    
    for(i = 0; i < sizeof(g_smil_prefs_map) / sizeof(*g_smil_prefs_map); i++)
    {
        g_smil_prefs_map[i].read_func(xml, &g_smil_prefs_map[i], dialog_info);
    }

    g_signal_connect (G_OBJECT (dialog), "destroy",
                      G_CALLBACK (hpd_destroy),
                      dialog_info);

    g_signal_connect (G_OBJECT (dialog), "response",
                      G_CALLBACK (hpd_response),
                      dialog_info);


    return GTK_DIALOG(dialog);
}
