OSDN Git Service

LinGui: change how x264 options are handled
[handbrake-jp/handbrake-jp-git.git] / gtk / src / callbacks.c
index ce40e29..8c1088f 100644 (file)
@@ -29,7 +29,6 @@
 #include "hb-backend.h"
 #include "ghb-dvd.h"
 
-extern gboolean ghb_autostart;
 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();
@@ -71,6 +70,8 @@ static dependency_t dep_map[] =
        {"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},
@@ -129,7 +130,6 @@ dep_check(signal_user_data_t *ud, const gchar *name)
 {
        GtkWidget *widget;
        GObject *dep_object;
-       gchar *value;
        int ii;
        int count = sizeof(dep_map) / sizeof(dependency_t);
        gboolean result = TRUE;
@@ -141,17 +141,22 @@ dep_check(signal_user_data_t *ud, const gchar *name)
                {
                        widget = GHB_WIDGET(ud->builder, dep_map[ii].widget_name);
                        dep_object = gtk_builder_get_object(ud->builder, dep_map[ii].dep_name);
-                       value = ghb_widget_short_opt(widget);
-                       if (dep_object == NULL || widget == NULL)
+                       if (dep_object == NULL)
                        {
                                g_message("Failed to find widget\n");
                        }
                        else
                        {
+                               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] == '>')
@@ -184,8 +189,8 @@ dep_check(signal_user_data_t *ud, const gchar *name)
                                sensitive = dep_map[ii].disable_if_equal ^ sensitive;
                                if (!sensitive) result = FALSE;
                                g_strfreev (values);
+                               g_free(value);
                        }
-                       g_free(value);
                }
        }
        return result;
@@ -298,18 +303,19 @@ 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 (ud->state & GHB_STATE_WORKING)
+    if (state & GHB_STATE_WORKING)
     {
         if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
         {
-                       ghb_hb_cleanup();
+                       ghb_hb_cleanup(FALSE);
                gtk_main_quit();
             return;
         }
         return;
     }
-       ghb_hb_cleanup();
+       ghb_hb_cleanup(FALSE);
        gtk_main_quit();
 }
 
@@ -597,7 +603,7 @@ do_scan(signal_user_data_t *ud, const gchar *filename)
                        path = ghb_settings_get_string( ud->settings, "source");
                        gtk_progress_bar_set_fraction (progress, 0);
                        gtk_progress_bar_set_text (progress, "Scanning ...");
-                       ud->state |= GHB_STATE_SCANNING;
+                       ghb_hb_cleanup(TRUE);
                        ghb_backend_scan (path, 0);
                }
                else
@@ -651,7 +657,7 @@ source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
                        if (strcmp(sourcename, filename) != 0)
                        {
                                ghb_settings_set_string (ud->settings, "default_source", filename);
-                               ghb_prefs_save (ud->settings);
+                               ghb_pref_save (ud->settings, "default_source");
                                ghb_dvd_set_current (filename, ud);
                        }
                        g_free(filename);
@@ -672,7 +678,7 @@ dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
        if (strcmp(sourcename, filename) != 0)
        {
                ghb_settings_set_string (ud->settings, "default_source", filename);
-               ghb_prefs_save (ud->settings);
+               ghb_pref_save (ud->settings, "default_source");
                ghb_dvd_set_current (filename, ud);
        }
 }
