OSDN Git Service

LinGui: refine deblock slider. now shows "Off" and values 5-15.
[handbrake-jp/handbrake-jp-git.git] / gtk / src / callbacks.c
index 8037372..98b107b 100644 (file)
 #include <sys/stat.h>
 #include <libhal-storage.h>
 #include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
 #include <glib/gstdio.h>
 #include <gio/gio.h>
 
 #include "callbacks.h"
+#include "resources.h"
 #include "settings.h"
+#include "presets.h"
+#include "values.h"
+#include "plist.h"
 #include "hb-backend.h"
 #include "ghb-dvd.h"
+#include "ghbcellrenderertext.h"
+#include "hb.h"
 
 static void update_chapter_list(signal_user_data_t *ud);
 static void clear_audio_list(signal_user_data_t *ud);
 static GList* dvd_device_list();
 static gboolean cancel_encode();
 static void audio_list_refresh_selected(signal_user_data_t *ud);
-static GHashTable* get_selected_asettings(signal_user_data_t *ud);
+static GValue* get_selected_asettings(signal_user_data_t *ud);
+static gint find_last_finished(GValue *queue);
 
 // This is a dependency map used for greying widgets
 // that are dependent on the state of another widget.
@@ -42,192 +50,162 @@ static GHashTable* get_selected_asettings(signal_user_data_t *ud);
 // obtained from ghb_widget_value().  For combo boxes
 // you will have to look further to combo box options
 // maps in hb-backend.c
-typedef struct
-{
-       const gchar *widget_name;
-       const gchar *dep_name;
-       const gchar *enable_value;
-       const gboolean disable_if_equal;
-} dependency_t;
-
-static dependency_t dep_map[] =
-{
-       {"title", "queue_add", "none", TRUE},
-       {"title", "queue_add_menu", "none", TRUE},
-       {"title", "preview_button", "none", TRUE},
-       {"title", "show_preview_menu", "none", TRUE},
-       {"title", "preview_frame", "none", TRUE},
-       {"title", "picture_label", "none", TRUE},
-       {"title", "picture_tab", "none", TRUE},
-       {"title", "chapters_label", "none", TRUE},
-       {"title", "chapters_tab", "none", TRUE},
-       {"title", "title", "none", TRUE},
-       {"title", "start_chapter", "none", TRUE},
-       {"title", "end_chapter", "none", TRUE},
-       {"vquality_type_bitrate", "video_bitrate", "enable", FALSE},
-       {"vquality_type_target", "video_target_size", "enable", FALSE},
-       {"vquality_type_constant", "video_quality", "enable", FALSE},
-       {"vquality_type_constant", "constant_rate_factor", "enable", FALSE},
-       {"vquality_type_constant", "two_pass", "enable", TRUE},
-       {"vquality_type_constant", "turbo", "enable", TRUE},
-       {"two_pass", "turbo", "enable", FALSE},
-       {"container", "large_mp4", "mp4|m4v", FALSE},
-       {"container", "http_optimize_mp4", "mp4|m4v", FALSE},
-       {"container", "ipod_file", "mp4|m4v", FALSE},
-       {"container", "variable_frame_rate", "avi", TRUE},
-       {"variable_frame_rate", "framerate", "enable", TRUE},
-       {"variable_frame_rate", "detelecine", "enable", TRUE},
-       {"decomb", "deinterlace", "enable", TRUE},
-       {"autocrop", "crop_top", "disable", FALSE},
-       {"autocrop", "crop_bottom", "disable", FALSE},
-       {"autocrop", "crop_left", "disable", FALSE},
-       {"autocrop", "crop_right", "disable", FALSE},
-       {"autoscale", "scale_width", "disable", FALSE},
-       {"autoscale", "scale_height", "disable", FALSE},
-       {"anamorphic", "keep_aspect", "disable", FALSE},
-       {"anamorphic", "scale_height", "disable", FALSE},
-       {"keep_aspect", "scale_height", "disable", FALSE},
-       {"video_codec", "x264_tab", "x264", FALSE},
-       {"video_codec", "x264_tab_label", "x264", FALSE},
-       {"video_codec", "ipod_file", "x264", FALSE},
-       {"audio_codec", "audio_bitrate", "ac3", TRUE},
-       {"audio_codec", "audio_rate", "ac3", TRUE},
-       {"audio_codec", "audio_mix", "ac3", TRUE},
-       {"audio_codec", "audio_drc", "ac3", TRUE},
-       {"x264_bframes", "x264_weighted_bframes", "0", TRUE},
-       {"x264_bframes", "x264_brdo", "0", TRUE},
-       {"x264_bframes", "x264_bime", "0", TRUE},
-       {"x264_bframes", "x264_bpyramid", "<2", TRUE},
-       {"x264_bframes", "x264_direct", "0", TRUE},
-       {"x264_refs", "x264_mixed_refs", "<2", TRUE},
-       {"x264_cabac", "x264_trellis", "enable", FALSE},
-       {"x264_subme", "x264_brdo", "<6", TRUE},
-       {"x264_analyse", "x264_direct", "none", TRUE},
-       {"x264_me", "x264_merange", "umh|esa", FALSE},
-       {"chapter_markers", "chapters_list", "enable", FALSE},
-};
+
+GValue *dep_map;
+GValue *rev_map;
+
+void
+ghb_init_dep_map()
+{
+       dep_map = ghb_resource_get("widget-deps");
+       rev_map = ghb_resource_get("widget-reverse-deps");
+}
 
 static gboolean
 dep_check(signal_user_data_t *ud, const gchar *name)
 {
        GtkWidget *widget;
        GObject *dep_object;
-       int ii;
-       int count = sizeof(dep_map) / sizeof(dependency_t);
+       gint ii;
+       gint count;
        gboolean result = TRUE;
+       GValue *array, *data;
+       gchar *widget_name;
        
-       g_debug("dep_check () %s\n", name);
+       g_debug("dep_check () %s", name);
+
+       array = ghb_dict_lookup(rev_map, name);
+       count = ghb_array_len(array);
        for (ii = 0; ii < count; ii++)
        {
-               if (strcmp(dep_map[ii].dep_name, name) == 0)
+               data = ghb_array_get_nth(array, ii);
+               widget_name = ghb_value_string(ghb_array_get_nth(data, 0));
+               widget = GHB_WIDGET(ud->builder, widget_name);
+               dep_object = gtk_builder_get_object(ud->builder, name);
+               g_free(widget_name);
+               if (dep_object == NULL)
                {
-                       widget = GHB_WIDGET(ud->builder, dep_map[ii].widget_name);
-                       dep_object = gtk_builder_get_object(ud->builder, dep_map[ii].dep_name);
-                       if (dep_object == NULL)
-                       {
-                               g_message("Failed to find widget\n");
-                       }
+                       g_message("Failed to find widget");
+               }
+               else
+               {
+                       gchar *value;
+                       gint jj = 0;
+                       gchar **values;
+                       gboolean sensitive = FALSE;
+                       gboolean die;
+
+                       die = ghb_value_boolean(ghb_array_get_nth(data, 2));
+                       value = ghb_value_string(ghb_array_get_nth(data, 1));
+                       values = g_strsplit(value, "|", 10);
+                       g_free(value);
+
+                       if (widget)
+                               value = ghb_widget_string(widget);
                        else
+                               value = ghb_settings_get_string(ud->settings, name);
+                       while (values && values[jj])
                        {
-                               gchar *value;
-                               gint jj = 0;
-                               gchar **values = g_strsplit(dep_map[ii].enable_value, "|", 10);
-                               gboolean sensitive = FALSE;
-
-                               if (widget)
-                                       value = ghb_widget_short_opt(widget);
-                               else
-                                       value = g_strdup( ghb_settings_get_short_opt(
-                                               ud->settings, dep_map[ii].widget_name));
-                               while (values && values[jj])
+                               if (values[jj][0] == '>')
                                {
-                                       if (values[jj][0] == '>')
-                                       {
-                                               gdouble dbl = g_strtod (&values[jj][1], NULL);
-                                               gdouble dvalue = ghb_widget_dbl (widget);
-                                               if (dvalue > dbl)
-                                               {
-                                                       sensitive = TRUE;
-                                                       break;
-                                               }
-                                       }
-                                       else if (values[jj][0] == '<')
+                                       gdouble dbl = g_strtod (&values[jj][1], NULL);
+                                       gdouble dvalue = ghb_widget_double(widget);
+                                       if (dvalue > dbl)
                                        {
-                                               gdouble dbl = g_strtod (&values[jj][1], NULL);
-                                               gdouble dvalue = ghb_widget_dbl (widget);
-                                               if (dvalue < dbl)
-                                               {
-                                                       sensitive = TRUE;
-                                                       break;
-                                               }
+                                               sensitive = TRUE;
+                                               break;
                                        }
-                                       if (strcmp(values[jj], value) == 0)
+                               }
+                               else if (values[jj][0] == '<')
+                               {
+                                       gdouble dbl = g_strtod (&values[jj][1], NULL);
+                                       gdouble dvalue = ghb_widget_double(widget);
+                                       if (dvalue < dbl)
                                        {
                                                sensitive = TRUE;
                                                break;
                                        }
-                                       jj++;
                                }
-                               sensitive = dep_map[ii].disable_if_equal ^ sensitive;
-                               if (!sensitive) result = FALSE;
-                               g_strfreev (values);
-                               g_free(value);
+                               if (strcmp(values[jj], value) == 0)
+                               {
+                                       sensitive = TRUE;
+                                       break;
+                               }
+                               jj++;
                        }
+                       sensitive = die ^ sensitive;
+                       if (!sensitive) result = FALSE;
+                       g_strfreev (values);
+                       g_free(value);
                }
        }
        return result;
 }
 
 static void
-check_depencency(signal_user_data_t *ud, GtkWidget *widget)
+check_dependency(signal_user_data_t *ud, GtkWidget *widget)
 {
        GObject *dep_object;
        const gchar *name;
-       int ii;
-       int count = sizeof(dep_map) / sizeof(dependency_t);
+       GValue *array, *data;
+       gint count, ii;
+       gchar *dep_name;
+       GType type;
+
+       type = GTK_WIDGET_TYPE(widget);
+       if (type == GTK_TYPE_COMBO_BOX || type == GTK_TYPE_COMBO_BOX_ENTRY)
+               if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) < 0) return;
 
-       if (ghb_widget_index(widget) < 0) return;
        name = gtk_widget_get_name(widget);
-       g_debug("check_depencency () %s\n", name);
+       g_debug("check_dependency () %s", name);
+
+       array = ghb_dict_lookup(dep_map, name);
+       count = ghb_array_len(array);
        for (ii = 0; ii < count; ii++)
        {
-               if (strcmp(dep_map[ii].widget_name, name) == 0)
-               {
-                       gboolean sensitive;
+               gboolean sensitive;
 
-                       dep_object = gtk_builder_get_object (ud->builder, dep_map[ii].dep_name);
-                       if (dep_object == NULL)
-                       {
-                               g_message("Failed to find dependent widget %s\n", dep_map[ii].dep_name);
-                               continue;
-                       }
-                       sensitive = dep_check(ud, dep_map[ii].dep_name);
-                       if (GTK_IS_ACTION(dep_object))
-                               gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
-                       else
-                               gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
+               data = ghb_array_get_nth(array, ii);
+               dep_name = ghb_value_string(data);
+               dep_object = gtk_builder_get_object(ud->builder, dep_name);
+               if (dep_object == NULL)
+               {
+                       g_message("Failed to find dependent widget %s", dep_name);
+                       g_free(dep_name);
+                       continue;
                }
+               sensitive = dep_check(ud, dep_name);
+               g_free(dep_name);
+               if (GTK_IS_ACTION(dep_object))
+                       gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
+               else
+                       gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
        }
 }
 
 void
 ghb_check_all_depencencies(signal_user_data_t *ud)
 {
+       GHashTableIter iter;
+       gchar *dep_name;
+       GValue *value;
        GObject *dep_object;
-       int ii;
-       int count = sizeof(dep_map) / sizeof(dependency_t);
 
-       g_debug("ghb_check_all_depencencies ()\n");
-       for (ii = 0; ii < count; ii++)
+       g_debug("ghb_check_all_depencencies ()");
+       ghb_dict_iter_init(&iter, rev_map);
+       // middle (void*) cast prevents gcc warning "defreferencing type-punned
+       // pointer will break strict-aliasing rules"
+       while (g_hash_table_iter_next(
+                       &iter, (gpointer*)(void*)&dep_name, (gpointer*)(void*)&value))
        {
                gboolean sensitive;
-               dep_object = gtk_builder_get_object (ud->builder, dep_map[ii].dep_name);
+               dep_object = gtk_builder_get_object (ud->builder, dep_name);
                if (dep_object == NULL)
                {
-                       g_message("Failed to find dependent widget %s\n", dep_map[ii].dep_name);
+                       g_message("Failed to find dependent widget %s", dep_name);
                        continue;
                }
-               sensitive = dep_check(ud, dep_map[ii].dep_name);
+               sensitive = dep_check(ud, dep_name);
                if (GTK_IS_ACTION(dep_object))
                        gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
                else
@@ -242,10 +220,11 @@ clear_presets_selection(signal_user_data_t *ud)
        GtkTreeSelection *selection;
        
        if (ud->dont_clear_presets) return;
-       g_debug("clear_presets_selection()\n");
+       g_debug("clear_presets_selection()");
        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
        selection = gtk_tree_view_get_selection (treeview);
        gtk_tree_selection_unselect_all (selection);
+       ghb_settings_set_boolean(ud->settings, "preset_modified", TRUE);
 }
 
 static gchar*
@@ -256,7 +235,7 @@ expand_tilde(const gchar *path)
        const gchar *suffix;
        gchar *expanded_path = NULL;
        
-       g_debug("expand_tilde ()\n");
+       g_debug("expand_tilde ()");
        if (path[0] == '~')
        {
                user_home = g_get_home_dir();
@@ -285,18 +264,18 @@ expand_tilde(const gchar *path)
 void
 on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud)
 {
-       gint state = ghb_get_state();
-       g_debug("on_quit1_activate ()\n");
-    if (state & GHB_STATE_WORKING)
-    {
-        if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
-        {
+       gint state = ghb_get_queue_state();
+       g_debug("on_quit1_activate ()");
+       if (state & GHB_STATE_WORKING)
+       {
+               if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
+               {
                        ghb_hb_cleanup(FALSE);
-               gtk_main_quit();
-            return;
-        }
-        return;
-    }
+                       gtk_main_quit();
+                       return;
+               }
+               return;
+       }
        ghb_hb_cleanup(FALSE);
        gtk_main_quit();
 }
@@ -304,22 +283,41 @@ on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud)
 static void
 set_destination(signal_user_data_t *ud)
 {
-       if (ghb_settings_get_bool(ud->settings, "use_source_name"))
+       g_debug("set_destination");
+       if (ghb_settings_get_boolean(ud->settings, "use_source_name"))
        {
-               const gchar *vol_name, *filename, *extension;
+               gchar *vol_name, *filename, *extension;
                gchar *dir, *new_name;
                
                filename = ghb_settings_get_string(ud->settings, "destination");
                extension = ghb_settings_get_string(ud->settings, "container");
                dir = g_path_get_dirname (filename);
                vol_name = ghb_settings_get_string(ud->settings, "volume_label");
-               g_debug("volume_label (%s)\n", vol_name);
-               if (vol_name == NULL)
+               if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
+               {
+                       gint start, end;
+
+                       start = ghb_settings_get_int(ud->settings, "start_chapter");
+                       end = ghb_settings_get_int(ud->settings, "end_chapter");
+                       if (start == end)
+                       {
+                               new_name = g_strdup_printf("%s/%s-%d.%s", 
+                                       dir, vol_name, start, extension);
+                       }
+                       else
+                       {
+                               new_name = g_strdup_printf("%s/%s-%d-%d.%s", 
+                                       dir, vol_name, start, end, extension);
+                       }
+               }
+               else
                {
-                       vol_name = "new_video";
+                       new_name = g_strdup_printf("%s/%s.%s", dir, vol_name, extension);
                }
-               new_name = g_strdup_printf("%s/%s.%s", dir, vol_name, extension);
-               ghb_ui_update(ud, "destination", new_name);
+               ghb_ui_update(ud, "destination", ghb_string_value(new_name));
+               g_free(filename);
+               g_free(extension);
+               g_free(vol_name);
                g_free(dir);
                g_free(new_name);
        }
@@ -489,36 +487,29 @@ dvd_device_changed_cb(GtkComboBox *combo, GtkWidget *dialog)
        }
 }
 
-
 void
 source_type_changed_cb(GtkToggleButton *toggle, GtkFileChooser *chooser)
 {
-       gchar *filename;
+       gchar *folder;
        
-       g_debug("source_type_changed_cb ()\n");
+       g_debug("source_type_changed_cb ()");
+       folder = gtk_file_chooser_get_current_folder (chooser);
        if (gtk_toggle_button_get_active (toggle))
        {
-               filename = gtk_file_chooser_get_filename (chooser);
                gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
-               if (filename != NULL)
-               {
-                       gtk_file_chooser_set_filename(chooser, filename);
-                       g_free(filename);
-               }
                gtk_widget_set_sensitive (dvd_device_combo, FALSE);
                gtk_combo_box_set_active (GTK_COMBO_BOX(dvd_device_combo), 0);
        }
        else
        {
-               filename = gtk_file_chooser_get_filename (chooser);
                gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_OPEN);
-               if (filename != NULL)
-               {
-                       gtk_file_chooser_set_filename(chooser, filename);
-                       g_free(filename);
-               }
                gtk_widget_set_sensitive (dvd_device_combo, TRUE);
        }
+       if (folder != NULL)
+       {
+               gtk_file_chooser_set_current_folder(chooser, folder);
+               g_free(folder);
+       }
 }
 
 static GtkWidget*
@@ -581,12 +572,13 @@ do_scan(signal_user_data_t *ud, const gchar *filename)
                {
                        GtkProgressBar *progress;
                        progress = GTK_PROGRESS_BAR(GHB_WIDGET(ud->builder, "progressbar"));
-                       const gchar *path;
+                       gchar *path;
                        path = ghb_settings_get_string( ud->settings, "source");
                        gtk_progress_bar_set_fraction (progress, 0);
                        gtk_progress_bar_set_text (progress, "Scanning ...");
                        ghb_hb_cleanup(TRUE);
                        ghb_backend_scan (path, 0);
+                       g_free(path);
                }
                else
                {
@@ -600,12 +592,12 @@ source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
 {
        GtkWidget *dialog;
        GtkWidget *widget;
-       const gchar *sourcename;
+       gchar *sourcename;
        gint    response;
        GtkFileChooserAction action;
        gboolean checkbutton_active;
 
-       g_debug("source_browse_clicked_cb ()\n");
+       g_debug("source_browse_clicked_cb ()");
        sourcename = ghb_settings_get_string(ud->settings, "source");
        checkbutton_active = FALSE;
        if (g_file_test(sourcename, G_FILE_TEST_IS_DIR))
@@ -645,6 +637,7 @@ source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
                        g_free(filename);
                }
        }
+       g_free(sourcename);
        gtk_widget_destroy(dialog);
 }
 
@@ -652,7 +645,7 @@ void
 dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
 {
        const gchar *filename;
-       const gchar *sourcename;
+       gchar *sourcename;
 
        sourcename = ghb_settings_get_string(ud->settings, "source");
        filename = gtk_action_get_name(action);
@@ -663,6 +656,7 @@ dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
                ghb_pref_save (ud->settings, "default_source");
                ghb_dvd_set_current (filename, ud);
        }
+       g_free(sourcename);
 }
 
 static void
@@ -670,11 +664,11 @@ update_destination_extension(signal_user_data_t *ud)
 {
        static gchar *containers[] = {".mkv", ".mp4", ".m4v", ".avi", ".ogm", NULL};
        gchar *filename;
-       const gchar *extension;
+       gchar *extension;
        gint ii;
        GtkEntry *entry;
 
-       g_debug("update_destination_extension ()\n");
+       g_debug("update_destination_extension ()");
        extension = ghb_settings_get_string(ud->settings, "container");
        entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "destination"));
        filename = g_strdup(gtk_entry_get_text(entry));
@@ -698,14 +692,52 @@ update_destination_extension(signal_user_data_t *ud)
                                break;
                        }
                        new_name = g_strjoin(".", filename, extension, NULL); 
