summaryrefslogtreecommitdiffstats
path: root/gtk/src/callbacks.c
diff options
context:
space:
mode:
Diffstat (limited to 'gtk/src/callbacks.c')
-rw-r--r--gtk/src/callbacks.c3260
1 files changed, 3260 insertions, 0 deletions
diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c
new file mode 100644
index 000000000..58d356248
--- /dev/null
+++ b/gtk/src/callbacks.c
@@ -0,0 +1,3260 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * callbacks.c
+ * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
+ *
+ * callbacks.c is free software.
+ *
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <libhal-storage.h>
+#include <gtk/gtk.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+
+#include "callbacks.h"
+#include "settings.h"
+#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();
+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);
+
+// This is a dependency map used for greying widgets
+// that are dependent on the state of another widget.
+// The enable_value comes from the values that are
+// 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", "audio_label", "none", TRUE},
+ {"title", "audio_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},
+ {"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_track", "audio_add", "none", TRUE},
+ {"audio_track", "audio_codec", "none", TRUE},
+ {"audio_track", "audio_bitrate", "none", TRUE},
+ {"audio_track", "audio_sample_rate", "none", TRUE},
+ {"audio_track", "audio_mix", "none", TRUE},
+ {"audio_track", "audio_drc", "none", TRUE},
+ {"audio_codec", "audio_bitrate", "ac3", TRUE},
+ {"audio_codec", "audio_sample_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},
+ {"pref_audio_codec1", "pref_audio_bitrate1", "none", TRUE},
+ {"pref_audio_codec1", "pref_audio_rate1", "none", TRUE},
+ {"pref_audio_codec1", "pref_audio_mix1", "none", TRUE},
+ {"pref_audio_codec1", "pref_audio_codec2", "none", TRUE},
+ {"pref_audio_codec1", "pref_audio_bitrate2", "none", TRUE},
+ {"pref_audio_codec1", "pref_audio_rate2", "none", TRUE},
+ {"pref_audio_codec1", "pref_audio_mix2", "none", TRUE},
+ {"pref_audio_codec2", "pref_audio_bitrate2", "none", TRUE},
+ {"pref_audio_codec2", "pref_audio_rate2", "none", TRUE},
+ {"pref_audio_codec2", "pref_audio_mix2", "none", TRUE},
+ {"chapter_markers", "chapters_list", "enable", FALSE},
+};
+
+static gboolean
+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;
+
+ g_debug("dep_check () %s\n", name);
+ for (ii = 0; ii < count; ii++)
+ {
+ if (strcmp(dep_map[ii].dep_name, name) == 0)
+ {
+ 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)
+ {
+ g_message("Failed to find widget\n");
+ }
+ else
+ {
+ gint jj = 0;
+ gchar **values = g_strsplit(dep_map[ii].enable_value, "|", 10);
+ gboolean sensitive = FALSE;
+
+ while (values && values[jj])
+ {
+ 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_dbl (widget);
+ if (dvalue < dbl)
+ {
+ sensitive = TRUE;
+ break;
+ }
+ }
+ if (strcmp(values[jj], value) == 0)
+ {
+ sensitive = TRUE;
+ break;
+ }
+ jj++;
+ }
+ sensitive = dep_map[ii].disable_if_equal ^ sensitive;
+ if (!sensitive) result = FALSE;
+ g_strfreev (values);
+ }
+ g_free(value);
+ }
+ }
+ return result;
+}
+
+static void
+check_depencency(signal_user_data_t *ud, GtkWidget *widget)
+{
+ GObject *dep_object;
+ const gchar *name;
+ int ii;
+ int count = sizeof(dep_map) / sizeof(dependency_t);
+
+ if (ghb_widget_index(widget) < 0) return;
+ name = gtk_widget_get_name(widget);
+ g_debug("check_depencency () %s\n", name);
+ for (ii = 0; ii < count; ii++)
+ {
+ if (strcmp(dep_map[ii].widget_name, name) == 0)
+ {
+ 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);
+ }
+ }
+}
+
+void
+ghb_check_all_depencencies(signal_user_data_t *ud)
+{
+ 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++)
+ {
+ 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);
+ }
+}
+
+static void
+clear_presets_selection(signal_user_data_t *ud)
+{
+ GtkTreeView *treeview;
+ GtkTreeSelection *selection;
+
+ if (ud->dont_clear_presets) return;
+ g_debug("clear_presets_selection()\n");
+ treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
+ selection = gtk_tree_view_get_selection (treeview);
+ gtk_tree_selection_unselect_all (selection);
+}
+
+static gchar*
+expand_tilde(const gchar *path)
+{
+ const gchar *user_home;
+ gchar *home;
+ const gchar *suffix;
+ gchar *expanded_path = NULL;
+
+ g_debug("expand_tilde ()\n");
+ if (path[0] == '~')
+ {
+ user_home = g_get_home_dir();
+ home = NULL; // squash warning about home uninitialized
+ if (path[1] == 0)
+ {
+ home = g_strdup(user_home);
+ suffix = "";
+ }
+ else if (path[1] == '/')
+ {
+ home = g_strdup(user_home);
+ suffix = &path[2];
+ }
+ else
+ {
+ home = g_path_get_dirname(user_home);
+ suffix = &path[1];
+ }
+ expanded_path = g_strdup_printf("%s/%s", home, suffix);
+ g_free(home);
+ }
+ return expanded_path;
+}
+
+void
+on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud)
+{
+ g_debug("on_quit1_activate ()\n");
+ if (ud->state == GHB_STATE_WORKING)
+ {
+ if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
+ {
+ gtk_main_quit();
+ return;
+ }
+ return;
+ }
+ gtk_main_quit();
+}
+
+static void
+set_destination(signal_user_data_t *ud)
+{
+ if (ghb_settings_get_bool(ud->settings, "use_source_name"))
+ {
+ const 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)
+ {
+ vol_name = "new_video";
+ }
+ new_name = g_strdup_printf("%s/%s.%s", dir, vol_name, extension);
+ ghb_ui_update(ud, "destination", new_name);
+ g_free(dir);
+ g_free(new_name);
+ }
+}
+
+gboolean
+uppers_and_unders(const gchar *str)
+{
+ if (str == NULL) return FALSE;
+ while (*str)
+ {
+ if (*str == ' ')
+ {
+ return FALSE;
+ }
+ if (*str >= 'a' && *str <= 'z')
+ {
+ return FALSE;
+ }
+ str++;
+ }
+ return TRUE;
+}
+
+enum
+{
+ CAMEL_FIRST_UPPER,
+ CAMEL_OTHER
+};
+
+void
+camel_convert(gchar *str)
+{
+ gint state = CAMEL_OTHER;
+
+ if (str == NULL) return;
+ while (*str)
+ {
+ if (*str == '_') *str = ' ';
+ switch (state)
+ {
+ case CAMEL_OTHER:
+ {
+ if (*str >= 'A' && *str <= 'Z')
+ state = CAMEL_FIRST_UPPER;
+ else
+ state = CAMEL_OTHER;
+
+ } break;
+ case CAMEL_FIRST_UPPER:
+ {
+ if (*str >= 'A' && *str <= 'Z')
+ *str = *str - 'A' + 'a';
+ else
+ state = CAMEL_OTHER;
+ } break;
+ }
+ str++;
+ }
+}
+
+static gboolean
+update_source_label(signal_user_data_t *ud, const gchar *source)
+{
+ gchar *label = NULL;
+ gint len;
+ gchar **path;
+ gchar *filename = g_strdup(source);
+
+ len = strlen(filename);
+ if (filename[len-1] == '/') filename[len-1] = 0;
+ if (g_file_test(filename, G_FILE_TEST_IS_DIR))
+ {
+ path = g_strsplit(filename, "/", -1);
+ len = g_strv_length (path);
+ if ((len > 1) && (strcmp("VIDEO_TS", path[len-1]) == 0))
+ {
+ label = g_strdup(path[len-2]);
+ }
+ else
+ {
+ label = g_strdup(path[len-1]);
+ }
+ g_strfreev (path);
+ }
+ else
+ {
+ // Is regular file or block dev.
+ // Check to see if it is a dvd image
+ label = ghb_dvd_volname (filename);
+ if (label == NULL)
+ {
+ path = g_strsplit(filename, "/", -1);
+ len = g_strv_length (path);
+ // Just use the last combonent of the path
+ label = g_strdup(path[len-1]);
+ g_strfreev (path);
+ }
+ else
+ {
+ if (uppers_and_unders(label))
+ {
+ camel_convert(label);
+ }
+ }
+ }
+ g_free(filename);
+ GtkWidget *widget = GHB_WIDGET (ud->builder, "source_title");
+ if (label != NULL)
+ {
+ gtk_label_set_text (GTK_LABEL(widget), label);
+ ghb_settings_set_string(ud->settings, "volume_label", label);
+ g_free(label);
+ set_destination(ud);
+ }
+ else
+ {
+ label = "No Title Found";
+ gtk_label_set_text (GTK_LABEL(widget), label);
+ ghb_settings_set_string(ud->settings, "volume_label", label);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static GtkWidget *dvd_device_combo = NULL;
+
+void
+chooser_file_selected_cb(GtkFileChooser *dialog, GtkComboBox *combo)
+{
+ const gchar *name = gtk_file_chooser_get_filename (dialog);
+ GtkTreeModel *store;
+ GtkTreeIter iter;
+ const gchar *device;
+ gboolean foundit = FALSE;
+
+ if (name == NULL) return;
+ store = gtk_combo_box_get_model(combo);
+ if (gtk_tree_model_get_iter_first(store, &iter))
+ {
+ do
+ {
+ gtk_tree_model_get(store, &iter, 0, &device, -1);
+ if (strcmp(name, device) == 0)
+ {
+ foundit = TRUE;
+ break;
+ }
+ } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
+ }
+ if (foundit)
+ gtk_combo_box_set_active_iter (combo, &iter);
+ else
+ gtk_combo_box_set_active (combo, 0);
+}
+
+void
+dvd_device_changed_cb(GtkComboBox *combo, GtkWidget *dialog)
+{
+ gint ii = gtk_combo_box_get_active (combo);
+ if (ii != 0)
+ {
+ const gchar *device = gtk_combo_box_get_active_text (combo);
+ const gchar *name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog));
+ if (name == NULL || strcmp(name, device) != 0)
+ gtk_file_chooser_select_filename (GTK_FILE_CHOOSER(dialog), device);
+ }
+}
+
+
+void
+source_type_changed_cb(GtkToggleButton *toggle, GtkFileChooser *chooser)
+{
+ gchar *filename;
+
+ g_debug("source_type_changed_cb ()\n");
+ 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);
+ }
+}
+
+static GtkWidget*
+source_dialog_extra_widgets(GtkWidget *dialog, gboolean checkbutton_active)
+{
+ GtkBox *vbox;
+ GtkWidget *checkbutton;
+
+ vbox = GTK_BOX(gtk_vbox_new (FALSE, 2));
+ checkbutton = gtk_check_button_new_with_label ("Open VIDEO_TS folder");
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), checkbutton_active);
+ gtk_box_pack_start (vbox, checkbutton, FALSE, FALSE, 1);
+ gtk_widget_show(checkbutton);
+
+ GtkWidget *combo;
+ GtkBox *hbox;
+ GList *drives, *link;
+ GtkWidget *label, *blank;
+
+ hbox = GTK_BOX(gtk_hbox_new (FALSE, 2));
+ combo = gtk_combo_box_new_text();
+ label = gtk_label_new("Detected DVD devices:");
+ blank = gtk_label_new("");
+ link = drives = dvd_device_list();
+ gtk_combo_box_append_text (GTK_COMBO_BOX(combo), "Not Selected");
+ while (link != NULL)
+ {
+ gchar *name = (gchar*)link->data;
+ gtk_combo_box_append_text (GTK_COMBO_BOX(combo), name);
+ g_free(name);
+ link = link->next;
+ }
+ g_list_free(drives);
+ gtk_combo_box_set_active (GTK_COMBO_BOX(combo), 0);
+ gtk_box_pack_start (vbox, GTK_WIDGET(hbox), FALSE, FALSE, 1);
+ gtk_widget_show(GTK_WIDGET(hbox));
+ gtk_box_pack_start (hbox, label, FALSE, FALSE, 1);
+ gtk_widget_show(label);
+ gtk_box_pack_start (hbox, combo, FALSE, FALSE, 2);
+ gtk_widget_show(combo);
+ gtk_box_pack_start (hbox, blank, TRUE, TRUE, 1);
+ gtk_widget_show(blank);
+
+ // Ugly hackish global alert
+ dvd_device_combo = combo;
+ g_signal_connect(combo, "changed", (GCallback)dvd_device_changed_cb, dialog);
+ g_signal_connect(dialog, "selection-changed", (GCallback)chooser_file_selected_cb, combo);
+
+ g_signal_connect(checkbutton, "toggled", (GCallback)source_type_changed_cb, dialog);
+ return GTK_WIDGET(vbox);
+}
+
+void
+source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
+{
+ GtkWidget *dialog;
+ GtkWidget *widget;
+ const gchar *sourcename;
+ gint response;
+ GtkFileChooserAction action;
+ gboolean checkbutton_active;
+
+ g_debug("source_browse_clicked_cb ()\n");
+ if (ud->state == GHB_STATE_WORKING)
+ {
+ if (!cancel_encode("Opening a new source will cancel the current encode.\n"))
+ {
+ return;
+ }
+ }
+ sourcename = ghb_settings_get_string(ud->settings, "source");
+
+ checkbutton_active = FALSE;
+ if (g_file_test(sourcename, G_FILE_TEST_IS_DIR))
+ {
+ action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
+ checkbutton_active = TRUE;
+ }
+ else
+ {
+ action = GTK_FILE_CHOOSER_ACTION_OPEN;
+ }
+ dialog = gtk_file_chooser_dialog_new ("Select Source",
+ NULL,
+ action,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+ NULL);
+ widget = source_dialog_extra_widgets(dialog, checkbutton_active);
+ gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), widget);
+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), sourcename);
+ response = gtk_dialog_run(GTK_DIALOG (dialog));
+ gtk_widget_hide(dialog);
+ if (response == GTK_RESPONSE_ACCEPT)
+ {
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+ if (filename != NULL)
+ {
+ ghb_settings_set_string(ud->settings, "source", filename);
+ if (update_source_label(ud, filename))
+ {
+ 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);
+ }
+ else
+ {
+ // TODO: error dialog
+ }
+ if (strcmp(sourcename, filename) != 0)
+ {
+ ghb_settings_set_string (ud->settings, "default_source", filename);
+ ghb_prefs_save (ud->settings);
+ ghb_dvd_set_current (filename, ud);
+ }
+ g_free(filename);
+ }
+ }
+ gtk_widget_destroy(dialog);
+}
+
+static void
+update_destination_extension(signal_user_data_t *ud)
+{
+ static gchar *containers[] = {"mkv", "mp4", "m4v", "avi", "ogm", NULL};
+ gchar *filename;
+ const gchar *extension;
+ gint ii;
+ GtkEntry *entry;
+
+ g_debug("update_destination_extension ()\n");
+ extension = ghb_settings_get_string(ud->settings, "container");
+ entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "destination"));
+ filename = g_strdup(gtk_entry_get_text(entry));
+ for (ii = 0; containers[ii] != NULL; ii++)
+ {
+ if (g_str_has_suffix(filename, containers[ii]))
+ {
+ gchar *pos;
+ gchar *new_name;
+
+ pos = g_strrstr( filename, "." );
+ *pos = 0;
+ if (strcmp(extension, &pos[1]) == 0)
+ {
+ // Extension is already correct
+ break;
+ }
+ new_name = g_strjoin(".", filename, extension, NULL);
+ ghb_ui_update(ud, "destination", new_name);
+ g_free(new_name);
+ break;
+ }
+ }
+ g_free(filename);
+}
+
+static gboolean update_default_destination = FALSE;
+
+void
+destination_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
+{
+ gchar *dest;
+
+ g_debug("destination_entry_changed_cb ()\n");
+ if ((dest = expand_tilde(gtk_entry_get_text(entry))) != NULL)
+ {
+ gtk_entry_set_text(entry, dest);
+ g_free(dest);
+ }
+ update_destination_extension(ud);
+ ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
+ // This signal goes off with ever keystroke, so I'm putting this
+ // update on the timer.
+ update_default_destination = TRUE;
+}
+
+void
+destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
+{
+ GtkWidget *dialog;
+ GtkEntry *entry;
+ const char *destname;
+ gchar *basename;
+
+ g_debug("destination_browse_clicked_cb ()\n");
+ 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);
+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), destname);
+ basename = g_path_get_basename(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)
+ {
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+ entry = (GtkEntry*)GHB_WIDGET(ud->builder, "destination");
+ if (entry == NULL)
+ {
+ g_debug("Failed to find widget: %s\n", "destination");
+ }
+ else
+ {
+ gtk_entry_set_text(entry, filename);
+ }
+ g_free (filename);
+ }
+ gtk_widget_destroy(dialog);
+}
+
+gboolean
+window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
+{
+ g_debug("window_destroy_event_cb ()\n");
+ gtk_main_quit();
+ return FALSE;
+}
+
+gboolean
+window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
+{
+ g_debug("window_delete_event_cb ()\n");
+ if (ud->state == GHB_STATE_WORKING)
+ {
+ if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
+ {
+ gtk_main_quit();
+ return FALSE;
+ }
+ return TRUE;
+ }
+ gtk_main_quit();
+ return FALSE;
+}
+
+static void
+update_acodec_combo(signal_user_data_t *ud)
+{
+ ghb_grey_combo_options (ud->builder);
+}
+
+void
+container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ g_debug("container_changed_cb ()\n");
+ ghb_widget_to_setting(ud->settings, widget);
+ update_destination_extension(ud);
+ check_depencency(ud, widget);
+ update_acodec_combo(ud);
+ clear_presets_selection(ud);
+}
+
+static gchar*
+get_aspect_string(gint aspect_n, gint aspect_d)
+{
+ gchar *aspect;
+
+ if (aspect_d < 10)
+ {
+ aspect = g_strdup_printf("%d:%d", aspect_n, aspect_d);
+ }
+ else
+ {
+ gdouble aspect_nf = (gdouble)aspect_n / aspect_d;
+ aspect = g_strdup_printf("%.2f:1", aspect_nf);
+ }
+ return aspect;
+}
+
+static gchar*
+get_rate_string(gint rate_base, gint rate)
+{
+ gdouble rate_f = (gdouble)rate / rate_base;
+ gchar *rate_s;
+
+ rate_s = g_strdup_printf("%.6g", rate_f);
+ return rate_s;
+}
+static void
+show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
+{
+ GtkWidget *widget;
+ gchar *text;
+
+ widget = GHB_WIDGET (ud->builder, "title_duration");
+ text = g_strdup_printf ("%02d:%02d:%02d", tinfo->hours, tinfo->minutes, tinfo->seconds);
+ gtk_label_set_text (GTK_LABEL(widget), text);
+ g_free(text);
+ 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);
+ g_free(text);
+ widget = GHB_WIDGET (ud->builder, "source_aspect");
+ text = get_aspect_string(tinfo->aspect_n, tinfo->aspect_d);
+ gtk_label_set_text (GTK_LABEL(widget), text);
+ g_free(text);
+
+ widget = GHB_WIDGET (ud->builder, "source_frame_rate");
+ text = (gchar*)get_rate_string(tinfo->rate_base, tinfo->rate);
+ 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]);
+ // 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");
+ if (!(keep_aspect || anamorphic))
+ ghb_ui_update_int (ud, "scale_height", 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.
+ gint bound;
+ bound = tinfo->height / 2 - 2;
+ widget = GHB_WIDGET (ud->builder, "crop_top");
+ gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
+ widget = GHB_WIDGET (ud->builder, "crop_bottom");
+ gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
+ bound = tinfo->width / 2 - 2;
+ widget = GHB_WIDGET (ud->builder, "crop_left");
+ 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"))
+ {
+ 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]);
+ }
+ g_debug("setting max end chapter %d\n", 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);
+ widget = GHB_WIDGET (ud->builder, "start_chapter");
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1);
+}
+
+static void
+adjust_audio_rate_combos(signal_user_data_t *ud)
+{
+ gint titleindex, audioindex, acodec;
+ ghb_audio_info_t ainfo;
+ GtkWidget *widget;
+
+ g_debug("adjust_audio_rate_combos ()\n");
+ titleindex = ghb_settings_get_index(ud->settings, "title");
+
+ widget = GHB_WIDGET(ud->builder, "audio_track");
+ audioindex = ghb_widget_int(widget);
+
+ widget = GHB_WIDGET(ud->builder, "audio_codec");
+ acodec = ghb_widget_int(widget);
+
+ if (ghb_get_audio_info (&ainfo, titleindex, audioindex) && ghb_audio_is_passthru (acodec))
+ {
+ // 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_sample_rate", 0);
+ ghb_ui_update_int (ud, "audio_mix", 0);
+ }
+ else
+ {
+ ghb_set_default_rate_opts (ud->builder);
+ }
+}
+
+static void
+set_pref_audio(gint titleindex, signal_user_data_t *ud)
+{
+ gint acodec, track, ivalue;
+ const gchar *svalue;
+ GtkWidget *button;
+ ghb_audio_info_t ainfo;
+ gboolean skipped_1st = FALSE;
+
+ // 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, "pref_source_audio_lang");
+ acodec = ghb_settings_get_int(ud->settings, "pref_source_audio_codec");
+ track = ghb_find_audio_track(titleindex, svalue, acodec);
+ ghb_ui_update_int(ud, "audio_track", track);
+ // Get the resulting track, it may not be what was asked for.
+ track = ghb_settings_get_int(ud->settings, "audio_track");
+ if (track == -1)
+ {
+ // No audio tracks. Perhaps no source dvd yet
+ // Just initialize the audio controls and do not add anything to
+ // the audio list
+ acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec1");
+ ghb_ui_update_int(ud, "audio_codec", acodec);
+ ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
+ ghb_ui_update_int(ud, "audio_bitrate", ivalue);
+ ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
+ ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
+ ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
+ ghb_ui_update_int(ud, "audio_mix", ivalue);
+ svalue = ghb_settings_get_string(ud->settings, "pref_audio_drc");
+ ghb_ui_update(ud, "audio_drc", svalue);
+ return;
+ }
+ acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec1");
+ // Check to see if:
+ // 1. pref codec is ac3
+ // 2. source codec is not ac3
+ // 3. 2nd pref is enabled
+ if (ghb_get_audio_info (&ainfo, titleindex, track) && ghb_audio_is_passthru (acodec))
+ {
+ if (!ghb_audio_is_passthru(ainfo.codec))
+ {
+ acodec = ghb_get_default_acodec();
+ if (ghb_settings_get_int(ud->settings, "pref_audio_codec2") != 0)
+ {
+ // Skip first pref audio
+ acodec = 0;
+ skipped_1st = TRUE;
+ }
+ }
+ }
+ ghb_ui_update_int(ud, "audio_codec", acodec);
+ if (!ghb_audio_is_passthru (acodec))
+ {
+ // This gets set autimatically if the codec is passthru
+ ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
+ ghb_ui_update_int(ud, "audio_bitrate", ivalue);
+ ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
+ ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
+ ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
+ ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
+ ghb_ui_update_int(ud, "audio_mix", ivalue);
+ }
+ svalue = ghb_settings_get_string(ud->settings, "pref_audio_drc");
+ ghb_ui_update(ud, "audio_drc", svalue);
+ if (acodec != 0) // 0 is none
+ {
+ // Add to audio list
+ g_signal_emit_by_name(button, "clicked", ud);
+ }
+ acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec2");
+ // Check to see if:
+ // 1. pref codec is ac3
+ // 2. source codec is not ac3
+ if (ghb_audio_is_passthru (acodec))
+ {
+ if (!ghb_audio_is_passthru(ainfo.codec) && skipped_1st)
+ {
+ acodec = ghb_get_default_acodec();
+ }
+ else
+ {
+ acodec = 0;
+ }
+ }
+ if (acodec != 0)
+ {
+ ghb_ui_update_int(ud, "audio_codec", acodec);
+ // Do the second prefs track
+ if (!ghb_audio_is_passthru (acodec))
+ {
+ ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate2");
+ ghb_ui_update_int(ud, "audio_bitrate", ivalue);
+ ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate2");
+ ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
+ ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix2");
+ ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
+ ghb_ui_update_int(ud, "audio_mix", ivalue);
+ }
+ g_signal_emit_by_name(button, "clicked", ud);
+ }
+}
+
+static gint preview_button_width;
+static gint preview_button_height;
+static gboolean update_preview = FALSE;
+
+static void
+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");
+ if (titleindex < 0) return;
+ widget = GHB_WIDGET (ud->builder, "preview_frame");
+ gint frame = ghb_widget_int(widget) - 1;
+ GdkPixbuf *preview = ghb_get_preview_image (titleindex, frame, ud->settings, TRUE);
+ if (preview == NULL) return;
+ widget = GHB_WIDGET (ud->builder, "preview_image");
+ gtk_image_set_from_pixbuf(GTK_IMAGE(widget), preview);
+
+ preview_width = gdk_pixbuf_get_width(preview);
+ preview_height = gdk_pixbuf_get_height(preview);
+ gchar *text = g_strdup_printf("%d x %d", preview_width, preview_height);
+ widget = GHB_WIDGET (ud->builder, "preview_dims");
+ gtk_label_set_text(GTK_LABEL(widget), text);
+ g_free(text);
+
+ g_debug("preview %d x %d\n", preview_width, preview_height);
+ target_height = MIN(preview_button_height - 12, 128);
+ height = target_height;
+ width = preview_width * height / preview_height;
+
+ if ((height >= 16) && (width >= 16))
+ {
+ GdkPixbuf *scaled_preview;
+ scaled_preview = gdk_pixbuf_scale_simple (preview, width, height, GDK_INTERP_NEAREST);
+ if (scaled_preview != NULL)
+ {
+ g_object_unref (preview);
+
+ widget = GHB_WIDGET (ud->builder, "preview_button_image");
+ gtk_image_set_from_pixbuf(GTK_IMAGE(widget), scaled_preview);
+ g_object_unref (scaled_preview);
+ }
+ }
+}
+
+void
+title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ ghb_title_info_t tinfo;
+ gint titleindex;
+ const gchar *preset;
+
+ g_debug("title_changed_cb ()\n");
+ ghb_widget_to_setting(ud->settings, widget);
+ check_depencency(ud, widget);
+
+ titleindex = ghb_settings_get_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");
+ if (ghb_get_title_info (&tinfo, titleindex))
+ {
+ show_title_info(ud, &tinfo);
+ }
+ update_chapter_list (ud);
+ adjust_audio_rate_combos(ud);
+ set_pref_audio(titleindex, ud);
+ if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
+ {
+ gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
+ ghb_ui_update_int (ud, "video_bitrate", 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);
+
+ set_preview_image (ud);
+}
+
+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");
+
+ acodec = ghb_widget_int(widget);
+ if (ghb_audio_is_passthru (prev_acodec) && !ghb_audio_is_passthru (acodec))
+ {
+ // 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_settings_get_int(ud->settings, "pref_audio_bitrate1");
+ ghb_ui_update_int (ud, "audio_bitrate", ivalue);
+ ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
+ ghb_ui_update_int (ud, "audio_sample_rate", ivalue);
+ ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
+ ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
+ ghb_ui_update_int (ud, "audio_mix", ivalue);
+ }
+ adjust_audio_rate_combos(ud);
+ ghb_grey_combo_options (ud->builder);
+ check_depencency(ud, widget);
+ prev_acodec = acodec;
+ asettings = get_selected_asettings(ud);
+ if (asettings != NULL)
+ {
+ ghb_widget_to_setting(asettings, widget);
+ audio_list_refresh_selected(ud);
+ }
+}
+
+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;
+
+ g_debug("audio_track_changed_cb ()\n");
+ adjust_audio_rate_combos(ud);
+ check_depencency(ud, widget);
+ ghb_grey_combo_options(ud->builder);
+ asettings = get_selected_asettings(ud);
+ if (asettings != NULL)
+ {
+ ghb_widget_to_setting(asettings, widget);
+ audio_list_refresh_selected(ud);
+ }
+}
+
+void
+audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ GHashTable *asettings;
+
+ g_debug("audio_widget_changed_cb ()\n");
+ check_depencency(ud, widget);
+ asettings = get_selected_asettings(ud);
+ if (asettings != NULL)
+ {
+ ghb_widget_to_setting(asettings, widget);
+ audio_list_refresh_selected(ud);
+ }
+}
+
+void
+generic_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ g_debug("generic_widget_changed_cb ()\n");
+ check_depencency(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);
+ clear_presets_selection(ud);
+}
+
+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);
+ ghb_widget_to_setting(ud->settings, widget);
+ check_depencency(ud, widget);
+ clear_presets_selection(ud);
+ if (ghb_settings_get_bool(ud->settings, "variable_frame_rate"))
+ {
+ ghb_ui_update_int(ud, "framerate", 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
+// would happen for regular settings.
+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);
+ ghb_widget_to_setting(ud->settings, widget);
+ check_depencency(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);
+ ghb_widget_to_setting(ud->settings, widget);
+ check_depencency(ud, widget);
+ clear_presets_selection(ud);
+ if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
+ {
+ gint titleindex = ghb_settings_get_int(ud->settings, "title");
+ gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
+ ghb_ui_update_int (ud, "video_bitrate", bitrate);
+ }
+}
+
+void
+start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ const gchar *name = gtk_widget_get_name(widget);
+ g_debug("start_chapter_changed_cb () %s\n", 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);
+}
+
+void
+end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ const gchar *name = gtk_widget_get_name(widget);
+ g_debug("end_chapter_changed_cb () %s\n", 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);
+ 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);
+}
+
+void
+scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ g_debug("scale_width_changed_cb ()\n");
+ ghb_widget_to_setting(ud->settings, widget);
+ check_depencency(ud, widget);
+ ghb_set_scale (ud, GHB_SCALE_KEEP_WIDTH);
+ update_preview = TRUE;
+ gchar *text;
+ gint width = ghb_settings_get_int(ud->settings, "scale_width");
+ gint height = ghb_settings_get_int(ud->settings, "scale_height");
+ widget = GHB_WIDGET (ud->builder, "scale_dimensions");
+ text = g_strdup_printf ("%d x %d", width, height);
+ gtk_label_set_text (GTK_LABEL(widget), text);
+ g_free(text);
+}
+
+void
+scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ g_debug("scale_height_changed_cb ()\n");
+ ghb_widget_to_setting(ud->settings, widget);
+ check_depencency(ud, widget);
+ ghb_set_scale (ud, GHB_SCALE_KEEP_HEIGHT);
+ update_preview = TRUE;
+ gchar *text;
+ gint width = ghb_settings_get_int(ud->settings, "scale_width");
+ gint height = ghb_settings_get_int(ud->settings, "scale_height");
+ widget = GHB_WIDGET (ud->builder, "scale_dimensions");
+ text = g_strdup_printf ("%d x %d", width, height);
+ gtk_label_set_text (GTK_LABEL(widget), text);
+ g_free(text);
+}
+
+void
+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");
+ ghb_widget_to_setting(ud->settings, widget);
+ check_depencency(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");
+ if (ghb_get_title_info (&tinfo, titleindex))
+ {
+ gint width, height;
+ gchar *text;
+
+ width = tinfo.width - crop[2] - crop[3];
+ height = tinfo.height - crop[0] - crop[1];
+ widget = GHB_WIDGET (ud->builder, "crop_dimensions");
+ text = g_strdup_printf ("%d x %d", width, height);
+ gtk_label_set_text (GTK_LABEL(widget), text);
+ g_free(text);
+ }
+ gchar *text;
+ widget = GHB_WIDGET (ud->builder, "crop_values");
+ text = g_strdup_printf ("%d:%d:%d:%d", crop[0], crop[1], crop[2], crop[3]);
+ gtk_label_set_text (GTK_LABEL(widget), text);
+ g_free(text);
+ update_preview = TRUE;
+}
+
+void
+scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ g_debug("scale_changed_cb ()\n");
+ ghb_widget_to_setting(ud->settings, widget);
+ check_depencency(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";
+ 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";
+ 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";
+ widget = GHB_WIDGET (ud->builder, "scale_anamorphic");
+ gtk_label_set_text (GTK_LABEL(widget), text);
+}
+
+void
+generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
+{
+ // Normally (due to user input) I only want to process the entry
+ // when editing is done and the focus-out signal is sent.
+ // But... there's always a but.
+ // If the entry is changed by software, the focus-out signal is not sent.
+ // 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");
+ if (!GTK_WIDGET_HAS_FOCUS((GtkWidget*)entry))
+ {
+ ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
+ }
+}
+
+gboolean
+generic_focus_out_cb(GtkWidget *widget, GdkEventFocus *event,
+ signal_user_data_t *ud)
+{
+ g_debug("generic_focus_out_cb ()\n");
+ ghb_widget_to_setting(ud->settings, widget);
+ return FALSE;
+}
+
+static void
+clear_audio_list(signal_user_data_t *ud)
+{
+ GtkTreeView *treeview;
+ GtkListStore *store;
+ GSList *link;
+
+ g_debug("clear_audio_list ()\n");
+ while (ud->audio_settings != 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);
+ }
+ 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)
+{
+ GtkTreeView *treeview;
+ GtkTreeIter iter;
+ GtkListStore *store;
+ GtkTreeSelection *selection;
+
+ g_debug("add_to_audio_list ()\n");
+ 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));
+
+ 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_sample_rate"),
+ 4, ghb_settings_get_option(settings, "audio_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_sample_rate"),
+ 10, ghb_settings_get_short_opt(settings, "audio_mix"),
+ -1);
+ gtk_tree_selection_select_iter(selection, &iter);
+}
+
+static void
+audio_list_refresh_selected(signal_user_data_t *ud)
+{
+ GtkTreeView *treeview;
+ GtkTreePath *treepath;
+ GtkTreeSelection *selection;
+ GtkTreeModel *store;
+ GtkTreeIter iter;
+ gint *indices;
+ gint row;
+ GSList *link;
+ GHashTable *asettings = NULL;
+
+ g_debug("get_selected_asettings ()\n");
+ 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
+ treepath = gtk_tree_model_get_path (store, &iter);
+ indices = gtk_tree_path_get_indices (treepath);
+ g_free(treepath);
+ row = indices[0];
+ // find audio settings
+ if (row < 0) return;
+ link = g_slist_nth(ud->audio_settings, row);
+ if (link == NULL) return;
+ 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_sample_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_sample_rate"),
+ 10, ghb_settings_get_short_opt(asettings, "audio_mix"),
+ -1);
+ }
+}
+
+static GHashTable*
+get_selected_asettings(signal_user_data_t *ud)
+{
+ GtkTreeView *treeview;
+ GtkTreePath *treepath;
+ GtkTreeSelection *selection;
+ GtkTreeModel *store;
+ GtkTreeIter iter;
+ gint *indices;
+ gint row;
+ GSList *link;
+ GHashTable *asettings = NULL;
+
+ g_debug("get_selected_asettings ()\n");
+ 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
+ treepath = gtk_tree_model_get_path (store, &iter);
+ indices = gtk_tree_path_get_indices (treepath);
+ g_free(treepath);
+ row = indices[0];
+ // 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;
+ }
+ return asettings;
+}
+
+void
+audio_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
+{
+ GtkTreeModel *store;
+ GtkTreeIter iter;
+ GtkWidget *widget;
+
+ g_debug("audio_list_selection_changed_cb ()\n");
+ if (gtk_tree_selection_get_selected(selection, &store, &iter))
+ {
+ const gchar *track, *codec, *bitrate, *sample_rate, *mix, *drc;
+ gtk_tree_model_get(store, &iter,
+ 6, &track,
+ 7, &codec,
+ 8, &bitrate,
+ 9, &sample_rate,
+ 10, &mix,
+ 5, &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_sample_rate", sample_rate);
+ ghb_ui_update(ud, "audio_mix", mix);
+ ghb_ui_update(ud, "audio_drc", drc);
+ widget = GHB_WIDGET (ud->builder, "audio_remove");
+ gtk_widget_set_sensitive(widget, TRUE);
+ //widget = GHB_WIDGET (ud->builder, "audio_update");
+ //gtk_widget_set_sensitive(widget, TRUE);
+ }
+ else
+ {
+ widget = GHB_WIDGET (ud->builder, "audio_remove");
+ gtk_widget_set_sensitive(widget, FALSE);
+ //widget = GHB_WIDGET (ud->builder, "audio_update");
+ //gtk_widget_set_sensitive(widget, FALSE);
+ }
+}
+
+void
+audio_add_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+ // Add the current audio settings to the list.
+ GHashTable *asettings;
+ GtkWidget *widget;
+ gint count;
+
+ g_debug("audio_add_clicked_cb ()\n");
+ // 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));
+ widget = GHB_WIDGET(ud->builder, "audio_codec");
+ ghb_settings_set(asettings, "audio_codec", ghb_widget_value(widget));
+ widget = GHB_WIDGET(ud->builder, "audio_bitrate");
+ ghb_settings_set(asettings, "audio_bitrate", ghb_widget_value(widget));
+ widget = GHB_WIDGET(ud->builder, "audio_sample_rate");
+ ghb_settings_set(asettings, "audio_sample_rate", ghb_widget_value(widget));
+ widget = GHB_WIDGET(ud->builder, "audio_mix");
+ ghb_settings_set(asettings, "audio_mix", ghb_widget_value(widget));
+ widget = GHB_WIDGET(ud->builder, "audio_drc");
+ ghb_settings_set(asettings, "audio_drc", ghb_widget_value(widget));
+
+ ud->audio_settings = g_slist_append(ud->audio_settings, asettings);
+ add_to_audio_list(ud, asettings);
+ count = g_slist_length(ud->audio_settings);
+ if (count >= 8)
+ {
+ gtk_widget_set_sensitive(xwidget, FALSE);
+ }
+}
+
+void
+audio_remove_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ GtkTreeView *treeview;
+ GtkTreePath *treepath;
+ GtkTreeSelection *selection;
+ GtkTreeModel *store;
+ GtkTreeIter iter, nextIter;
+ gint *indices;
+ gint row;
+ GSList *link;
+
+ g_debug("audio_remove_clicked_cb ()\n");
+ 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))
+ {
+ nextIter = iter;
+ if (!gtk_tree_model_iter_next(store, &nextIter))
+ {
+ nextIter = iter;
+ if (gtk_tree_model_get_iter_first(store, &nextIter))
+ {
+ gtk_tree_selection_select_iter (selection, &nextIter);
+ }
+ }
+ else
+ {
+ gtk_tree_selection_select_iter (selection, &nextIter);
+ }
+ // 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];
+ // 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);
+ }
+}
+
+static void
+audio_list_refresh(signal_user_data_t *ud)
+{
+ GtkTreeView *treeview;
+ GtkTreeIter iter;
+ GtkListStore *store;
+ gboolean done;
+
+ g_debug("audio_list_refresh ()\n");
+ GSList *link = ud->audio_settings;
+ if (link == NULL) return;
+ 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;
+
+ 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_sample_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_sample_rate"),
+ 10, ghb_settings_get_short_opt(asettings, "audio_mix"),
+ -1);
+ done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
+ link = link->next;
+ } while (!done && link);
+ }
+}
+
+void
+ghb_presets_list_update(signal_user_data_t *ud)
+{
+ GtkTreeView *treeview;
+ GtkTreeIter iter;
+ GtkListStore *store;
+ gboolean done;
+ gint ii = 0;
+ gint index;
+ gchar **presets;
+ gchar **descriptions;
+ gint flags, custom, def;
+
+ g_debug("ghb_presets_list_update ()\n");
+ presets = ghb_presets_get_names();
+ descriptions = ghb_presets_get_descriptions();
+ 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))
+ {
+ // Update row with settings data
+ g_debug("Updating row\n");
+ flags = ghb_preset_flags(presets[ii], &index);
+ def = flags & PRESET_DEFAULT;
+ custom = flags & PRESET_CUSTOM;
+ gtk_list_store_set(store, &iter,
+ 0, presets[ii],
+ 1, def ? 800 : 400,
+ 2, def ? 2 : 0,
+ 3, custom ? "black" : "blue",
+ 4, descriptions[ii],
+ -1);
+ ii++;
+ done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
+ }
+ else
+ {
+ // No more settings data, remove row
+ g_debug("Removing row\n");
+ done = !gtk_list_store_remove(store, &iter);
+ }
+ } while (!done);
+ }
+ while ((presets != NULL) && (presets[ii] != NULL))
+ {
+ // Additional settings, add row
+ g_debug("Adding row %s\n", presets[ii]);
+ gtk_list_store_append(store, &iter);
+ flags = ghb_preset_flags(presets[ii], &index);
+ def = flags & PRESET_DEFAULT;
+ custom = flags & PRESET_CUSTOM;
+ gtk_list_store_set(store, &iter, 0, presets[ii],
+ 1, def ? 800 : 400,
+ 2, def ? 2 : 0,
+ 3, custom ? "black" : "blue",
+ 4, descriptions[ii],
+ -1);
+ ii++;
+ }
+ g_strfreev (presets);
+}
+
+void
+ghb_select_preset(GtkBuilder *builder, const gchar *preset)
+{
+ GtkTreeView *treeview;
+ GtkTreeSelection *selection;
+ GtkTreeModel *store;
+ GtkTreeIter iter;
+ gchar *tpreset;
+ gboolean done;
+
+ g_debug("select_preset()\n");
+ if (preset == NULL) return;
+ treeview = GTK_TREE_VIEW(GHB_WIDGET(builder, "presets_list"));
+ selection = gtk_tree_view_get_selection (treeview);
+ store = gtk_tree_view_get_model (treeview);
+ if (gtk_tree_model_get_iter_first(store, &iter))
+ {
+ do
+ {
+ gtk_tree_model_get(store, &iter, 0, &tpreset, -1);
+ if (strcmp(preset, tpreset) == 0)
+ {
+ gtk_tree_selection_select_iter (selection, &iter);
+ break;
+ }
+ done = !gtk_tree_model_iter_next(store, &iter);
+ } while (!done);
+ }
+}
+
+void
+presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+ GtkWidget *dialog;
+ GtkEntry *entry;
+ GtkTextView *desc;
+ GtkResponseType response;
+ const gchar *preset = "";
+
+ g_debug("presets_save_clicked_cb ()\n");
+ 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);
+ 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");
+ ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
+ ghb_settings_save(ud, name);
+ ghb_presets_list_update(ud);
+ // Make the new preset the selected item
+ ghb_select_preset(ud->builder, name);
+ }
+}
+
+void
+presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+ GtkTreeView *treeview;
+ GtkTreeSelection *selection;
+ GtkTreeModel *store;
+ GtkTreeIter iter;
+ gchar *preset;
+ GtkResponseType response;
+
+ g_debug("presets_remove_clicked_cb ()\n");
+ 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))
+ {
+ 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)
+ {
+ 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
+ {
+ 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);
+ }
+ }
+}
+
+static void
+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]);
+ // 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");
+ if (!(keep_aspect || anamorphic))
+ ghb_ui_update_int (ud, "scale_height", 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.
+ gint bound;
+ bound = tinfo->height / 2 - 2;
+ widget = GHB_WIDGET (ud->builder, "crop_top");
+ gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
+ widget = GHB_WIDGET (ud->builder, "crop_bottom");
+ gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
+ bound = tinfo->width / 2 - 2;
+ widget = GHB_WIDGET (ud->builder, "crop_left");
+ 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"))
+ {
+ 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]);
+ }
+}
+
+void
+presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
+{
+ GtkTreeModel *store;
+ GtkTreeIter iter;
+ gchar *preset;
+ GtkWidget *widget;
+ gboolean sensitive = FALSE;
+ ghb_title_info_t tinfo;
+
+ g_debug("presets_list_selection_changed_cb ()\n");
+ 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;
+ ghb_set_preset(ud, preset);
+ gint titleindex = ghb_settings_get_int(ud->settings, "title");
+ set_pref_audio(titleindex, ud);
+ ud->dont_clear_presets = FALSE;
+ if (ghb_get_title_info (&tinfo, titleindex))
+ {
+ preset_update_title_deps(ud, &tinfo);
+ }
+ ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
+ }
+ else
+ {
+ g_debug("No selection??? Perhaps unselected.\n");
+ }
+ widget = GHB_WIDGET (ud->builder, "presets_remove");
+ gtk_widget_set_sensitive(widget, sensitive);
+}
+
+void
+queue_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
+{
+ GtkTreeModel *store;
+ GtkTreeIter iter, piter;
+
+ g_debug("queue_list_selection_changed_cb ()\n");
+ // 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.
+ // This is purely cosmetic.
+ if (gtk_tree_selection_get_selected(selection, &store, &iter))
+ {
+ if (gtk_tree_model_iter_parent (store, &piter, &iter))
+ {
+ GtkTreePath *path;
+ GtkTreeView *treeview;
+
+ gtk_tree_selection_select_iter (selection, &piter);
+ path = gtk_tree_model_get_path (store, &piter);
+ 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);
+ }
+ }
+}
+
+static void
+add_to_queue_list(signal_user_data_t *ud, job_settings_t *item)
+{
+ GtkTreeView *treeview;
+ GtkTreeIter iter;
+ GtkTreeStore *store;
+ gchar *info;
+ gint num_pass = 1;
+ gint ii;
+ GtkTreeIter citer;
+
+ g_debug("update_queue_list ()\n");
+ if (item == 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";
+ 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");
+
+ 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);
+
+ gtk_tree_store_append(store, &citer, &iter);
+ gtk_tree_store_set(store, &citer, 1, info, -1);
+ g_free(info);
+
+ 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)
+ {
+ if (round_dim)
+ {
+ aspect_desc = "(Anamorphic)";
+ }
+ else
+ {
+ aspect_desc = "(Strict Anamorphic)";
+ }
+ }
+ else
+ {
+ if (keep_aspect)
+ {
+ aspect_desc = "(Aspect Preserved)";
+ }
+ else
+ {
+ aspect_desc = "(Aspect Lost)";
+ }
+ }
+ gboolean vqtype = ghb_settings_get_bool(item->settings, "vquality_type_constant");
+ gint vqvalue = 0;
+ gchar *vq_desc = "Error";
+ if (!vqtype)
+ {
+ vqtype = ghb_settings_get_bool(item->settings, "vquality_type_target");
+ if (!vqtype)
+ {
+ // Has to be bitrate
+ vqvalue = ghb_settings_get_int(item->settings, "video_bitrate");
+ vq_desc = "kbps";
+ }
+ else
+ {
+ // Target file size
+ vqvalue = ghb_settings_get_int(item->settings, "video_target");
+ vq_desc = "MB";
+ }
+ }
+ else
+ {
+ // Constant quality
+ vqvalue = ghb_settings_get_int(item->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)
+ {
+ 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);
+ }
+ else
+ {
+ extra_opts = g_strdup("");
+ }
+ gboolean turbo = ghb_settings_get_bool (item->settings, "turbo");
+ gchar *turbo_desc = "\n<b>Turbo:</b> Off";;
+ if (turbo)
+ {
+ turbo_desc = "\n<b>Turbo:</b> On";
+ }
+ num_pass = pass2 ? 2 : 1;
+ for (ii = 0; ii < num_pass; 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);
+
+ if (final)
+ {
+ // 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_sample_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;
+ }
+ }
+ 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);
+ }
+ g_free(extra_opts);
+}
+
+gboolean
+ghb_message_dialog(GtkMessageType type, const gchar *message, const gchar *no, const gchar *yes)
+{
+ GtkWidget *dialog;
+ GtkResponseType response;
+
+ // Toss up a warning dialog
+ dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
+ type, GTK_BUTTONS_NONE,
+ message);
+ gtk_dialog_add_buttons( GTK_DIALOG(dialog),
+ no, GTK_RESPONSE_NO,
+ yes, GTK_RESPONSE_YES, NULL);
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy (dialog);
+ if (response == GTK_RESPONSE_NO)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gint64
+estimate_file_size(signal_user_data_t *ud)
+{
+ ghb_title_info_t tinfo;
+ gint duration;
+ gint bitrate;
+ gint64 size;
+ gint titleindex = ghb_settings_get_int(ud->settings, "title");
+ if (titleindex < 0) return 0;
+
+ if (!ghb_get_title_info(&tinfo, titleindex)) return 0;
+ duration = ((tinfo.hours*60)+tinfo.minutes)*60+tinfo.seconds;
+ bitrate = ghb_guess_bitrate(ud->settings);
+ size = (gint64)duration * (gint64)bitrate/8;
+ return size;
+}
+
+#define DISK_FREE_THRESH (1024L*1024L*1024L*3)
+
+static gboolean
+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");
+ if (titleindex < 0) return FALSE;
+ const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
+ GSList *link = ud->queue;
+ while (link != NULL)
+ {
+ job_settings_t *item;
+ const gchar *filename;
+ item = (job_settings_t*)link->data;
+ filename = ghb_settings_get_string(item->settings, "destination");
+ if (strcmp(dest, filename) == 0)
+ {
+ message = g_strdup_printf(
+ "Destination: %s\n\n"
+ "Another queued job has specified the same destination.\n"
+ "Do you want to overwrite?",
+ dest);
+ if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
+ {
+ g_free(message);
+ return FALSE;
+ }
+ g_free(message);
+ break;
+ }
+ link = link->next;
+ }
+ gchar *destdir = g_path_get_dirname(dest);
+ if (!g_file_test(destdir, G_FILE_TEST_IS_DIR))
+ {
+ message = g_strdup_printf(
+ "Destination: %s\n\n"
+ "This is not a valid directory.",
+ destdir);
+ ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
+ g_free(message);
+ g_free(destdir);
+ return FALSE;
+ }
+ if (g_access(destdir, R_OK|W_OK) != 0)
+ {
+ message = g_strdup_printf(
+ "Destination: %s\n\n"
+ "Can not read or write the directory.",
+ destdir);
+ ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
+ g_free(message);
+ g_free(destdir);
+ return FALSE;
+ }
+ GFile *gfile;
+ GFileInfo *info;
+ guint64 size;
+ gchar *resolved = ghb_resolve_symlink(destdir);
+
+ gfile = g_file_new_for_path(resolved);
+ info = g_file_query_filesystem_info(gfile,
+ G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, NULL);
+ if (info != NULL)
+ {
+ if (g_file_info_has_attribute(info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE))
+ {
+ size = g_file_info_get_attribute_uint64(info,
+ G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
+
+ gint64 fsize = estimate_file_size(ud);
+ if (size < fsize)
+ {
+ message = g_strdup_printf(
+ "Destination filesystem is almost full: %uM free\n\n"
+ "Encode may be incomplete if you proceed.\n",
+ (guint)(size / (1024L*1024L)));
+ if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Proceed"))
+ {
+ g_free(message);
+ return FALSE;
+ }
+ g_free(message);
+ }
+ }
+ g_object_unref(info);
+ }
+ g_object_unref(gfile);
+ g_free(resolved);
+ g_free(destdir);
+ if (g_file_test(dest, G_FILE_TEST_EXISTS))
+ {
+ message = g_strdup_printf(
+ "Destination: %s\n\n"
+ "File already exhists.\n"
+ "Do you want to overwrite?",
+ dest);
+ if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
+ {
+ g_free(message);
+ return FALSE;
+ }
+ g_free(message);
+ g_unlink(dest);
+ }
+ // Validate video quality is in a reasonable range
+ if (!ghb_validate_vquality(ud->settings))
+ {
+ return FALSE;
+ }
+ // Validate audio settings
+ if (!ghb_validate_audio(ud))
+ {
+ return FALSE;
+ }
+ // Validate video settings
+ if (!ghb_validate_video(ud))
+ {
+ return FALSE;
+ }
+ audio_list_refresh(ud);
+ return TRUE;
+}
+
+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;
+
+ g_debug("queue_add ()\n");
+ if (!validate_settings(ud))
+ {
+ return FALSE;
+ }
+ // 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++;
+ return TRUE;
+}
+
+void
+queue_add_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ g_debug("queue_add_clicked_cb ()\n");
+ queue_add(ud);
+}
+
+static gboolean
+cancel_encode(const gchar *extra_msg)
+{
+ GtkWidget *dialog;
+ GtkResponseType response;
+
+ if (extra_msg == NULL) extra_msg = "";
+ // Toss up a warning dialog
+ dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
+ "%sYour movie will be lost if you don't continue encoding.",
+ extra_msg);
+ gtk_dialog_add_buttons( GTK_DIALOG(dialog),
+ "Continue Encoding", GTK_RESPONSE_NO,
+ "Stop Encoding", GTK_RESPONSE_YES, NULL);
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy (dialog);
+ if (response == GTK_RESPONSE_NO) return FALSE;
+ ghb_stop_queue();
+ return TRUE;
+}
+
+void
+queue_remove_clicked_cb(GtkWidget *widget, gchar *path, signal_user_data_t *ud)
+{
+ GtkTreeView *treeview;
+ GtkTreePath *treepath;
+ GtkTreeModel *store;
+ GtkTreeIter iter;
+ gint row;
+ GSList *link;
+ gint *indices;
+ job_settings_t *queue_item;
+ gint unique_id;
+
+ g_debug("queue_remove_clicked_cb ()\n");
+ g_debug("ud %p\n", ud);
+ g_debug("ud->builder %p\n", ud->builder);
+
+ 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_model_get_iter(store, &iter, treepath))
+ {
+ // 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;
+ 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)
+ {
+ // Ask if wants to stop encode.
+ if (!cancel_encode(NULL))
+ {
+ return;
+ }
+ }
+ // 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);
+ }
+ else
+ {
+ gtk_tree_path_free (treepath);
+ }
+}
+
+static gint
+find_queue_item(GSList *queue, gint unique_id, job_settings_t **job)
+{
+ job_settings_t *js;
+ gint index = -1;
+
+ while (queue != NULL)
+ {
+ index++;
+ js = (job_settings_t*)queue->data;
+ if (js->unique_id == unique_id)
+ {
+ *job = js;
+ return index;
+ }
+ queue = queue->next;
+ }
+ *job = NULL;
+ return index;
+}
+
+static void
+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);
+ widget = GHB_WIDGET (ud->builder, "queue_start1");
+ gtk_widget_set_sensitive (widget, !working && title_ok);
+ widget = GHB_WIDGET (ud->builder, "queue_start2");
+ gtk_widget_set_sensitive (widget, !working && title_ok);
+ action = GHB_ACTION (ud->builder, "queue_start_menu");
+ gtk_action_set_sensitive (action, !working && title_ok);
+ widget = GHB_WIDGET (ud->builder, "queue_pause1");
+ gtk_widget_set_sensitive (widget, working);
+ widget = GHB_WIDGET (ud->builder, "queue_pause2");
+ gtk_widget_set_sensitive (widget, working);
+ action = GHB_ACTION (ud->builder, "queue_pause_menu");
+ gtk_action_set_sensitive (action, working);
+ widget = GHB_WIDGET (ud->builder, "queue_stop");
+ gtk_widget_set_sensitive (widget, working);
+ action = GHB_ACTION (ud->builder, "queue_stop_menu");
+ gtk_action_set_sensitive (action, working);
+}
+
+void queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud);
+
+static gint autostart_timeout = -1;
+
+gboolean
+autostart_timer_cb(gpointer data)
+{
+ GtkWidget *widget;
+ 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;
+ GtkTreeView *treeview;
+ GtkTreeStore *store;
+ GtkTreeIter iter;
+ static gint working = 0;
+ static gboolean work_started = FALSE;
+
+ signal_user_data_t *ud = (signal_user_data_t*)data;
+ switch (ghb_backend_events (ud, &unique_id))
+ {
+ 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 (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, unique_id, &js);
+ if (js != NULL)
+ {
+ js->status = GHB_QUEUE_RUNNING;
+ current_id = unique_id;
+ }
+ }
+ 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))
+ {
+ gtk_tree_store_set(store, &iter, 0, working_icon, -1);
+ }
+ g_free(path);
+ }
+ } break;
+ case GHB_EVENT_PAUSED:
+ {
+ } break;
+ case GHB_EVENT_WORK_DONE:
+ {
+ ud->state = GHB_STATE_IDLE;
+ work_started = FALSE;
+ queue_buttons_grey(ud, FALSE);
+ 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);
+ }
+ current_id = -1;
+ if (ghb_autostart)
+ {
+ 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);
+ 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);
+ }
+ current_id = -1;
+ } break;
+ case GHB_EVENT_SCAN_DONE:
+ {
+ ghb_title_info_t tinfo;
+
+ ud->state = GHB_STATE_IDLE;
+ 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:
+ {
+ if (work_started)
+ {
+ work_started = FALSE;
+ queue_buttons_grey(ud, FALSE);
+ }
+ } break;
+ }
+ 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");
+ if (strcmp(dest_dir, def_dest) != 0)
+ {
+ ghb_settings_set_string (ud->settings, "destination_dir", dest_dir);
+ ghb_prefs_save (ud->settings);
+ }
+ update_default_destination = FALSE;
+ }
+ if (update_preview)
+ {
+ 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)
+{
+ gchar *text = NULL;
+ gsize length;
+ GtkTextView *textview;
+ GtkTextBuffer *buffer;
+ GtkTextMark *mark;
+ GError *gerror = NULL;
+ GIOStatus status;
+
+ signal_user_data_t *ud = (signal_user_data_t*)data;
+
+ status = g_io_channel_read_line (source, &text, &length, NULL, &gerror);
+ if (text != NULL)
+ {
+ 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);
+ g_io_channel_write_chars (ud->activity_log, text, length, &length, NULL);
+ g_free(text);
+ }
+ if (status != G_IO_STATUS_NORMAL)
+ {
+ // 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");
+ if (gerror != NULL)
+ {
+ g_warning("%s\n", gerror->message);
+ g_error_free (gerror);
+ }
+ return FALSE;
+ }
+ if (gerror != NULL)
+ g_error_free (gerror);
+ return TRUE;
+}
+
+void
+about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+ GtkWidget *widget = GHB_WIDGET (ud->builder, "hb_about");
+ gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(widget), ghb_version());
+ gtk_widget_show (widget);
+}
+
+void
+hb_about_response_cb(GtkWidget *widget, gint response, signal_user_data_t *ud)
+{
+ gtk_widget_hide (widget);
+}
+
+void
+show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+ GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
+ gtk_widget_show (widget);
+}
+
+void
+show_queue_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+ GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
+ gtk_widget_show (widget);
+}
+
+void
+show_presets_toggled_cb(GtkToggleButton *button, signal_user_data_t *ud)
+{
+ GtkWidget *widget;
+ GtkWindow *hb_window;
+
+ g_debug("show_presets_clicked_cb ()\n");
+ widget = GHB_WIDGET (ud->builder, "presets_frame");
+ if (gtk_toggle_button_get_active(button))
+ {
+ gtk_widget_show_now(widget);
+ }
+ else
+ {
+ gtk_widget_hide(widget);
+ hb_window = GTK_WINDOW(GHB_WIDGET (ud->builder, "hb_window"));
+ gtk_window_resize(hb_window, 16, 16);
+ }
+ ghb_widget_to_setting(ud->settings, GTK_WIDGET(button));
+ ghb_prefs_save(ud->settings);
+}
+
+void
+presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
+{
+ GtkTreeView *treeview;
+ GtkTreeSelection *selection;
+ GtkTreeModel *store;
+ GtkTreeIter iter;
+
+ 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))
+ {
+ GtkTreePath *path;
+ 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);
+ }
+}
+
+static void
+update_chapter_list(signal_user_data_t *ud)
+{
+ GtkTreeView *treeview;
+ GtkTreeIter iter;
+ GtkListStore *store;
+ gboolean done;
+ gchar **chapters;
+ gint titleindex, ii;
+
+ g_debug("update_chapter_list ()\n");
+ titleindex = ghb_settings_get_index(ud->settings, "title");
+ chapters = ghb_get_chapters(titleindex);
+ if (ud->chapter_list != NULL)
+ g_strfreev (ud->chapter_list);
+ ud->chapter_list = chapters;
+
+ treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
+ store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
+ ii = 0;
+ if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
+ {
+ do
+ {
+ if (chapters != NULL && chapters[ii])
+ {
+ // Update row with settings data
+ g_debug("Updating row\n");
+ gtk_list_store_set(store, &iter,
+ 0, ii+1,
+ 1, chapters[ii],
+ 2, TRUE,
+ -1);
+ ii++;
+ done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
+ }
+ else
+ {
+ // No more settings data, remove row
+ g_debug("Removing row\n");
+ done = !gtk_list_store_remove(store, &iter);
+ }
+ } while (!done);
+ }
+ while (chapters != NULL && chapters[ii])
+ {
+ // Additional settings, add row
+ g_debug("Adding row\n");
+ g_debug("%d -- %s\n", ii, chapters[ii]);
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter,
+ 0, ii+1,
+ 1, chapters[ii],
+ 2, TRUE,
+ -1);
+ ii++;
+ }
+}
+
+void
+chapter_edited_cb(GtkCellRendererText *cell, gchar *path, gchar *text, signal_user_data_t *ud)
+{
+ GtkTreePath *treepath;
+ GtkListStore *store;
+ GtkTreeView *treeview;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ gint index;
+
+ g_debug("chapter_edited_cb ()\n");
+ g_debug("path (%s)\n", path);
+ g_debug("text (%s)\n", 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);
+ 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))
+ {
+ 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);
+ }
+}
+
+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??
+ }
+}
+
+void
+queue_list_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, GtkCellRenderer *cell)
+{
+ GtkTreeViewColumn *column;
+ gint width;
+
+ 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);
+ // 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
+ g_object_set(cell, "wrap-width", width-70, NULL);
+}
+
+void
+preview_button_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+ gint titleindex = ghb_settings_get_int(ud->settings, "title");
+ if (titleindex < 0) return;
+ g_debug("titleindex %d\n", titleindex);
+
+ GtkWidget *widget = GHB_WIDGET (ud->builder, "preview_window");
+ gtk_widget_show (widget);
+}
+
+void
+preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ set_preview_image(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);
+ if (preview_button_width == allocation->width &&
+ preview_button_height == allocation->height)
+ {
+ // Nothing to do. Bug out.
+ g_debug("nothing to do\n");
+ return;
+ }
+ g_debug("-------------------------------prev allocate %d x %d\n", preview_button_width, preview_button_height);
+ preview_button_width = allocation->width;
+ preview_button_height = allocation->height;
+ set_preview_image(ud);
+}
+
+void
+queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+ GSList *link = ud->queue;
+ job_settings_t *job;
+ gboolean running = FALSE;
+ while (link != NULL)
+ {
+ job = (job_settings_t*)link->data;
+ if ((job->status == GHB_QUEUE_RUNNING) ||
+ (job->status == GHB_QUEUE_PENDING))
+ {
+ running = TRUE;
+ break;
+ }
+ link = link->next;
+ }
+ if (!running)
+ {
+ // The queue has no running or pending jobs.
+ // Add current settings to the queue, then run.
+ if (!queue_add(ud))
+ return;
+ }
+ ud->state = GHB_STATE_WORKING;
+ ghb_start_queue();
+}
+
+void
+queue_stop_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+ cancel_encode(NULL);
+}
+
+void
+queue_pause_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+ ghb_pause_queue();
+}
+
+void
+presets_default_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
+{
+ ghb_set_preset_default(ud->settings);
+ ghb_presets_list_update(ud);
+}
+
+void
+debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data)
+{
+ signal_user_data_t *ud = (signal_user_data_t*)data;
+
+ if (ud->debug)
+ {
+ printf("%s: %s\n", domain, msg);
+ }
+}
+
+static void
+set_visible(GtkWidget *widget, gboolean visible)
+{
+ if (visible)
+ {
+ gtk_widget_show_now(widget);
+ }
+ else
+ {
+ gtk_widget_hide(widget);
+ }
+}
+
+void
+ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
+{
+ GtkWidget *widget;
+ g_debug("ghb_hbfd\n");
+ widget = GHB_WIDGET(ud->builder, "queue_pause1");
+ set_visible(widget, !hbfd);
+ widget = GHB_WIDGET(ud->builder, "queue_add");
+ set_visible(widget, !hbfd);
+ widget = GHB_WIDGET(ud->builder, "show_queue");
+ set_visible(widget, !hbfd);
+ widget = GHB_WIDGET(ud->builder, "show_activity");
+ set_visible(widget, !hbfd);
+
+ widget = GHB_WIDGET(ud->builder, "chapter_box");
+ set_visible(widget, !hbfd);
+ widget = GHB_WIDGET(ud->builder, "container_box");
+ set_visible(widget, !hbfd);
+ widget = GHB_WIDGET(ud->builder, "settings_box");
+ set_visible(widget, !hbfd);
+ widget = GHB_WIDGET(ud->builder, "presets_save");
+ set_visible(widget, !hbfd);
+ widget = GHB_WIDGET(ud->builder, "presets_remove");
+ set_visible(widget, !hbfd);
+ widget = GHB_WIDGET(ud->builder, "presets_default");
+ set_visible(widget, !hbfd);
+ widget = GHB_WIDGET (ud->builder, "hb_window");
+ gtk_window_resize(GTK_WINDOW(widget), 16, 16);
+
+}
+
+void
+hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ g_debug("hbfd_toggled_cb\n");
+ 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);
+}
+
+gboolean ghb_is_cd(GDrive *gd);
+
+static GList*
+dvd_device_list()
+{
+ GVolumeMonitor *gvm;
+ GList *drives, *link;
+ GList *dvd_devices = NULL;
+
+ gvm = g_volume_monitor_get ();
+ drives = g_volume_monitor_get_connected_drives (gvm);
+ link = drives;
+ while (link != NULL)
+ {
+ GDrive *gd;
+
+ gd = (GDrive*)link->data;
+ if (ghb_is_cd(gd))
+ {
+ gchar *device;
+ device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
+ dvd_devices = g_list_append(dvd_devices, (gpointer)device);
+ }
+ g_object_unref (gd);
+ link = link->next;
+ }
+ g_list_free(drives);
+ return dvd_devices;
+}
+
+
+static DBusConnection *dbus_connection = NULL;
+static LibHalContext *hal_ctx;
+
+gboolean
+ghb_is_cd(GDrive *gd)
+{
+ gchar *device;
+ LibHalDrive *halDrive;
+ LibHalDriveType dtype;
+
+ 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);
+ g_free(device);
+ return (dtype == LIBHAL_DRIVE_TYPE_CDROM);
+}
+
+void
+drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
+{
+ gchar *device;
+
+ if (ud->current_dvd_device == NULL) return;
+ if (ud->state != GHB_STATE_IDLE) return;
+ device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
+
+ // DVD insertion detected. Scan it.
+ if (strcmp(device, ud->current_dvd_device) == 0)
+ {
+ if (g_drive_has_media (gd))
+ {
+ GtkProgressBar *progress;
+ progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
+ 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_backend_scan(device, 0);
+ }
+ else
+ {
+ ud->state = GHB_STATE_SCANNING;
+ ghb_backend_scan("/dev/null", 0);
+ }
+ }
+ g_free(device);
+}
+
+
+static gboolean
+dbus_init (void)
+{
+ DBusError error;
+
+ 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_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;
+}
+
+void
+ghb_hal_init()
+{
+ DBusError error;
+ char **devices;
+ int nr;
+
+ if (!dbus_init ())
+ return;
+
+ if (!(hal_ctx = libhal_ctx_new ())) {
+ g_warning ("failed to create a HAL context!");
+ 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;
+ }
+
+ /*
+ * 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);
+
+ //gvm_hal_claim_branch ("/org/freedesktop/Hal/devices/local");
+}
+