@@ -680,7 +686,7 @@ dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
 static void
 update_destination_extension(signal_user_data_t *ud)
 {
-       static gchar *containers[] = {"mkv", "mp4", "m4v", "avi", "ogm", NULL};
+       static gchar *containers[] = {".mkv", ".mp4", ".m4v", ".avi", ".ogm", NULL};
        gchar *filename;
        const gchar *extension;
        gint ii;
@@ -698,6 +704,11 @@ update_destination_extension(signal_user_data_t *ud)
                        gchar *new_name;
                        
                        pos = g_strrstr( filename, "." );
+                       if (pos == NULL)
+                       {
+                               // No period? shouldn't happen
+                               break;
+                       }
                        *pos = 0;
                        if (strcmp(extension, &pos[1]) == 0)
                        {
@@ -776,7 +787,7 @@ gboolean
 window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
 {
        g_debug("window_destroy_event_cb ()\n");
-       ghb_hb_cleanup();
+       ghb_hb_cleanup(FALSE);
        gtk_main_quit();
     return FALSE;
 }
@@ -784,18 +795,19 @@ window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *
 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 (ud->state & GHB_STATE_WORKING)
+    if (state & GHB_STATE_WORKING)
     {
         if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
         {
-                       ghb_hb_cleanup();
+                       ghb_hb_cleanup(FALSE);
                gtk_main_quit();
             return FALSE;
         }
         return TRUE;
     }
-       ghb_hb_cleanup();
+       ghb_hb_cleanup(FALSE);
        gtk_main_quit();
     return FALSE;
 }
@@ -815,6 +827,16 @@ container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
        check_depencency(ud, widget);
        update_acodec_combo(ud);
        clear_presets_selection(ud);
+       if (ghb_ac3_in_audio_list (ud->audio_settings))
+       {
+               const gchar *container;
+
+               container = ghb_settings_get_string(ud->settings, "container");
+               if (strcmp(container, "mp4") == 0)
+               {
+                       ghb_ui_update(ud, "container", "m4v");
+               }
+       }
 }
 
 static gchar*
@@ -850,7 +872,15 @@ show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
        gchar *text;
 
        widget = GHB_WIDGET (ud->builder, "title_duration");
-       text = g_strdup_printf ("%02d:%02d:%02d", tinfo->hours, tinfo->minutes, tinfo->seconds);
+       if (tinfo->duration != 0)
+       {
+               text = g_strdup_printf ("%02d:%02d:%02d", tinfo->hours, 
+                               tinfo->minutes, tinfo->seconds);
+       }
+       else
+       {
+               text = g_strdup_printf ("Unknown");
+       }
        gtk_label_set_text (GTK_LABEL(widget), text);
        g_free(text);
        widget = GHB_WIDGET (ud->builder, "source_dimensions");
@@ -1159,6 +1189,16 @@ audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
                ghb_widget_to_setting(asettings, widget);
                audio_list_refresh_selected(ud);
        }
+       if (ghb_ac3_in_audio_list (ud->audio_settings))
+       {
+               const gchar *container;
+
+               container = ghb_settings_get_string(ud->settings, "container");
+               if (strcmp(container, "mp4") == 0)
+               {
+                       ghb_ui_update(ud, "container", "m4v");
+               }
+       }
 }
 
 static void audio_list_refresh_selected(signal_user_data_t *ud);
@@ -1212,6 +1252,28 @@ setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 }
 
 void
+http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+       ghb_widget_to_setting(ud->settings, widget);
+       check_depencency(ud, widget);
+       clear_presets_selection(ud);
+       ghb_grey_combo_options (ud->builder);
+}
+
+void
+vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+       gint vqmin, vqmax;
+
+       ghb_widget_to_setting(ud->settings, widget);
+       check_depencency(ud, widget);
+       clear_presets_selection(ud);
+       ghb_vquality_range(ud, &vqmin, &vqmax);
+       GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
+       gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
+}
+
+void
 vfr_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
        //const gchar *name = gtk_widget_get_name(widget);
@@ -1417,6 +1479,59 @@ generic_focus_out_cb(GtkWidget *widget, GdkEventFocus *event,
        return FALSE;
 }
 
+// Flag needed to prevent x264 options processing from chasing its tail
+static gboolean ignore_options_update = FALSE;
+
+void
+x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+       ghb_widget_to_setting(ud->settings, widget);
+       if (!ignore_options_update)
+       {
+               ignore_options_update = TRUE;
+               ghb_x264_opt_update(ud, widget);
+               ignore_options_update = FALSE;
+       }
+       check_depencency(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");
+       if (!ignore_options_update)
+       {
+               GtkWidget *textview;
+               textview = GTK_WIDGET(GHB_WIDGET(ud->builder, "x264_options"));
+               ghb_widget_to_setting(ud->settings, textview);
+               const gchar *options;
+               options = ghb_settings_get_string(ud->settings, "x264_options");
+               ignore_options_update = TRUE;
+               ghb_x264_parse_options(ud, options);
+               ignore_options_update = FALSE;
+       }
+}
+
+gboolean
+x264_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
+    signal_user_data_t *ud)
+{
+       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);
+       ignore_options_update = TRUE;
+       if (options != NULL)
+       {
+               ghb_ui_update(ud, "x264_options", options);
+               ghb_x264_parse_options(ud, options);
+               g_free(options);
+       }
+       ignore_options_update = FALSE;
+       return FALSE;
+}
+
 static void
 clear_audio_list(signal_user_data_t *ud)
 {
@@ -1838,6 +1953,18 @@ presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 }
 
 void
+prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+       GtkWidget *dialog;
+       GtkResponseType response;
+
+       g_debug("prefs_dialog_cb ()\n");
+       dialog = GHB_WIDGET(ud->builder, "prefs_dialog");
+       response = gtk_dialog_run(GTK_DIALOG(dialog));
+       gtk_widget_hide(dialog);
+}
+
+void
 presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
        GtkTreeView *treeview;
@@ -1949,6 +2076,15 @@ presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_
                        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
+               // truncated when set.  The range will be readjusted below
+               GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
+               gtk_range_set_range (GTK_RANGE(qp), 0, 100);
+               // Clear the audio list prior to changing the preset.  Existing audio
+               // can cause the container extension to be automatically changed when
+               // it shouldn't be
+               clear_audio_list(ud);
                ghb_set_preset(ud, preset);
                gint titleindex = ghb_settings_get_int(ud->settings, "title");
                set_pref_audio(titleindex, ud);
@@ -1958,6 +2094,10 @@ presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_
                        preset_update_title_deps(ud, &tinfo);
                }
                ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
+
+               gint vqmin, vqmax;
+               ghb_vquality_range(ud, &vqmin, &vqmax);
+               gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
        }
        else
        {
@@ -2319,6 +2459,11 @@ validate_settings(signal_user_data_t *ud)
        {
                return FALSE;
        }
+       // Validate container settings
+       if (!ghb_validate_container(ud))
+       {
+               return FALSE;
+       }
        audio_list_refresh(ud);
        return TRUE;
 }
@@ -2503,39 +2648,13 @@ queue_buttons_grey(signal_user_data_t *ud, gboolean working)
 
 void queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud);
 