-                       ghb_ui_update(ud, "destination", new_name);
+                       ghb_ui_update(ud, "destination", ghb_string_value(new_name));
                        g_free(new_name);
                        break;
                }
        }
+       g_free(extension);
        g_free(filename);
 }
 
+static void
+destination_select_title(GtkEntry *entry)
+{
+       const gchar *dest;
+       gint start, end;
+
+       dest = gtk_entry_get_text(entry);
+       for (end = strlen(dest)-1; end > 0; end--)
+       {
+               if (dest[end] == '.')
+               {
+                       break;
+               }
+       }
+       for (start = end; start >= 0; start--)
+       {
+               if (dest[start] == '/')
+               {
+                       start++;
+                       break;
+               }
+       }
+       if (start < end)
+       {
+               gtk_editable_select_region(GTK_EDITABLE(entry), start, end);
+       }
+}
+
+gboolean
+destination_grab_cb(
+       GtkEntry *entry, 
+       signal_user_data_t *ud)
+{
+       destination_select_title(entry);
+       return FALSE;
+}
+
 static gboolean update_default_destination = FALSE;
 
 void
@@ -713,7 +745,7 @@ destination_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
 {
        gchar *dest;
        
-       g_debug("destination_entry_changed_cb ()\n");
+       g_debug("destination_entry_changed_cb ()");
        if ((dest = expand_tilde(gtk_entry_get_text(entry))) != NULL)
        {
                gtk_entry_set_text(entry, dest);
@@ -731,19 +763,20 @@ destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
 {
        GtkWidget *dialog;
        GtkEntry *entry;
-       const char *destname;
+       gchar *destname;
        gchar *basename;
 
-       g_debug("destination_browse_clicked_cb ()\n");
+       g_debug("destination_browse_clicked_cb ()");
        destname = ghb_settings_get_string(ud->settings, "destination");
        dialog = gtk_file_chooser_dialog_new ("Choose Destination",
-                      NULL,
-                      GTK_FILE_CHOOSER_ACTION_SAVE,
-                      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                      GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
-                      NULL);
+                                         NULL,
+                                         GTK_FILE_CHOOSER_ACTION_SAVE,
+                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                         GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+                                         NULL);
        gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), destname);
        basename = g_path_get_basename(destname);
+       g_free(destname);
        gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
        g_free(basename);
        if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
@@ -754,7 +787,7 @@ destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
                entry = (GtkEntry*)GHB_WIDGET(ud->builder, "destination");
                if (entry == NULL)
                {
-                       g_debug("Failed to find widget: %s\n", "destination");
+                       g_debug("Failed to find widget: %s", "destination");
                }
                else
                {
@@ -768,30 +801,30 @@ destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
 gboolean
 window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
 {
-       g_debug("window_destroy_event_cb ()\n");
+       g_debug("window_destroy_event_cb ()");
        ghb_hb_cleanup(FALSE);
        gtk_main_quit();
-    return FALSE;
+       return FALSE;
 }
 
 gboolean
 window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
 {
-       gint state = ghb_get_state();
-       g_debug("window_delete_event_cb ()\n");
-    if (state & GHB_STATE_WORKING)
-    {
-        if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
-        {
+       gint state = ghb_get_queue_state();
+       g_debug("window_delete_event_cb ()");
+       if (state & GHB_STATE_WORKING)
+       {
+               if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
+               {
                        ghb_hb_cleanup(FALSE);
-               gtk_main_quit();
-            return FALSE;
-        }
-        return TRUE;
-    }
+                       gtk_main_quit();
+                       return FALSE;
+               }
+               return TRUE;
+       }
        ghb_hb_cleanup(FALSE);
        gtk_main_quit();
-    return FALSE;
+       return FALSE;
 }
 
 static void
@@ -803,21 +836,25 @@ update_acodec_combo(signal_user_data_t *ud)
 void
 container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
-       g_debug("container_changed_cb ()\n");
+       const GValue *audio_list;
+       g_debug("container_changed_cb ()");
        ghb_widget_to_setting(ud->settings, widget);
        update_destination_extension(ud);
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
        update_acodec_combo(ud);
        clear_presets_selection(ud);
-       if (ghb_ac3_in_audio_list (ud->audio_settings))
+
+       audio_list = ghb_settings_get_value(ud->settings, "audio_list");
+       if (ghb_ac3_in_audio_list (audio_list))
        {
-               const gchar *container;
+               gchar *container;
 
                container = ghb_settings_get_string(ud->settings, "container");
                if (strcmp(container, "mp4") == 0)
                {
-                       ghb_ui_update(ud, "container", "m4v");
+                       ghb_ui_update(ud, "container", ghb_string_value("m4v"));
                }
+               g_free(container);
        }
 }
 
@@ -868,6 +905,8 @@ show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
        widget = GHB_WIDGET (ud->builder, "source_dimensions");
        text = g_strdup_printf ("%d x %d", tinfo->width, tinfo->height);
        gtk_label_set_text (GTK_LABEL(widget), text);
+       ghb_settings_set_int(ud->settings, "source_width", tinfo->width);
+       ghb_settings_set_int(ud->settings, "source_height", tinfo->height);
        g_free(text);
        widget = GHB_WIDGET (ud->builder, "source_aspect");
        text = get_aspect_string(tinfo->aspect_n, tinfo->aspect_d);
@@ -879,12 +918,17 @@ show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
        gtk_label_set_text (GTK_LABEL(widget), text);
        g_free(text);
 
-       ghb_ui_update_int (ud, "scale_width", tinfo->width - tinfo->crop[2] - tinfo->crop[3]);
+       ghb_ui_update(ud, "scale_width", 
+               ghb_int64_value(tinfo->width - tinfo->crop[2] - tinfo->crop[3]));
        // If anamorphic or keep_aspect, the hight will be automatically calculated
-       gboolean keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
-       gboolean anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
+       gboolean keep_aspect, anamorphic;
+       keep_aspect = ghb_settings_get_boolean(ud->settings, "keep_aspect");
+       anamorphic = ghb_settings_get_boolean(ud->settings, "anamorphic");
        if (!(keep_aspect || anamorphic))
-               ghb_ui_update_int (ud, "scale_height", tinfo->height - tinfo->crop[0] - tinfo->crop[1]);
+       {
+               ghb_ui_update(ud, "scale_height", 
+                       ghb_int64_value(tinfo->height - tinfo->crop[0] - tinfo->crop[1]));
+       }
 
        // Set the limits of cropping.  hb_set_anamorphic_size crashes if
        // you pass it a cropped width or height == 0.
@@ -899,14 +943,14 @@ show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
        gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
        widget = GHB_WIDGET (ud->builder, "crop_right");
        gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
-       if (ghb_settings_get_bool (ud->settings, "autocrop"))
+       if (ghb_settings_get_boolean(ud->settings, "autocrop"))
        {
-               ghb_ui_update_int (ud, "crop_top", tinfo->crop[0]);
-               ghb_ui_update_int (ud, "crop_bottom", tinfo->crop[1]);
-               ghb_ui_update_int (ud, "crop_left", tinfo->crop[2]);
-               ghb_ui_update_int (ud, "crop_right", tinfo->crop[3]);
+               ghb_ui_update(ud, "crop_top", ghb_int64_value(tinfo->crop[0]));
+               ghb_ui_update(ud, "crop_bottom", ghb_int64_value(tinfo->crop[1]));
+               ghb_ui_update(ud, "crop_left", ghb_int64_value(tinfo->crop[2]));
+               ghb_ui_update(ud, "crop_right", ghb_int64_value(tinfo->crop[3]));
        }
-       g_debug("setting max end chapter %d\n", tinfo->num_chapters);
+       g_debug("setting max end chapter %d", tinfo->num_chapters);
        widget = GHB_WIDGET (ud->builder, "end_chapter");
        gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters);
        gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), tinfo->num_chapters);
@@ -921,104 +965,140 @@ adjust_audio_rate_combos(signal_user_data_t *ud)
        ghb_audio_info_t ainfo;
        GtkWidget *widget;
        
-       g_debug("adjust_audio_rate_combos ()\n");
-       titleindex = ghb_settings_get_index(ud->settings, "title");
+       g_debug("adjust_audio_rate_combos ()");
+       titleindex = ghb_settings_combo_int(ud->settings, "title");
 
        widget = GHB_WIDGET(ud->builder, "audio_track");
-       audioindex = ghb_widget_int(widget);
+       audioindex = ghb_lookup_combo_int("audio_track", ghb_widget_value(widget));
 
        widget = GHB_WIDGET(ud->builder, "audio_codec");
-       acodec = ghb_widget_int(widget);
+       acodec = ghb_lookup_combo_int("audio_codec", ghb_widget_value(widget));
 
-       if (ghb_get_audio_info (&ainfo, titleindex, audioindex) && ghb_audio_is_passthru (acodec))
+       if (ghb_audio_is_passthru (acodec))
+       {
+               ghb_set_default_bitrate_opts (ud->builder, -1);
+               if (ghb_get_audio_info (&ainfo, titleindex, audioindex))
+               {
+                       gint br = ainfo.bitrate / 1000;
+                       // Set the values for bitrate and samplerate to the input rates
+                       ghb_set_passthru_bitrate_opts (ud->builder, br);
+                       ghb_ui_update(ud, "audio_bitrate", ghb_int64_value(br));
+                       ghb_ui_update(ud, "audio_rate", ghb_int64_value(0));
+                       ghb_ui_update(ud, "audio_mix", ghb_int64_value(0));
+               }
+               else
+               {
+                       ghb_ui_update(ud, "audio_bitrate", ghb_int64_value(384));
+                       ghb_ui_update(ud, "audio_rate", ghb_int64_value(0));
+                       ghb_ui_update(ud, "audio_mix", ghb_int64_value(0));
+               }
+       }
+       else if (acodec == HB_ACODEC_FAAC)
        {
-               // Set the values for bitrate and samplerate to the input rates
-               ghb_set_passthru_rate_opts (ud->builder, ainfo.bitrate);
-               ghb_ui_update_int (ud, "audio_bitrate", ainfo.bitrate);
-               ghb_ui_update_int (ud, "audio_rate", 0);
-               ghb_ui_update_int (ud, "audio_mix", 0);
+               gint br;
+
+               widget = GHB_WIDGET(ud->builder, "audio_bitrate");
+               br = ghb_lookup_combo_int("audio_bitrate", ghb_widget_value(widget));
+               if (br > 160)
+                       ghb_ui_update(ud, "audio_bitrate", ghb_int64_value(160));
+               ghb_set_default_bitrate_opts (ud->builder, 160);
        }
        else
        {
-               ghb_set_default_rate_opts (ud->builder);
+               ghb_set_default_bitrate_opts (ud->builder, -1);
        }
 }
 
 static void
 set_pref_audio(gint titleindex, signal_user_data_t *ud)
 {
-       gint acodec, track, ivalue;
-       const gchar *svalue;
+       gint acodec_code, mix_code, track;
+       gchar *source_lang;
        GtkWidget *button;
        ghb_audio_info_t ainfo;
-       gchar* drcstr;
        gint index;
        GHashTable *track_indicies;
        gint *iptr;
+
+       GValue *pref_audio;
+       GValue *audio, *acodec, *bitrate, *rate, *mix, *drc;
+       gint count, ii, list_count;
        
+       g_debug("set_pref_audio");
        track_indicies = g_hash_table_new(g_int_hash, g_int_equal);
        // Clear the audio list
        clear_audio_list(ud);
        // Find "best" audio based on audio preferences
        button = GHB_WIDGET (ud->builder, "audio_add");
-       svalue = ghb_settings_get_short_opt(ud->settings, "source_audio_lang");
-       gint acount = ghb_pref_acount();
-       gint ii;
-       gint list_count = 0;
-       for (ii = 0; ii < acount; ii++)
+       source_lang = ghb_settings_get_string(ud->settings, "source_audio_lang");
+
+       pref_audio = ghb_settings_get_value(ud->settings, "pref_audio_list");
+
+       list_count = 0;
+       count = ghb_array_len(pref_audio);
+       for (ii = 0; ii < count; ii++)
        {
-               acodec = ghb_pref_acodec(ii);
-               iptr = g_hash_table_lookup(track_indicies, &acodec);
+               audio = ghb_array_get_nth(pref_audio, ii);
+               acodec = ghb_settings_get_value(audio, "audio_codec");
+               bitrate = ghb_settings_get_value(audio, "audio_bitrate");
+               rate = ghb_settings_get_value(audio, "audio_rate");
+               mix = ghb_settings_get_value(audio, "audio_mix");
+               drc = ghb_settings_get_value(audio, "audio_drc");
+               acodec_code = ghb_lookup_combo_int("audio_codec", acodec);
+               // If there are multiple audios using the same codec, then
+               // select sequential tracks for each.  This hash keeps track 
+               // of the last used track for each codec.
+               iptr = g_hash_table_lookup(track_indicies, &acodec_code);
                if (iptr == NULL)
                        index = 0;
                else
                        index = *(gint*)iptr;
 
-               track = ghb_find_audio_track(titleindex, svalue, index);
+               track = ghb_find_audio_track(titleindex, source_lang, index);
                // Check to see if:
                // 1. pref codec is ac3
                // 2. source codec is not ac3
                // 3. next pref is enabled
                if (ghb_get_audio_info (&ainfo, titleindex, track) && 
-                       ghb_audio_is_passthru (acodec))
+                       ghb_audio_is_passthru (acodec_code))
                {
                        if (!ghb_audio_is_passthru(ainfo.codec))
                        {
-                               acodec = ghb_get_default_acodec();
-                               if ((ii + 1 < acount) || (list_count != 0))
+                               acodec_code = ghb_get_default_acodec();
+                               // If there's more audio to process, or we've already
+                               // placed one in the list, then we can skip this one
+                               if ((ii + 1 < count) || (list_count != 0))
                                {
                                        // Skip this audio
-                                       acodec = 0;
+                                       acodec_code = 0;
                                }
                        }
                }
                if (titleindex >= 0 && track < 0)
-                       acodec = 0;
-               if (acodec != 0)
+                       acodec_code = 0;
+               if (acodec_code != 0)
                {
                        // Add to audio list
                        g_signal_emit_by_name(button, "clicked", ud);
                        list_count++;
-                       ghb_ui_update_int(ud, "audio_track", track);
-                       ghb_ui_update_int(ud, "audio_codec", acodec);
-                       if (!ghb_audio_is_passthru (acodec))
+                       ghb_ui_update(ud, "audio_track", ghb_int64_value(track));
+                       ghb_ui_update(ud, "audio_codec", acodec);
+                       if (!ghb_audio_is_passthru (acodec_code))
                        {
                                // This gets set autimatically if the codec is passthru
-                               ivalue = ghb_pref_bitrate(ii);
-                               ghb_ui_update_int(ud, "audio_bitrate", ivalue);
-                               ivalue = ghb_pref_rate(ii);
-                               ghb_ui_update_int(ud, "audio_rate", ivalue);
-                               ivalue = ghb_pref_mix(ii);
-                               ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
-                               ghb_ui_update_int(ud, "audio_mix", ivalue);
+                               ghb_ui_update(ud, "audio_bitrate", bitrate);
+                               ghb_ui_update(ud, "audio_rate", rate);
+                               mix_code = ghb_lookup_combo_int("audio_mix", mix);
+                               mix_code = ghb_get_best_mix(
+                                       titleindex, track, acodec_code, mix_code);
+                               ghb_ui_update(ud, "audio_mix", ghb_int64_value(mix_code));
                        }
-                       drcstr = g_strdup_printf("%.2g", ghb_pref_drc(ii));
-                       ghb_ui_update(ud, "audio_drc", drcstr);
-                       g_free(drcstr);
+                       ghb_ui_update(ud, "audio_drc", drc);
                        index++;
-                       g_hash_table_insert(track_indicies, &acodec, &index);
+                       g_hash_table_insert(track_indicies, &acodec_code, &index);
                }
        }
+       g_free(source_lang);
        g_hash_table_destroy(track_indicies);
 }
 
@@ -1032,8 +1112,10 @@ set_preview_image(signal_user_data_t *ud)
        GtkWidget *widget;
        gint preview_width, preview_height, target_height, width, height;
 
-       g_debug("set_preview_button_image ()\n");
-       gint titleindex = ghb_settings_get_int(ud->settings, "title");
+       g_debug("set_preview_button_image ()");
+       gint titleindex;
+
+       titleindex = ghb_settings_combo_int(ud->settings, "title");
        if (titleindex < 0) return;
        widget = GHB_WIDGET (ud->builder, "preview_frame");
        gint frame = ghb_widget_int(widget) - 1;
@@ -1049,7 +1131,7 @@ set_preview_image(signal_user_data_t *ud)
        gtk_label_set_text(GTK_LABEL(widget), text);
        g_free(text);
        
-       g_debug("preview %d x %d\n", preview_width, preview_height);
+       g_debug("preview %d x %d", preview_width, preview_height);
        target_height = MIN(preview_button_height - 12, 128);
        height = target_height;
        width = preview_width * height / preview_height;
@@ -1074,17 +1156,19 @@ title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
        ghb_title_info_t tinfo;
        gint titleindex;
-       const gchar *preset;
+       gchar *preset;
        
-       g_debug("title_changed_cb ()\n");
+       g_debug("title_changed_cb ()");
        ghb_widget_to_setting(ud->settings, widget);
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
 
-       titleindex = ghb_settings_get_int(ud->settings, "title");
+       titleindex = ghb_settings_combo_int(ud->settings, "title");
        ghb_update_ui_combo_box (ud->builder, "audio_track", titleindex, FALSE);
        ghb_update_ui_combo_box (ud->builder, "subtitle_lang", titleindex, FALSE);
+
        preset = ghb_settings_get_string (ud->settings, "preset");
        ghb_update_from_preset(ud, preset, "subtitle_lang");
+       g_free(preset);
        if (ghb_get_title_info (&tinfo, titleindex))
        {
                show_title_info(ud, &tinfo);
@@ -1092,17 +1176,17 @@ title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
        update_chapter_list (ud);
        adjust_audio_rate_combos(ud);
        set_pref_audio(titleindex, ud);
-       if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
+       if (ghb_settings_get_boolean(ud->settings, "vquality_type_target"))
        {
                gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
-               ghb_ui_update_int (ud, "video_bitrate", bitrate);
+               ghb_ui_update(ud, "video_bitrate", ghb_int64_value(bitrate));
        }
 
        // Unfortunately, there is no way to query how many frames were
        // actually generated during the scan.  It attempts to make 10.
        // If I knew how many were generated, I would adjust the spin
        // control range here.
-       ghb_ui_update_int (ud, "preview_frame", 1);
+       ghb_ui_update(ud, "preview_frame", ghb_int64_value(1));
 
        set_preview_image (ud);
 }
@@ -1111,76 +1195,85 @@ void
 audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
        static gint prev_acodec = 0;
-       gint acodec, ivalue;
-       GHashTable *asettings;
-       
-       g_debug("audio_codec_changed_cb ()\n");
+       gint acodec_code, mix_code;
+       GValue *asettings;
        
-       acodec = ghb_widget_int(widget);
-       if (ghb_audio_is_passthru (prev_acodec) && !ghb_audio_is_passthru (acodec))
+       g_debug("audio_codec_changed_cb ()");
+       acodec_code = ghb_lookup_combo_int("audio_codec", ghb_widget_value(widget));
+       if (ghb_audio_is_passthru (prev_acodec) && 
+               !ghb_audio_is_passthru (acodec_code))
        {
                // Transition from passthru to not, put some audio settings back to 
                // pref settings
-               gint titleindex = ghb_settings_get_int(ud->settings, "title");
-               gint track = ghb_settings_get_int(ud->settings, "audio_track");
-
-               ivalue = ghb_pref_bitrate(0);
-               ghb_ui_update_int (ud, "audio_bitrate", ivalue);
-               ivalue = ghb_pref_rate(0);
-               ghb_ui_update_int (ud, "audio_rate", ivalue);
-               ivalue = ghb_pref_mix(0);
-               ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
-               ghb_ui_update_int (ud, "audio_mix", ivalue);
+               gint titleindex;
+               gint track;
+
+               titleindex = ghb_settings_combo_int(ud->settings, "title");
+               track = ghb_settings_combo_int(ud->settings, "audio_track");
+
+               ghb_ui_update(ud, "audio_bitrate", ghb_string_value("160"));
+               ghb_ui_update(ud, "audio_rate", ghb_string_value("source"));
+               mix_code = ghb_lookup_combo_int("audio_mix", ghb_string_value("dpl2"));
+               mix_code = ghb_get_best_mix( titleindex, track, acodec_code, mix_code);
+               ghb_ui_update(ud, "audio_mix", ghb_int64_value(mix_code));
+               ghb_ui_update(ud, "audio_drc", ghb_double_value(1.0));
        }
        adjust_audio_rate_combos(ud);
        ghb_grey_combo_options (ud->builder);