-static gint autostart_timeout = -1;
-
-gboolean
-autostart_timer_cb(gpointer data)
+static void
+ghb_backend_events(signal_user_data_t *ud)
 {
-       GtkWidget *widget;
+       ghb_status_t status;
+       gchar *status_str;
        GtkProgressBar *progress;
-       signal_user_data_t *ud = (signal_user_data_t*)data;
-       
-       if (autostart_timeout < 0) return FALSE;
-       gchar *remaining = g_strdup_printf("Encoding will start in %d second%c",
-                                                                          (autostart_timeout-1) / 40 + 1, autostart_timeout <= 40 ? ' ':'s');
-       progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "autostart_countdown"));
-       gtk_progress_bar_set_fraction (progress, (gdouble)autostart_timeout / 800);
-       gtk_progress_bar_set_text(progress, remaining);
-       g_free(remaining);
-       autostart_timeout--;
-       if (autostart_timeout == 0)
-       {
-               widget = GHB_WIDGET(ud->builder, "autostart_dialog");
-               gtk_widget_hide(widget);
-               queue_start_clicked_cb(NULL, ud);
-               return FALSE;
-       }
-       return TRUE;
-}
-
-gboolean
-ghb_timer_cb(gpointer data)
-{
-       static gint ticks = 0;
        gint titleindex;
-       gint unique_id;
        job_settings_t *js;
        static gint current_id = -1;
        gint index;
@@ -2544,25 +2663,83 @@ ghb_timer_cb(gpointer data)
        GtkTreeIter iter;
        static gint working = 0;
        static gboolean work_started = FALSE;
+       
+       ghb_track_status();
+       ghb_get_status(&status);
+       progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
+       if (status.state & GHB_STATE_SCANNING)
+       {
+               status_str = g_strdup_printf ("Scanning title %d of %d...", 
+                                                                 status.title_cur, status.title_count );
+               gtk_progress_bar_set_text (progress, status_str);
+               g_free(status_str);
+               if (status.title_count > 0)
+               {
+                       gtk_progress_bar_set_fraction (progress, 
+                               (gdouble)status.title_cur / status.title_count);
+               }
+       }
+       else if (status.state & GHB_STATE_SCANDONE)
+       {
+               status_str = g_strdup_printf ("Scan done"); 
+               gtk_progress_bar_set_text (progress, status_str);
+               g_free(status_str);
+               gtk_progress_bar_set_fraction (progress, 1.0);
 
-       signal_user_data_t *ud = (signal_user_data_t*)data;
-       switch (ghb_backend_events (ud, &unique_id))
+               ghb_title_info_t tinfo;
+                       
+               ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE);
+               titleindex = ghb_longest_title();
+               ghb_ui_update_int(ud, "title", titleindex);
+
+               // Are there really any titles.
+               if (!ghb_get_title_info(&tinfo, titleindex))
+               {
+                       GtkProgressBar *progress;
+                       progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
+                       gtk_progress_bar_set_fraction (progress, 0);
+                       gtk_progress_bar_set_text (progress, "No Source");
+               }
+               ghb_clear_state(GHB_STATE_SCANDONE);
+               queue_buttons_grey(ud, (0 != (status.state & GHB_STATE_WORKING)));
+       }
+       else if (status.state & GHB_STATE_WORKING)
        {
-        case GHB_EVENT_WORKING:
-        {
-                       if (!work_started)
-                       {
-                               work_started = TRUE;
-                               queue_buttons_grey(ud, TRUE);
-                       }
-                       if (unique_id != current_id)
-                       {
-                               index = find_queue_item(ud->queue, current_id, &js);
+               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 );
+               }
+               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)
+       {
+               work_started = FALSE;
+               queue_buttons_grey(ud, FALSE);
+               index = find_queue_item(ud->queue, current_id, &js);
+               treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
+               store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
+               switch( status.error )
+               {
+                       case GHB_ERROR_NONE:
+                               gtk_progress_bar_set_text( progress, "Rip done!" );
                                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))
                                        {
@@ -2570,38 +2747,56 @@ ghb_timer_cb(gpointer data)
                                        }
                                        g_free(path);
                                }
-
-                               index = find_queue_item(ud->queue, unique_id, &js);
+                               break;
+                       case GHB_ERROR_CANCELED:
+                               gtk_progress_bar_set_text( progress, "Rip canceled." );
                                if (js != NULL)
                                {
-                                       js->status = GHB_QUEUE_RUNNING;
-                                       current_id = unique_id;
+                                       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))
+                                       {
+                                               gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
+                                       }
+                                       g_free(path);
                                }
-                       }
-                       index = find_queue_item(ud->queue, unique_id, &js);
-                       if (index >= 0)
-                       {
-                               gchar working_icon[] = "hb-working0";
-                               working_icon[10] = '0' + working;
-                               working = (working+1) % 6;
-                               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))
+                               break;
+                       default:
+                               gtk_progress_bar_set_text( progress, "Rip failed.");
+                               if (js != NULL)
                                {
-                                       gtk_tree_store_set(store, &iter, 0, working_icon, -1);
+                                       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))
+                                       {
+                                               gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
+                                       }
+                                       g_free(path);
                                }
-                               g_free(path);
-                       }
-        } break;
-        case GHB_EVENT_PAUSED:
-        {
-               } break;
-        case GHB_EVENT_WORK_DONE:
-        {
-                       ud->state &= ~GHB_STATE_WORKING;
-                       work_started = FALSE;
-                       queue_buttons_grey(ud, FALSE);
+               }
+               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);
+       }
+       else if (status.state & GHB_STATE_MUXING)
+       {
+               gtk_progress_bar_set_text(progress, "Muxing: this may take awhile...");
+       }
+       if (status.state & GHB_STATE_WORKING)
+       {
+               if (!work_started)
+               {
+                       work_started = TRUE;
+                       queue_buttons_grey(ud, TRUE);
+               }
+               if (status.unique_id != current_id)
+               {
                        index = find_queue_item(ud->queue, current_id, &js);
                        if (js != NULL)
                        {
@@ -2615,97 +2810,38 @@ ghb_timer_cb(gpointer data)
                                }
                                g_free(path);
                        }
-                       current_id = -1;
-                       if (ghb_autostart)
-                       {
-                               ghb_hb_cleanup();
-                               gtk_main_quit();
-                       }
-        } break;
-        case GHB_EVENT_WORK_CANCELED:
-        {
-                       work_started = FALSE;
-                       queue_buttons_grey(ud, FALSE);
-                       index = find_queue_item(ud->queue, current_id, &js);
+
+                       index = find_queue_item(ud->queue, status.unique_id, &js);
                        if (js != NULL)
                        {
-                               js->status = GHB_QUEUE_CANCELED;
-                               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-canceled", -1);
-                               }
-                               g_free(path);
+                               js->status = GHB_QUEUE_RUNNING;
+                               current_id = status.unique_id;
                        }
-                       current_id = -1;
-        } break;
-               case GHB_EVENT_SCAN_DONE:
-               {
-                       ghb_title_info_t tinfo;
-                       
-                       ud->state &= ~GHB_STATE_SCANNING;
-                       ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE);
-                       titleindex = ghb_longest_title();
-                       ghb_ui_update_int(ud, "title", titleindex);
-                       queue_buttons_grey(ud, FALSE);
-
-                       // Are there really any titles.
-                       if (ghb_get_title_info(&tinfo, titleindex))
-                       {
-                               if (ghb_autostart)
-                               {
-                                       GtkWidget *widget;
-                                       
-                                       gint title = ghb_settings_get_int(ud->settings, "title");
-                                       gint start_chapter = ghb_settings_get_int(ud->settings, "start_chapter");
-                                       gint end_chapter = ghb_settings_get_int(ud->settings, "end_chapter");
-                                       gboolean pass2 = ghb_settings_get_bool(ud->settings, "two_pass");
-                                       const gchar *vol_name = ghb_settings_get_string(ud->settings, "volume_label");
-                                       if (vol_name == NULL)
-                                               vol_name = "No Title";
-                                       const gchar *vcodec = ghb_settings_get_option(ud->settings, "video_codec");
-                                       const gchar *container = ghb_settings_get_option(ud->settings, "container");
-                                       const gchar *acodec = ghb_settings_get_option(ud->settings, "audio_codec");
-                                       const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
-                                       const gchar *preset = ghb_settings_get_string(ud->settings, "preset");
-                                       gchar *info = g_strdup_printf 
-                                               (
-                                                "<big><b>%s</b></big> (Title %d, Chapters %d through %d, %d Video %s)"
-                                                "\n<b>Preset:</b> %s"
-                                                "\n<b>Format:</b> %s Container, %s Video + %s Audio"
-                                                "\n<b>Destination:</b> %s",
-                                                vol_name, title+1, start_chapter, end_chapter, 
-                                                pass2 ? 2:1, pass2 ? "Passes":"Pass",
-                                                preset, container, vcodec, acodec, dest);
-
-                                       widget = GHB_WIDGET (ud->builder, "autostart_summary");
-                                       gtk_label_set_markup (GTK_LABEL(widget), info);
-                                       g_free(info);
-                                       widget = GHB_WIDGET(ud->builder, "autostart_dialog");
-                                       gtk_widget_show_now(widget);
-                                       g_timeout_add (25, autostart_timer_cb, (gpointer)ud);
-                                       autostart_timeout = 800;
-                               }
-                       }
-                       else
-                       {
-                               GtkProgressBar *progress;
-                               progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
-                               gtk_progress_bar_set_fraction (progress, 0);
-                               gtk_progress_bar_set_text (progress, "No Source");
-                       }
-               } break;
-               default:
+               }
+               index = find_queue_item(ud->queue, status.unique_id, &js);
+               if (index >= 0)
                {
-                       if (work_started)
+                       gchar working_icon[] = "hb-working0";
+                       working_icon[10] = '0' + working;
+                       working = (working+1) % 6;
+                       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))
                        {
-                               work_started = FALSE;
-                               queue_buttons_grey(ud, FALSE);
+                               gtk_tree_store_set(store, &iter, 0, working_icon, -1);
                        }