-       check_depencency(ud, widget);
-       prev_acodec = acodec;
+       check_dependency(ud, widget);
+       prev_acodec = acodec_code;
        asettings = get_selected_asettings(ud);
        if (asettings != NULL)
        {
                ghb_widget_to_setting(asettings, widget);
                audio_list_refresh_selected(ud);
        }
-       if (ghb_ac3_in_audio_list (ud->audio_settings))
+
+       const GValue *audio_list;
+       audio_list = ghb_settings_get_value(ud->settings, "audio_list");
+       if (ghb_ac3_in_audio_list (audio_list))
        {
-               const gchar *container;
+               gchar *container;
 
                container = ghb_settings_get_string(ud->settings, "container");
                if (strcmp(container, "mp4") == 0)
                {
-                       ghb_ui_update(ud, "container", "m4v");
+                       ghb_ui_update(ud, "container", ghb_string_value("m4v"));
                }
+               g_free(container);
        }
 }
 
 static void audio_list_refresh_selected(signal_user_data_t *ud);
-static GHashTable* get_selected_asettings(signal_user_data_t *ud);
 
 void
 audio_track_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
-       GHashTable *asettings;
+       GValue *asettings;
 
-       g_debug("audio_track_changed_cb ()\n");
+       g_debug("audio_track_changed_cb ()");
        adjust_audio_rate_combos(ud);
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
        ghb_grey_combo_options(ud->builder);
        asettings = get_selected_asettings(ud);
        if (asettings != NULL)
        {
+               const gchar *track;
+
                ghb_widget_to_setting(asettings, widget);
                audio_list_refresh_selected(ud);
+               track = ghb_settings_combo_option(asettings, "audio_track");
+               ghb_settings_set_string(asettings, "audio_track_long", track);
        }
 }
 
 void
 audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
-       GHashTable *asettings;
+       GValue *asettings;
 
-       g_debug("audio_widget_changed_cb ()\n");
-       check_depencency(ud, widget);
+       g_debug("audio_widget_changed_cb ()");
+       check_dependency(ud, widget);
        asettings = get_selected_asettings(ud);
        if (asettings != NULL)
        {
@@ -1192,23 +1285,76 @@ audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 void
 generic_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
-       g_debug("generic_widget_changed_cb ()\n");
-       check_depencency(ud, widget);
+       g_debug("generic_widget_changed_cb ()");
+       check_dependency(ud, widget);
 }
 
 void
 setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
        ghb_widget_to_setting(ud->settings, widget);
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
        clear_presets_selection(ud);
 }
 
+static void
+validate_filter_widget(signal_user_data_t *ud, const gchar *name)
+{
+       GtkTreeModel *store;
+       GtkTreeIter iter;
+       const gchar *str;
+       gboolean foundit = FALSE;
+       GtkComboBox *combo = GTK_COMBO_BOX(GHB_WIDGET(ud->builder, name));
+       if (gtk_combo_box_get_active(combo) < 0)
+       { // Validate user input
+               gchar *val = ghb_settings_get_string(ud->settings, name);
+               store = gtk_combo_box_get_model(combo);
+               // Check to see if user manually entered one of the combo options
+               if (gtk_tree_model_get_iter_first(store, &iter))
+               {
+                       do
+                       {
+                               gtk_tree_model_get(store, &iter, 0, &str, -1);
+                               if (strcasecmp(val, str) == 0)
+                               {
+                                       gtk_combo_box_set_active_iter(combo, &iter);
+                                       foundit = TRUE;
+                                       break;
+                               }
+                       } while (gtk_tree_model_iter_next(store, &iter));
+               }
+               if (!foundit)
+               { // validate format of filter string
+                       if (!ghb_validate_filter_string(val, -1))
+                               gtk_combo_box_set_active(combo, 0);
+               }
+               g_free(val);
+       }
+}
+
+gboolean
+deint_tweak_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
+       signal_user_data_t *ud)
+{
+       g_debug("deint_tweak_focus_out_cb ()");
+       validate_filter_widget(ud, "tweak_deinterlace");
+       return FALSE;
+}
+
+gboolean
+denoise_tweak_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
+       signal_user_data_t *ud)
+{
+       g_debug("denoise_tweak_focus_out_cb ()");
+       validate_filter_widget(ud, "tweak_noise");
+       return FALSE;
+}
+
 void
 http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
        ghb_widget_to_setting(ud->settings, widget);
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
        clear_presets_selection(ud);
        ghb_grey_combo_options (ud->builder);
 }
@@ -1219,7 +1365,7 @@ vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
        gint vqmin, vqmax;
 
        ghb_widget_to_setting(ud->settings, widget);
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
        clear_presets_selection(ud);
        ghb_vquality_range(ud, &vqmin, &vqmax);
        GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
@@ -1230,32 +1376,16 @@ void
 vfr_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
        //const gchar *name = gtk_widget_get_name(widget);
-       //g_debug("setting_widget_changed_cb () %s\n", name);
+       //g_debug("setting_widget_changed_cb () %s", name);
        ghb_widget_to_setting(ud->settings, widget);
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
        clear_presets_selection(ud);
-       if (ghb_settings_get_bool(ud->settings, "variable_frame_rate"))
+       if (ghb_settings_get_boolean(ud->settings, "variable_frame_rate"))
        {
-               ghb_ui_update_int(ud, "framerate", 0);
+               ghb_ui_update(ud, "framerate", ghb_int64_value(0));
        }
 }
 
-void
-mirror_cb(GtkWidget *widget, signal_user_data_t *ud)
-{
-       const gchar *name = gtk_widget_get_name(widget);
-       if (name == NULL) return;
-       
-       g_debug("mirror_cb () %s\n", name);
-       gchar *mirror = g_strdup(name);
-       gchar *pos = g_strrstr(mirror, "_mirror");
-       if (pos == NULL) return;
-       *pos = 0;
-       gchar *value = ghb_widget_short_opt (widget);
-       ghb_ui_update (ud, mirror, value);
-       g_free(mirror);
-}
-
 // subtitles have their differ from other settings in that
 // the selection is updated automaitcally when the title
 // changes.  I don't want the preset selection changed as
@@ -1264,61 +1394,72 @@ void
 subtitle_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
        const gchar *name = gtk_widget_get_name(widget);
-       g_debug("subtitle_changed_cb () %s\n", name);
+       g_debug("subtitle_changed_cb () %s", name);
        ghb_widget_to_setting(ud->settings, widget);
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
 }
 
 void
 target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
        const gchar *name = gtk_widget_get_name(widget);
-       g_debug("setting_widget_changed_cb () %s\n", name);
+       g_debug("setting_widget_changed_cb () %s", name);
        ghb_widget_to_setting(ud->settings, widget);
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
        clear_presets_selection(ud);
-       if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
+       if (ghb_settings_get_boolean(ud->settings, "vquality_type_target"))
        {
-               gint titleindex = ghb_settings_get_int(ud->settings, "title");
+               gint titleindex;
+               titleindex = ghb_settings_combo_int(ud->settings, "title");
                gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
-               ghb_ui_update_int (ud, "video_bitrate", bitrate);
+               ghb_ui_update(ud, "video_bitrate", ghb_int64_value(bitrate));
        }
 }
 
 void
 start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
+       gint start, end;
        const gchar *name = gtk_widget_get_name(widget);
-       g_debug("start_chapter_changed_cb () %s\n", name);
+
+       g_debug("start_chapter_changed_cb () %s", name);
        ghb_widget_to_setting(ud->settings, widget);
-       GtkWidget *end_ch = GHB_WIDGET (ud->builder, "end_chapter");
-       gdouble start, end;
-       gtk_spin_button_get_range (GTK_SPIN_BUTTON(end_ch), &start, &end);
        start = ghb_settings_get_int(ud->settings, "start_chapter");
-       gtk_spin_button_set_range (GTK_SPIN_BUTTON(end_ch), start, end);
-       check_depencency(ud, widget);
+       end = ghb_settings_get_int(ud->settings, "end_chapter");
+       if (start > end)
+               ghb_ui_update(ud, "end_chapter", ghb_int_value(start));
+       check_dependency(ud, widget);
+       if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
+       {
+               set_destination(ud);
+       }
 }
 
 void
 end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
+       gint start, end;
        const gchar *name = gtk_widget_get_name(widget);
-       g_debug("end_chapter_changed_cb () %s\n", name);
+
+       g_debug("end_chapter_changed_cb () %s", name);
        ghb_widget_to_setting(ud->settings, widget);
-       GtkWidget *start_ch = GHB_WIDGET (ud->builder, "start_chapter");
-       gdouble start, end;
-       gtk_spin_button_get_range (GTK_SPIN_BUTTON(start_ch), &start, &end);
+       start = ghb_settings_get_int(ud->settings, "start_chapter");
        end = ghb_settings_get_int(ud->settings, "end_chapter");
-       gtk_spin_button_set_range (GTK_SPIN_BUTTON(start_ch), start, end);
-       check_depencency(ud, widget);
+       if (start > end)
+               ghb_ui_update(ud, "start_chapter", ghb_int_value(end));
+       check_dependency(ud, widget);
+       if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
+       {
+               set_destination(ud);
+       }
 }
 
 void
 scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
-       g_debug("scale_width_changed_cb ()\n");
+       g_debug("scale_width_changed_cb ()");
        ghb_widget_to_setting(ud->settings, widget);
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
        ghb_set_scale (ud, GHB_SCALE_KEEP_WIDTH);
        update_preview = TRUE;
        gchar *text;
@@ -1333,9 +1474,9 @@ scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 void
 scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
-       g_debug("scale_height_changed_cb ()\n");
+       g_debug("scale_height_changed_cb ()");
        ghb_widget_to_setting(ud->settings, widget);
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
        ghb_set_scale (ud, GHB_SCALE_KEEP_HEIGHT);
        update_preview = TRUE;
        gchar *text;
@@ -1353,16 +1494,16 @@ crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
        gint titleindex, crop[4];
        ghb_title_info_t tinfo;
        
-       g_debug("crop_changed_cb ()\n");
+       g_debug("crop_changed_cb ()");
        ghb_widget_to_setting(ud->settings, widget);
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
        ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
 
        crop[0] = ghb_settings_get_int(ud->settings, "crop_top");
        crop[1] = ghb_settings_get_int(ud->settings, "crop_bottom");
        crop[2] = ghb_settings_get_int(ud->settings, "crop_left");
        crop[3] = ghb_settings_get_int(ud->settings, "crop_right");
-       titleindex = ghb_settings_get_index(ud->settings, "title");
+       titleindex = ghb_settings_combo_int(ud->settings, "title");
        if (ghb_get_title_info (&tinfo, titleindex))
        {
                gint width, height;
@@ -1386,22 +1527,22 @@ crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 void
 scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
-       g_debug("scale_changed_cb ()\n");
+       g_debug("scale_changed_cb ()");
        ghb_widget_to_setting(ud->settings, widget);
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
        clear_presets_selection(ud);
        ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
        update_preview = TRUE;
        
        gchar *text;
        
-       text = ghb_settings_get_bool(ud->settings, "autocrop") ? "On" : "Off";
+       text = ghb_settings_get_boolean(ud->settings, "autocrop") ? "On" : "Off";
        widget = GHB_WIDGET (ud->builder, "crop_auto");
        gtk_label_set_text (GTK_LABEL(widget), text);
-       text = ghb_settings_get_bool(ud->settings, "autoscale") ? "On" : "Off";
+       text = ghb_settings_get_boolean(ud->settings, "autoscale") ? "On" : "Off";
        widget = GHB_WIDGET (ud->builder, "scale_auto");
        gtk_label_set_text (GTK_LABEL(widget), text);
-       text = ghb_settings_get_bool(ud->settings, "anamorphic") ? "On" : "Off";
+       text = ghb_settings_get_boolean(ud->settings, "anamorphic") ? "On" : "Off";
        widget = GHB_WIDGET (ud->builder, "scale_anamorphic");
        gtk_label_set_text (GTK_LABEL(widget), text);
 }
@@ -1416,7 +1557,7 @@ generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
        // The changed signal is sent ... so here we are.
        // I don't want to process upon every keystroke, so I prevent processing
        // while the widget has focus.
-       g_debug("generic_entry_changed_cb ()\n");
+       g_debug("generic_entry_changed_cb ()");
        if (!GTK_WIDGET_HAS_FOCUS((GtkWidget*)entry))
        {
                ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
@@ -1425,9 +1566,9 @@ generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
 
 gboolean
 generic_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
-    signal_user_data_t *ud)
+       signal_user_data_t *ud)
 {
-       g_debug("generic_focus_out_cb ()\n");
+       g_debug("generic_focus_out_cb ()");
        ghb_widget_to_setting(ud->settings, widget);
        return FALSE;
 }
@@ -1445,49 +1586,55 @@ x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
                ghb_x264_opt_update(ud, widget);
                ignore_options_update = FALSE;
        }
-       check_depencency(ud, widget);
+       check_dependency(ud, widget);
        clear_presets_selection(ud);
 }
 
 void
 x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
-       g_debug("x264_entry_changed_cb ()\n");
+       g_debug("x264_entry_changed_cb ()");
        if (!ignore_options_update)
        {
                GtkWidget *textview;
+               gchar *options;
+
                textview = GTK_WIDGET(GHB_WIDGET(ud->builder, "x264_options"));
                ghb_widget_to_setting(ud->settings, textview);
-               gchar *options;
-               options = (gchar*)ghb_settings_get_string(ud->settings, "x264_options");
+               options = ghb_settings_get_string(ud->settings, "x264_options");
                ignore_options_update = TRUE;
                ghb_x264_parse_options(ud, options);
                if (!GTK_WIDGET_HAS_FOCUS(textview))
                {
-                       options = ghb_sanitize_x264opts(ud, options);
-                       ghb_ui_update(ud, "x264_options", options);
-                       ghb_x264_parse_options(ud, options);
-                       g_free(options);
+                       gchar *sopts;
+
+                       sopts = ghb_sanitize_x264opts(ud, options);
+                       ghb_ui_update(ud, "x264_options", ghb_string_value(sopts));
+                       ghb_x264_parse_options(ud, sopts);
+                       g_free(sopts);
                }
+               g_free(options);
                ignore_options_update = FALSE;
        }
 }
 
 gboolean
 x264_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
-    signal_user_data_t *ud)
+       signal_user_data_t *ud)
 {
+       gchar *options, *sopts;
+
        ghb_widget_to_setting(ud->settings, widget);
-       gchar *options;
-       options = (gchar*)ghb_settings_get_string(ud->settings, "x264_options");
-       options = ghb_sanitize_x264opts(ud, options);
+       options = ghb_settings_get_string(ud->settings, "x264_options");
+       sopts = ghb_sanitize_x264opts(ud, options);
        ignore_options_update = TRUE;
-       if (options != NULL)
+       if (sopts != NULL)
        {
-               ghb_ui_update(ud, "x264_options", options);
-               ghb_x264_parse_options(ud, options);
-               g_free(options);
+               ghb_ui_update(ud, "x264_options", ghb_string_value(sopts));
+               ghb_x264_parse_options(ud, sopts);
        }
+       g_free(options);
+       g_free(sopts);
        ignore_options_update = FALSE;
        return FALSE;
 }
@@ -1497,51 +1644,76 @@ clear_audio_list(signal_user_data_t *ud)
 {
        GtkTreeView *treeview;
        GtkListStore *store;
-       GSList *link;
+       GValue *audio_list;
        
-       g_debug("clear_audio_list ()\n");
-       while (ud->audio_settings != NULL)
+       g_debug("clear_audio_list ()");
+       audio_list = ghb_settings_get_value(ud->settings, "audio_list");
+       if (audio_list == NULL)
        {
-               link = ud->audio_settings;
-               ud->audio_settings = g_slist_remove_link(ud->audio_settings, link);
-               g_hash_table_destroy((GHashTable*)link->data);
-               g_slist_free_1(link);
+               audio_list = ghb_array_value_new(8);
+               ghb_settings_set_value(ud->settings, "audio_list", audio_list);
        }
+       else
+               ghb_array_value_reset(audio_list, 8);
        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
        store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
        gtk_list_store_clear (store);
 }
 
 static void
-add_to_audio_list(signal_user_data_t *ud, GHashTable *settings)
+add_to_audio_list(signal_user_data_t *ud, GValue *settings)
 {
        GtkTreeView *treeview;
        GtkTreeIter iter;
        GtkListStore *store;
        GtkTreeSelection *selection;
+       const gchar *track, *codec, *br, *sr, *mix;
+       gchar *drc, *s_track, *s_codec, *s_br, *s_sr, *s_mix;
+       gdouble s_drc;
        
-       g_debug("add_to_audio_list ()\n");
+       g_debug("add_to_audio_list ()");
        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
        selection = gtk_tree_view_get_selection (treeview);
        store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
 
+       track = ghb_settings_combo_option(settings, "audio_track");
+       codec = ghb_settings_combo_option(settings, "audio_codec");
+       br = ghb_settings_combo_option(settings, "audio_bitrate");
+       sr = ghb_settings_combo_option(settings, "audio_rate");
+       mix = ghb_settings_combo_option(settings, "audio_mix");
+       drc = ghb_settings_get_string(settings, "audio_drc");
+
+       s_track = ghb_settings_get_string(settings, "audio_track");
+       s_codec = ghb_settings_get_string(settings, "audio_codec");
+       s_br = ghb_settings_get_string(settings, "audio_bitrate");
+       s_sr = ghb_settings_get_string(settings, "audio_rate");
+       s_mix = ghb_settings_get_string(settings, "audio_mix");
+       s_drc = ghb_settings_get_double(settings, "audio_drc");
+
        gtk_list_store_append(store, &iter);
        gtk_list_store_set(store, &iter, 
                // These are displayed in list
-               0, ghb_settings_get_option(settings, "audio_track"),
-               1, ghb_settings_get_option(settings, "audio_codec"),
-               2, ghb_settings_get_option(settings, "audio_bitrate"),
-               3, ghb_settings_get_option(settings, "audio_rate"),
-               4, ghb_settings_get_option(settings, "audio_mix"),
+               0, track,
+               1, codec,
+               2, br,
+               3, sr,
+               4, mix,
                // These are used to set combo box values when a list item is selected
-               5, ghb_settings_get_string(settings, "audio_drc"),
-               6, ghb_settings_get_short_opt(settings, "audio_track"),
-               7, ghb_settings_get_short_opt(settings, "audio_codec"),
-               8, ghb_settings_get_short_opt(settings, "audio_bitrate"),
-               9, ghb_settings_get_short_opt(settings, "audio_rate"),
-               10, ghb_settings_get_short_opt(settings, "audio_mix"),
+               5, drc,
+               6, s_track,
+               7, s_codec,
+               8, s_br,
+               9, s_sr,
+               10, s_mix,
+               11, s_drc,
                -1);
        gtk_tree_selection_select_iter(selection, &iter);
+       g_free(drc);
+       g_free(s_track);
+       g_free(s_codec);
+       g_free(s_br);
+       g_free(s_sr);
+       g_free(s_mix);
 }
 
 static void
@@ -1554,43 +1726,69 @@ audio_list_refresh_selected(signal_user_data_t *ud)
        GtkTreeIter iter;
        gint *indices;
        gint row;
-       GSList *link;
-       GHashTable *asettings = NULL;
+       GValue *asettings = NULL;
+       const GValue *audio_list;
        
-       g_debug("get_selected_asettings ()\n");
+       g_debug("audio_list_refresh_selected ()");
        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
        selection = gtk_tree_view_get_selection (treeview);
        if (gtk_tree_selection_get_selected(selection, &store, &iter))
        {
-        // Get the row number
+               const gchar *track, *codec, *br, *sr, *mix;
+               gchar *drc, *s_track, *s_codec, *s_br, *s_sr, *s_mix;
+               gdouble s_drc;
+               // Get the row number
                treepath = gtk_tree_model_get_path (store, &iter);
                indices = gtk_tree_path_get_indices (treepath);
-               g_free(treepath);
                row = indices[0];
+               gtk_tree_path_free(treepath);
                // find audio settings
                if (row < 0) return;
-               link = g_slist_nth(ud->audio_settings, row);
-               if (link == NULL) return;
-               asettings = (GHashTable*)link->data;
+               audio_list = ghb_settings_get_value(ud->settings, "audio_list");
+               if (row >= ghb_array_len(audio_list))
+                       return;
+               asettings = ghb_array_get_nth(audio_list, row);
+
+               track = ghb_settings_combo_option(asettings, "audio_track");
+               codec = ghb_settings_combo_option(asettings, "audio_codec");
+               br = ghb_settings_combo_option(asettings, "audio_bitrate");
+               sr = ghb_settings_combo_option(asettings, "audio_rate");
+               mix = ghb_settings_combo_option(asettings, "audio_mix");
+               drc = ghb_settings_get_string(asettings, "audio_drc");
+
+               s_track = ghb_settings_get_string(asettings, "audio_track");
+               s_codec = ghb_settings_get_string(asettings, "audio_codec");
+               s_br = ghb_settings_get_string(asettings, "audio_bitrate");
+               s_sr = ghb_settings_get_string(asettings, "audio_rate");
+               s_mix = ghb_settings_get_string(asettings, "audio_mix");
+               s_drc = ghb_settings_get_double(asettings, "audio_drc");
+
                gtk_list_store_set(GTK_LIST_STORE(store), &iter, 
                        // These are displayed in list
-                       0, ghb_settings_get_option(asettings, "audio_track"),
-                       1, ghb_settings_get_option(asettings, "audio_codec"),
-                       2, ghb_settings_get_option(asettings, "audio_bitrate"),
-                       3, ghb_settings_get_option(asettings, "audio_rate"),
-                       4, ghb_settings_get_option(asettings, "audio_mix"),
-                       // These are used to set combo box values when a list item is selected
-                       5, ghb_settings_get_string(asettings, "audio_drc"),
-                       6, ghb_settings_get_short_opt(asettings, "audio_track"),
-                       7, ghb_settings_get_short_opt(asettings, "audio_codec"),
-                       8, ghb_settings_get_short_opt(asettings, "audio_bitrate"),
-                       9, ghb_settings_get_short_opt(asettings, "audio_rate"),
-                       10, ghb_settings_get_short_opt(asettings, "audio_mix"),
+                       0, track,
+                       1, codec,
+                       2, br,
+                       3, sr,
+                       4, mix,
+                       // These are used to set combo values when a list item is selected
+                       5, drc,
+                       6, s_track,
+                       7, s_codec,
+                       8, s_br,
+                       9, s_sr,
+                       10, s_mix,
+                       11, s_drc,
                        -1);
+               g_free(drc);
+               g_free(s_track);
+               g_free(s_codec);
+               g_free(s_br);
+               g_free(s_sr);
+               g_free(s_mix);
        }
 }
 
-static GHashTable*
+static GValue*
 get_selected_asettings(signal_user_data_t *ud)
 {
        GtkTreeView *treeview;
@@ -1600,24 +1798,25 @@ get_selected_asettings(signal_user_data_t *ud)
        GtkTreeIter iter;
        gint *indices;
        gint row;
-       GSList *link;
-       GHashTable *asettings = NULL;
+       GValue *asettings = NULL;
+       const GValue *audio_list;
        
-       g_debug("get_selected_asettings ()\n");
+       g_debug("get_selected_asettings ()");
        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
        selection = gtk_tree_view_get_selection (treeview);
        if (gtk_tree_selection_get_selected(selection, &store, &iter))
        {
-        // Get the row number
+               // Get the row number
                treepath = gtk_tree_model_get_path (store, &iter);
                indices = gtk_tree_path_get_indices (treepath);
-               g_free(treepath);
                row = indices[0];
+               gtk_tree_path_free(treepath);
                // find audio settings
                if (row < 0) return NULL;
-               link = g_slist_nth(ud->audio_settings, row);
-               if (link == NULL) return NULL;
-               asettings = (GHashTable*)link->data;
+               audio_list = ghb_settings_get_value(ud->settings, "audio_list");
+               if (row >= ghb_array_len(audio_list))
+                       return NULL;
+               asettings = ghb_array_get_nth(audio_list, row);
        }
        return asettings;
 }
@@ -1629,24 +1828,26 @@ audio_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t
        GtkTreeIter iter;
        GtkWidget *widget;
        
-       g_debug("audio_list_selection_changed_cb ()\n");
+       g_debug("audio_list_selection_changed_cb ()");
        if (gtk_tree_selection_get_selected(selection, &store, &iter))
        {
-               const gchar *track, *codec, *bitrate, *sample_rate, *mix, *drc;
+               const gchar *track, *codec, *bitrate, *sample_rate, *mix;
+               gdouble drc;
+
                gtk_tree_model_get(store, &iter,
                                                   6, &track,
                                                   7, &codec,
                                                   8, &bitrate,
                                                   9, &sample_rate,
                                                   10, &mix,
-                                                  5, &drc,
+                                                  11, &drc,
                                                   -1);
-               ghb_ui_update(ud, "audio_track", track);
-               ghb_ui_update(ud, "audio_codec", codec);
-               ghb_ui_update(ud, "audio_bitrate", bitrate);
-               ghb_ui_update(ud, "audio_rate", sample_rate);
-               ghb_ui_update(ud, "audio_mix", mix);
-               ghb_ui_update(ud, "audio_drc", drc);
+               ghb_ui_update(ud, "audio_track", ghb_string_value(track));
+               ghb_ui_update(ud, "audio_codec", ghb_string_value(codec));
+               ghb_ui_update(ud, "audio_bitrate", ghb_string_value(bitrate));
+               ghb_ui_update(ud, "audio_rate", ghb_string_value(sample_rate));
+               ghb_ui_update(ud, "audio_mix", ghb_string_value(mix));
+               ghb_ui_update(ud, "audio_drc", ghb_double_value(drc));
                widget = GHB_WIDGET (ud->builder, "audio_remove");
                gtk_widget_set_sensitive(widget, TRUE);
                //widget = GHB_WIDGET (ud->builder, "audio_update");
@@ -1665,29 +1866,39 @@ void
 audio_add_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
        // Add the current audio settings to the list.
-       GHashTable *asettings;
+       GValue *asettings;
        GtkWidget *widget;
        gint count;
+       GValue *audio_list;
+       const gchar *track;
        
-       g_debug("audio_add_clicked_cb ()\n");
+       g_debug("audio_add_clicked_cb ()");
+       asettings = ghb_dict_value_new();
        // Only allow up to 8 audio entries
-       asettings = ghb_settings_new();
        widget = GHB_WIDGET(ud->builder, "audio_track");
-       ghb_settings_set(asettings,     "audio_track", ghb_widget_value(widget));
+       ghb_settings_take_value(asettings, "audio_track", ghb_widget_value(widget));
        widget = GHB_WIDGET(ud->builder, "audio_codec");
-       ghb_settings_set(asettings,     "audio_codec", ghb_widget_value(widget));
+       ghb_settings_take_value(asettings, "audio_codec", ghb_widget_value(widget));
        widget = GHB_WIDGET(ud->builder, "audio_bitrate");
-       ghb_settings_set(asettings,     "audio_bitrate", ghb_widget_value(widget));
+       ghb_settings_take_value(asettings, "audio_bitrate", ghb_widget_value(widget));
        widget = GHB_WIDGET(ud->builder, "audio_rate");
-       ghb_settings_set(asettings,     "audio_rate", ghb_widget_value(widget));
+       ghb_settings_take_value(asettings, "audio_rate", ghb_widget_value(widget));
        widget = GHB_WIDGET(ud->builder, "audio_mix");
-       ghb_settings_set(asettings,     "audio_mix", ghb_widget_value(widget));
+       ghb_settings_take_value(asettings, "audio_mix", ghb_widget_value(widget));
        widget = GHB_WIDGET(ud->builder, "audio_drc");
-       ghb_settings_set(asettings,     "audio_drc", ghb_widget_value(widget));
+       ghb_settings_take_value(asettings, "audio_drc", ghb_widget_value(widget));
+       track = ghb_settings_combo_option(asettings, "audio_track");
+       ghb_settings_set_string(asettings, "audio_track_long", track);
 
-       ud->audio_settings = g_slist_append(ud->audio_settings, asettings);
+       audio_list = ghb_settings_get_value(ud->settings, "audio_list");
+       if (audio_list == NULL)
+       {
+               audio_list = ghb_array_value_new(8);
+               ghb_settings_set_value(ud->settings, "audio_list", audio_list);
+       }
+       ghb_array_append(audio_list, asettings);
        add_to_audio_list(ud, asettings);
-       count = g_slist_length(ud->audio_settings);
+       count = ghb_array_len(audio_list);
        if (count >= 8)
        {
                gtk_widget_set_sensitive(xwidget, FALSE);
@@ -1704,9 +1915,9 @@ audio_remove_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
        GtkTreeIter iter, nextIter;
        gint *indices;
        gint row;
-       GSList *link;
+       GValue *audio_list;
 
-       g_debug("audio_remove_clicked_cb ()\n");
+       g_debug("audio_remove_clicked_cb ()");
        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
        selection = gtk_tree_view_get_selection (treeview);
        if (gtk_tree_selection_get_selected(selection, &store, &iter))
@@ -1724,22 +1935,23 @@ audio_remove_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
                {
                        gtk_tree_selection_select_iter (selection, &nextIter);
                }
-        // Get the row number
+               // Get the row number
                treepath = gtk_tree_model_get_path (store, &iter);
                indices = gtk_tree_path_get_indices (treepath);
-               g_free(treepath);
                row = indices[0];
+               gtk_tree_path_free(treepath);
                // Remove the selected item
                gtk_list_store_remove (GTK_LIST_STORE(store), &iter);
                // remove from audio settings list
                if (row < 0) return;
-               link = g_slist_nth(ud->audio_settings, row);
-               if (link == NULL) return;
-               ud->audio_settings = g_slist_remove_link(ud->audio_settings, link);
-               g_hash_table_destroy((GHashTable*)link->data);
-               g_slist_free_1(link);
                widget = GHB_WIDGET (ud->builder, "audio_add");
                gtk_widget_set_sensitive(widget, TRUE);
+               audio_list = ghb_settings_get_value(ud->settings, "audio_list");
+               if (row >= ghb_array_len(audio_list))
+                       return;
+               GValue *old = ghb_array_get_nth(audio_list, row);
+               ghb_value_free(old);
+               ghb_array_remove(audio_list, row);
        }
 }
 
@@ -1750,37 +1962,65 @@ audio_list_refresh(signal_user_data_t *ud)
        GtkTreeIter iter;
        GtkListStore *store;
        gboolean done;
-       
-       g_debug("audio_list_refresh ()\n");
-       GSList *link = ud->audio_settings;
-       if (link == NULL) return;
+       gint row = 0;
+       GValue *audio_list;
+
+       g_debug("audio_list_refresh ()");
        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
        store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
        if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
        {
                do
                {
-                       GHashTable *asettings;
+                       const gchar *track, *codec, *br, *sr, *mix;
+                       gchar *drc, *s_track, *s_codec, *s_br, *s_sr, *s_mix;
+                       gdouble s_drc;
+                       GValue *asettings;
+
+                       audio_list = ghb_settings_get_value(ud->settings, "audio_list");
+                       if (row >= ghb_array_len(audio_list))
+                               return;
+                       asettings = ghb_array_get_nth(audio_list, row);
+
+                       track = ghb_settings_combo_option(asettings, "audio_track");
+                       codec = ghb_settings_combo_option(asettings, "audio_codec");
+                       br = ghb_settings_combo_option(asettings, "audio_bitrate");
+                       sr = ghb_settings_combo_option(asettings, "audio_rate");
+                       mix = ghb_settings_combo_option(asettings, "audio_mix");
+                       drc = ghb_settings_get_string(asettings, "audio_drc");
+
+                       s_track = ghb_settings_get_string(asettings, "audio_track");
+                       s_codec = ghb_settings_get_string(asettings, "audio_codec");
+                       s_br = ghb_settings_get_string(asettings, "audio_bitrate");
+                       s_sr = ghb_settings_get_string(asettings, "audio_rate");
+                       s_mix = ghb_settings_get_string(asettings, "audio_mix");
+                       s_drc = ghb_settings_get_double(asettings, "audio_drc");
 
-                       asettings = (GHashTable*)link->data;
                        gtk_list_store_set(GTK_LIST_STORE(store), &iter, 
                                // These are displayed in list
-                               0, ghb_settings_get_option(asettings, "audio_track"),
-                               1, ghb_settings_get_option(asettings, "audio_codec"),
-                               2, ghb_settings_get_option(asettings, "audio_bitrate"),
-                               3, ghb_settings_get_option(asettings, "audio_rate"),
-                               4, ghb_settings_get_option(asettings, "audio_mix"),
-                               // These are used to set combo box values when a list item is selected
-                               5, ghb_settings_get_string(asettings, "audio_drc"),
-                               6, ghb_settings_get_short_opt(asettings, "audio_track"),
-                               7, ghb_settings_get_short_opt(asettings, "audio_codec"),
-                               8, ghb_settings_get_short_opt(asettings, "audio_bitrate"),
-                               9, ghb_settings_get_short_opt(asettings, "audio_rate"),
-                               10, ghb_settings_get_short_opt(asettings, "audio_mix"),
+                               0, track,
+                               1, codec,
+                               2, br,
+                               3, sr,
+                               4, mix,
+                               // These are used to set combo values when an item is selected
+                               5, drc,
+                               6, s_track,
+                               7, s_codec,
+                               8, s_br,
+                               9, s_sr,
+                               10, s_mix,
+                               11, s_drc,
                                -1);
+                       g_free(drc);
+                       g_free(s_track);
+                       g_free(s_codec);
+                       g_free(s_br);
+                       g_free(s_sr);
+                       g_free(s_mix);
                        done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
-                       link = link->next;
-               } while (!done && link);
+                       row++;
+               } while (!done);
        }
 }
 
@@ -1791,63 +2031,75 @@ ghb_presets_list_update(signal_user_data_t *ud)
        GtkTreeIter iter;
        GtkListStore *store;
        gboolean done;
-       gint ii = 0;
-       gint index;
-       gchar **presets;
-       gchar **descriptions;
+       GList *presets, *plink;
+       gchar *preset, *def_preset;
+       gchar *description;
        gint flags, custom, def;
        
-       g_debug("ghb_presets_list_update ()\n");
-       presets = ghb_presets_get_names();
-       descriptions = ghb_presets_get_descriptions();
+       g_debug("ghb_presets_list_update ()");
+       def_preset = ghb_settings_get_string(ud->settings, "default_preset");
+       plink = presets = ghb_presets_get_names();
        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
        store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
        if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
        {
                do
                {
-                       if ((presets != NULL) && (presets[ii] != NULL))
+                       if (plink)
                        {
                                // Update row with settings data
-                               g_debug("Updating row\n");
-                               flags = ghb_preset_flags(presets[ii], &index);
-                               def = flags & PRESET_DEFAULT;
+                               g_debug("Updating row");
+                               preset = (gchar*)plink->data;
+                               def = 0;
+                               if (strcmp(preset, def_preset) == 0)
+                                       def = PRESET_DEFAULT;
+                               
+                               description = ghb_presets_get_description(preset);
+                               flags = ghb_preset_flags(preset);
                                custom = flags & PRESET_CUSTOM;
                                gtk_list_store_set(store, &iter, 
-                                                       0, presets[ii]
+                                                       0, preset, 
                                                        1, def ? 800 : 400, 
                                                        2, def ? 2 : 0,
                                                        3, custom ? "black" : "blue", 
-                                                       4, descriptions[ii],
+                                                       4, description,
                                                        -1);
-                               ii++;
+                               plink = plink->next;
+                               g_free(description);
                                done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
                        }
                        else
                        {
                                // No more settings data, remove row
-                               g_debug("Removing row\n");
+                               g_debug("Removing row");
                                done = !gtk_list_store_remove(store, &iter);
                        }
                } while (!done);
        }
-       while ((presets != NULL) && (presets[ii] != NULL))
+       while (plink)
        {
                // Additional settings, add row
-               g_debug("Adding row %s\n", presets[ii]);
+               g_debug("Adding rows");
+               preset = (gchar*)plink->data;
+               def = 0;
+               if (strcmp(preset, def_preset) == 0)
+                       def = PRESET_DEFAULT;
+
+               description = ghb_presets_get_description(preset);
                gtk_list_store_append(store, &iter);
-               flags = ghb_preset_flags(presets[ii], &index);
-               def = flags & PRESET_DEFAULT;
+               flags = ghb_preset_flags(preset);
                custom = flags & PRESET_CUSTOM;
-               gtk_list_store_set(store, &iter, 0, presets[ii]
+               gtk_list_store_set(store, &iter, 0, preset, 
                                                        1, def ? 800 : 400, 
                                                        2, def ? 2 : 0,
                                                        3, custom ? "black" : "blue", 
-                                                       4, descriptions[ii],
+                                                       4, description,
                                                        -1);
-               ii++;
+               plink = plink->next;
+               g_free(description);
        }
-       g_strfreev (presets);
+       g_free(def_preset);
+       g_list_free (presets);
 }
 
 void
@@ -1859,8 +2111,9 @@ ghb_select_preset(GtkBuilder *builder, const gchar *preset)
        GtkTreeIter iter;
        gchar *tpreset;
        gboolean done;
+       gboolean foundit = FALSE;
        
-       g_debug("select_preset()\n");
+       g_debug("select_preset()");
        if (preset == NULL) return;
        treeview = GTK_TREE_VIEW(GHB_WIDGET(builder, "presets_list"));
        selection = gtk_tree_view_get_selection (treeview);
@@ -1873,56 +2126,29 @@ ghb_select_preset(GtkBuilder *builder, const gchar *preset)
                        if (strcmp(preset, tpreset) == 0)
                        {
                                gtk_tree_selection_select_iter (selection, &iter);
+                               foundit = TRUE;
+                               g_free(tpreset);
                                break;
                        }
+                       g_free(tpreset);
                        done = !gtk_tree_model_iter_next(store, &iter);
                } while (!done);
        }
+       if (!foundit)
+       {
+               gtk_tree_model_get_iter_first(store, &iter);
+               gtk_tree_selection_select_iter (selection, &iter);
+       }
 }
 
 static void
 update_audio_presets(signal_user_data_t *ud)
 {
-       GSList *link = ud->audio_settings;
-       GHashTable *asettings;
-       gchar *acodec, *bitrate, *rate, *mix, *drc;
-       GString *pref_acodec, *pref_bitrate, *pref_rate, *pref_mix, *pref_drc;
-       pref_acodec = g_string_new("");
-       pref_bitrate = g_string_new("");
-       pref_rate = g_string_new("");
-       pref_mix = g_string_new("");
-       pref_drc = g_string_new("");
-       while (link)
-       {
-               gchar *format = link->next ? "%s," : "%s";
-               asettings = (GHashTable*)link->data;
-               acodec = (gchar*)ghb_settings_get_short_opt(asettings, "audio_codec");
-               g_string_append_printf( pref_acodec, format, acodec);
-               bitrate = (gchar*)ghb_settings_get_string(asettings, "audio_bitrate");
-               g_string_append_printf( pref_bitrate, format, bitrate);
-               rate = (gchar*)ghb_settings_get_string(asettings, "audio_rate");
-               g_string_append_printf( pref_rate, format, rate);
-               mix = (gchar*)ghb_settings_get_short_opt(asettings, "audio_mix");
-               g_string_append_printf( pref_mix, format, mix);
-               drc = (gchar*)ghb_settings_get_string(asettings, "audio_drc");
-               g_string_append_printf( pref_drc, format, drc);
-               link = link->next;
-       }
-       acodec = g_string_free(pref_acodec, FALSE);
-       bitrate = g_string_free(pref_bitrate, FALSE);
-       rate = g_string_free(pref_rate, FALSE);
-       mix = g_string_free(pref_mix, FALSE);
-       drc = g_string_free(pref_drc, FALSE);
-       ghb_settings_set_string(ud->settings, "pref_audio_codec", acodec);
-       ghb_settings_set_string(ud->settings, "pref_audio_bitrate", bitrate);
-       ghb_settings_set_string(ud->settings, "pref_audio_rate", rate);
-       ghb_settings_set_string(ud->settings, "pref_audio_mix", mix);
-       ghb_settings_set_string(ud->settings, "pref_audio_drc", drc);
-       g_free(acodec);
-       g_free(bitrate);
-       g_free(rate);
-       g_free(mix);
-       g_free(drc);
+       g_debug("update_audio_presets");
+       const GValue *audio_list;
+
+       audio_list = ghb_settings_get_value(ud->settings, "audio_list");
+       ghb_settings_set_value(ud->settings, "pref_audio_list", audio_list);
 }
 
 void