-               } break;
+                       g_free(path);
+               }
        }
+}
+
+gboolean
+ghb_timer_cb(gpointer data)
+{
+       signal_user_data_t *ud = (signal_user_data_t*)data;
+
+       ghb_backend_events(ud);
        if (update_default_destination)
        {
                const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
@@ -2714,7 +2850,7 @@ ghb_timer_cb(gpointer data)
                if (strcmp(dest_dir, def_dest) != 0)
                {
                        ghb_settings_set_string (ud->settings, "destination_dir", dest_dir);
-                       ghb_prefs_save (ud->settings);
+                       ghb_pref_save (ud->settings, "destination_dir");
                }
                update_default_destination = FALSE;
        }
@@ -2723,42 +2859,9 @@ ghb_timer_cb(gpointer data)
                set_preview_image (ud);
                update_preview = FALSE;
        }
-       if (ticks == 3 && ghb_autostart)
-       {
-               // Make sure this doesn't happen twice
-               const gchar *source = ghb_settings_get_string(ud->settings, "source");
-               if (update_source_label(ud, source))
-               {
-                       GtkProgressBar *progress;
-                       progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
-                       const gchar *path = ghb_settings_get_string( ud->settings, "source");
-                       gtk_progress_bar_set_fraction (progress, 0);
-                       gtk_progress_bar_set_text (progress, "Scanning ...");
-                       ud->state |= GHB_STATE_SCANNING;
-                       ghb_backend_scan (path, 0);
-               }
-       }
-       ticks++;
        return TRUE;
 }
 
-void
-autostart_ok_cb(GtkWidget *widget, signal_user_data_t *ud)
-{
-       widget = GHB_WIDGET(ud->builder, "autostart_dialog");
-       gtk_widget_hide(widget);
-       queue_start_clicked_cb(NULL, ud);
-       autostart_timeout = -1;
-}
-
-void
-autostart_cancel_cb(GtkWidget *widget, signal_user_data_t *ud)
-{
-       widget = GHB_WIDGET(ud->builder, "autostart_dialog");
-       gtk_widget_hide(widget);
-       autostart_timeout = -1;
-}
-
 gboolean
 ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
 {
@@ -2766,6 +2869,7 @@ ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
        gsize length;
        GtkTextView *textview;
        GtkTextBuffer *buffer;
+       GtkTextIter iter;
        GtkTextMark *mark;
        GError *gerror = NULL;
        GIOStatus status;
@@ -2775,11 +2879,42 @@ ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
        status = g_io_channel_read_line (source, &text, &length, NULL, &gerror);
        if (text != NULL)
        {
+               GdkWindow *window;
+               gint width, height;
+               gint x, y;
+               gboolean bottom = FALSE;
+
                textview = GTK_TEXT_VIEW(GHB_WIDGET (ud->builder, "activity_view"));
                buffer = gtk_text_view_get_buffer (textview);
-               mark = gtk_text_buffer_get_insert (buffer);
-               gtk_text_view_scroll_mark_onscreen(textview, mark);
-               gtk_text_buffer_insert_at_cursor (buffer, text, -1);
+               // I would like to auto-scroll the window when the scrollbar
+               // is at the bottom, 
+               // must determining whether the insert point is at
+               // the bottom of the window 
+               window = gtk_text_view_get_window(textview, GTK_TEXT_WINDOW_TEXT);
+               if (window != NULL)
+               {
+                       gdk_drawable_get_size(GDK_DRAWABLE(window), &width, &height);
+                       gtk_text_view_window_to_buffer_coords(textview, 
+                               GTK_TEXT_WINDOW_TEXT, width, height, &x, &y);
+                       gtk_text_view_get_iter_at_location(textview, &iter, x, y);
+                       if (gtk_text_iter_is_end(&iter))
+                       {
+                               bottom = TRUE;
+                       }
+               }
+               else
+               {
+                       // If the window isn't available, assume bottom
+                       bottom = TRUE;
+               }
+               gtk_text_buffer_get_end_iter(buffer, &iter);
+               gtk_text_buffer_insert(buffer, &iter, text, -1);
+               if (bottom)
+               {
+                       //gtk_text_view_scroll_to_iter(textview, &iter, 0, FALSE, 0, 0);
+                       mark = gtk_text_buffer_get_insert (buffer);
+                       gtk_text_view_scroll_mark_onscreen(textview, mark);
+               }
                g_io_channel_write_chars (ud->activity_log, text, length, &length, NULL);
                g_free(text);
        }
@@ -2809,6 +2944,36 @@ about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 }
 
 void