@@ -1932,25 +2158,25 @@ presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
        GtkEntry *entry;
        GtkTextView *desc;
        GtkResponseType response;
-       const gchar *preset = "";
+       gchar *preset;
 
-       g_debug("presets_save_clicked_cb ()\n");
-       // Construct the audio settings presets from the current audio list
+       g_debug("presets_save_clicked_cb ()");
        preset = ghb_settings_get_string (ud->settings, "preset");
        // Clear the description
        desc = GTK_TEXT_VIEW(GHB_WIDGET(ud->builder, "preset_description"));
-       //gtk_entry_set_text(desc, "");
        dialog = GHB_WIDGET(ud->builder, "preset_save_dialog");
        entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "preset_name"));
        gtk_entry_set_text(entry, preset);
+       g_free(preset);
        response = gtk_dialog_run(GTK_DIALOG(dialog));
        gtk_widget_hide(dialog);
        if (response == GTK_RESPONSE_OK)
        {
                // save the preset
                const gchar *name = gtk_entry_get_text(entry);
-               g_debug("description to settings\n");
+               g_debug("description to settings");
                ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
+               // Construct the audio settings presets from the current audio list
                update_audio_presets(ud);
                ghb_settings_save(ud, name);
                ghb_presets_list_update(ud);
@@ -1960,12 +2186,26 @@ presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 }
 
 void
+presets_restore_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+       g_debug("presets_restore_clicked_cb ()");
+       // Reload only the standard presets
+       ghb_presets_reload(ud);
+       ghb_presets_list_update(ud);
+       // Updating the presets list shuffles things around
+       // need to make sure the proper preset is selected
+       gchar *preset = ghb_settings_get_string (ud->settings, "preset");
+       ghb_select_preset(ud->builder, preset);
+       g_free(preset);
+}
+
+void
 prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
        GtkWidget *dialog;
        GtkResponseType response;
 
-       g_debug("prefs_dialog_cb ()\n");
+       g_debug("prefs_dialog_cb ()");
        dialog = GHB_WIDGET(ud->builder, "prefs_dialog");
        response = gtk_dialog_run(GTK_DIALOG(dialog));
        gtk_widget_hide(dialog);
@@ -1981,7 +2221,7 @@ presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
        gchar *preset;
        GtkResponseType response;
 
-       g_debug("presets_remove_clicked_cb ()\n");
+       g_debug("presets_remove_clicked_cb ()");
        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
        selection = gtk_tree_view_get_selection (treeview);
        if (gtk_tree_selection_get_selected(selection, &store, &iter))
@@ -1989,43 +2229,32 @@ presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
                GtkWidget *dialog;
 
                gtk_tree_model_get(store, &iter, 0, &preset, -1);
-               if (!ghb_presets_is_standard(preset))
-               {
-                       dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
-                                                                       GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
-                                                                       "Confirm deletion of preset %s.", preset);
-                       response = gtk_dialog_run(GTK_DIALOG(dialog));
-                       gtk_widget_destroy (dialog);
-                       if (response == GTK_RESPONSE_YES)
+               dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
+                                                               GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
+                                                               "Confirm deletion of preset %s.", preset);
+               response = gtk_dialog_run(GTK_DIALOG(dialog));
+               gtk_widget_destroy (dialog);
+               if (response == GTK_RESPONSE_YES)
+               {
+                       GtkTreeIter nextIter = iter;
+                       gchar *nextPreset = NULL;
+                       if (!gtk_tree_model_iter_next(store, &nextIter))
                        {
-                               GtkTreeIter nextIter = iter;
-                               gchar *nextPreset = NULL;
-                               if (!gtk_tree_model_iter_next(store, &nextIter))
-                               {
-                                       if (gtk_tree_model_get_iter_first(store, &nextIter))
-                                       {
-                                               gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
-                                       }
-                               }
-                               else
+                               if (gtk_tree_model_get_iter_first(store, &nextIter))
                                {
                                        gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
                                }
-                               // Remove the selected item
-                               // First unselect it so that selecting the new item works properly
-                               gtk_tree_selection_unselect_iter (selection, &iter);
-                               ghb_presets_remove(ud->settings, preset);
-                               ghb_presets_list_update(ud);
-                               ghb_select_preset(ud->builder, nextPreset);
                        }
-               }
-               else
-               {
-                       dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
-                                                                       GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
-                                                                       "Can not delete standard preset %s.", preset);
-                       response = gtk_dialog_run(GTK_DIALOG(dialog));
-                       gtk_widget_destroy (dialog);
+                       else
+                       {
+                               gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
+                       }
+                       // Remove the selected item
+                       // First unselect it so that selecting the new item works properly
+                       gtk_tree_selection_unselect_iter (selection, &iter);
+                       ghb_presets_remove(preset);
+                       ghb_presets_list_update(ud);
+                       ghb_select_preset(ud->builder, nextPreset);
                }
        }
 }
@@ -2035,12 +2264,17 @@ preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
 {
        GtkWidget *widget;
 
-       ghb_ui_update_int (ud, "scale_width", tinfo->width - tinfo->crop[2] - tinfo->crop[3]);
+       ghb_ui_update(ud, "scale_width", 
+                       ghb_int64_value(tinfo->width - tinfo->crop[2] - tinfo->crop[3]));
        // If anamorphic or keep_aspect, the hight will be automatically calculated
-       gboolean keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
-       gboolean anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
+       gboolean keep_aspect, anamorphic;
+       keep_aspect = ghb_settings_get_boolean(ud->settings, "keep_aspect");
+       anamorphic = ghb_settings_get_boolean(ud->settings, "anamorphic");
        if (!(keep_aspect || anamorphic))
-               ghb_ui_update_int (ud, "scale_height", tinfo->height - tinfo->crop[0] - tinfo->crop[1]);
+       {
+               ghb_ui_update(ud, "scale_height", 
+                       ghb_int64_value(tinfo->height - tinfo->crop[0] - tinfo->crop[1]));
+       }
 
        // Set the limits of cropping.  hb_set_anamorphic_size crashes if
        // you pass it a cropped width or height == 0.
@@ -2055,12 +2289,12 @@ preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
        gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
        widget = GHB_WIDGET (ud->builder, "crop_right");
        gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
-       if (ghb_settings_get_bool (ud->settings, "autocrop"))
+       if (ghb_settings_get_boolean(ud->settings, "autocrop"))
        {
-               ghb_ui_update_int (ud, "crop_top", tinfo->crop[0]);
-               ghb_ui_update_int (ud, "crop_bottom", tinfo->crop[1]);
-               ghb_ui_update_int (ud, "crop_left", tinfo->crop[2]);
-               ghb_ui_update_int (ud, "crop_right", tinfo->crop[3]);
+               ghb_ui_update(ud, "crop_top", ghb_int64_value(tinfo->crop[0]));
+               ghb_ui_update(ud, "crop_bottom", ghb_int64_value(tinfo->crop[1]));
+               ghb_ui_update(ud, "crop_left", ghb_int64_value(tinfo->crop[2]));
+               ghb_ui_update(ud, "crop_right", ghb_int64_value(tinfo->crop[3]));
        }
 }
 
@@ -2070,18 +2304,14 @@ presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_
        GtkTreeModel *store;
        GtkTreeIter iter;
        gchar *preset;
-       GtkWidget *widget;
-       gboolean sensitive = FALSE;
        ghb_title_info_t tinfo;
+       GtkWidget *widget;
        
-       g_debug("presets_list_selection_changed_cb ()\n");
+       g_debug("presets_list_selection_changed_cb ()");
+       widget = GHB_WIDGET (ud->builder, "presets_remove");
        if (gtk_tree_selection_get_selected(selection, &store, &iter))
        {
                gtk_tree_model_get(store, &iter, 0, &preset, -1);
-               if (!ghb_presets_is_standard(preset))
-               {
-                       sensitive = TRUE;
-               }
                ud->dont_clear_presets = TRUE;
                // Temporarily set the video_quality range to (0,100)
                // This is needed so the video_quality value does not get
@@ -2093,8 +2323,10 @@ presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_
                // it shouldn't be
                clear_audio_list(ud);
                ghb_set_preset(ud, preset);
-               gint titleindex = ghb_settings_get_int(ud->settings, "title");
+               gint titleindex;
+               titleindex = ghb_settings_combo_int(ud->settings, "title");
                set_pref_audio(titleindex, ud);
+               ghb_settings_set_boolean(ud->settings, "preset_modified", FALSE);
                ud->dont_clear_presets = FALSE;
                if (ghb_get_title_info (&tinfo, titleindex))
                {
@@ -2105,13 +2337,13 @@ presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_
                gint vqmin, vqmax;
                ghb_vquality_range(ud, &vqmin, &vqmax);
                gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
+               gtk_widget_set_sensitive(widget, TRUE);
        }
        else
        {
-               g_debug("No selection???  Perhaps unselected.\n");
+               g_debug("No selection???  Perhaps unselected.");
+               gtk_widget_set_sensitive(widget, FALSE);
        }
-       widget = GHB_WIDGET (ud->builder, "presets_remove");
-       gtk_widget_set_sensitive(widget, sensitive);
 }
 
 void
@@ -2120,7 +2352,7 @@ queue_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t
        GtkTreeModel *store;
        GtkTreeIter iter, piter;
        
-       g_debug("queue_list_selection_changed_cb ()\n");
+       g_debug("queue_list_selection_changed_cb ()");
        // A queue entry is made up of a parent and multiple
        // children that are visible when expanded.  When and entry
        // is selected, I want the parent to be selected.
@@ -2137,72 +2369,133 @@ queue_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t
                        treeview = gtk_tree_selection_get_tree_view (selection);
                        // Make the parent visible in scroll window if it is not.
                        gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
-                       g_free(path);
+                       gtk_tree_path_free(path);
                }
        }
 }
 
 static void
-add_to_queue_list(signal_user_data_t *ud, job_settings_t *item)
+add_to_queue_list(signal_user_data_t *ud, GValue *settings, GtkTreeIter *piter)
 {
        GtkTreeView *treeview;
        GtkTreeIter iter;
        GtkTreeStore *store;
        gchar *info;
-       gint num_pass = 1;
-       gint ii;
+       gint status;
        GtkTreeIter citer;
+       gchar *dest, *preset, *vol_name;
+       const gchar *vcodec, *container;
+       gchar *fps, *vcodec_abbr;
+       gint title, start_chapter, end_chapter, width, height, vqvalue;
+       gint source_width, source_height;
+       gboolean pass2, anamorphic, round_dim, keep_aspect, vqtype, turbo;
        
-       g_debug("update_queue_list ()\n");
-       if (item == NULL) return;
+       g_debug("update_queue_list ()");
+       if (settings == NULL) return;
        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
        store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
                
-       gint title = ghb_settings_get_int(item->settings, "title");
-       gint start_chapter = ghb_settings_get_int(item->settings, "start_chapter");
-       gint end_chapter = ghb_settings_get_int(item->settings, "end_chapter");
-       gboolean pass2 = ghb_settings_get_bool(item->settings, "two_pass");
-       const gchar *vol_name = ghb_settings_get_string(item->settings, "volume_label");
-       if (vol_name == NULL)
-               vol_name = "No Title";
+       title = ghb_settings_combo_int(settings, "title");
+       start_chapter = ghb_settings_get_int(settings, "start_chapter");
+       end_chapter = ghb_settings_get_int(settings, "end_chapter");
+       pass2 = ghb_settings_get_boolean(settings, "two_pass");
+       vol_name = ghb_settings_get_string(settings, "volume_label");
        info = g_strdup_printf 
-               (
+       (
                 "<big><b>%s</b></big> (Title %d, Chapters %d through %d, %d Video %s)",
                 vol_name, title+1, start_chapter, end_chapter, 
-                pass2 ? 2:1, pass2 ? "Passes":"Pass");
+                pass2 ? 2:1, pass2 ? "Passes":"Pass"
+       );
 
-       gtk_tree_store_append(store, &iter, NULL);
-       gtk_tree_store_set(store, &iter, 0, "hb-queue-job", 1, info, 2, "hb-queue-delete", -1);
-       g_free(info);
-       
-       const gchar *vcodec = ghb_settings_get_option(item->settings, "video_codec");
-       const gchar *container = ghb_settings_get_option(item->settings, "container");
-       const gchar *acodec = ghb_settings_get_option(item->settings, "audio_codec");
-       const gchar *dest = ghb_settings_get_string(item->settings, "destination");
-       const gchar *preset = ghb_settings_get_string(item->settings, "preset");
-       info = g_strdup_printf 
-               (
-                "<b>Preset:</b> %s\n"
-                "<b>Format:</b> %s Container, %s Video + %s Audio\n"
-                "<b>Destination:</b> %s",
-                preset, container, vcodec, acodec, dest);
+       if (piter)
+               iter = *piter;
+       else
+               gtk_tree_store_append(store, &iter, NULL);
 
-       gtk_tree_store_append(store, &citer, &iter);
-       gtk_tree_store_set(store, &citer, 1, info, -1);
+       gtk_tree_store_set(store, &iter, 1, info, 2, "hb-queue-delete", -1);
        g_free(info);
+       status = ghb_settings_get_int(settings, "job_status");
+       switch (status)
+       {
+               case GHB_QUEUE_PENDING:
+                       gtk_tree_store_set(store, &iter, 0, "hb-queue-job", -1);
+                       break;
+               case GHB_QUEUE_CANCELED:
+                       gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
+                       break;
+               case GHB_QUEUE_RUNNING:
+                       gtk_tree_store_set(store, &iter, 0, "hb-working0", -1);
+                       break;
+               case GHB_QUEUE_DONE:
+                       gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
+                       break;
+               default:
+                       gtk_tree_store_set(store, &iter, 0, "hb-queue-job", -1);
+                       break;
+       }
 
-       gint width = ghb_settings_get_int(item->settings, "scale_width");
-       gint height = ghb_settings_get_int(item->settings, "scale_height");
-       gboolean anamorphic = ghb_settings_get_bool(item->settings, "anamorphic");
-       gboolean round_dim = ghb_settings_get_bool(item->settings, "round_dimensions");
-       gboolean keep_aspect = ghb_settings_get_bool(item->settings, "keep_aspect");
-       gchar *aspect_desc;
-       if (anamorphic)
+       GString *str = g_string_new("");
+       gboolean markers;
+       gboolean preset_modified;
+       gint mux;
+
+       container = ghb_settings_combo_option(settings, "container");
+       mux = ghb_settings_combo_int(settings, "container");
+       dest = ghb_settings_get_string(settings, "destination");
+       preset_modified = ghb_settings_get_boolean(settings, "preset_modified");
+       preset = ghb_settings_get_string(settings, "preset");
+       markers = ghb_settings_get_boolean(settings, "chapter_markers");
+
+       if (preset_modified)
+               g_string_append_printf(str, "<b>Customized Preset Based On:</b> %s\n", 
+                                                               preset);
+       else
+               g_string_append_printf(str, "<b>Preset:</b> %s\n", preset);
+
+       if (markers)
        {
-               if (round_dim)
-               {
-                       aspect_desc = "(Anamorphic)";
-               }
+               g_string_append_printf(str, 
+                       "<b>Format:</b> %s Container, Chapter Markers\n", container);
+       }
+       else
+       {
+               g_string_append_printf(str, 
+                       "<b>Format:</b> %s Container\n", container);
+       }
+       if (mux == HB_MUX_MP4)
+       {
+               gboolean ipod, http, large;
+
+               ipod = ghb_settings_get_boolean(settings, "ipod_file");
+               http = ghb_settings_get_boolean(settings, "http_optimize_mp4");
+               large = ghb_settings_get_boolean(settings, "large_mp4");
+               if (http || ipod || large)
+               {
+                       g_string_append_printf(str, "<b>MP4 Options:</b>");
+                       if (ipod)
+                               g_string_append_printf(str, " - iPod Atom");
+                       if (http)
+                               g_string_append_printf(str, " - Http Optimized");
+                       if (large)
+                               g_string_append_printf(str, " - 64 Bit");
+                       g_string_append_printf(str, "\n");
+               }
+       }
+       g_string_append_printf(str, "<b>Destination:</b> %s\n", dest);
+
+       width = ghb_settings_get_int(settings, "scale_width");
+       height = ghb_settings_get_int(settings, "scale_height");
+       anamorphic = ghb_settings_get_boolean(settings, "anamorphic");
+       round_dim = ghb_settings_get_boolean(settings, "round_dimensions");
+       keep_aspect = ghb_settings_get_boolean(settings, "keep_aspect");
+
+       gchar *aspect_desc;
+       if (anamorphic)
+       {
+               if (round_dim)
+               {
+                       aspect_desc = "(Anamorphic)";
+               }
                else
                {
                        aspect_desc = "(Strict Anamorphic)";
@@ -2219,89 +2512,104 @@ add_to_queue_list(signal_user_data_t *ud, job_settings_t *item)
                        aspect_desc = "(Aspect Lost)";
                }
        }
-       gboolean vqtype = ghb_settings_get_bool(item->settings, "vquality_type_constant");
-       gint vqvalue = 0;
+       vqtype = ghb_settings_get_boolean(settings, "vquality_type_constant");
+       vqvalue = 0;
+
        gchar *vq_desc = "Error";
+       gchar *vq_units = "";
        if (!vqtype)
        {
-               vqtype = ghb_settings_get_bool(item->settings, "vquality_type_target");
+               vqtype = ghb_settings_get_boolean(settings, "vquality_type_target");
                if (!vqtype)
                {
                        // Has to be bitrate
-                       vqvalue = ghb_settings_get_int(item->settings, "video_bitrate");
-                       vq_desc = "kbps";
+                       vqvalue = ghb_settings_get_int(settings, "video_bitrate");
+                       vq_desc = "Bitrate:";
+                       vq_units = "kbps";
                }
                else
                {
                        // Target file size
-                       vqvalue = ghb_settings_get_int(item->settings, "video_target");
-                       vq_desc = "MB";
+                       vqvalue = ghb_settings_get_int(settings, "video_target");
+                       vq_desc = "Target Size:";
+                       vq_units = "MB";
                }
        }
        else
        {
                // Constant quality
-               vqvalue = ghb_settings_get_int(item->settings, "video_quality");
-               vq_desc = "% Constant Quality";
+               vqvalue = ghb_settings_get_int(settings, "video_quality");
+               vq_desc = "Constant Quality:";
        }
-       const gchar *fps = ghb_settings_get_string(item->settings, "framerate");
-       const gchar *vcodec_abbr = ghb_settings_get_short_opt(item->settings, "video_codec");
-       gchar *extra_opts;
-       if (strcmp(vcodec_abbr, "x264") == 0)
+       fps = ghb_settings_get_string(settings, "framerate");
+       if (strcmp("source", fps) == 0)
        {
-               gchar *x264opts = ghb_build_x264opts_string(item->settings);
-               g_debug("xopts (%s)\n", x264opts);
-               extra_opts = g_strdup_printf ("\n<b>x264 Options:</b> %s", x264opts);
-               g_free(x264opts);
+               g_free(fps);
+               fps = g_strdup("Same As Source");
        }
-       else
+       vcodec = ghb_settings_combo_option(settings, "video_codec");
+       vcodec_abbr = ghb_settings_get_string(settings, "video_codec");
+       source_width = ghb_settings_get_int(settings, "source_width");
+       source_height = ghb_settings_get_int(settings, "source_height");
+       g_string_append_printf(str,
+               "<b>Picture:</b> Source: %d x %d, Output %d x %d %s\n"
+               "<b>Video:</b> %s, Framerate: %s, %s %d%s\n",
+                        source_width, source_height, width, height, aspect_desc,
+                        vcodec, fps, vq_desc, vqvalue, vq_units);
+
+       turbo = ghb_settings_get_boolean(settings, "turbo");
+       if (turbo)
        {
-               extra_opts = g_strdup("");
+               g_string_append_printf(str, "<b>Turbo:</b> On\n");
        }
-       gboolean turbo = ghb_settings_get_bool (item->settings, "turbo");
-       gchar *turbo_desc = "\n<b>Turbo:</b> Off";;
-       if (turbo)
+       if (strcmp(vcodec_abbr, "x264") == 0)
        {
-               turbo_desc = "\n<b>Turbo:</b> On";
+               gchar *x264opts = ghb_build_x264opts_string(settings);
+               g_string_append_printf(str, "<b>x264 Options:</b> %s\n", x264opts);
+               g_free(x264opts);
        }
-       num_pass = pass2 ? 2 : 1;
-       for (ii = 0; ii < num_pass; ii++)
+       // Add the audios
+       gint count, ii;
+       const GValue *audio_list;
+
+       audio_list = ghb_settings_get_value(settings, "audio_list");
+       count = ghb_array_len(audio_list);
+       for (ii = 0; ii < count; ii++)
        {
-               gboolean final = (ii == (num_pass - 1));
-               GString *pass = g_string_new("");
-               g_string_append_printf( pass,
-                       "<b>%s Pass</b>\n"
-                       "<b>Picture:</b> %d x %d %s\n"
-                       "<b>Video:</b> %s, %d %s, %s fps"
-                       "%s",
-                        ii ? "2nd":"1st", width, height, aspect_desc,
-                        vcodec, vqvalue, vq_desc, fps, 
-                        final ? extra_opts : turbo_desc);
+               gchar *bitrate, *samplerate, *track;
+               const gchar *acodec, *mix;
+               GValue *asettings;
+
+               asettings = ghb_array_get_nth(audio_list, ii);
 
-               if (final)
+               acodec = ghb_settings_combo_option(asettings, "audio_codec");
+               bitrate = ghb_settings_get_string(asettings, "audio_bitrate");
+               samplerate = ghb_settings_get_string(asettings, "audio_rate");
+               if (strcmp("source", samplerate) == 0)
                {
-                       // Add the audios
-                       GSList *link = item->audio_settings;
-                       while (link)
-                       {
-                               GHashTable *asettings = (GHashTable*)link->data;
-                               const gchar *acodec = ghb_settings_get_option(asettings, "audio_codec");
-                               const gchar *bitrate = ghb_settings_get_string(asettings, "audio_bitrate");
-                               const gchar *samplerate = ghb_settings_get_string(asettings, "audio_rate");
-                               gint track = ghb_settings_get_int(asettings, "audio_track");
-                               const gchar *mix = ghb_settings_get_option(asettings, "audio_mix");
-                               g_string_append_printf(pass,
-                                       "\n<b>Audio:</b> %s, %s kbps, %s kHz, Track %d: %s",
-                                        acodec, bitrate, samplerate, track+1, mix);
-                               link = link->next;
-                       }
+                       g_free(samplerate);
+                       samplerate = g_strdup("Same As Source");
                }
-               info = g_string_free(pass, FALSE);
-               gtk_tree_store_append(store, &citer, &iter);
-               gtk_tree_store_set(store, &citer, 0, ii ? "hb-queue-pass2" : "hb-queue-pass1", 1, info, -1);
-               g_free(info);
+               track = ghb_settings_get_string(asettings, "audio_track_long");
+               mix = ghb_settings_combo_option(asettings, "audio_mix");
+               g_string_append_printf(str,
+                       "<b>Audio:</b> %s, Encoder: %s, Mixdown: %s, SampleRate: %s, Bitrate: %s",
+                        track, acodec, mix, samplerate, bitrate);
+               if (ii < count-1)
+                       g_string_append_printf(str, "\n");
+               g_free(track);
+               g_free(bitrate);
+               g_free(samplerate);
        }
-       g_free(extra_opts);
+       info = g_string_free(str, FALSE);
+       gtk_tree_store_append(store, &citer, &iter);
+       gtk_tree_store_set(store, &citer, 1, info, -1);
+       g_free(info);
+       g_free(fps);
+       g_free(vcodec_abbr);
+       g_free(vol_name);
+       g_free(dest);
+       g_free(preset);
 }
 
 gboolean
@@ -2333,7 +2641,9 @@ estimate_file_size(signal_user_data_t *ud)
        gint duration;
        gint bitrate;
        gint64 size;
-       gint titleindex = ghb_settings_get_int(ud->settings, "title");
+       gint titleindex;
+
+       titleindex = ghb_settings_combo_int(ud->settings, "title");
        if (titleindex < 0) return 0;
                        
        if (!ghb_get_title_info(&tinfo, titleindex)) return 0;
@@ -2350,17 +2660,21 @@ validate_settings(signal_user_data_t *ud)
 {
        // Check to see if the dest file exists or is
        // already in the queue
-       gchar *message;
-       gint titleindex = ghb_settings_get_int(ud->settings, "title");
+       gchar *message, *dest;
+       gint count, ii;
+       gint titleindex;
+
+       titleindex = ghb_settings_combo_int(ud->settings, "title");
        if (titleindex < 0) return FALSE;
-       const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
-       GSList *link = ud->queue;
-       while (link != NULL)
+       dest = ghb_settings_get_string(ud->settings, "destination");
+       count = ghb_array_len(ud->queue);
+       for (ii = 0; ii < count; ii++)
        {
-               job_settings_t *item;
-               const gchar *filename;
-               item = (job_settings_t*)link->data;
-               filename = ghb_settings_get_string(item->settings, "destination");
+               GValue *js;
+               gchar *filename;
+
+               js = ghb_array_get_nth(ud->queue, ii);
+               filename = ghb_settings_get_string(js, "destination");
                if (strcmp(dest, filename) == 0)
                {
                        message = g_strdup_printf(
@@ -2370,13 +2684,15 @@ validate_settings(signal_user_data_t *ud)
                                                dest);
                        if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
                        {
+                               g_free(filename);
+                               g_free(dest);
                                g_free(message);
                                return FALSE;
                        }
                        g_free(message);
                        break;
                }
-               link = link->next;
+               g_free(filename);
        }
        gchar *destdir = g_path_get_dirname(dest);
        if (!g_file_test(destdir, G_FILE_TEST_IS_DIR))
@@ -2386,6 +2702,7 @@ validate_settings(signal_user_data_t *ud)
                                        "This is not a valid directory.",
                                        destdir);
                ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
+               g_free(dest);
                g_free(message);
                g_free(destdir);
                return FALSE;
@@ -2397,6 +2714,7 @@ validate_settings(signal_user_data_t *ud)
                                        "Can not read or write the directory.",
                                        destdir);
                ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
+               g_free(dest);
                g_free(message);
                g_free(destdir);
                return FALSE;
@@ -2425,6 +2743,7 @@ validate_settings(signal_user_data_t *ud)
                                                        (guint)(size / (1024L*1024L)));
                                if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Proceed"))
                                {
+                                       g_free(dest);
                                        g_free(message);
                                        return FALSE;
                                }
@@ -2445,12 +2764,14 @@ validate_settings(signal_user_data_t *ud)
                                        dest);
                if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
                {
+                       g_free(dest);
                        g_free(message);
                        return FALSE;
                }
                g_free(message);
                g_unlink(dest);
        }
+       g_free(dest);
        // Validate video quality is in a reasonable range
        if (!ghb_validate_vquality(ud->settings))
        {
@@ -2484,42 +2805,35 @@ static gboolean
 queue_add(signal_user_data_t *ud)
 {
        // Add settings to the queue
-       job_settings_t *queue_item;
-       GSList *link;
-       static gint unique_id = 0;
+       GValue *settings;
+       gint titleindex;
+       gint titlenum;
        
-       g_debug("queue_add ()\n");
+       g_debug("queue_add ()");
        if (!validate_settings(ud))
        {
                return FALSE;
        }
+       if (ud->queue == NULL)
+               ud->queue = ghb_array_value_new(32);
        // Make a copy of current settings to be used for the new job
-       queue_item = g_malloc(sizeof(job_settings_t));
-       queue_item->settings = ghb_settings_dup(ud->settings);
-       queue_item->audio_settings = NULL;
-       link = ud->audio_settings;
-       while (link != NULL)
-       {
-               GHashTable *asettings;
-               asettings = ghb_settings_dup((GHashTable*)link->data);
-               queue_item->audio_settings =
-                       g_slist_append(queue_item->audio_settings, asettings);
-               link = g_slist_next(link);
-       }
-       queue_item->chapter_list = g_strdupv(ud->chapter_list);
-       ud->queue = g_slist_append(ud->queue, queue_item);
-       add_to_queue_list(ud, queue_item);
-       ghb_add_job (queue_item, unique_id);
-       queue_item->unique_id = unique_id;
-       queue_item->status = GHB_QUEUE_PENDING;
-       unique_id++;
+       settings = ghb_value_dup(ud->settings);
+       ghb_settings_set_int(settings, "job_status", GHB_QUEUE_PENDING);
+       ghb_settings_set_int(settings, "job_unique_id", 0);
+       titleindex = ghb_settings_combo_int(settings, "title");
+       titlenum = ghb_get_title_number(titleindex);
+       ghb_settings_set_int(settings, "titlenum", titlenum);
+       ghb_array_append(ud->queue, settings);
+       add_to_queue_list(ud, settings, NULL);
+       ghb_save_queue(ud->queue);
+
        return TRUE;
 }
 
 void
 queue_add_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
-       g_debug("queue_add_clicked_cb ()\n");
+       g_debug("queue_add_clicked_cb ()");
        queue_add(ud);
 }
 
@@ -2553,18 +2867,16 @@ queue_remove_clicked_cb(GtkWidget *widget, gchar *path, signal_user_data_t *ud)
        GtkTreeModel *store;
        GtkTreeIter iter;
        gint row;
-       GSList *link;
        gint *indices;
-       job_settings_t *queue_item;
        gint unique_id;
+       GValue *settings;
+       gint status;
 
-       g_debug("queue_remove_clicked_cb ()\n");
-       g_debug("ud %p\n", ud);
-       g_debug("ud->builder %p\n", ud->builder);
-
+       g_debug("queue_remove_clicked_cb ()");
        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
        store = gtk_tree_view_get_model(treeview);
        treepath = gtk_tree_path_new_from_string (path);
+       if (gtk_tree_path_get_depth(treepath) > 1) return;
        if (gtk_tree_model_get_iter(store, &iter, treepath))
        {
                // Find the entry in the queue
@@ -2574,37 +2886,27 @@ queue_remove_clicked_cb(GtkWidget *widget, gchar *path, signal_user_data_t *ud)
                // indices since this points into treepath somewhere.
                gtk_tree_path_free (treepath);
                if (row < 0) return;
-               link = g_slist_nth(ud->queue, row);
-               if (link == NULL) return;
-               queue_item = (job_settings_t*)link->data;
-               if (queue_item->status == GHB_QUEUE_RUNNING)
+               if (row >= ghb_array_len(ud->queue))
+                       return;
+               settings = ghb_array_get_nth(ud->queue, row);
+               status = ghb_settings_get_int(settings, "job_status");
+               if (status == GHB_QUEUE_RUNNING)
                {
                        // Ask if wants to stop encode.
                        if (!cancel_encode(NULL))
                        {
                                return;
                        }
+                       unique_id = ghb_settings_get_int(settings, "job_unique_id");
+                       ghb_remove_job(unique_id);
                }
                // Remove the selected item
-               g_debug(" should be removing from treestore\n");
                gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
                // Remove the corresponding item from the queue list
-               ud->queue = g_slist_remove_link(ud->queue, link);
-               g_slist_free_1(link);
-               g_hash_table_destroy(queue_item->settings);
-               link = queue_item->audio_settings;
-               while (link != NULL)
-               {
-                       GSList *nextlink;
-                       g_hash_table_destroy((GHashTable*)link->data);
-                       nextlink = g_slist_next(link);
-                       g_slist_free_1(link);
-                       link = nextlink;
-               }
-               g_strfreev (queue_item->chapter_list);
-               unique_id = queue_item->unique_id;
-               g_free(queue_item);
-               ghb_remove_job(unique_id);
+               GValue *old = ghb_array_get_nth(ud->queue, row);
+               ghb_value_free(old);
+               ghb_array_remove(ud->queue, row);
+               ghb_save_queue(ud->queue);
        }
        else
        {       
@@ -2612,25 +2914,234 @@ queue_remove_clicked_cb(GtkWidget *widget, gchar *path, signal_user_data_t *ud)
        }
 }
 