+guide_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+       gboolean result;
+       char *argv[] = 
+               {"xdg-open","http://trac.handbrake.fr/wiki/HandBrakeGuide",NULL,NULL};
+       result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
+                               NULL, NULL, NULL);
+       if (result) return;
+
+       argv[0] = "gnome-open";
+       result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
+                               NULL, NULL, NULL);
+       if (result) return;
+
+       argv[0] = "kfmclient";
+       argv[1] = "exec";
+       argv[2] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
+       result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
+                               NULL, NULL, NULL);
+       if (result) return;
+
+       argv[0] = "firefox";
+       argv[1] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
+       argv[2] = NULL;
+       result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
+                               NULL, NULL, NULL);
+       if (result) return;
+}
+
+void
 hb_about_response_cb(GtkWidget *widget, gint response, signal_user_data_t *ud)
 {
        gtk_widget_hide (widget);
@@ -2847,7 +3012,7 @@ show_presets_toggled_cb(GtkToggleButton *button, signal_user_data_t *ud)
                gtk_window_resize(hb_window, 16, 16);
        }
        ghb_widget_to_setting(ud->settings, GTK_WIDGET(button));
-       ghb_prefs_save(ud->settings);
+       ghb_pref_save(ud->settings, "show_presets");
 }
 
 void
@@ -3049,7 +3214,6 @@ queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
                if (!queue_add(ud))
                        return;
        }
-       ud->state |= GHB_STATE_WORKING;
        ghb_start_queue();
 }
 
@@ -3134,7 +3298,16 @@ hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
        ghb_widget_to_setting (ud->settings, widget);
        gboolean hbfd = ghb_settings_get_bool(ud->settings, "hbfd");
        ghb_hbfd(ud, hbfd);
-       ghb_prefs_save(ud->settings);
+       ghb_pref_save(ud->settings, "hbfd");
+}
+
+void
+pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+       g_debug("pref_changed_cb\n");
+       ghb_widget_to_setting (ud->settings, widget);
+       const gchar *name = gtk_widget_get_name(widget);
+       ghb_pref_save(ud->settings, name);
 }
 
 void
@@ -3227,9 +3400,18 @@ void
 drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
 {
        gchar *device;
+       gint state = ghb_get_state();
+       static gboolean first_time = TRUE;
 
        if (ud->current_dvd_device == NULL) return;
-       if (ud->state != GHB_STATE_IDLE) return;
+       // A drive change event happens when the program initially starts
+       // and I don't want to automatically scan at that time.
+       if (first_time)
+       {
+               first_time = FALSE;
+               return;
+       }
+       if (state != GHB_STATE_IDLE) return;
        device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
        
        // DVD insertion detected.  Scan it.
@@ -3242,12 +3424,12 @@ drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
                        gtk_progress_bar_set_text (progress, "Scanning ...");
                        gtk_progress_bar_set_fraction (progress, 0);
                        update_source_label(ud, device);
-                       ud->state |= GHB_STATE_SCANNING;
+                       ghb_hb_cleanup(TRUE);
                        ghb_backend_scan(device, 0);
                }
                else
                {
-                       ud->state |= GHB_STATE_SCANNING;
+                       ghb_hb_cleanup(TRUE);
                        ghb_backend_scan("/dev/null", 0);
                }
        }