+// This little bit is needed to prevent the default drag motion
+// handler from expanding rows if you hover over them while
+// dragging.
+// Also controls where valid drop locations are
+gboolean
+queue_drag_motion_cb(
+       GtkTreeView *tv,
+       GdkDragContext *ctx,
+       gint x,
+       gint y,
+       guint time,
+       signal_user_data_t *ud)
+{
+       GtkTreePath *path = NULL;
+       GtkTreeViewDropPosition pos;
+       gint *indices, row, status, finished;
+       GValue *js;
+       GtkTreeIter iter;
+       GtkTreeView *srctv;
+       GtkTreeModel *model;
+       GtkTreeSelection *select;
+
+       // This bit checks to see if the source is allowed to be
+       // moved.  Only pending and canceled items may be moved.
+       srctv = GTK_TREE_VIEW(gtk_drag_get_source_widget(ctx));
+       select = gtk_tree_view_get_selection (srctv);
+       gtk_tree_selection_get_selected (select, &model, &iter);
+       path = gtk_tree_model_get_path (model, &iter);
+       indices = gtk_tree_path_get_indices(path);
+       row = indices[0];
+       gtk_tree_path_free(path);
+       js = ghb_array_get_nth(ud->queue, row);
+       status = ghb_settings_get_int(js, "job_status");
+       if (status != GHB_QUEUE_PENDING && status != GHB_QUEUE_CANCELED)
+       {
+               gdk_drag_status(ctx, 0, time);
+               return TRUE;
+       }
+
+       // The reset checks that the destination is a valid position
+       // in the list.  Can not move above any finished or running items
+       gtk_tree_view_get_dest_row_at_pos (tv, x, y, &path, &pos);
+       if (path == NULL)
+       {
+               gdk_drag_status(ctx, GDK_ACTION_MOVE, time);
+               return TRUE;
+       }
+       // Don't allow *drop into*
+       if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
+               pos = GTK_TREE_VIEW_DROP_BEFORE;
+       if (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
+               pos = GTK_TREE_VIEW_DROP_AFTER;
+       // Don't allow droping int child items
+       if (gtk_tree_path_get_depth(path) > 1)
+       {
+               gtk_tree_path_up(path);
+               pos = GTK_TREE_VIEW_DROP_AFTER;
+       }
+       indices = gtk_tree_path_get_indices(path);
+       row = indices[0];
+       js = ghb_array_get_nth(ud->queue, row);
+
+       finished = find_last_finished(ud->queue);
+       if (row < finished)
+       {
+               gtk_tree_path_free(path);
+               gdk_drag_status(ctx, 0, time);
+               return TRUE;
+       }
+       if (pos != GTK_TREE_VIEW_DROP_AFTER && 
+               row == finished)
+       {
+               gtk_tree_path_free(path);
+               gdk_drag_status(ctx, 0, time);
+               return TRUE;
+       }
+       gtk_tree_view_set_drag_dest_row(tv, path, pos);
+       gtk_tree_path_free(path);
+       gdk_drag_status(ctx, GDK_ACTION_MOVE, time);
+       return TRUE;
+}
+
+void 
+queue_drag_cb(
+       GtkTreeView *dstwidget, 
+       GdkDragContext *dc, 
+       gint x, gint y, 
+       GtkSelectionData *selection_data, 
+       guint info, guint t, 
+       signal_user_data_t *ud)
+{
+       GtkTreePath *path = NULL;
+       //GtkTreeModel *model;
+       GtkTreeViewDropPosition pos;
+       GtkTreeIter dstiter, srciter;
+       gint *indices, row;
+       GValue *js;
+       
+       GtkTreeModel *dstmodel = gtk_tree_view_get_model(dstwidget);
+                       
+       g_debug("queue_drag_cb ()");
+       // This doesn't work here for some reason...
+       // gtk_tree_view_get_drag_dest_row(dstwidget, &path, &pos);
+       gtk_tree_view_get_dest_row_at_pos (dstwidget, x, y, &path, &pos);
+       // This little hack is needed because attempting to drop after
+       // the last item gives us no path or pos.
+       if (path == NULL)
+       {
+               gint n_children;
+
+               n_children = gtk_tree_model_iter_n_children(dstmodel, NULL);
+               if (n_children)
+               {
+                       pos = GTK_TREE_VIEW_DROP_AFTER;
+                       path = gtk_tree_path_new_from_indices(n_children-1, -1);
+               }
+               else
+               {
+                       pos = GTK_TREE_VIEW_DROP_BEFORE;
+                       path = gtk_tree_path_new_from_indices(0, -1);
+               }
+       }
+       if (path)
+       {
+               if (gtk_tree_path_get_depth(path) > 1)
+                       gtk_tree_path_up(path);
+               if (gtk_tree_model_get_iter (dstmodel, &dstiter, path))
+               {
+                       GtkTreeIter iter;
+                       GtkTreeView *srcwidget;
+                       GtkTreeModel *srcmodel;
+                       GtkTreeSelection *select;
+                       GtkTreePath *srcpath = NULL;
+                       GtkTreePath *dstpath = NULL;
+
+                       srcwidget = GTK_TREE_VIEW(gtk_drag_get_source_widget(dc));
+                       //srcmodel = gtk_tree_view_get_model(srcwidget);
+                       select = gtk_tree_view_get_selection (srcwidget);
+                       gtk_tree_selection_get_selected (select, &srcmodel, &srciter);
+
+                       srcpath = gtk_tree_model_get_path (srcmodel, &srciter);
+                       indices = gtk_tree_path_get_indices(srcpath);
+                       row = indices[0];
+                       gtk_tree_path_free(srcpath);
+                       js = ghb_array_get_nth(ud->queue, row);
+
+                       switch (pos)
+                       {
+                               case GTK_TREE_VIEW_DROP_BEFORE:
+                               case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
+                                       gtk_tree_store_insert_before (GTK_TREE_STORE (dstmodel), 
+                                                                                                       &iter, NULL, &dstiter);
+                                       break;
+
+                               case GTK_TREE_VIEW_DROP_AFTER:
+                               case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
+                                       gtk_tree_store_insert_after (GTK_TREE_STORE (dstmodel), 
+                                                                                                       &iter, NULL, &dstiter);
+                                       break;
+
+                               default:
+                                       break;
+                       }
+                       // Reset job to pending
+                       ghb_settings_set_int(js, "job_status", GHB_QUEUE_PENDING);
+                       add_to_queue_list(ud, js, &iter);
+
+                       dstpath = gtk_tree_model_get_path (dstmodel, &iter);
+                       indices = gtk_tree_path_get_indices(dstpath);
+                       row = indices[0];
+                       gtk_tree_path_free(dstpath);
+                       ghb_array_insert(ud->queue, row, js);
+
+                       srcpath = gtk_tree_model_get_path (srcmodel, &srciter);
+                       indices = gtk_tree_path_get_indices(srcpath);
+                       row = indices[0];
+                       gtk_tree_path_free(srcpath);
+                       ghb_array_remove(ud->queue, row);
+                       gtk_tree_store_remove (GTK_TREE_STORE (srcmodel), &srciter);
+                       ghb_save_queue(ud->queue);
+               }
+               gtk_tree_path_free(path);
+       }
+}
+
+
 static gint
-find_queue_item(GSList *queue, gint unique_id, job_settings_t **job)
+find_last_finished(GValue *queue)
 {
-       job_settings_t *js;
-       gint index = -1;
+       GValue *js;
+       gint ii, count;
+       gint status;
        
-       while (queue != NULL)
+       g_debug("find_last_finished");
+       count = ghb_array_len(queue);
+       for (ii = 0; ii < count; ii++)
        {
-               index++;
-               js = (job_settings_t*)queue->data;
-               if (js->unique_id == unique_id)
+               js = ghb_array_get_nth(queue, ii);
+               status = ghb_settings_get_int(js, "job_status");
+               if (status != GHB_QUEUE_DONE && status != GHB_QUEUE_RUNNING)
                {
-                       *job = js;
-                       return index;
+                       return ii-1;
                }
-               queue = queue->next;
        }
+       return -1;
+}
+
+static gint
+find_queue_job(GValue *queue, gint unique_id, GValue **job)
+{
+       GValue *js;
+       gint ii, count;
+       gint job_unique_id;
+       
        *job = NULL;
-       return index;
+       g_debug("find_queue_job");
+       count = ghb_array_len(queue);
+       for (ii = 0; ii < count; ii++)
+       {
+               js = ghb_array_get_nth(queue, ii);
+               job_unique_id = ghb_settings_get_int(js, "job_unique_id");
+               if (job_unique_id == unique_id)
+               {
+                       *job = js;
+                       return ii;
+               }
+       }
+       return -1;
 }
 
 static void
@@ -2638,14 +3149,20 @@ queue_buttons_grey(signal_user_data_t *ud, gboolean working)
 {
        GtkWidget *widget;
        GtkAction *action;
-       gint titleindex = ghb_settings_get_int(ud->settings, "title");
-       gboolean title_ok = (titleindex >= 0);
+       gint queue_count;
+       gint titleindex;
+       gboolean title_ok;
+
+       queue_count = ghb_array_len(ud->queue);
+       titleindex = ghb_settings_combo_int(ud->settings, "title");
+       title_ok = (titleindex >= 0);
+
        widget = GHB_WIDGET (ud->builder, "queue_start1");
-       gtk_widget_set_sensitive (widget, !working && title_ok);
+       gtk_widget_set_sensitive (widget, !working && (title_ok || queue_count));
        widget = GHB_WIDGET (ud->builder, "queue_start2");
-       gtk_widget_set_sensitive (widget, !working && title_ok);
+       gtk_widget_set_sensitive (widget, !working && (title_ok || queue_count));
        action = GHB_ACTION (ud->builder, "queue_start_menu");
-       gtk_action_set_sensitive (action, !working && title_ok);
+       gtk_action_set_sensitive (action, !working && (title_ok || queue_count));
        widget = GHB_WIDGET (ud->builder, "queue_pause1");
        gtk_widget_set_sensitive (widget, working);
        widget = GHB_WIDGET (ud->builder, "queue_pause2");
@@ -2661,14 +3178,153 @@ queue_buttons_grey(signal_user_data_t *ud, gboolean working)
 void queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud);
 
 static void
+submit_job(GValue *settings)
+{
+       static gint unique_id = 1;
+
+       g_debug("submit_job");
+       if (settings == NULL) return;
+       ghb_settings_set_int(settings, "job_unique_id", unique_id);
+       ghb_settings_set_int(settings, "job_status", GHB_QUEUE_RUNNING);
+       ghb_add_job (settings, unique_id);
+       ghb_start_queue();
+       unique_id++;
+}
+
+static void
+queue_scan(GValue *js)
+{
+       gchar *path;
+       gint titlenum;
+
+       path = ghb_settings_get_string( js, "source");
+       titlenum = ghb_settings_get_int(js, "titlenum");
+       ghb_backend_queue_scan(path, titlenum);
+       g_free(path);
+}
+
+static GValue* 
+start_next_job(signal_user_data_t *ud, gboolean find_first)
+{
+       static gint current = 0;
+       gint count, ii, jj;
+       GValue *js;
+       gint status;
+
+       g_debug("start_next_job");
+       count = ghb_array_len(ud->queue);
+       if (find_first)
+       {       // Start the first pending item in the queue
+               current = 0;
+               for (ii = 0; ii < count; ii++)
+               {
+
+                       js = ghb_array_get_nth(ud->queue, ii);
+                       status = ghb_settings_get_int(js, "job_status");
+                       if (status == GHB_QUEUE_PENDING)
+                       {
+                               current = ii;
+                               queue_scan(js);
+                               return js;
+                       }
+               }
+               // Nothing pending
+               return NULL;
+       }
+       // Find the next pending item after the current running item
+       for (ii = 0; ii < count-1; ii++)
+       {
+               js = ghb_array_get_nth(ud->queue, ii);
+               status = ghb_settings_get_int(js, "job_status");
+               if (status == GHB_QUEUE_RUNNING)
+               {
+                       for (jj = ii+1; jj < count; jj++)
+                       {
+                               js = ghb_array_get_nth(ud->queue, jj);
+                               status = ghb_settings_get_int(js, "job_status");
+                               if (status == GHB_QUEUE_PENDING)
+                               {
+                                       current = jj;
+                                       queue_scan(js);
+                                       return js;
+                               }
+                       }
+               }
+       }
+       // No running item found? Maybe it was deleted
+       // Look for a pending item starting from the last index we started
+       for (ii = current; ii < count; ii++)
+       {
+               js = ghb_array_get_nth(ud->queue, ii);
+               status = ghb_settings_get_int(js, "job_status");
+               if (status == GHB_QUEUE_PENDING)
+               {
+                       current = ii;
+                       queue_scan(js);
+                       return js;
+               }
+       }
+       // Nothing found
+       return NULL;
+}
+
+gchar*
+working_status_string(signal_user_data_t *ud, ghb_status_t *status)
+{
+       gchar *task_str, *job_str, *status_str;
+       gint qcount;
+       gint index;
+       GValue *js;
+
+       if (status->job_count > 1)
+       {
+               task_str = g_strdup_printf("pass %d of %d, ", 
+                       status->job_cur, status->job_count);
+       }
+       else
+       {
+               task_str = g_strdup("");
+       }
+       qcount = ghb_array_len(ud->queue);
+       if (qcount > 1)
+       {
+               index = find_queue_job(ud->queue, status->unique_id, &js);
+               job_str = g_strdup_printf("job %d of %d, ", index+1, qcount);
+       }
+       else
+       {
+               job_str = g_strdup("");
+       }
+       if(status->seconds > -1)
+       {
+               status_str= g_strdup_printf(
+                       "Encoding: %s%s%.2f %%"
+                       " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)",
+                       job_str, task_str,
+                       100.0 * status->progress,
+                       status->rate_cur, status->rate_avg, status->hours, 
+                       status->minutes, status->seconds );
+       }
+       else
+       {
+               status_str= g_strdup_printf(
+                       "Encoding: %s%s%.2f %%",
+                       job_str, task_str,
+                       100.0 * status->progress );
+       }
+       g_free(task_str);
+       g_free(job_str);
+       return status_str;
+}
+
+static void
 ghb_backend_events(signal_user_data_t *ud)
 {
        ghb_status_t status;
        gchar *status_str;
        GtkProgressBar *progress;
        gint titleindex;
-       job_settings_t *js;
-       static gint current_id = -1;
+       GValue *js;
        gint index;
        GtkTreeView *treeview;
        GtkTreeStore *store;
@@ -2679,6 +3335,8 @@ ghb_backend_events(signal_user_data_t *ud)
        ghb_track_status();
        ghb_get_status(&status);
        progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
+       // First handle the status of title scans
+       // Then handle the status of the queue
        if (status.state & GHB_STATE_SCANNING)
        {
                status_str = g_strdup_printf ("Scanning title %d of %d...", 
@@ -2702,7 +3360,7 @@ ghb_backend_events(signal_user_data_t *ud)
                        
                ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE);
                titleindex = ghb_longest_title();
-               ghb_ui_update_int(ud, "title", titleindex);
+               ghb_ui_update(ud, "title", ghb_int64_value(titleindex));
 
                // Are there really any titles.
                if (!ghb_get_title_info(&tinfo, titleindex))
@@ -2713,47 +3371,54 @@ ghb_backend_events(signal_user_data_t *ud)
                        gtk_progress_bar_set_text (progress, "No Source");
                }
                ghb_clear_state(GHB_STATE_SCANDONE);
-               queue_buttons_grey(ud, (0 != (status.state & GHB_STATE_WORKING)));
+               queue_buttons_grey(ud, work_started);
        }
-       else if (status.state & GHB_STATE_WORKING)
+       else if (status.queue_state & GHB_STATE_SCANNING)
        {
-               if(status.seconds > -1)
-               {
-                       status_str= g_strdup_printf(
-                               "Encoding: task %d of %d, %.2f %%"
-                               " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)",
-                               status.job_cur, status.job_count, 
-                               100.0 * status.progress,
-                               status.rate_cur, status.rate_avg, status.hours, 
-                               status.minutes, status.seconds );
-               }
-               else
-               {
-                       status_str= g_strdup_printf(
-                               "Encoding: task %d of %d, %.2f %%",
-                               status.job_cur, status.job_count, 
-                               100.0 * status.progress );
-               }
+               status_str = g_strdup_printf ("Scanning ...");
+               gtk_progress_bar_set_text (progress, status_str);
+               g_free(status_str);
+               gtk_progress_bar_set_fraction (progress, 0);
+       }
+       else if (status.queue_state & GHB_STATE_SCANDONE)
+       {
+               ghb_clear_queue_state(GHB_STATE_SCANDONE);
+               submit_job(ud->current_job);
+       }
+       else if (status.queue_state & GHB_STATE_PAUSED)
+       {
+               status_str = g_strdup_printf ("Paused"); 
+               gtk_progress_bar_set_text (progress, status_str);
+               g_free(status_str);
+       }
+       else if (status.queue_state & GHB_STATE_WORKING)
+       {
+               status_str = working_status_string(ud, &status);
                gtk_progress_bar_set_text (progress, status_str);
                gtk_progress_bar_set_fraction (progress, status.progress);
                g_free(status_str);
        }
-       else if (status.state & GHB_STATE_WORKDONE)
+       else if (status.queue_state & GHB_STATE_WORKDONE)
        {
+               gint qstatus;
+
                work_started = FALSE;
                queue_buttons_grey(ud, FALSE);
-               index = find_queue_item(ud->queue, current_id, &js);
+               index = find_queue_job(ud->queue, status.unique_id, &js);
                treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
                store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
+               if (ud->cancel_encode)
+                       status.error = GHB_ERROR_CANCELED;
                switch( status.error )
                {
                        case GHB_ERROR_NONE:
                                gtk_progress_bar_set_text( progress, "Rip done!" );
+                               qstatus = GHB_QUEUE_DONE;
                                if (js != NULL)
                                {
-                                       js->status = GHB_QUEUE_DONE;
                                        gchar *path = g_strdup_printf ("%d", index);
-                                       if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
+                                       if (gtk_tree_model_get_iter_from_string(
+                                                       GTK_TREE_MODEL(store), &iter, path))
                                        {
                                                gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
                                        }
@@ -2762,11 +3427,12 @@ ghb_backend_events(signal_user_data_t *ud)
                                break;
                        case GHB_ERROR_CANCELED:
                                gtk_progress_bar_set_text( progress, "Rip canceled." );
+                               qstatus = GHB_QUEUE_CANCELED;
                                if (js != NULL)
                                {
-                                       js->status = GHB_QUEUE_CANCELED;
                                        gchar *path = g_strdup_printf ("%d", index);
-                                       if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
+                                       if (gtk_tree_model_get_iter_from_string(
+                                                       GTK_TREE_MODEL(store), &iter, path))
                                        {
                                                gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
                                        }
@@ -2775,63 +3441,54 @@ ghb_backend_events(signal_user_data_t *ud)
                                break;
                        default:
                                gtk_progress_bar_set_text( progress, "Rip failed.");
+                               qstatus = GHB_QUEUE_CANCELED;
                                if (js != NULL)
                                {
-                                       js->status = GHB_QUEUE_CANCELED;
                                        gchar *path = g_strdup_printf ("%d", index);
-                                       if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
+                                       if (gtk_tree_model_get_iter_from_string(
+                                                       GTK_TREE_MODEL(store), &iter, path))
                                        {
                                                gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
                                        }
                                        g_free(path);
                                }
                }
-               current_id = -1;
                gtk_progress_bar_set_fraction (progress, 1.0);
-               ghb_clear_state(GHB_STATE_WORKDONE);
-       }
-       else if (status.state & GHB_STATE_PAUSED)
-       {
-               status_str = g_strdup_printf ("Paused"); 
-               gtk_progress_bar_set_text (progress, status_str);
-               g_free(status_str);
+               ghb_clear_queue_state(GHB_STATE_WORKDONE);
+               if (!ud->cancel_encode)
+                       ud->current_job = start_next_job(ud, FALSE);
+               else
+                       ud->current_job = NULL;
+               if (js)
+                       ghb_settings_set_int(js, "job_status", qstatus);
+               ghb_save_queue(ud->queue);
+               ud->cancel_encode = FALSE;
        }
-       else if (status.state & GHB_STATE_MUXING)
+       else if (status.queue_state & GHB_STATE_MUXING)
        {
                gtk_progress_bar_set_text(progress, "Muxing: this may take awhile...");
        }
-       if (status.state & GHB_STATE_WORKING)
+       if (status.queue_state & GHB_STATE_SCANNING)
        {
+               // This needs to be in scanning and working since scanning
+               // happens fast enough that it can be missed
                if (!work_started)
                {
                        work_started = TRUE;
                        queue_buttons_grey(ud, TRUE);
                }
-               if (status.unique_id != current_id)
+       }
+       if (status.queue_state & GHB_STATE_WORKING)
+       {
+               // This needs to be in scanning and working since scanning
+               // happens fast enough that it can be missed
+               if (!work_started)
                {
-                       index = find_queue_item(ud->queue, current_id, &js);
-                       if (js != NULL)
-                       {
-                               js->status = GHB_QUEUE_DONE;
-                               treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
-                               store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
-                               gchar *path = g_strdup_printf ("%d", index);
-                               if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
-                               {
-                                       gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
-                               }
-                               g_free(path);
-                       }
-
-                       index = find_queue_item(ud->queue, status.unique_id, &js);
-                       if (js != NULL)
-                       {
-                               js->status = GHB_QUEUE_RUNNING;
-                               current_id = status.unique_id;
-                       }
+                       work_started = TRUE;
+                       queue_buttons_grey(ud, TRUE);
                }
-               index = find_queue_item(ud->queue, status.unique_id, &js);
-               if (index >= 0)
+               index = find_queue_job(ud->queue, status.unique_id, &js);
+               if (status.unique_id != 0 && index >= 0)
                {
                        gchar working_icon[] = "hb-working0";
                        working_icon[10] = '0' + working;
@@ -2839,12 +3496,20 @@ ghb_backend_events(signal_user_data_t *ud)
                        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
                        store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
                        gchar *path = g_strdup_printf ("%d", index);
-                       if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
+                       if (gtk_tree_model_get_iter_from_string(
+                                       GTK_TREE_MODEL(store), &iter, path))
                        {
                                gtk_tree_store_set(store, &iter, 0, working_icon, -1);
                        }
                        g_free(path);
                }
+               GtkLabel *label;
+               gchar *status_str;
+
+               status_str = working_status_string(ud, &status);
+               label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_status"));
+               gtk_label_set_text (label, status_str);
+               g_free(status_str);
        }
 }
 
@@ -2856,14 +3521,18 @@ ghb_timer_cb(gpointer data)
        ghb_backend_events(ud);
        if (update_default_destination)
        {
-               const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
-               gchar *dest_dir = g_path_get_dirname (dest);
-               const gchar *def_dest = ghb_settings_get_string(ud->settings, "destination_dir");
+               gchar *dest, *dest_dir, *def_dest;
+               dest = ghb_settings_get_string(ud->settings, "destination");
+               dest_dir = g_path_get_dirname (dest);
+               def_dest = ghb_settings_get_string(ud->settings, "destination_dir");
                if (strcmp(dest_dir, def_dest) != 0)
                {
                        ghb_settings_set_string (ud->settings, "destination_dir", dest_dir);
                        ghb_pref_save (ud->settings, "destination_dir");
                }
+               g_free(dest);
+               g_free(dest_dir);
+               g_free(def_dest);
                update_default_destination = FALSE;
        }
        if (update_preview)
@@ -2934,10 +3603,10 @@ ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
        {
                // This should never happen, but if it does I would get into an
                // infinite loop.  Returning false removes this callback.
-               g_warning("Error while reading activity from pipe\n");
+               g_warning("Error while reading activity from pipe");
                if (gerror != NULL)
                {
-                       g_warning("%s\n", gerror->message);
+                       g_warning("%s", gerror->message);
                        g_error_free (gerror);
                }
                return FALSE;
@@ -3011,7 +3680,7 @@ show_presets_toggled_cb(GtkToggleButton *button, signal_user_data_t *ud)
        GtkWidget *widget;
        GtkWindow *hb_window;
        
-       g_debug("show_presets_clicked_cb ()\n");
+       g_debug("show_presets_clicked_cb ()");
        widget = GHB_WIDGET (ud->builder, "presets_frame");
        if (gtk_toggle_button_get_active(button))
        {
@@ -3043,7 +3712,7 @@ presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, sig
                path = gtk_tree_model_get_path (store, &iter);
                // Make the parent visible in scroll window if it is not.
                gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
-               g_free(path);
+               gtk_tree_path_free(path);
        }
 }
 
@@ -3054,15 +3723,16 @@ update_chapter_list(signal_user_data_t *ud)
        GtkTreeIter iter;
        GtkListStore *store;
        gboolean done;
-       gchar **chapters;
+       GValue *chapters;
        gint titleindex, ii;
+       gint count;
        
-       g_debug("update_chapter_list ()\n");
-       titleindex = ghb_settings_get_index(ud->settings, "title");
+       g_debug("update_chapter_list ()");
+       titleindex = ghb_settings_combo_int(ud->settings, "title");
        chapters = ghb_get_chapters(titleindex);
-       if (ud->chapter_list != NULL)
-               g_strfreev (ud->chapter_list);
-       ud->chapter_list = chapters;
+       count = ghb_array_len(chapters);
+       if (chapters)
+               ghb_settings_set_value(ud->settings, "chapter_list", chapters);
        
        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
        store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
@@ -3071,86 +3741,145 @@ update_chapter_list(signal_user_data_t *ud)
        {
                do
                {
-                       if (chapters != NULL && chapters[ii])
+
+                       if (ii < count)
                        {
+                               gchar *chapter;
+
                                // Update row with settings data
-                               g_debug("Updating row\n");
+                               g_debug("Updating row");
+                               chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
                                gtk_list_store_set(store, &iter, 
                                        0, ii+1,
-                                       1, chapters[ii],
+                                       1, chapter,
                                        2, TRUE,
                                        -1);
+                               g_free(chapter);
                                ii++;
                                done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
                        }
                        else
                        {
                                // No more settings data, remove row
-                               g_debug("Removing row\n");
+                               g_debug("Removing row");
                                done = !gtk_list_store_remove(store, &iter);
                        }
                } while (!done);
        }
-       while (chapters != NULL && chapters[ii])
+       while (ii < count)
        {
+               gchar *chapter;
+
                // Additional settings, add row
-               g_debug("Adding row\n");
-               g_debug("%d -- %s\n", ii, chapters[ii]);
+               g_debug("Adding row");
+               chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
                gtk_list_store_append(store, &iter);
                gtk_list_store_set(store, &iter, 
                        0, ii+1,
-                       1, chapters[ii],
+                       1, chapter,
                        2, TRUE,
                        -1);
+               g_free(chapter);
                ii++;
        }
 }
 
+static gint chapter_edit_key = 0;
+
+gboolean
+chapter_keypress_cb(
+       GhbCellRendererText *cell,
+       GdkEventKey *event,
+       signal_user_data_t *ud)
+{
+       chapter_edit_key = event->keyval;
+       return FALSE;
+}
+
 void
-chapter_edited_cb(GtkCellRendererText *cell, gchar *path, gchar *text, signal_user_data_t *ud)
+chapter_edited_cb(
+       GhbCellRendererText *cell, 
+       gchar *path, 
+       gchar *text, 
+       signal_user_data_t *ud)
 {
        GtkTreePath *treepath;
        GtkListStore *store;
        GtkTreeView *treeview;
-       GtkTreeViewColumn *column;
        GtkTreeIter iter;
        gint index;
+       gint *pi;
+       gint row;
        
-       g_debug("chapter_edited_cb ()\n");
-       g_debug("path (%s)\n", path);
-       g_debug("text (%s)\n", text);
+       g_debug("chapter_edited_cb ()");
+       g_debug("path (%s)", path);
+       g_debug("text (%s)", text);
        treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
        store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
        treepath = gtk_tree_path_new_from_string (path);
+       pi = gtk_tree_path_get_indices(treepath);
+       row = pi[0];
        gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
-       gtk_tree_path_free (treepath);
        gtk_list_store_set(store, &iter, 
                1, text,
                2, TRUE,
                -1);
        gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &index, -1);
-       g_free(ud->chapter_list[index-1]);
-       ud->chapter_list[index-1] = g_strdup(text);
-       if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
+
+       GValue *chapters;
+       GValue *chapter;
+
+       chapters = ghb_settings_get_value(ud->settings, "chapter_list");
+       chapter = ghb_array_get_nth(chapters, index-1);
+       g_value_set_string(chapter, text);
+       if ((chapter_edit_key == GDK_Return || chapter_edit_key == GDK_Down) &&
+               gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
        {
+               GtkTreeViewColumn *column;
+
+               gtk_tree_path_next(treepath);
+               // When a cell has been edited, I want to advance to the
+               // next cell and start editing it automaitcally.
+               // Unfortunately, we may not be in a state here where
+               // editing is allowed.  This happens when the user selects
+               // a new cell with the mouse instead of just hitting enter.
+               // Some kind of Gtk quirk.  widget_editable==NULL assertion.
+               // Editing is enabled again once the selection event has been
+               // processed.  So I'm queueing up a callback to be called
+               // when things go idle.  There, I will advance to the next
+               // cell and initiate editing.
+               //
+               // Now, you might be asking why I don't catch the keypress
+               // event and determine what action to take based on that.
+               // The Gtk developers in their infinite wisdom have made the 
+               // actual GtkEdit widget being used a private member of
+               // GtkCellRendererText, so it can not be accessed to hang a
+               // signal handler off of.  And they also do not propagate the
+               // keypress signals in any other way.  So that information is lost.
+               //g_idle_add((GSourceFunc)next_cell, ud);
+               //
+               // Keeping the above comment for posterity.
+               // I got industrious and made my own CellTextRendererText that
+               // passes on the key-press-event. So now I have much better
+               // control of this.
                column = gtk_tree_view_get_column(treeview, 1);
-               treepath = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
                gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
-               gtk_tree_path_free (treepath);
        }
+       else if (chapter_edit_key == GDK_Up && row > 0)
+       {
+               GtkTreeViewColumn *column;
+               gtk_tree_path_prev(treepath);
+               column = gtk_tree_view_get_column(treeview, 1);
+               gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
+       }
+       gtk_tree_path_free (treepath);
 }
 
 void
 chapter_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
 {
-       GtkTreeModel *store;
-       GtkTreeIter iter;
-       
-       g_debug("chapter_list_selection_changed_cb ()\n");
-       if (gtk_tree_selection_get_selected(selection, &store, &iter))
-       {
-               // What to do??
-       }
+       g_debug("chapter_list_selection_changed_cb ()");
+       //chapter_selection_changed = TRUE;
 }
 
 void
@@ -3161,7 +3890,7 @@ queue_list_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, GtkCel
        
        column = gtk_tree_view_get_column (GTK_TREE_VIEW(widget), 0);
        width = gtk_tree_view_column_get_width(column);
-       g_debug("col width %d alloc width %d\n", width, allocation->width);
+       g_debug("col width %d alloc width %d", width, allocation->width);
        // Set new wrap-width.  Shave a little off to accomidate the icons
        // that share this column.
        if (width >= 564) // Don't allow below a certain size
@@ -3171,9 +3900,11 @@ queue_list_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, GtkCel
 void
 preview_button_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
-       gint titleindex = ghb_settings_get_int(ud->settings, "title");
+       gint titleindex;
+
+       titleindex = ghb_settings_combo_int(ud->settings, "title");
        if (titleindex < 0) return;
-       g_debug("titleindex %d\n", titleindex);
+       g_debug("titleindex %d", titleindex);
 
        GtkWidget *widget = GHB_WIDGET (ud->builder, "preview_window");
        gtk_widget_show (widget);
@@ -3188,15 +3919,15 @@ preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 void
 preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
 {
-       g_debug("-------------------------------allocate %d x %d\n", allocation->width, allocation->height);
+       g_debug("-------------------------------allocate %d x %d", allocation->width, allocation->height);
        if (preview_button_width == allocation->width &&
                preview_button_height == allocation->height)
        {
                // Nothing to do. Bug out.
-               g_debug("nothing to do\n");
+               g_debug("nothing to do");
                return;
        }
-       g_debug("-------------------------------prev allocate %d x %d\n", preview_button_width, preview_button_height);
+       g_debug("-------------------------------prev allocate %d x %d", preview_button_width, preview_button_height);
        preview_button_width = allocation->width;
        preview_button_height = allocation->height;
        set_preview_image(ud);
@@ -3205,19 +3936,23 @@ preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, si
 void
 queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
-       GSList *link = ud->queue;
-       job_settings_t *job;
+       GValue *js;
        gboolean running = FALSE;
-       while (link != NULL)
+       gint count, ii;
+       gint status;
+       gint state;
+
+       count = ghb_array_len(ud->queue);
+       for (ii = 0; ii < count; ii++)
        {
-               job = (job_settings_t*)link->data;
-               if ((job->status == GHB_QUEUE_RUNNING) || 
-                       (job->status == GHB_QUEUE_PENDING))
+               js = ghb_array_get_nth(ud->queue, ii);
+               status = ghb_settings_get_int(js, "job_status");
+               if ((status == GHB_QUEUE_RUNNING) || 
+                       (status == GHB_QUEUE_PENDING))
                {
                        running = TRUE;
                        break;
                }
-               link = link->next;
        }
        if (!running)
        {
@@ -3226,12 +3961,18 @@ queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
                if (!queue_add(ud))
                        return;
        }
-       ghb_start_queue();
+       state = ghb_get_queue_state();
+       if (state == GHB_STATE_IDLE)
+       {
+               // Add the first pending queue item and start
+               ud->current_job = start_next_job(ud, TRUE);
+       }
 }
 
 void
 queue_stop_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
+       ud->cancel_encode = TRUE;
        cancel_encode(NULL);
 }
 
@@ -3276,7 +4017,7 @@ void
 ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
 {
        GtkWidget *widget;
-       g_debug("ghb_hbfd\n");
+       g_debug("ghb_hbfd");
        widget = GHB_WIDGET(ud->builder, "queue_pause1");
        set_visible(widget, !hbfd);
        widget = GHB_WIDGET(ud->builder, "queue_add");
@@ -3306,9 +4047,9 @@ ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
 void
 hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
-       g_debug("hbfd_toggled_cb\n");
+       g_debug("hbfd_toggled_cb");
        ghb_widget_to_setting (ud->settings, widget);
-       gboolean hbfd = ghb_settings_get_bool(ud->settings, "hbfd");
+       gboolean hbfd = ghb_settings_get_boolean(ud->settings, "hbfd");
        ghb_hbfd(ud, hbfd);
        ghb_pref_save(ud->settings, "hbfd");
 }
@@ -3316,13 +4057,70 @@ hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
 void
 pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
-       g_debug("pref_changed_cb\n");
+       g_debug("pref_changed_cb");
        ghb_widget_to_setting (ud->settings, widget);
+       check_dependency(ud, widget);
        const gchar *name = gtk_widget_get_name(widget);
        ghb_pref_save(ud->settings, name);
 }
 
 void
+tweaks_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+       g_debug("tweaks_changed_cb");
+       ghb_widget_to_setting (ud->settings, widget);
+       const gchar *name = gtk_widget_get_name(widget);
+       ghb_pref_save(ud->settings, name);
+
+       gboolean tweaks = ghb_settings_get_boolean(ud->settings, "allow_tweaks");
+       widget = GHB_WIDGET(ud->builder, "deinterlace");
+       tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
+       widget = GHB_WIDGET(ud->builder, "tweak_deinterlace");
+       !tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
+
+       widget = GHB_WIDGET(ud->builder, "denoise");
+       tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
+       widget = GHB_WIDGET(ud->builder, "tweak_denoise");
+       !tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
+       if (tweaks)
+       {
+               const GValue *value;
+               value = ghb_settings_get_value(ud->settings, "deinterlace");
+               ghb_ui_update(ud, "tweak_deinterlace", value);
+               value = ghb_settings_get_value(ud->settings, "denoise");
+               ghb_ui_update(ud, "tweak_denoise", value);
+       }
+       else
+       {
+               const GValue *value;
+               value = ghb_settings_get_value(ud->settings, "tweak_deinterlace");
+               ghb_ui_update(ud, "deinterlace", value);
+               value = ghb_settings_get_value(ud->settings, "tweak_denoise");
+               ghb_ui_update(ud, "denoise", value);
+       }
+}
+
+void
+hbfd_feature_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+       g_debug("hbfd_feature_changed_cb");
+       ghb_widget_to_setting (ud->settings, widget);
+       const gchar *name = gtk_widget_get_name(widget);
+       ghb_pref_save(ud->settings, name);
+
+       gboolean hbfd = ghb_settings_get_boolean(ud->settings, "hbfd_feature");
+       GtkAction *action;
+       if (hbfd)
+       {
+               const GValue *val;
+               val = ghb_settings_get_value(ud->settings, "hbfd");
+               ghb_ui_update(ud, "hbfd", val);
+       }
+       action = GHB_ACTION (ud->builder, "hbfd");
+       gtk_action_set_visible(action, hbfd);
+}
+
+void
 ghb_file_menu_add_dvd(signal_user_data_t *ud)
 {
        GList *link, *drives;
@@ -3404,6 +4202,7 @@ ghb_is_cd(GDrive *gd)
        device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
        halDrive = libhal_drive_from_device_file (hal_ctx, device);
        dtype = libhal_drive_get_type(halDrive);
+       libhal_drive_free(halDrive);
        g_free(device);
        return (dtype == LIBHAL_DRIVE_TYPE_CDROM);
 }
@@ -3452,67 +4251,67 @@ drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
 static gboolean
 dbus_init (void)
 {
-    DBusError error;
+       DBusError error;
 
-    if (dbus_connection != NULL)
-        return TRUE;
+       if (dbus_connection != NULL)
+               return TRUE;
 
-    dbus_error_init (&error);
-    if (!(dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) {
-        g_debug ("could not get system bus: %s\n", error.message);
-        dbus_error_free (&error);
-        return FALSE;
-    }
+       dbus_error_init (&error);
+       if (!(dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) {
+               g_debug ("could not get system bus: %s", error.message);
+               dbus_error_free (&error);
+               return FALSE;
+       }
 
-    //dbus_connection_setup_with_g_main (dbus_connection, NULL);
-    //dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
-    //dbus_connection_add_filter (dbus_connection, gvm_dbus_filter_function, NULL, NULL);
+       //dbus_connection_setup_with_g_main (dbus_connection, NULL);
+       //dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
+       //dbus_connection_add_filter (dbus_connection, gvm_dbus_filter_function, NULL, NULL);
 
-    return TRUE;
+       return TRUE;
 }
 
 void
 ghb_hal_init()
 {
-    DBusError error;
-    char **devices;
-    int nr;
-
-    if (!dbus_init ())
-        return;
+       DBusError error;
+       char **devices;
+       int nr;
 
-    if (!(hal_ctx = libhal_ctx_new ())) {
-        g_warning ("failed to create a HAL context!");
-        return;
-    }
+       if (!dbus_init ())
+               return;
 
-    libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
-    dbus_error_init (&error);
-    if (!libhal_ctx_init (hal_ctx, &error)) {
-        g_warning ("libhal_ctx_init failed: %s", error.message ? error.message : "unknown");
-        dbus_error_free (&error);
-        libhal_ctx_free (hal_ctx);
-        return;
-    }
+       if (!(hal_ctx = libhal_ctx_new ())) {
+               g_warning ("failed to create a HAL context!");
+               return;
+       }
 
-    /*
-     * Do something to ping the HAL daemon - the above functions will
-     * succeed even if hald is not running, so long as DBUS is.  But we
-     * want to exit silently if hald is not running, to behave on
-     * pre-2.6 systems.
-     */
-    if (!(devices = libhal_get_all_devices (hal_ctx, &nr, &error))) {
-        g_warning ("seems that HAL is not running: %s", error.message ? error.message : "unknown");
-        dbus_error_free (&error);
+       libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
+       dbus_error_init (&error);
+       if (!libhal_ctx_init (hal_ctx, &error)) {
+               g_warning ("libhal_ctx_init failed: %s", error.message ? error.message : "unknown");
+               dbus_error_free (&error);
+               libhal_ctx_free (hal_ctx);
+               return;
+       }
 
-        libhal_ctx_shutdown (hal_ctx, NULL);
-        libhal_ctx_free (hal_ctx);
-        return;
-    }
+       /*
+        * Do something to ping the HAL daemon - the above functions will
+        * succeed even if hald is not running, so long as DBUS is.  But we
+        * want to exit silently if hald is not running, to behave on
+        * pre-2.6 systems.
+        */
+       if (!(devices = libhal_get_all_devices (hal_ctx, &nr, &error))) {
+               g_warning ("seems that HAL is not running: %s", error.message ? error.message : "unknown");
+               dbus_error_free (&error);
+
+               libhal_ctx_shutdown (hal_ctx, NULL);
+               libhal_ctx_free (hal_ctx);
+               return;
+       }
 
-    libhal_free_string_array (devices);
+       libhal_free_string_array (devices);
 
-    //gvm_hal_claim_branch ("/org/freedesktop/Hal/devices/local");
+       //gvm_hal_claim_branch ("/org/freedesktop/Hal/devices/local");
 }
 
 gboolean 
@@ -3527,13 +4326,13 @@ tweak_setting_cb(
        gboolean allow_tweaks;
 
        g_debug("press %d %d", event->type, event->button);
-       allow_tweaks = ghb_settings_get_bool (ud->settings, "allow_tweaks");
+       allow_tweaks = ghb_settings_get_boolean(ud->settings, "allow_tweaks");
        if (allow_tweaks && event->type == GDK_BUTTON_PRESS && event->button == 3)
        { // Its a right mouse click
                GtkWidget *dialog;
                GtkEntry *entry;
                GtkResponseType response;
-               const gchar *tweak = NULL;
+               gchar *tweak = NULL;
 
                name = gtk_widget_get_name(widget);
                if (g_str_has_prefix(name, "tweak_"))
@@ -3550,12 +4349,15 @@ tweak_setting_cb(
                gtk_window_set_title(GTK_WINDOW(dialog), tweak_name);
                entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "tweak_setting"));
                if (tweak)
+               {
                        gtk_entry_set_text(entry, tweak);
+                       g_free(tweak);
+               }
                response = gtk_dialog_run(GTK_DIALOG(dialog));
                gtk_widget_hide(dialog);
                if (response == GTK_RESPONSE_OK)
                {
-                       tweak = gtk_entry_get_text(entry);
+                       tweak = (gchar*)gtk_entry_get_text(entry);
                        if (ghb_validate_filter_string(tweak, -1))
                                ghb_settings_set_string(ud->settings, tweak_name, tweak);
                        else
@@ -3574,3 +4376,167 @@ tweak_setting_cb(
        return ret;
 }
 
+gboolean 
+easter_egg_cb(
+       GtkWidget *widget, 
+       GdkEventButton *event, 
+       signal_user_data_t *ud)
+{
+       g_debug("press %d %d", event->type, event->button);
+       if (event->type == GDK_3BUTTON_PRESS && event->button == 1)
+       { // Its a tripple left mouse button click
+               GtkWidget *widget;
+               widget = GHB_WIDGET(ud->builder, "allow_tweaks");
+               gtk_widget_show(widget);
+               widget = GHB_WIDGET(ud->builder, "hbfd_feature");
+               gtk_widget_show(widget);
+       }
+       else if (event->type == GDK_BUTTON_PRESS && event->button == 1)
+       {
+               GtkWidget *widget;
+               widget = GHB_WIDGET(ud->builder, "allow_tweaks");
+               gtk_widget_hide(widget);
+               widget = GHB_WIDGET(ud->builder, "hbfd_feature");
+               gtk_widget_hide(widget);
+       }
+       return FALSE;
+}
+
+gboolean
+ghb_reload_queue(signal_user_data_t *ud)
+{
+       GValue *queue;
+       gint unfinished = 0;
+       gint count, ii;
+       gint status;
+       GValue *settings;
+       gchar *message;
+
+       g_debug("ghb_reload_queue");
+       queue = ghb_load_queue();
+       // Look for unfinished entries
+       count = ghb_array_len(queue);
+       for (ii = 0; ii < count; ii++)
+       {
+               settings = ghb_array_get_nth(queue, ii);
+               status = ghb_settings_get_int(settings, "job_status");
+               if (status != GHB_QUEUE_DONE && status != GHB_QUEUE_CANCELED)
+               {
+                       unfinished++;
+               }
+       }
+       if (unfinished)
+       {
+               message = g_strdup_printf(
+                                       "You have %d unfinished job%s in a saved queue.\n\n"
+                                       "Would you like to reload %s?",
+                                       unfinished, 
+                                       (unfinished > 1) ? "s" : "",
+                                       (unfinished > 1) ? "them" : "it");
+               if (ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "No", "Yes"))
+               {
+                       GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
+                       gtk_widget_show (widget);
+
+                       ud->queue = queue;
+                       // First get rid of any old items we don't want
+                       for (ii = count-1; ii >= 0; ii--)
+                       {
+                               settings = ghb_array_get_nth(queue, ii);
+                               status = ghb_settings_get_int(settings, "job_status");
+                               if (status == GHB_QUEUE_DONE || status == GHB_QUEUE_CANCELED)
+                               {
+                                       GValue *old = ghb_array_get_nth(queue, ii);
+                                       ghb_value_free(old);
+                                       ghb_array_remove(queue, ii);
+                               }
+                       }
+                       count = ghb_array_len(queue);
+                       for (ii = 0; ii < count; ii++)
+                       {
+                               settings = ghb_array_get_nth(queue, ii);
+                               ghb_settings_set_int(settings, "job_unique_id", 0);
+                               ghb_settings_set_int(settings, "job_status", GHB_QUEUE_PENDING);
+                               add_to_queue_list(ud, settings, NULL);
+                       }
+                       queue_buttons_grey(ud, FALSE);
+               }
+               else
+               {
+                       ghb_value_free(queue);
+                       ghb_remove_queue_file();
+               }
+               g_free(message);
+       }
+       return FALSE;
+}
+
+gboolean queue_key_press_cb(
+       GtkWidget *widget, 
+       GdkEventKey *event,
+       signal_user_data_t *ud)
+{
+       GtkTreeView *treeview;
+       GtkTreeSelection *selection;
+       GtkTreeModel *store;
+       GtkTreeIter iter;
+       gint row;
+       gint *indices;
+       gint unique_id;
+       GValue *settings;
+       gint status;
+
+       g_message("queue_key_press_cb ()");
+       treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
+       store = gtk_tree_view_get_model(treeview);
+
+       selection = gtk_tree_view_get_selection (treeview);
+       if (gtk_tree_selection_get_selected(selection, &store, &iter))
+       {
+               GtkTreePath *treepath;
+
+               treepath = gtk_tree_model_get_path (store, &iter);
+               // Find the entry in the queue
+               indices = gtk_tree_path_get_indices (treepath);
+               row = indices[0];
+               // Can only free the treepath After getting what I need from
+               // indices since this points into treepath somewhere.
+               gtk_tree_path_free (treepath);
+               if (row < 0) return FALSE;
+               if (row >= ghb_array_len(ud->queue))
+                       return FALSE;
+               settings = ghb_array_get_nth(ud->queue, row);
+               status = ghb_settings_get_int(settings, "job_status");
+               if (status == GHB_QUEUE_RUNNING)
+               {
+                       // Ask if wants to stop encode.
+                       if (!cancel_encode(NULL))
+                       {
+                               return FALSE;
+                       }
+                       unique_id = ghb_settings_get_int(settings, "job_unique_id");
+                       ghb_remove_job(unique_id);
+               }
+               // Remove the selected item
+               gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
+               // Remove the corresponding item from the queue list
+               GValue *old = ghb_array_get_nth(ud->queue, row);
+               ghb_value_free(old);
+               ghb_array_remove(ud->queue, row);
+               ghb_save_queue(ud->queue);
+       }
+       return FALSE;
+}
+
+gchar*
+format_deblock_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
+{
+       if (val < 5.0)
+       {
+               return g_strdup_printf("Off");
+       }
+       else
+       {
+               return g_strdup_printf("%d", (gint)val);
+       }
+}