1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
6 * callbacks.c is free software.
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
22 #include <libhal-storage.h>
24 #include <glib/gstdio.h>
27 #include "callbacks.h"
29 #include "hb-backend.h"
32 extern gboolean ghb_autostart;
33 static void update_chapter_list(signal_user_data_t *ud);
34 static void clear_audio_list(signal_user_data_t *ud);
35 static GList* dvd_device_list();
36 static gboolean cancel_encode();
37 static void audio_list_refresh_selected(signal_user_data_t *ud);
38 static GHashTable* get_selected_asettings(signal_user_data_t *ud);
40 // This is a dependency map used for greying widgets
41 // that are dependent on the state of another widget.
42 // The enable_value comes from the values that are
43 // obtained from ghb_widget_value(). For combo boxes
44 // you will have to look further to combo box options
45 // maps in hb-backend.c
48 const gchar *widget_name;
49 const gchar *dep_name;
50 const gchar *enable_value;
51 const gboolean disable_if_equal;
54 static dependency_t dep_map[] =
56 {"title", "queue_add", "none", TRUE},
57 {"title", "queue_add_menu", "none", TRUE},
58 {"title", "preview_button", "none", TRUE},
59 {"title", "show_preview_menu", "none", TRUE},
60 {"title", "preview_frame", "none", TRUE},
61 {"title", "picture_label", "none", TRUE},
62 {"title", "picture_tab", "none", TRUE},
63 {"title", "audio_label", "none", TRUE},
64 {"title", "audio_tab", "none", TRUE},
65 {"title", "chapters_label", "none", TRUE},
66 {"title", "chapters_tab", "none", TRUE},
67 {"title", "title", "none", TRUE},
68 {"title", "start_chapter", "none", TRUE},
69 {"title", "end_chapter", "none", TRUE},
70 {"vquality_type_bitrate", "video_bitrate", "enable", FALSE},
71 {"vquality_type_target", "video_target_size", "enable", FALSE},
72 {"vquality_type_constant", "video_quality", "enable", FALSE},
73 {"vquality_type_constant", "constant_rate_factor", "enable", FALSE},
74 {"two_pass", "turbo", "enable", FALSE},
75 {"container", "large_mp4", "mp4|m4v", FALSE},
76 {"container", "http_optimize_mp4", "mp4|m4v", FALSE},
77 {"container", "ipod_file", "mp4|m4v", FALSE},
78 {"container", "variable_frame_rate", "avi", TRUE},
79 {"variable_frame_rate", "framerate", "enable", TRUE},
80 {"variable_frame_rate", "detelecine", "enable", TRUE},
81 {"decomb", "deinterlace", "enable", TRUE},
82 {"autocrop", "crop_top", "disable", FALSE},
83 {"autocrop", "crop_bottom", "disable", FALSE},
84 {"autocrop", "crop_left", "disable", FALSE},
85 {"autocrop", "crop_right", "disable", FALSE},
86 {"autoscale", "scale_width", "disable", FALSE},
87 {"autoscale", "scale_height", "disable", FALSE},
88 {"anamorphic", "keep_aspect", "disable", FALSE},
89 {"anamorphic", "scale_height", "disable", FALSE},
90 {"keep_aspect", "scale_height", "disable", FALSE},
91 {"video_codec", "x264_tab", "x264", FALSE},
92 {"video_codec", "x264_tab_label", "x264", FALSE},
93 {"video_codec", "ipod_file", "x264", FALSE},
94 {"audio_track", "audio_add", "none", TRUE},
95 {"audio_track", "audio_codec", "none", TRUE},
96 {"audio_track", "audio_bitrate", "none", TRUE},
97 {"audio_track", "audio_sample_rate", "none", TRUE},
98 {"audio_track", "audio_mix", "none", TRUE},
99 {"audio_track", "audio_drc", "none", TRUE},
100 {"audio_codec", "audio_bitrate", "ac3", TRUE},
101 {"audio_codec", "audio_sample_rate", "ac3", TRUE},
102 {"audio_codec", "audio_mix", "ac3", TRUE},
103 {"audio_codec", "audio_drc", "ac3", TRUE},
104 {"x264_bframes", "x264_weighted_bframes", "0", TRUE},
105 {"x264_bframes", "x264_brdo", "0", TRUE},
106 {"x264_bframes", "x264_bime", "0", TRUE},
107 {"x264_bframes", "x264_bpyramid", "<2", TRUE},
108 {"x264_bframes", "x264_direct", "0", TRUE},
109 {"x264_refs", "x264_mixed_refs", "<2", TRUE},
110 {"x264_cabac", "x264_trellis", "enable", FALSE},
111 {"x264_subme", "x264_brdo", "<6", TRUE},
112 {"x264_analyse", "x264_direct", "none", TRUE},
113 {"x264_me", "x264_merange", "umh|esa", FALSE},
114 {"pref_audio_codec1", "pref_audio_bitrate1", "none", TRUE},
115 {"pref_audio_codec1", "pref_audio_rate1", "none", TRUE},
116 {"pref_audio_codec1", "pref_audio_mix1", "none", TRUE},
117 {"pref_audio_codec1", "pref_audio_codec2", "none", TRUE},
118 {"pref_audio_codec1", "pref_audio_bitrate2", "none", TRUE},
119 {"pref_audio_codec1", "pref_audio_rate2", "none", TRUE},
120 {"pref_audio_codec1", "pref_audio_mix2", "none", TRUE},
121 {"pref_audio_codec2", "pref_audio_bitrate2", "none", TRUE},
122 {"pref_audio_codec2", "pref_audio_rate2", "none", TRUE},
123 {"pref_audio_codec2", "pref_audio_mix2", "none", TRUE},
124 {"chapter_markers", "chapters_list", "enable", FALSE},
128 dep_check(signal_user_data_t *ud, const gchar *name)
134 int count = sizeof(dep_map) / sizeof(dependency_t);
135 gboolean result = TRUE;
137 g_debug("dep_check () %s\n", name);
138 for (ii = 0; ii < count; ii++)
140 if (strcmp(dep_map[ii].dep_name, name) == 0)
142 widget = GHB_WIDGET(ud->builder, dep_map[ii].widget_name);
143 dep_object = gtk_builder_get_object(ud->builder, dep_map[ii].dep_name);
144 value = ghb_widget_short_opt(widget);
145 if (dep_object == NULL || widget == NULL)
147 g_message("Failed to find widget\n");
152 gchar **values = g_strsplit(dep_map[ii].enable_value, "|", 10);
153 gboolean sensitive = FALSE;
155 while (values && values[jj])
157 if (values[jj][0] == '>')
159 gdouble dbl = g_strtod (&values[jj][1], NULL);
160 gdouble dvalue = ghb_widget_dbl (widget);
167 else if (values[jj][0] == '<')
169 gdouble dbl = g_strtod (&values[jj][1], NULL);
170 gdouble dvalue = ghb_widget_dbl (widget);
177 if (strcmp(values[jj], value) == 0)
184 sensitive = dep_map[ii].disable_if_equal ^ sensitive;
185 if (!sensitive) result = FALSE;
195 check_depencency(signal_user_data_t *ud, GtkWidget *widget)
200 int count = sizeof(dep_map) / sizeof(dependency_t);
202 if (ghb_widget_index(widget) < 0) return;
203 name = gtk_widget_get_name(widget);
204 g_debug("check_depencency () %s\n", name);
205 for (ii = 0; ii < count; ii++)
207 if (strcmp(dep_map[ii].widget_name, name) == 0)
211 dep_object = gtk_builder_get_object (ud->builder, dep_map[ii].dep_name);
212 if (dep_object == NULL)
214 g_message("Failed to find dependent widget %s\n", dep_map[ii].dep_name);
217 sensitive = dep_check(ud, dep_map[ii].dep_name);
218 if (GTK_IS_ACTION(dep_object))
219 gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
221 gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
227 ghb_check_all_depencencies(signal_user_data_t *ud)
231 int count = sizeof(dep_map) / sizeof(dependency_t);
233 g_debug("ghb_check_all_depencencies ()\n");
234 for (ii = 0; ii < count; ii++)
237 dep_object = gtk_builder_get_object (ud->builder, dep_map[ii].dep_name);
238 if (dep_object == NULL)
240 g_message("Failed to find dependent widget %s\n", dep_map[ii].dep_name);
243 sensitive = dep_check(ud, dep_map[ii].dep_name);
244 if (GTK_IS_ACTION(dep_object))
245 gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
247 gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
252 clear_presets_selection(signal_user_data_t *ud)
254 GtkTreeView *treeview;
255 GtkTreeSelection *selection;
257 if (ud->dont_clear_presets) return;
258 g_debug("clear_presets_selection()\n");
259 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
260 selection = gtk_tree_view_get_selection (treeview);
261 gtk_tree_selection_unselect_all (selection);
265 expand_tilde(const gchar *path)
267 const gchar *user_home;
270 gchar *expanded_path = NULL;
272 g_debug("expand_tilde ()\n");
275 user_home = g_get_home_dir();
276 home = NULL; // squash warning about home uninitialized
279 home = g_strdup(user_home);
282 else if (path[1] == '/')
284 home = g_strdup(user_home);
289 home = g_path_get_dirname(user_home);
292 expanded_path = g_strdup_printf("%s/%s", home, suffix);
295 return expanded_path;
299 on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud)
301 g_debug("on_quit1_activate ()\n");
302 if (ud->state & GHB_STATE_WORKING)
304 if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
317 set_destination(signal_user_data_t *ud)
319 if (ghb_settings_get_bool(ud->settings, "use_source_name"))
321 const gchar *vol_name, *filename, *extension;
322 gchar *dir, *new_name;
324 filename = ghb_settings_get_string(ud->settings, "destination");
325 extension = ghb_settings_get_string(ud->settings, "container");
326 dir = g_path_get_dirname (filename);
327 vol_name = ghb_settings_get_string(ud->settings, "volume_label");
328 g_debug("volume_label (%s)\n", vol_name);
329 if (vol_name == NULL)
331 vol_name = "new_video";
333 new_name = g_strdup_printf("%s/%s.%s", dir, vol_name, extension);
334 ghb_ui_update(ud, "destination", new_name);
341 uppers_and_unders(const gchar *str)
343 if (str == NULL) return FALSE;
350 if (*str >= 'a' && *str <= 'z')
366 camel_convert(gchar *str)
368 gint state = CAMEL_OTHER;
370 if (str == NULL) return;
373 if (*str == '_') *str = ' ';
378 if (*str >= 'A' && *str <= 'Z')
379 state = CAMEL_FIRST_UPPER;
384 case CAMEL_FIRST_UPPER:
386 if (*str >= 'A' && *str <= 'Z')
387 *str = *str - 'A' + 'a';
397 update_source_label(signal_user_data_t *ud, const gchar *source)
402 gchar *filename = g_strdup(source);
404 len = strlen(filename);
405 if (filename[len-1] == '/') filename[len-1] = 0;
406 if (g_file_test(filename, G_FILE_TEST_IS_DIR))
408 path = g_strsplit(filename, "/", -1);
409 len = g_strv_length (path);
410 if ((len > 1) && (strcmp("VIDEO_TS", path[len-1]) == 0))
412 label = g_strdup(path[len-2]);
416 label = g_strdup(path[len-1]);
422 // Is regular file or block dev.
423 // Check to see if it is a dvd image
424 label = ghb_dvd_volname (filename);
427 path = g_strsplit(filename, "/", -1);
428 len = g_strv_length (path);
429 // Just use the last combonent of the path
430 label = g_strdup(path[len-1]);
435 if (uppers_and_unders(label))
437 camel_convert(label);
442 GtkWidget *widget = GHB_WIDGET (ud->builder, "source_title");
445 gtk_label_set_text (GTK_LABEL(widget), label);
446 ghb_settings_set_string(ud->settings, "volume_label", label);
452 label = "No Title Found";
453 gtk_label_set_text (GTK_LABEL(widget), label);
454 ghb_settings_set_string(ud->settings, "volume_label", label);
460 static GtkWidget *dvd_device_combo = NULL;
463 chooser_file_selected_cb(GtkFileChooser *dialog, GtkComboBox *combo)
465 const gchar *name = gtk_file_chooser_get_filename (dialog);
469 gboolean foundit = FALSE;
471 if (name == NULL) return;
472 store = gtk_combo_box_get_model(combo);
473 if (gtk_tree_model_get_iter_first(store, &iter))
477 gtk_tree_model_get(store, &iter, 0, &device, -1);
478 if (strcmp(name, device) == 0)
483 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
486 gtk_combo_box_set_active_iter (combo, &iter);
488 gtk_combo_box_set_active (combo, 0);
492 dvd_device_changed_cb(GtkComboBox *combo, GtkWidget *dialog)
494 gint ii = gtk_combo_box_get_active (combo);
497 const gchar *device = gtk_combo_box_get_active_text (combo);
498 const gchar *name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog));
499 if (name == NULL || strcmp(name, device) != 0)
500 gtk_file_chooser_select_filename (GTK_FILE_CHOOSER(dialog), device);
506 source_type_changed_cb(GtkToggleButton *toggle, GtkFileChooser *chooser)
510 g_debug("source_type_changed_cb ()\n");
511 if (gtk_toggle_button_get_active (toggle))
513 filename = gtk_file_chooser_get_filename (chooser);
514 gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
515 if (filename != NULL)
517 gtk_file_chooser_set_filename(chooser, filename);
520 gtk_widget_set_sensitive (dvd_device_combo, FALSE);
521 gtk_combo_box_set_active (GTK_COMBO_BOX(dvd_device_combo), 0);
525 filename = gtk_file_chooser_get_filename (chooser);
526 gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_OPEN);
527 if (filename != NULL)
529 gtk_file_chooser_set_filename(chooser, filename);
532 gtk_widget_set_sensitive (dvd_device_combo, TRUE);
537 source_dialog_extra_widgets(GtkWidget *dialog, gboolean checkbutton_active)
540 GtkWidget *checkbutton;
542 vbox = GTK_BOX(gtk_vbox_new (FALSE, 2));
543 checkbutton = gtk_check_button_new_with_label ("Open VIDEO_TS folder");
544 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), checkbutton_active);
545 gtk_box_pack_start (vbox, checkbutton, FALSE, FALSE, 1);
546 gtk_widget_show(checkbutton);
550 GList *drives, *link;
551 GtkWidget *label, *blank;
553 hbox = GTK_BOX(gtk_hbox_new (FALSE, 2));
554 combo = gtk_combo_box_new_text();
555 label = gtk_label_new("Detected DVD devices:");
556 blank = gtk_label_new("");
557 link = drives = dvd_device_list();
558 gtk_combo_box_append_text (GTK_COMBO_BOX(combo), "Not Selected");
561 gchar *name = (gchar*)link->data;
562 gtk_combo_box_append_text (GTK_COMBO_BOX(combo), name);
567 gtk_combo_box_set_active (GTK_COMBO_BOX(combo), 0);
568 gtk_box_pack_start (vbox, GTK_WIDGET(hbox), FALSE, FALSE, 1);
569 gtk_widget_show(GTK_WIDGET(hbox));
570 gtk_box_pack_start (hbox, label, FALSE, FALSE, 1);
571 gtk_widget_show(label);
572 gtk_box_pack_start (hbox, combo, FALSE, FALSE, 2);
573 gtk_widget_show(combo);
574 gtk_box_pack_start (hbox, blank, TRUE, TRUE, 1);
575 gtk_widget_show(blank);
577 // Ugly hackish global alert
578 dvd_device_combo = combo;
579 g_signal_connect(combo, "changed", (GCallback)dvd_device_changed_cb, dialog);
580 g_signal_connect(dialog, "selection-changed", (GCallback)chooser_file_selected_cb, combo);
582 g_signal_connect(checkbutton, "toggled", (GCallback)source_type_changed_cb, dialog);
583 return GTK_WIDGET(vbox);
587 do_scan(signal_user_data_t *ud, const gchar *filename)
589 if (filename != NULL)
591 ghb_settings_set_string(ud->settings, "source", filename);
592 if (update_source_label(ud, filename))
594 GtkProgressBar *progress;
595 progress = GTK_PROGRESS_BAR(GHB_WIDGET(ud->builder, "progressbar"));
597 path = ghb_settings_get_string( ud->settings, "source");
598 gtk_progress_bar_set_fraction (progress, 0);
599 gtk_progress_bar_set_text (progress, "Scanning ...");
600 ud->state |= GHB_STATE_SCANNING;
601 ghb_backend_scan (path, 0);
605 // TODO: error dialog
611 source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
615 const gchar *sourcename;
617 GtkFileChooserAction action;
618 gboolean checkbutton_active;
620 g_debug("source_browse_clicked_cb ()\n");
621 sourcename = ghb_settings_get_string(ud->settings, "source");
622 checkbutton_active = FALSE;
623 if (g_file_test(sourcename, G_FILE_TEST_IS_DIR))
625 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
626 checkbutton_active = TRUE;
630 action = GTK_FILE_CHOOSER_ACTION_OPEN;
632 dialog = gtk_file_chooser_dialog_new ("Select Source",
635 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
636 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
638 widget = source_dialog_extra_widgets(dialog, checkbutton_active);
639 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), widget);
640 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), sourcename);
641 response = gtk_dialog_run(GTK_DIALOG (dialog));
642 gtk_widget_hide(dialog);
643 if (response == GTK_RESPONSE_ACCEPT)
647 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
648 if (filename != NULL)
650 do_scan(ud, filename);
651 if (strcmp(sourcename, filename) != 0)
653 ghb_settings_set_string (ud->settings, "default_source", filename);
654 ghb_prefs_save (ud->settings);
655 ghb_dvd_set_current (filename, ud);
660 gtk_widget_destroy(dialog);
664 dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
666 const gchar *filename;
667 const gchar *sourcename;
669 sourcename = ghb_settings_get_string(ud->settings, "source");
670 filename = gtk_action_get_name(action);
671 do_scan(ud, filename);
672 if (strcmp(sourcename, filename) != 0)
674 ghb_settings_set_string (ud->settings, "default_source", filename);
675 ghb_prefs_save (ud->settings);
676 ghb_dvd_set_current (filename, ud);
681 update_destination_extension(signal_user_data_t *ud)
683 static gchar *containers[] = {"mkv", "mp4", "m4v", "avi", "ogm", NULL};
685 const gchar *extension;
689 g_debug("update_destination_extension ()\n");
690 extension = ghb_settings_get_string(ud->settings, "container");
691 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "destination"));
692 filename = g_strdup(gtk_entry_get_text(entry));
693 for (ii = 0; containers[ii] != NULL; ii++)
695 if (g_str_has_suffix(filename, containers[ii]))
700 pos = g_strrstr( filename, "." );
702 if (strcmp(extension, &pos[1]) == 0)
704 // Extension is already correct
707 new_name = g_strjoin(".", filename, extension, NULL);
708 ghb_ui_update(ud, "destination", new_name);
716 static gboolean update_default_destination = FALSE;
719 destination_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
723 g_debug("destination_entry_changed_cb ()\n");
724 if ((dest = expand_tilde(gtk_entry_get_text(entry))) != NULL)
726 gtk_entry_set_text(entry, dest);
729 update_destination_extension(ud);
730 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
731 // This signal goes off with ever keystroke, so I'm putting this
732 // update on the timer.
733 update_default_destination = TRUE;
737 destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
741 const char *destname;
744 g_debug("destination_browse_clicked_cb ()\n");
745 destname = ghb_settings_get_string(ud->settings, "destination");
746 dialog = gtk_file_chooser_dialog_new ("Choose Destination",
748 GTK_FILE_CHOOSER_ACTION_SAVE,
749 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
750 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
752 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), destname);
753 basename = g_path_get_basename(destname);
754 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
756 if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
760 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
761 entry = (GtkEntry*)GHB_WIDGET(ud->builder, "destination");
764 g_debug("Failed to find widget: %s\n", "destination");
768 gtk_entry_set_text(entry, filename);
772 gtk_widget_destroy(dialog);
776 window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
778 g_debug("window_destroy_event_cb ()\n");
785 window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
787 g_debug("window_delete_event_cb ()\n");
788 if (ud->state & GHB_STATE_WORKING)
790 if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
804 update_acodec_combo(signal_user_data_t *ud)
806 ghb_grey_combo_options (ud->builder);
810 container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
812 g_debug("container_changed_cb ()\n");
813 ghb_widget_to_setting(ud->settings, widget);
814 update_destination_extension(ud);
815 check_depencency(ud, widget);
816 update_acodec_combo(ud);
817 clear_presets_selection(ud);
821 get_aspect_string(gint aspect_n, gint aspect_d)
827 aspect = g_strdup_printf("%d:%d", aspect_n, aspect_d);
831 gdouble aspect_nf = (gdouble)aspect_n / aspect_d;
832 aspect = g_strdup_printf("%.2f:1", aspect_nf);
838 get_rate_string(gint rate_base, gint rate)
840 gdouble rate_f = (gdouble)rate / rate_base;
843 rate_s = g_strdup_printf("%.6g", rate_f);
847 show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
852 widget = GHB_WIDGET (ud->builder, "title_duration");
853 text = g_strdup_printf ("%02d:%02d:%02d", tinfo->hours, tinfo->minutes, tinfo->seconds);
854 gtk_label_set_text (GTK_LABEL(widget), text);
856 widget = GHB_WIDGET (ud->builder, "source_dimensions");
857 text = g_strdup_printf ("%d x %d", tinfo->width, tinfo->height);
858 gtk_label_set_text (GTK_LABEL(widget), text);
860 widget = GHB_WIDGET (ud->builder, "source_aspect");
861 text = get_aspect_string(tinfo->aspect_n, tinfo->aspect_d);
862 gtk_label_set_text (GTK_LABEL(widget), text);
865 widget = GHB_WIDGET (ud->builder, "source_frame_rate");
866 text = (gchar*)get_rate_string(tinfo->rate_base, tinfo->rate);
867 gtk_label_set_text (GTK_LABEL(widget), text);
870 ghb_ui_update_int (ud, "scale_width", tinfo->width - tinfo->crop[2] - tinfo->crop[3]);
871 // If anamorphic or keep_aspect, the hight will be automatically calculated
872 gboolean keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
873 gboolean anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
874 if (!(keep_aspect || anamorphic))
875 ghb_ui_update_int (ud, "scale_height", tinfo->height - tinfo->crop[0] - tinfo->crop[1]);
877 // Set the limits of cropping. hb_set_anamorphic_size crashes if
878 // you pass it a cropped width or height == 0.
880 bound = tinfo->height / 2 - 2;
881 widget = GHB_WIDGET (ud->builder, "crop_top");
882 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
883 widget = GHB_WIDGET (ud->builder, "crop_bottom");
884 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
885 bound = tinfo->width / 2 - 2;
886 widget = GHB_WIDGET (ud->builder, "crop_left");
887 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
888 widget = GHB_WIDGET (ud->builder, "crop_right");
889 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
890 if (ghb_settings_get_bool (ud->settings, "autocrop"))
892 ghb_ui_update_int (ud, "crop_top", tinfo->crop[0]);
893 ghb_ui_update_int (ud, "crop_bottom", tinfo->crop[1]);
894 ghb_ui_update_int (ud, "crop_left", tinfo->crop[2]);
895 ghb_ui_update_int (ud, "crop_right", tinfo->crop[3]);
897 g_debug("setting max end chapter %d\n", tinfo->num_chapters);
898 widget = GHB_WIDGET (ud->builder, "end_chapter");
899 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters);
900 gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), tinfo->num_chapters);
901 widget = GHB_WIDGET (ud->builder, "start_chapter");
902 gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1);
906 adjust_audio_rate_combos(signal_user_data_t *ud)
908 gint titleindex, audioindex, acodec;
909 ghb_audio_info_t ainfo;
912 g_debug("adjust_audio_rate_combos ()\n");
913 titleindex = ghb_settings_get_index(ud->settings, "title");
915 widget = GHB_WIDGET(ud->builder, "audio_track");
916 audioindex = ghb_widget_int(widget);
918 widget = GHB_WIDGET(ud->builder, "audio_codec");
919 acodec = ghb_widget_int(widget);
921 if (ghb_get_audio_info (&ainfo, titleindex, audioindex) && ghb_audio_is_passthru (acodec))
923 // Set the values for bitrate and samplerate to the input rates
924 ghb_set_passthru_rate_opts (ud->builder, ainfo.bitrate);
925 ghb_ui_update_int (ud, "audio_bitrate", ainfo.bitrate);
926 ghb_ui_update_int (ud, "audio_sample_rate", 0);
927 ghb_ui_update_int (ud, "audio_mix", 0);
931 ghb_set_default_rate_opts (ud->builder);
936 set_pref_audio(gint titleindex, signal_user_data_t *ud)
938 gint acodec, track, ivalue;
941 ghb_audio_info_t ainfo;
942 gboolean skipped_1st = FALSE;
944 // Clear the audio list
945 clear_audio_list(ud);
947 // Find "best" audio based on audio preferences
948 button = GHB_WIDGET (ud->builder, "audio_add");
949 svalue = ghb_settings_get_short_opt(ud->settings, "pref_source_audio_lang");
950 acodec = ghb_settings_get_int(ud->settings, "pref_source_audio_codec");
951 track = ghb_find_audio_track(titleindex, svalue, acodec);
952 ghb_ui_update_int(ud, "audio_track", track);
953 // Get the resulting track, it may not be what was asked for.
954 track = ghb_settings_get_int(ud->settings, "audio_track");
957 // No audio tracks. Perhaps no source dvd yet
958 // Just initialize the audio controls and do not add anything to
960 acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec1");
961 ghb_ui_update_int(ud, "audio_codec", acodec);
962 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
963 ghb_ui_update_int(ud, "audio_bitrate", ivalue);
964 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
965 ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
966 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
967 ghb_ui_update_int(ud, "audio_mix", ivalue);
968 svalue = ghb_settings_get_string(ud->settings, "pref_audio_drc");
969 ghb_ui_update(ud, "audio_drc", svalue);
972 acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec1");
974 // 1. pref codec is ac3
975 // 2. source codec is not ac3
976 // 3. 2nd pref is enabled
977 if (ghb_get_audio_info (&ainfo, titleindex, track) && ghb_audio_is_passthru (acodec))
979 if (!ghb_audio_is_passthru(ainfo.codec))
981 acodec = ghb_get_default_acodec();
982 if (ghb_settings_get_int(ud->settings, "pref_audio_codec2") != 0)
984 // Skip first pref audio
990 ghb_ui_update_int(ud, "audio_codec", acodec);
991 if (!ghb_audio_is_passthru (acodec))
993 // This gets set autimatically if the codec is passthru
994 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
995 ghb_ui_update_int(ud, "audio_bitrate", ivalue);
996 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
997 ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
998 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
999 ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1000 ghb_ui_update_int(ud, "audio_mix", ivalue);
1002 svalue = ghb_settings_get_string(ud->settings, "pref_audio_drc");
1003 ghb_ui_update(ud, "audio_drc", svalue);
1004 if (acodec != 0) // 0 is none
1006 // Add to audio list
1007 g_signal_emit_by_name(button, "clicked", ud);
1009 acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec2");
1011 // 1. pref codec is ac3
1012 // 2. source codec is not ac3
1013 if (ghb_audio_is_passthru (acodec))
1015 if (!ghb_audio_is_passthru(ainfo.codec) && skipped_1st)
1017 acodec = ghb_get_default_acodec();
1026 ghb_ui_update_int(ud, "audio_codec", acodec);
1027 // Do the second prefs track
1028 if (!ghb_audio_is_passthru (acodec))
1030 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate2");
1031 ghb_ui_update_int(ud, "audio_bitrate", ivalue);
1032 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate2");
1033 ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
1034 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix2");
1035 ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1036 ghb_ui_update_int(ud, "audio_mix", ivalue);
1038 g_signal_emit_by_name(button, "clicked", ud);
1042 static gint preview_button_width;
1043 static gint preview_button_height;
1044 static gboolean update_preview = FALSE;
1047 set_preview_image(signal_user_data_t *ud)
1050 gint preview_width, preview_height, target_height, width, height;
1052 g_debug("set_preview_button_image ()\n");
1053 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1054 if (titleindex < 0) return;
1055 widget = GHB_WIDGET (ud->builder, "preview_frame");
1056 gint frame = ghb_widget_int(widget) - 1;
1057 GdkPixbuf *preview = ghb_get_preview_image (titleindex, frame, ud->settings, TRUE);
1058 if (preview == NULL) return;
1059 widget = GHB_WIDGET (ud->builder, "preview_image");
1060 gtk_image_set_from_pixbuf(GTK_IMAGE(widget), preview);
1062 preview_width = gdk_pixbuf_get_width(preview);
1063 preview_height = gdk_pixbuf_get_height(preview);
1064 gchar *text = g_strdup_printf("%d x %d", preview_width, preview_height);
1065 widget = GHB_WIDGET (ud->builder, "preview_dims");
1066 gtk_label_set_text(GTK_LABEL(widget), text);
1069 g_debug("preview %d x %d\n", preview_width, preview_height);
1070 target_height = MIN(preview_button_height - 12, 128);
1071 height = target_height;
1072 width = preview_width * height / preview_height;
1074 if ((height >= 16) && (width >= 16))
1076 GdkPixbuf *scaled_preview;
1077 scaled_preview = gdk_pixbuf_scale_simple (preview, width, height, GDK_INTERP_NEAREST);
1078 if (scaled_preview != NULL)
1080 g_object_unref (preview);
1082 widget = GHB_WIDGET (ud->builder, "preview_button_image");
1083 gtk_image_set_from_pixbuf(GTK_IMAGE(widget), scaled_preview);
1084 g_object_unref (scaled_preview);
1090 title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1092 ghb_title_info_t tinfo;
1094 const gchar *preset;
1096 g_debug("title_changed_cb ()\n");
1097 ghb_widget_to_setting(ud->settings, widget);
1098 check_depencency(ud, widget);
1100 titleindex = ghb_settings_get_int(ud->settings, "title");
1101 ghb_update_ui_combo_box (ud->builder, "audio_track", titleindex, FALSE);
1102 ghb_update_ui_combo_box (ud->builder, "subtitle_lang", titleindex, FALSE);
1103 preset = ghb_settings_get_string (ud->settings, "preset");
1104 ghb_update_from_preset(ud, preset, "subtitle_lang");
1105 if (ghb_get_title_info (&tinfo, titleindex))
1107 show_title_info(ud, &tinfo);
1109 update_chapter_list (ud);
1110 adjust_audio_rate_combos(ud);
1111 set_pref_audio(titleindex, ud);
1112 if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
1114 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1115 ghb_ui_update_int (ud, "video_bitrate", bitrate);
1118 // Unfortunately, there is no way to query how many frames were
1119 // actually generated during the scan. It attempts to make 10.
1120 // If I knew how many were generated, I would adjust the spin
1121 // control range here.
1122 ghb_ui_update_int (ud, "preview_frame", 1);
1124 set_preview_image (ud);
1128 audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1130 static gint prev_acodec = 0;
1131 gint acodec, ivalue;
1132 GHashTable *asettings;
1134 g_debug("audio_codec_changed_cb ()\n");
1136 acodec = ghb_widget_int(widget);
1137 if (ghb_audio_is_passthru (prev_acodec) && !ghb_audio_is_passthru (acodec))
1139 // Transition from passthru to not, put some audio settings back to
1141 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1142 gint track = ghb_settings_get_int(ud->settings, "audio_track");
1144 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
1145 ghb_ui_update_int (ud, "audio_bitrate", ivalue);
1146 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
1147 ghb_ui_update_int (ud, "audio_sample_rate", ivalue);
1148 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
1149 ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1150 ghb_ui_update_int (ud, "audio_mix", ivalue);
1152 adjust_audio_rate_combos(ud);
1153 ghb_grey_combo_options (ud->builder);
1154 check_depencency(ud, widget);
1155 prev_acodec = acodec;
1156 asettings = get_selected_asettings(ud);
1157 if (asettings != NULL)
1159 ghb_widget_to_setting(asettings, widget);
1160 audio_list_refresh_selected(ud);
1164 static void audio_list_refresh_selected(signal_user_data_t *ud);
1165 static GHashTable* get_selected_asettings(signal_user_data_t *ud);
1168 audio_track_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1170 GHashTable *asettings;
1172 g_debug("audio_track_changed_cb ()\n");
1173 adjust_audio_rate_combos(ud);
1174 check_depencency(ud, widget);
1175 ghb_grey_combo_options(ud->builder);
1176 asettings = get_selected_asettings(ud);
1177 if (asettings != NULL)
1179 ghb_widget_to_setting(asettings, widget);
1180 audio_list_refresh_selected(ud);
1185 audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1187 GHashTable *asettings;
1189 g_debug("audio_widget_changed_cb ()\n");
1190 check_depencency(ud, widget);
1191 asettings = get_selected_asettings(ud);
1192 if (asettings != NULL)
1194 ghb_widget_to_setting(asettings, widget);
1195 audio_list_refresh_selected(ud);
1200 generic_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1202 g_debug("generic_widget_changed_cb ()\n");
1203 check_depencency(ud, widget);
1207 setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1209 ghb_widget_to_setting(ud->settings, widget);
1210 check_depencency(ud, widget);
1211 clear_presets_selection(ud);
1215 vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1219 ghb_widget_to_setting(ud->settings, widget);
1220 check_depencency(ud, widget);
1221 clear_presets_selection(ud);
1222 ghb_vquality_range(ud, &vqmin, &vqmax);
1223 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1224 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1228 vfr_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1230 //const gchar *name = gtk_widget_get_name(widget);
1231 //g_debug("setting_widget_changed_cb () %s\n", name);
1232 ghb_widget_to_setting(ud->settings, widget);
1233 check_depencency(ud, widget);
1234 clear_presets_selection(ud);
1235 if (ghb_settings_get_bool(ud->settings, "variable_frame_rate"))
1237 ghb_ui_update_int(ud, "framerate", 0);
1242 mirror_cb(GtkWidget *widget, signal_user_data_t *ud)
1244 const gchar *name = gtk_widget_get_name(widget);
1245 if (name == NULL) return;
1247 g_debug("mirror_cb () %s\n", name);
1248 gchar *mirror = g_strdup(name);
1249 gchar *pos = g_strrstr(mirror, "_mirror");
1250 if (pos == NULL) return;
1252 gchar *value = ghb_widget_short_opt (widget);
1253 ghb_ui_update (ud, mirror, value);
1257 // subtitles have their differ from other settings in that
1258 // the selection is updated automaitcally when the title
1259 // changes. I don't want the preset selection changed as
1260 // would happen for regular settings.
1262 subtitle_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1264 const gchar *name = gtk_widget_get_name(widget);
1265 g_debug("subtitle_changed_cb () %s\n", name);
1266 ghb_widget_to_setting(ud->settings, widget);
1267 check_depencency(ud, widget);
1271 target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1273 const gchar *name = gtk_widget_get_name(widget);
1274 g_debug("setting_widget_changed_cb () %s\n", name);
1275 ghb_widget_to_setting(ud->settings, widget);
1276 check_depencency(ud, widget);
1277 clear_presets_selection(ud);
1278 if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
1280 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1281 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1282 ghb_ui_update_int (ud, "video_bitrate", bitrate);
1287 start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1289 const gchar *name = gtk_widget_get_name(widget);
1290 g_debug("start_chapter_changed_cb () %s\n", name);
1291 ghb_widget_to_setting(ud->settings, widget);
1292 GtkWidget *end_ch = GHB_WIDGET (ud->builder, "end_chapter");
1294 gtk_spin_button_get_range (GTK_SPIN_BUTTON(end_ch), &start, &end);
1295 start = ghb_settings_get_int(ud->settings, "start_chapter");
1296 gtk_spin_button_set_range (GTK_SPIN_BUTTON(end_ch), start, end);
1297 check_depencency(ud, widget);
1301 end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1303 const gchar *name = gtk_widget_get_name(widget);
1304 g_debug("end_chapter_changed_cb () %s\n", name);
1305 ghb_widget_to_setting(ud->settings, widget);
1306 GtkWidget *start_ch = GHB_WIDGET (ud->builder, "start_chapter");
1308 gtk_spin_button_get_range (GTK_SPIN_BUTTON(start_ch), &start, &end);
1309 end = ghb_settings_get_int(ud->settings, "end_chapter");
1310 gtk_spin_button_set_range (GTK_SPIN_BUTTON(start_ch), start, end);
1311 check_depencency(ud, widget);
1315 scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1317 g_debug("scale_width_changed_cb ()\n");
1318 ghb_widget_to_setting(ud->settings, widget);
1319 check_depencency(ud, widget);
1320 ghb_set_scale (ud, GHB_SCALE_KEEP_WIDTH);
1321 update_preview = TRUE;
1323 gint width = ghb_settings_get_int(ud->settings, "scale_width");
1324 gint height = ghb_settings_get_int(ud->settings, "scale_height");
1325 widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1326 text = g_strdup_printf ("%d x %d", width, height);
1327 gtk_label_set_text (GTK_LABEL(widget), text);
1332 scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1334 g_debug("scale_height_changed_cb ()\n");
1335 ghb_widget_to_setting(ud->settings, widget);
1336 check_depencency(ud, widget);
1337 ghb_set_scale (ud, GHB_SCALE_KEEP_HEIGHT);
1338 update_preview = TRUE;
1340 gint width = ghb_settings_get_int(ud->settings, "scale_width");
1341 gint height = ghb_settings_get_int(ud->settings, "scale_height");
1342 widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1343 text = g_strdup_printf ("%d x %d", width, height);
1344 gtk_label_set_text (GTK_LABEL(widget), text);
1349 crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1351 gint titleindex, crop[4];
1352 ghb_title_info_t tinfo;
1354 g_debug("crop_changed_cb ()\n");
1355 ghb_widget_to_setting(ud->settings, widget);
1356 check_depencency(ud, widget);
1357 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1359 crop[0] = ghb_settings_get_int(ud->settings, "crop_top");
1360 crop[1] = ghb_settings_get_int(ud->settings, "crop_bottom");
1361 crop[2] = ghb_settings_get_int(ud->settings, "crop_left");
1362 crop[3] = ghb_settings_get_int(ud->settings, "crop_right");
1363 titleindex = ghb_settings_get_index(ud->settings, "title");
1364 if (ghb_get_title_info (&tinfo, titleindex))
1369 width = tinfo.width - crop[2] - crop[3];
1370 height = tinfo.height - crop[0] - crop[1];
1371 widget = GHB_WIDGET (ud->builder, "crop_dimensions");
1372 text = g_strdup_printf ("%d x %d", width, height);
1373 gtk_label_set_text (GTK_LABEL(widget), text);
1377 widget = GHB_WIDGET (ud->builder, "crop_values");
1378 text = g_strdup_printf ("%d:%d:%d:%d", crop[0], crop[1], crop[2], crop[3]);
1379 gtk_label_set_text (GTK_LABEL(widget), text);
1381 update_preview = TRUE;
1385 scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1387 g_debug("scale_changed_cb ()\n");
1388 ghb_widget_to_setting(ud->settings, widget);
1389 check_depencency(ud, widget);
1390 clear_presets_selection(ud);
1391 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1392 update_preview = TRUE;
1396 text = ghb_settings_get_bool(ud->settings, "autocrop") ? "On" : "Off";
1397 widget = GHB_WIDGET (ud->builder, "crop_auto");
1398 gtk_label_set_text (GTK_LABEL(widget), text);
1399 text = ghb_settings_get_bool(ud->settings, "autoscale") ? "On" : "Off";
1400 widget = GHB_WIDGET (ud->builder, "scale_auto");
1401 gtk_label_set_text (GTK_LABEL(widget), text);
1402 text = ghb_settings_get_bool(ud->settings, "anamorphic") ? "On" : "Off";
1403 widget = GHB_WIDGET (ud->builder, "scale_anamorphic");
1404 gtk_label_set_text (GTK_LABEL(widget), text);
1408 generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
1410 // Normally (due to user input) I only want to process the entry
1411 // when editing is done and the focus-out signal is sent.
1412 // But... there's always a but.
1413 // If the entry is changed by software, the focus-out signal is not sent.
1414 // The changed signal is sent ... so here we are.
1415 // I don't want to process upon every keystroke, so I prevent processing
1416 // while the widget has focus.
1417 g_debug("generic_entry_changed_cb ()\n");
1418 if (!GTK_WIDGET_HAS_FOCUS((GtkWidget*)entry))
1420 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
1425 generic_focus_out_cb(GtkWidget *widget, GdkEventFocus *event,
1426 signal_user_data_t *ud)
1428 g_debug("generic_focus_out_cb ()\n");
1429 ghb_widget_to_setting(ud->settings, widget);
1434 clear_audio_list(signal_user_data_t *ud)
1436 GtkTreeView *treeview;
1437 GtkListStore *store;
1440 g_debug("clear_audio_list ()\n");
1441 while (ud->audio_settings != NULL)
1443 link = ud->audio_settings;
1444 ud->audio_settings = g_slist_remove_link(ud->audio_settings, link);
1445 g_hash_table_destroy((GHashTable*)link->data);
1446 g_slist_free_1(link);
1448 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1449 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1450 gtk_list_store_clear (store);
1454 add_to_audio_list(signal_user_data_t *ud, GHashTable *settings)
1456 GtkTreeView *treeview;
1458 GtkListStore *store;
1459 GtkTreeSelection *selection;
1461 g_debug("add_to_audio_list ()\n");
1462 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1463 selection = gtk_tree_view_get_selection (treeview);
1464 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1466 gtk_list_store_append(store, &iter);
1467 gtk_list_store_set(store, &iter,
1468 // These are displayed in list
1469 0, ghb_settings_get_option(settings, "audio_track"),
1470 1, ghb_settings_get_option(settings, "audio_codec"),
1471 2, ghb_settings_get_option(settings, "audio_bitrate"),
1472 3, ghb_settings_get_option(settings, "audio_sample_rate"),
1473 4, ghb_settings_get_option(settings, "audio_mix"),
1474 // These are used to set combo box values when a list item is selected
1475 5, ghb_settings_get_string(settings, "audio_drc"),
1476 6, ghb_settings_get_short_opt(settings, "audio_track"),
1477 7, ghb_settings_get_short_opt(settings, "audio_codec"),
1478 8, ghb_settings_get_short_opt(settings, "audio_bitrate"),
1479 9, ghb_settings_get_short_opt(settings, "audio_sample_rate"),
1480 10, ghb_settings_get_short_opt(settings, "audio_mix"),
1482 gtk_tree_selection_select_iter(selection, &iter);
1486 audio_list_refresh_selected(signal_user_data_t *ud)
1488 GtkTreeView *treeview;
1489 GtkTreePath *treepath;
1490 GtkTreeSelection *selection;
1491 GtkTreeModel *store;
1496 GHashTable *asettings = NULL;
1498 g_debug("get_selected_asettings ()\n");
1499 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1500 selection = gtk_tree_view_get_selection (treeview);
1501 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1503 // Get the row number
1504 treepath = gtk_tree_model_get_path (store, &iter);
1505 indices = gtk_tree_path_get_indices (treepath);
1508 // find audio settings
1509 if (row < 0) return;
1510 link = g_slist_nth(ud->audio_settings, row);
1511 if (link == NULL) return;
1512 asettings = (GHashTable*)link->data;
1513 gtk_list_store_set(GTK_LIST_STORE(store), &iter,
1514 // These are displayed in list
1515 0, ghb_settings_get_option(asettings, "audio_track"),
1516 1, ghb_settings_get_option(asettings, "audio_codec"),
1517 2, ghb_settings_get_option(asettings, "audio_bitrate"),
1518 3, ghb_settings_get_option(asettings, "audio_sample_rate"),
1519 4, ghb_settings_get_option(asettings, "audio_mix"),
1520 // These are used to set combo box values when a list item is selected
1521 5, ghb_settings_get_string(asettings, "audio_drc"),
1522 6, ghb_settings_get_short_opt(asettings, "audio_track"),
1523 7, ghb_settings_get_short_opt(asettings, "audio_codec"),
1524 8, ghb_settings_get_short_opt(asettings, "audio_bitrate"),
1525 9, ghb_settings_get_short_opt(asettings, "audio_sample_rate"),
1526 10, ghb_settings_get_short_opt(asettings, "audio_mix"),
1532 get_selected_asettings(signal_user_data_t *ud)
1534 GtkTreeView *treeview;
1535 GtkTreePath *treepath;
1536 GtkTreeSelection *selection;
1537 GtkTreeModel *store;
1542 GHashTable *asettings = NULL;
1544 g_debug("get_selected_asettings ()\n");
1545 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1546 selection = gtk_tree_view_get_selection (treeview);
1547 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1549 // Get the row number
1550 treepath = gtk_tree_model_get_path (store, &iter);
1551 indices = gtk_tree_path_get_indices (treepath);
1554 // find audio settings
1555 if (row < 0) return NULL;
1556 link = g_slist_nth(ud->audio_settings, row);
1557 if (link == NULL) return NULL;
1558 asettings = (GHashTable*)link->data;
1564 audio_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
1566 GtkTreeModel *store;
1570 g_debug("audio_list_selection_changed_cb ()\n");
1571 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1573 const gchar *track, *codec, *bitrate, *sample_rate, *mix, *drc;
1574 gtk_tree_model_get(store, &iter,
1582 ghb_ui_update(ud, "audio_track", track);
1583 ghb_ui_update(ud, "audio_codec", codec);
1584 ghb_ui_update(ud, "audio_bitrate", bitrate);
1585 ghb_ui_update(ud, "audio_sample_rate", sample_rate);
1586 ghb_ui_update(ud, "audio_mix", mix);
1587 ghb_ui_update(ud, "audio_drc", drc);
1588 widget = GHB_WIDGET (ud->builder, "audio_remove");
1589 gtk_widget_set_sensitive(widget, TRUE);
1590 //widget = GHB_WIDGET (ud->builder, "audio_update");
1591 //gtk_widget_set_sensitive(widget, TRUE);
1595 widget = GHB_WIDGET (ud->builder, "audio_remove");
1596 gtk_widget_set_sensitive(widget, FALSE);
1597 //widget = GHB_WIDGET (ud->builder, "audio_update");
1598 //gtk_widget_set_sensitive(widget, FALSE);
1603 audio_add_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1605 // Add the current audio settings to the list.
1606 GHashTable *asettings;
1610 g_debug("audio_add_clicked_cb ()\n");
1611 // Only allow up to 8 audio entries
1612 asettings = ghb_settings_new();
1613 widget = GHB_WIDGET(ud->builder, "audio_track");
1614 ghb_settings_set(asettings, "audio_track", ghb_widget_value(widget));
1615 widget = GHB_WIDGET(ud->builder, "audio_codec");
1616 ghb_settings_set(asettings, "audio_codec", ghb_widget_value(widget));
1617 widget = GHB_WIDGET(ud->builder, "audio_bitrate");
1618 ghb_settings_set(asettings, "audio_bitrate", ghb_widget_value(widget));
1619 widget = GHB_WIDGET(ud->builder, "audio_sample_rate");
1620 ghb_settings_set(asettings, "audio_sample_rate", ghb_widget_value(widget));
1621 widget = GHB_WIDGET(ud->builder, "audio_mix");
1622 ghb_settings_set(asettings, "audio_mix", ghb_widget_value(widget));
1623 widget = GHB_WIDGET(ud->builder, "audio_drc");
1624 ghb_settings_set(asettings, "audio_drc", ghb_widget_value(widget));
1626 ud->audio_settings = g_slist_append(ud->audio_settings, asettings);
1627 add_to_audio_list(ud, asettings);
1628 count = g_slist_length(ud->audio_settings);
1631 gtk_widget_set_sensitive(xwidget, FALSE);
1636 audio_remove_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
1638 GtkTreeView *treeview;
1639 GtkTreePath *treepath;
1640 GtkTreeSelection *selection;
1641 GtkTreeModel *store;
1642 GtkTreeIter iter, nextIter;
1647 g_debug("audio_remove_clicked_cb ()\n");
1648 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1649 selection = gtk_tree_view_get_selection (treeview);
1650 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1653 if (!gtk_tree_model_iter_next(store, &nextIter))
1656 if (gtk_tree_model_get_iter_first(store, &nextIter))
1658 gtk_tree_selection_select_iter (selection, &nextIter);
1663 gtk_tree_selection_select_iter (selection, &nextIter);
1665 // Get the row number
1666 treepath = gtk_tree_model_get_path (store, &iter);
1667 indices = gtk_tree_path_get_indices (treepath);
1670 // Remove the selected item
1671 gtk_list_store_remove (GTK_LIST_STORE(store), &iter);
1672 // remove from audio settings list
1673 if (row < 0) return;
1674 link = g_slist_nth(ud->audio_settings, row);
1675 if (link == NULL) return;
1676 ud->audio_settings = g_slist_remove_link(ud->audio_settings, link);
1677 g_hash_table_destroy((GHashTable*)link->data);
1678 g_slist_free_1(link);
1679 widget = GHB_WIDGET (ud->builder, "audio_add");
1680 gtk_widget_set_sensitive(widget, TRUE);
1685 audio_list_refresh(signal_user_data_t *ud)
1687 GtkTreeView *treeview;
1689 GtkListStore *store;
1692 g_debug("audio_list_refresh ()\n");
1693 GSList *link = ud->audio_settings;
1694 if (link == NULL) return;
1695 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1696 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1697 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1701 GHashTable *asettings;
1703 asettings = (GHashTable*)link->data;
1704 gtk_list_store_set(GTK_LIST_STORE(store), &iter,
1705 // These are displayed in list
1706 0, ghb_settings_get_option(asettings, "audio_track"),
1707 1, ghb_settings_get_option(asettings, "audio_codec"),
1708 2, ghb_settings_get_option(asettings, "audio_bitrate"),
1709 3, ghb_settings_get_option(asettings, "audio_sample_rate"),
1710 4, ghb_settings_get_option(asettings, "audio_mix"),
1711 // These are used to set combo box values when a list item is selected
1712 5, ghb_settings_get_string(asettings, "audio_drc"),
1713 6, ghb_settings_get_short_opt(asettings, "audio_track"),
1714 7, ghb_settings_get_short_opt(asettings, "audio_codec"),
1715 8, ghb_settings_get_short_opt(asettings, "audio_bitrate"),
1716 9, ghb_settings_get_short_opt(asettings, "audio_sample_rate"),
1717 10, ghb_settings_get_short_opt(asettings, "audio_mix"),
1719 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1721 } while (!done && link);
1726 ghb_presets_list_update(signal_user_data_t *ud)
1728 GtkTreeView *treeview;
1730 GtkListStore *store;
1735 gchar **descriptions;
1736 gint flags, custom, def;
1738 g_debug("ghb_presets_list_update ()\n");
1739 presets = ghb_presets_get_names();
1740 descriptions = ghb_presets_get_descriptions();
1741 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1742 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1743 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1747 if ((presets != NULL) && (presets[ii] != NULL))
1749 // Update row with settings data
1750 g_debug("Updating row\n");
1751 flags = ghb_preset_flags(presets[ii], &index);
1752 def = flags & PRESET_DEFAULT;
1753 custom = flags & PRESET_CUSTOM;
1754 gtk_list_store_set(store, &iter,
1758 3, custom ? "black" : "blue",
1759 4, descriptions[ii],
1762 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1766 // No more settings data, remove row
1767 g_debug("Removing row\n");
1768 done = !gtk_list_store_remove(store, &iter);
1772 while ((presets != NULL) && (presets[ii] != NULL))
1774 // Additional settings, add row
1775 g_debug("Adding row %s\n", presets[ii]);
1776 gtk_list_store_append(store, &iter);
1777 flags = ghb_preset_flags(presets[ii], &index);
1778 def = flags & PRESET_DEFAULT;
1779 custom = flags & PRESET_CUSTOM;
1780 gtk_list_store_set(store, &iter, 0, presets[ii],
1783 3, custom ? "black" : "blue",
1784 4, descriptions[ii],
1788 g_strfreev (presets);
1792 ghb_select_preset(GtkBuilder *builder, const gchar *preset)
1794 GtkTreeView *treeview;
1795 GtkTreeSelection *selection;
1796 GtkTreeModel *store;
1801 g_debug("select_preset()\n");
1802 if (preset == NULL) return;
1803 treeview = GTK_TREE_VIEW(GHB_WIDGET(builder, "presets_list"));
1804 selection = gtk_tree_view_get_selection (treeview);
1805 store = gtk_tree_view_get_model (treeview);
1806 if (gtk_tree_model_get_iter_first(store, &iter))
1810 gtk_tree_model_get(store, &iter, 0, &tpreset, -1);
1811 if (strcmp(preset, tpreset) == 0)
1813 gtk_tree_selection_select_iter (selection, &iter);
1816 done = !gtk_tree_model_iter_next(store, &iter);
1822 presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1827 GtkResponseType response;
1828 const gchar *preset = "";
1830 g_debug("presets_save_clicked_cb ()\n");
1831 preset = ghb_settings_get_string (ud->settings, "preset");
1832 // Clear the description
1833 desc = GTK_TEXT_VIEW(GHB_WIDGET(ud->builder, "preset_description"));
1834 //gtk_entry_set_text(desc, "");
1835 dialog = GHB_WIDGET(ud->builder, "preset_save_dialog");
1836 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "preset_name"));
1837 gtk_entry_set_text(entry, preset);
1838 response = gtk_dialog_run(GTK_DIALOG(dialog));
1839 gtk_widget_hide(dialog);
1840 if (response == GTK_RESPONSE_OK)
1843 const gchar *name = gtk_entry_get_text(entry);
1844 g_debug("description to settings\n");
1845 ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
1846 ghb_settings_save(ud, name);
1847 ghb_presets_list_update(ud);
1848 // Make the new preset the selected item
1849 ghb_select_preset(ud->builder, name);
1854 prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1857 GtkResponseType response;
1859 g_debug("prefs_dialog_cb ()\n");
1860 dialog = GHB_WIDGET(ud->builder, "prefs_dialog");
1861 response = gtk_dialog_run(GTK_DIALOG(dialog));
1862 gtk_widget_hide(dialog);
1866 presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1868 GtkTreeView *treeview;
1869 GtkTreeSelection *selection;
1870 GtkTreeModel *store;
1873 GtkResponseType response;
1875 g_debug("presets_remove_clicked_cb ()\n");
1876 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1877 selection = gtk_tree_view_get_selection (treeview);
1878 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1882 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1883 if (!ghb_presets_is_standard(preset))
1885 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1886 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1887 "Confirm deletion of preset %s.", preset);
1888 response = gtk_dialog_run(GTK_DIALOG(dialog));
1889 gtk_widget_destroy (dialog);
1890 if (response == GTK_RESPONSE_YES)
1892 GtkTreeIter nextIter = iter;
1893 gchar *nextPreset = NULL;
1894 if (!gtk_tree_model_iter_next(store, &nextIter))
1896 if (gtk_tree_model_get_iter_first(store, &nextIter))
1898 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1903 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1905 // Remove the selected item
1906 // First unselect it so that selecting the new item works properly
1907 gtk_tree_selection_unselect_iter (selection, &iter);
1908 ghb_presets_remove(ud->settings, preset);
1909 ghb_presets_list_update(ud);
1910 ghb_select_preset(ud->builder, nextPreset);
1915 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1916 GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
1917 "Can not delete standard preset %s.", preset);
1918 response = gtk_dialog_run(GTK_DIALOG(dialog));
1919 gtk_widget_destroy (dialog);
1925 preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
1929 ghb_ui_update_int (ud, "scale_width", tinfo->width - tinfo->crop[2] - tinfo->crop[3]);
1930 // If anamorphic or keep_aspect, the hight will be automatically calculated
1931 gboolean keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
1932 gboolean anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
1933 if (!(keep_aspect || anamorphic))
1934 ghb_ui_update_int (ud, "scale_height", tinfo->height - tinfo->crop[0] - tinfo->crop[1]);
1936 // Set the limits of cropping. hb_set_anamorphic_size crashes if
1937 // you pass it a cropped width or height == 0.
1939 bound = tinfo->height / 2 - 2;
1940 widget = GHB_WIDGET (ud->builder, "crop_top");
1941 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1942 widget = GHB_WIDGET (ud->builder, "crop_bottom");
1943 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1944 bound = tinfo->width / 2 - 2;
1945 widget = GHB_WIDGET (ud->builder, "crop_left");
1946 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1947 widget = GHB_WIDGET (ud->builder, "crop_right");
1948 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1949 if (ghb_settings_get_bool (ud->settings, "autocrop"))
1951 ghb_ui_update_int (ud, "crop_top", tinfo->crop[0]);
1952 ghb_ui_update_int (ud, "crop_bottom", tinfo->crop[1]);
1953 ghb_ui_update_int (ud, "crop_left", tinfo->crop[2]);
1954 ghb_ui_update_int (ud, "crop_right", tinfo->crop[3]);
1959 presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
1961 GtkTreeModel *store;
1965 gboolean sensitive = FALSE;
1966 ghb_title_info_t tinfo;
1968 g_debug("presets_list_selection_changed_cb ()\n");
1969 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1971 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1972 if (!ghb_presets_is_standard(preset))
1976 ud->dont_clear_presets = TRUE;
1977 // Temporarily set the video_quality range to (0,100)
1978 // This is needed so the video_quality value does not get
1979 // truncated when set. The range will be readjusted below
1980 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1981 gtk_range_set_range (GTK_RANGE(qp), 0, 100);
1982 ghb_set_preset(ud, preset);
1983 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1984 set_pref_audio(titleindex, ud);
1985 ud->dont_clear_presets = FALSE;
1986 if (ghb_get_title_info (&tinfo, titleindex))
1988 preset_update_title_deps(ud, &tinfo);
1990 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1993 ghb_vquality_range(ud, &vqmin, &vqmax);
1994 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1998 g_debug("No selection??? Perhaps unselected.\n");
2000 widget = GHB_WIDGET (ud->builder, "presets_remove");
2001 gtk_widget_set_sensitive(widget, sensitive);
2005 queue_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
2007 GtkTreeModel *store;
2008 GtkTreeIter iter, piter;
2010 g_debug("queue_list_selection_changed_cb ()\n");
2011 // A queue entry is made up of a parent and multiple
2012 // children that are visible when expanded. When and entry
2013 // is selected, I want the parent to be selected.
2014 // This is purely cosmetic.
2015 if (gtk_tree_selection_get_selected(selection, &store, &iter))
2017 if (gtk_tree_model_iter_parent (store, &piter, &iter))
2020 GtkTreeView *treeview;
2022 gtk_tree_selection_select_iter (selection, &piter);
2023 path = gtk_tree_model_get_path (store, &piter);
2024 treeview = gtk_tree_selection_get_tree_view (selection);
2025 // Make the parent visible in scroll window if it is not.
2026 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
2033 add_to_queue_list(signal_user_data_t *ud, job_settings_t *item)
2035 GtkTreeView *treeview;
2037 GtkTreeStore *store;
2043 g_debug("update_queue_list ()\n");
2044 if (item == NULL) return;
2045 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2046 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2048 gint title = ghb_settings_get_int(item->settings, "title");
2049 gint start_chapter = ghb_settings_get_int(item->settings, "start_chapter");
2050 gint end_chapter = ghb_settings_get_int(item->settings, "end_chapter");
2051 gboolean pass2 = ghb_settings_get_bool(item->settings, "two_pass");
2052 const gchar *vol_name = ghb_settings_get_string(item->settings, "volume_label");
2053 if (vol_name == NULL)
2054 vol_name = "No Title";
2055 info = g_strdup_printf
2057 "<big><b>%s</b></big> (Title %d, Chapters %d through %d, %d Video %s)",
2058 vol_name, title+1, start_chapter, end_chapter,
2059 pass2 ? 2:1, pass2 ? "Passes":"Pass");
2061 gtk_tree_store_append(store, &iter, NULL);
2062 gtk_tree_store_set(store, &iter, 0, "hb-queue-job", 1, info, 2, "hb-queue-delete", -1);
2065 const gchar *vcodec = ghb_settings_get_option(item->settings, "video_codec");
2066 const gchar *container = ghb_settings_get_option(item->settings, "container");
2067 const gchar *acodec = ghb_settings_get_option(item->settings, "audio_codec");
2068 const gchar *dest = ghb_settings_get_string(item->settings, "destination");
2069 const gchar *preset = ghb_settings_get_string(item->settings, "preset");
2070 info = g_strdup_printf
2072 "<b>Preset:</b> %s\n"
2073 "<b>Format:</b> %s Container, %s Video + %s Audio\n"
2074 "<b>Destination:</b> %s",
2075 preset, container, vcodec, acodec, dest);
2077 gtk_tree_store_append(store, &citer, &iter);
2078 gtk_tree_store_set(store, &citer, 1, info, -1);
2081 gint width = ghb_settings_get_int(item->settings, "scale_width");
2082 gint height = ghb_settings_get_int(item->settings, "scale_height");
2083 gboolean anamorphic = ghb_settings_get_bool(item->settings, "anamorphic");
2084 gboolean round_dim = ghb_settings_get_bool(item->settings, "round_dimensions");
2085 gboolean keep_aspect = ghb_settings_get_bool(item->settings, "keep_aspect");
2091 aspect_desc = "(Anamorphic)";
2095 aspect_desc = "(Strict Anamorphic)";
2102 aspect_desc = "(Aspect Preserved)";
2106 aspect_desc = "(Aspect Lost)";
2109 gboolean vqtype = ghb_settings_get_bool(item->settings, "vquality_type_constant");
2111 gchar *vq_desc = "Error";
2114 vqtype = ghb_settings_get_bool(item->settings, "vquality_type_target");
2117 // Has to be bitrate
2118 vqvalue = ghb_settings_get_int(item->settings, "video_bitrate");
2124 vqvalue = ghb_settings_get_int(item->settings, "video_target");
2131 vqvalue = ghb_settings_get_int(item->settings, "video_quality");
2132 vq_desc = "% Constant Quality";
2134 const gchar *fps = ghb_settings_get_string(item->settings, "framerate");
2135 const gchar *vcodec_abbr = ghb_settings_get_short_opt(item->settings, "video_codec");
2137 if (strcmp(vcodec_abbr, "x264") == 0)
2139 gchar *x264opts = ghb_build_x264opts_string(item->settings);
2140 g_debug("xopts (%s)\n", x264opts);
2141 extra_opts = g_strdup_printf ("\n<b>x264 Options:</b> %s", x264opts);
2146 extra_opts = g_strdup("");
2148 gboolean turbo = ghb_settings_get_bool (item->settings, "turbo");
2149 gchar *turbo_desc = "\n<b>Turbo:</b> Off";;
2152 turbo_desc = "\n<b>Turbo:</b> On";
2154 num_pass = pass2 ? 2 : 1;
2155 for (ii = 0; ii < num_pass; ii++)
2157 gboolean final = (ii == (num_pass - 1));
2158 GString *pass = g_string_new("");
2159 g_string_append_printf( pass,
2161 "<b>Picture:</b> %d x %d %s\n"
2162 "<b>Video:</b> %s, %d %s, %s fps"
2164 ii ? "2nd":"1st", width, height, aspect_desc,
2165 vcodec, vqvalue, vq_desc, fps,
2166 final ? extra_opts : turbo_desc);
2171 GSList *link = item->audio_settings;
2174 GHashTable *asettings = (GHashTable*)link->data;
2175 const gchar *acodec = ghb_settings_get_option(asettings, "audio_codec");
2176 const gchar *bitrate = ghb_settings_get_string(asettings, "audio_bitrate");
2177 const gchar *samplerate = ghb_settings_get_string(asettings, "audio_sample_rate");
2178 gint track = ghb_settings_get_int(asettings, "audio_track");
2179 const gchar *mix = ghb_settings_get_option(asettings, "audio_mix");
2180 g_string_append_printf(pass,
2181 "\n<b>Audio:</b> %s, %s kbps, %s kHz, Track %d: %s",
2182 acodec, bitrate, samplerate, track+1, mix);
2186 info = g_string_free(pass, FALSE);
2187 gtk_tree_store_append(store, &citer, &iter);
2188 gtk_tree_store_set(store, &citer, 0, ii ? "hb-queue-pass2" : "hb-queue-pass1", 1, info, -1);
2195 ghb_message_dialog(GtkMessageType type, const gchar *message, const gchar *no, const gchar *yes)
2198 GtkResponseType response;
2200 // Toss up a warning dialog
2201 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2202 type, GTK_BUTTONS_NONE,
2204 gtk_dialog_add_buttons( GTK_DIALOG(dialog),
2205 no, GTK_RESPONSE_NO,
2206 yes, GTK_RESPONSE_YES, NULL);
2207 response = gtk_dialog_run(GTK_DIALOG(dialog));
2208 gtk_widget_destroy (dialog);
2209 if (response == GTK_RESPONSE_NO)
2217 estimate_file_size(signal_user_data_t *ud)
2219 ghb_title_info_t tinfo;
2223 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2224 if (titleindex < 0) return 0;
2226 if (!ghb_get_title_info(&tinfo, titleindex)) return 0;
2227 duration = ((tinfo.hours*60)+tinfo.minutes)*60+tinfo.seconds;
2228 bitrate = ghb_guess_bitrate(ud->settings);
2229 size = (gint64)duration * (gint64)bitrate/8;
2233 #define DISK_FREE_THRESH (1024L*1024L*1024L*3)
2236 validate_settings(signal_user_data_t *ud)
2238 // Check to see if the dest file exists or is
2239 // already in the queue
2241 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2242 if (titleindex < 0) return FALSE;
2243 const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
2244 GSList *link = ud->queue;
2245 while (link != NULL)
2247 job_settings_t *item;
2248 const gchar *filename;
2249 item = (job_settings_t*)link->data;
2250 filename = ghb_settings_get_string(item->settings, "destination");
2251 if (strcmp(dest, filename) == 0)
2253 message = g_strdup_printf(
2254 "Destination: %s\n\n"
2255 "Another queued job has specified the same destination.\n"
2256 "Do you want to overwrite?",
2258 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
2268 gchar *destdir = g_path_get_dirname(dest);
2269 if (!g_file_test(destdir, G_FILE_TEST_IS_DIR))
2271 message = g_strdup_printf(
2272 "Destination: %s\n\n"
2273 "This is not a valid directory.",
2275 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2280 if (g_access(destdir, R_OK|W_OK) != 0)
2282 message = g_strdup_printf(
2283 "Destination: %s\n\n"
2284 "Can not read or write the directory.",
2286 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2294 gchar *resolved = ghb_resolve_symlink(destdir);
2296 gfile = g_file_new_for_path(resolved);
2297 info = g_file_query_filesystem_info(gfile,
2298 G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, NULL);
2301 if (g_file_info_has_attribute(info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE))
2303 size = g_file_info_get_attribute_uint64(info,
2304 G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
2306 gint64 fsize = estimate_file_size(ud);
2309 message = g_strdup_printf(
2310 "Destination filesystem is almost full: %uM free\n\n"
2311 "Encode may be incomplete if you proceed.\n",
2312 (guint)(size / (1024L*1024L)));
2313 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Proceed"))
2321 g_object_unref(info);
2323 g_object_unref(gfile);
2326 if (g_file_test(dest, G_FILE_TEST_EXISTS))
2328 message = g_strdup_printf(
2329 "Destination: %s\n\n"
2330 "File already exhists.\n"
2331 "Do you want to overwrite?",
2333 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
2341 // Validate video quality is in a reasonable range
2342 if (!ghb_validate_vquality(ud->settings))
2346 // Validate audio settings
2347 if (!ghb_validate_audio(ud))
2351 // Validate video settings
2352 if (!ghb_validate_video(ud))
2356 audio_list_refresh(ud);
2361 queue_add(signal_user_data_t *ud)
2363 // Add settings to the queue
2364 job_settings_t *queue_item;
2366 static gint unique_id = 0;
2368 g_debug("queue_add ()\n");
2369 if (!validate_settings(ud))
2373 // Make a copy of current settings to be used for the new job
2374 queue_item = g_malloc(sizeof(job_settings_t));
2375 queue_item->settings = ghb_settings_dup(ud->settings);
2376 queue_item->audio_settings = NULL;
2377 link = ud->audio_settings;
2378 while (link != NULL)
2380 GHashTable *asettings;
2381 asettings = ghb_settings_dup((GHashTable*)link->data);
2382 queue_item->audio_settings =
2383 g_slist_append(queue_item->audio_settings, asettings);
2384 link = g_slist_next(link);
2386 queue_item->chapter_list = g_strdupv(ud->chapter_list);
2387 ud->queue = g_slist_append(ud->queue, queue_item);
2388 add_to_queue_list(ud, queue_item);
2389 ghb_add_job (queue_item, unique_id);
2390 queue_item->unique_id = unique_id;
2391 queue_item->status = GHB_QUEUE_PENDING;
2397 queue_add_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
2399 g_debug("queue_add_clicked_cb ()\n");
2404 cancel_encode(const gchar *extra_msg)
2407 GtkResponseType response;
2409 if (extra_msg == NULL) extra_msg = "";
2410 // Toss up a warning dialog
2411 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2412 GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
2413 "%sYour movie will be lost if you don't continue encoding.",
2415 gtk_dialog_add_buttons( GTK_DIALOG(dialog),
2416 "Continue Encoding", GTK_RESPONSE_NO,
2417 "Stop Encoding", GTK_RESPONSE_YES, NULL);
2418 response = gtk_dialog_run(GTK_DIALOG(dialog));
2419 gtk_widget_destroy (dialog);
2420 if (response == GTK_RESPONSE_NO) return FALSE;
2426 queue_remove_clicked_cb(GtkWidget *widget, gchar *path, signal_user_data_t *ud)
2428 GtkTreeView *treeview;
2429 GtkTreePath *treepath;
2430 GtkTreeModel *store;
2435 job_settings_t *queue_item;
2438 g_debug("queue_remove_clicked_cb ()\n");
2439 g_debug("ud %p\n", ud);
2440 g_debug("ud->builder %p\n", ud->builder);
2442 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2443 store = gtk_tree_view_get_model(treeview);
2444 treepath = gtk_tree_path_new_from_string (path);
2445 if (gtk_tree_model_get_iter(store, &iter, treepath))
2447 // Find the entry in the queue
2448 indices = gtk_tree_path_get_indices (treepath);
2450 // Can only free the treepath After getting what I need from
2451 // indices since this points into treepath somewhere.
2452 gtk_tree_path_free (treepath);
2453 if (row < 0) return;
2454 link = g_slist_nth(ud->queue, row);
2455 if (link == NULL) return;
2456 queue_item = (job_settings_t*)link->data;
2457 if (queue_item->status == GHB_QUEUE_RUNNING)
2459 // Ask if wants to stop encode.
2460 if (!cancel_encode(NULL))
2465 // Remove the selected item
2466 g_debug(" should be removing from treestore\n");
2467 gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
2468 // Remove the corresponding item from the queue list
2469 ud->queue = g_slist_remove_link(ud->queue, link);
2470 g_slist_free_1(link);
2471 g_hash_table_destroy(queue_item->settings);
2472 link = queue_item->audio_settings;
2473 while (link != NULL)
2476 g_hash_table_destroy((GHashTable*)link->data);
2477 nextlink = g_slist_next(link);
2478 g_slist_free_1(link);
2481 g_strfreev (queue_item->chapter_list);
2482 unique_id = queue_item->unique_id;
2484 ghb_remove_job(unique_id);
2488 gtk_tree_path_free (treepath);
2493 find_queue_item(GSList *queue, gint unique_id, job_settings_t **job)
2498 while (queue != NULL)
2501 js = (job_settings_t*)queue->data;
2502 if (js->unique_id == unique_id)
2507 queue = queue->next;
2514 queue_buttons_grey(signal_user_data_t *ud, gboolean working)
2518 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2519 gboolean title_ok = (titleindex >= 0);
2520 widget = GHB_WIDGET (ud->builder, "queue_start1");
2521 gtk_widget_set_sensitive (widget, !working && title_ok);
2522 widget = GHB_WIDGET (ud->builder, "queue_start2");
2523 gtk_widget_set_sensitive (widget, !working && title_ok);
2524 action = GHB_ACTION (ud->builder, "queue_start_menu");
2525 gtk_action_set_sensitive (action, !working && title_ok);
2526 widget = GHB_WIDGET (ud->builder, "queue_pause1");
2527 gtk_widget_set_sensitive (widget, working);
2528 widget = GHB_WIDGET (ud->builder, "queue_pause2");
2529 gtk_widget_set_sensitive (widget, working);
2530 action = GHB_ACTION (ud->builder, "queue_pause_menu");
2531 gtk_action_set_sensitive (action, working);
2532 widget = GHB_WIDGET (ud->builder, "queue_stop");
2533 gtk_widget_set_sensitive (widget, working);
2534 action = GHB_ACTION (ud->builder, "queue_stop_menu");
2535 gtk_action_set_sensitive (action, working);
2538 void queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud);
2540 static gint autostart_timeout = -1;
2543 autostart_timer_cb(gpointer data)
2546 GtkProgressBar *progress;
2547 signal_user_data_t *ud = (signal_user_data_t*)data;
2549 if (autostart_timeout < 0) return FALSE;
2550 gchar *remaining = g_strdup_printf("Encoding will start in %d second%c",
2551 (autostart_timeout-1) / 40 + 1, autostart_timeout <= 40 ? ' ':'s');
2552 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "autostart_countdown"));
2553 gtk_progress_bar_set_fraction (progress, (gdouble)autostart_timeout / 800);
2554 gtk_progress_bar_set_text(progress, remaining);
2556 autostart_timeout--;
2557 if (autostart_timeout == 0)
2559 widget = GHB_WIDGET(ud->builder, "autostart_dialog");
2560 gtk_widget_hide(widget);
2561 queue_start_clicked_cb(NULL, ud);
2568 ghb_timer_cb(gpointer data)
2570 static gint ticks = 0;
2574 static gint current_id = -1;
2576 GtkTreeView *treeview;
2577 GtkTreeStore *store;
2579 static gint working = 0;
2580 static gboolean work_started = FALSE;
2582 signal_user_data_t *ud = (signal_user_data_t*)data;
2583 switch (ghb_backend_events (ud, &unique_id))
2585 case GHB_EVENT_WORKING:
2589 work_started = TRUE;
2590 queue_buttons_grey(ud, TRUE);
2592 if (unique_id != current_id)
2594 index = find_queue_item(ud->queue, current_id, &js);
2597 js->status = GHB_QUEUE_DONE;
2598 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2599 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2600 gchar *path = g_strdup_printf ("%d", index);
2601 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2603 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
2608 index = find_queue_item(ud->queue, unique_id, &js);
2611 js->status = GHB_QUEUE_RUNNING;
2612 current_id = unique_id;
2615 index = find_queue_item(ud->queue, unique_id, &js);
2618 gchar working_icon[] = "hb-working0";
2619 working_icon[10] = '0' + working;
2620 working = (working+1) % 6;
2621 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2622 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2623 gchar *path = g_strdup_printf ("%d", index);
2624 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2626 gtk_tree_store_set(store, &iter, 0, working_icon, -1);
2631 case GHB_EVENT_PAUSED:
2634 case GHB_EVENT_WORK_DONE:
2636 ud->state &= ~GHB_STATE_WORKING;
2637 work_started = FALSE;
2638 queue_buttons_grey(ud, FALSE);
2639 index = find_queue_item(ud->queue, current_id, &js);
2642 js->status = GHB_QUEUE_DONE;
2643 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2644 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2645 gchar *path = g_strdup_printf ("%d", index);
2646 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2648 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
2659 case GHB_EVENT_WORK_CANCELED:
2661 work_started = FALSE;
2662 queue_buttons_grey(ud, FALSE);
2663 index = find_queue_item(ud->queue, current_id, &js);
2666 js->status = GHB_QUEUE_CANCELED;
2667 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2668 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2669 gchar *path = g_strdup_printf ("%d", index);
2670 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2672 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
2678 case GHB_EVENT_SCAN_DONE:
2680 ghb_title_info_t tinfo;
2682 ud->state &= ~GHB_STATE_SCANNING;
2683 ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE);
2684 titleindex = ghb_longest_title();
2685 ghb_ui_update_int(ud, "title", titleindex);
2686 queue_buttons_grey(ud, FALSE);
2688 // Are there really any titles.
2689 if (ghb_get_title_info(&tinfo, titleindex))
2695 gint title = ghb_settings_get_int(ud->settings, "title");
2696 gint start_chapter = ghb_settings_get_int(ud->settings, "start_chapter");
2697 gint end_chapter = ghb_settings_get_int(ud->settings, "end_chapter");
2698 gboolean pass2 = ghb_settings_get_bool(ud->settings, "two_pass");
2699 const gchar *vol_name = ghb_settings_get_string(ud->settings, "volume_label");
2700 if (vol_name == NULL)
2701 vol_name = "No Title";
2702 const gchar *vcodec = ghb_settings_get_option(ud->settings, "video_codec");
2703 const gchar *container = ghb_settings_get_option(ud->settings, "container");
2704 const gchar *acodec = ghb_settings_get_option(ud->settings, "audio_codec");
2705 const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
2706 const gchar *preset = ghb_settings_get_string(ud->settings, "preset");
2707 gchar *info = g_strdup_printf
2709 "<big><b>%s</b></big> (Title %d, Chapters %d through %d, %d Video %s)"
2710 "\n<b>Preset:</b> %s"
2711 "\n<b>Format:</b> %s Container, %s Video + %s Audio"
2712 "\n<b>Destination:</b> %s",
2713 vol_name, title+1, start_chapter, end_chapter,
2714 pass2 ? 2:1, pass2 ? "Passes":"Pass",
2715 preset, container, vcodec, acodec, dest);
2717 widget = GHB_WIDGET (ud->builder, "autostart_summary");
2718 gtk_label_set_markup (GTK_LABEL(widget), info);
2720 widget = GHB_WIDGET(ud->builder, "autostart_dialog");
2721 gtk_widget_show_now(widget);
2722 g_timeout_add (25, autostart_timer_cb, (gpointer)ud);
2723 autostart_timeout = 800;
2728 GtkProgressBar *progress;
2729 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2730 gtk_progress_bar_set_fraction (progress, 0);
2731 gtk_progress_bar_set_text (progress, "No Source");
2738 work_started = FALSE;
2739 queue_buttons_grey(ud, FALSE);
2743 if (update_default_destination)
2745 const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
2746 gchar *dest_dir = g_path_get_dirname (dest);
2747 const gchar *def_dest = ghb_settings_get_string(ud->settings, "destination_dir");
2748 if (strcmp(dest_dir, def_dest) != 0)
2750 ghb_settings_set_string (ud->settings, "destination_dir", dest_dir);
2751 ghb_prefs_save (ud->settings);
2753 update_default_destination = FALSE;
2757 set_preview_image (ud);
2758 update_preview = FALSE;
2760 if (ticks == 3 && ghb_autostart)
2762 // Make sure this doesn't happen twice
2763 const gchar *source = ghb_settings_get_string(ud->settings, "source");
2764 if (update_source_label(ud, source))
2766 GtkProgressBar *progress;
2767 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2768 const gchar *path = ghb_settings_get_string( ud->settings, "source");
2769 gtk_progress_bar_set_fraction (progress, 0);
2770 gtk_progress_bar_set_text (progress, "Scanning ...");
2771 ud->state |= GHB_STATE_SCANNING;
2772 ghb_backend_scan (path, 0);
2780 autostart_ok_cb(GtkWidget *widget, signal_user_data_t *ud)
2782 widget = GHB_WIDGET(ud->builder, "autostart_dialog");
2783 gtk_widget_hide(widget);
2784 queue_start_clicked_cb(NULL, ud);
2785 autostart_timeout = -1;
2789 autostart_cancel_cb(GtkWidget *widget, signal_user_data_t *ud)
2791 widget = GHB_WIDGET(ud->builder, "autostart_dialog");
2792 gtk_widget_hide(widget);
2793 autostart_timeout = -1;
2797 ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
2801 GtkTextView *textview;
2802 GtkTextBuffer *buffer;
2804 GError *gerror = NULL;
2807 signal_user_data_t *ud = (signal_user_data_t*)data;
2809 status = g_io_channel_read_line (source, &text, &length, NULL, &gerror);
2812 textview = GTK_TEXT_VIEW(GHB_WIDGET (ud->builder, "activity_view"));
2813 buffer = gtk_text_view_get_buffer (textview);
2814 mark = gtk_text_buffer_get_insert (buffer);
2815 gtk_text_view_scroll_mark_onscreen(textview, mark);
2816 gtk_text_buffer_insert_at_cursor (buffer, text, -1);
2817 g_io_channel_write_chars (ud->activity_log, text, length, &length, NULL);
2820 if (status != G_IO_STATUS_NORMAL)
2822 // This should never happen, but if it does I would get into an
2823 // infinite loop. Returning false removes this callback.
2824 g_warning("Error while reading activity from pipe\n");
2827 g_warning("%s\n", gerror->message);
2828 g_error_free (gerror);
2833 g_error_free (gerror);
2838 about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2840 GtkWidget *widget = GHB_WIDGET (ud->builder, "hb_about");
2841 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(widget), ghb_version());
2842 gtk_widget_show (widget);
2846 guide_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2850 {"xdg-open","http://trac.handbrake.fr/wiki/HandBrakeGuide",NULL,NULL};
2851 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2855 argv[0] = "gnome-open";
2856 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2860 argv[0] = "kfmclient";
2862 argv[2] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2863 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2867 argv[0] = "firefox";
2868 argv[1] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2870 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2876 hb_about_response_cb(GtkWidget *widget, gint response, signal_user_data_t *ud)
2878 gtk_widget_hide (widget);
2882 show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2884 GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
2885 gtk_widget_show (widget);
2889 show_queue_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2891 GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
2892 gtk_widget_show (widget);
2896 show_presets_toggled_cb(GtkToggleButton *button, signal_user_data_t *ud)
2899 GtkWindow *hb_window;
2901 g_debug("show_presets_clicked_cb ()\n");
2902 widget = GHB_WIDGET (ud->builder, "presets_frame");
2903 if (gtk_toggle_button_get_active(button))
2905 gtk_widget_show_now(widget);
2909 gtk_widget_hide(widget);
2910 hb_window = GTK_WINDOW(GHB_WIDGET (ud->builder, "hb_window"));
2911 gtk_window_resize(hb_window, 16, 16);
2913 ghb_widget_to_setting(ud->settings, GTK_WIDGET(button));
2914 ghb_prefs_save(ud->settings);
2918 presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
2920 GtkTreeView *treeview;
2921 GtkTreeSelection *selection;
2922 GtkTreeModel *store;
2925 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
2926 selection = gtk_tree_view_get_selection(treeview);
2927 if (gtk_tree_selection_get_selected(selection, &store, &iter))
2930 path = gtk_tree_model_get_path (store, &iter);
2931 // Make the parent visible in scroll window if it is not.
2932 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
2938 update_chapter_list(signal_user_data_t *ud)
2940 GtkTreeView *treeview;
2942 GtkListStore *store;
2945 gint titleindex, ii;
2947 g_debug("update_chapter_list ()\n");
2948 titleindex = ghb_settings_get_index(ud->settings, "title");
2949 chapters = ghb_get_chapters(titleindex);
2950 if (ud->chapter_list != NULL)
2951 g_strfreev (ud->chapter_list);
2952 ud->chapter_list = chapters;
2954 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
2955 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
2957 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
2961 if (chapters != NULL && chapters[ii])
2963 // Update row with settings data
2964 g_debug("Updating row\n");
2965 gtk_list_store_set(store, &iter,
2971 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
2975 // No more settings data, remove row
2976 g_debug("Removing row\n");
2977 done = !gtk_list_store_remove(store, &iter);
2981 while (chapters != NULL && chapters[ii])
2983 // Additional settings, add row
2984 g_debug("Adding row\n");
2985 g_debug("%d -- %s\n", ii, chapters[ii]);
2986 gtk_list_store_append(store, &iter);
2987 gtk_list_store_set(store, &iter,
2997 chapter_edited_cb(GtkCellRendererText *cell, gchar *path, gchar *text, signal_user_data_t *ud)
2999 GtkTreePath *treepath;
3000 GtkListStore *store;
3001 GtkTreeView *treeview;
3002 GtkTreeViewColumn *column;
3006 g_debug("chapter_edited_cb ()\n");
3007 g_debug("path (%s)\n", path);
3008 g_debug("text (%s)\n", text);
3009 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
3010 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
3011 treepath = gtk_tree_path_new_from_string (path);
3012 gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
3013 gtk_tree_path_free (treepath);
3014 gtk_list_store_set(store, &iter,
3018 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &index, -1);
3019 g_free(ud->chapter_list[index-1]);
3020 ud->chapter_list[index-1] = g_strdup(text);
3021 if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
3023 column = gtk_tree_view_get_column(treeview, 1);
3024 treepath = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
3025 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
3026 gtk_tree_path_free (treepath);
3031 chapter_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
3033 GtkTreeModel *store;
3036 g_debug("chapter_list_selection_changed_cb ()\n");
3037 if (gtk_tree_selection_get_selected(selection, &store, &iter))
3044 queue_list_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, GtkCellRenderer *cell)
3046 GtkTreeViewColumn *column;
3049 column = gtk_tree_view_get_column (GTK_TREE_VIEW(widget), 0);
3050 width = gtk_tree_view_column_get_width(column);
3051 g_debug("col width %d alloc width %d\n", width, allocation->width);
3052 // Set new wrap-width. Shave a little off to accomidate the icons
3053 // that share this column.
3054 if (width >= 564) // Don't allow below a certain size
3055 g_object_set(cell, "wrap-width", width-70, NULL);
3059 preview_button_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3061 gint titleindex = ghb_settings_get_int(ud->settings, "title");
3062 if (titleindex < 0) return;
3063 g_debug("titleindex %d\n", titleindex);
3065 GtkWidget *widget = GHB_WIDGET (ud->builder, "preview_window");
3066 gtk_widget_show (widget);
3070 preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3072 set_preview_image(ud);
3076 preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
3078 g_debug("-------------------------------allocate %d x %d\n", allocation->width, allocation->height);
3079 if (preview_button_width == allocation->width &&
3080 preview_button_height == allocation->height)
3082 // Nothing to do. Bug out.
3083 g_debug("nothing to do\n");
3086 g_debug("-------------------------------prev allocate %d x %d\n", preview_button_width, preview_button_height);
3087 preview_button_width = allocation->width;
3088 preview_button_height = allocation->height;
3089 set_preview_image(ud);
3093 queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3095 GSList *link = ud->queue;
3096 job_settings_t *job;
3097 gboolean running = FALSE;
3098 while (link != NULL)
3100 job = (job_settings_t*)link->data;
3101 if ((job->status == GHB_QUEUE_RUNNING) ||
3102 (job->status == GHB_QUEUE_PENDING))
3111 // The queue has no running or pending jobs.
3112 // Add current settings to the queue, then run.
3116 ud->state |= GHB_STATE_WORKING;
3121 queue_stop_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3123 cancel_encode(NULL);
3127 queue_pause_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3133 presets_default_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3135 ghb_set_preset_default(ud->settings);
3136 ghb_presets_list_update(ud);
3140 debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data)
3142 signal_user_data_t *ud = (signal_user_data_t*)data;
3146 printf("%s: %s\n", domain, msg);
3151 set_visible(GtkWidget *widget, gboolean visible)
3155 gtk_widget_show_now(widget);
3159 gtk_widget_hide(widget);
3164 ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
3167 g_debug("ghb_hbfd\n");
3168 widget = GHB_WIDGET(ud->builder, "queue_pause1");
3169 set_visible(widget, !hbfd);
3170 widget = GHB_WIDGET(ud->builder, "queue_add");
3171 set_visible(widget, !hbfd);
3172 widget = GHB_WIDGET(ud->builder, "show_queue");
3173 set_visible(widget, !hbfd);
3174 widget = GHB_WIDGET(ud->builder, "show_activity");
3175 set_visible(widget, !hbfd);
3177 widget = GHB_WIDGET(ud->builder, "chapter_box");
3178 set_visible(widget, !hbfd);
3179 widget = GHB_WIDGET(ud->builder, "container_box");
3180 set_visible(widget, !hbfd);
3181 widget = GHB_WIDGET(ud->builder, "settings_box");
3182 set_visible(widget, !hbfd);
3183 widget = GHB_WIDGET(ud->builder, "presets_save");
3184 set_visible(widget, !hbfd);
3185 widget = GHB_WIDGET(ud->builder, "presets_remove");
3186 set_visible(widget, !hbfd);
3187 widget = GHB_WIDGET(ud->builder, "presets_default");
3188 set_visible(widget, !hbfd);
3189 widget = GHB_WIDGET (ud->builder, "hb_window");
3190 gtk_window_resize(GTK_WINDOW(widget), 16, 16);
3195 hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
3197 g_debug("hbfd_toggled_cb\n");
3198 ghb_widget_to_setting (ud->settings, widget);
3199 gboolean hbfd = ghb_settings_get_bool(ud->settings, "hbfd");
3201 ghb_prefs_save(ud->settings);
3205 pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3207 g_debug("pref_changed_cb\n");
3208 ghb_widget_to_setting (ud->settings, widget);
3209 ghb_prefs_save(ud->settings);
3213 ghb_file_menu_add_dvd(signal_user_data_t *ud)
3215 GList *link, *drives;
3217 GtkActionGroup *agroup = GTK_ACTION_GROUP(
3218 gtk_builder_get_object(ud->builder, "actiongroup1"));
3219 GtkUIManager *ui = GTK_UI_MANAGER(
3220 gtk_builder_get_object(ud->builder, "uimanager1"));
3221 guint merge_id = gtk_ui_manager_new_merge_id(ui);
3223 link = drives = dvd_device_list();
3224 while (link != NULL)
3226 gchar *name = (gchar*)link->data;
3227 // Create action for this drive
3228 GtkAction *action = gtk_action_new(name, name,
3229 "Scan this DVD source", "gtk-cdrom");
3230 // Add action to action group
3231 gtk_action_group_add_action_with_accel(agroup, action, "");
3232 // Add to ui manager
3233 gtk_ui_manager_add_ui(ui, merge_id,
3234 "ui/menubar1/menuitem1/quit1", name, name,
3235 GTK_UI_MANAGER_AUTO, TRUE);
3236 // Connect signal to action (menu item)
3237 g_signal_connect(action, "activate",
3238 (GCallback)dvd_source_activate_cb, ud);
3242 g_list_free(drives);
3245 gtk_ui_manager_add_ui(ui, merge_id,
3246 "ui/menubar1/menuitem1/quit1", "", NULL,
3247 GTK_UI_MANAGER_AUTO, TRUE);
3250 gboolean ghb_is_cd(GDrive *gd);
3255 GVolumeMonitor *gvm;
3256 GList *drives, *link;
3257 GList *dvd_devices = NULL;
3259 gvm = g_volume_monitor_get ();
3260 drives = g_volume_monitor_get_connected_drives (gvm);
3262 while (link != NULL)
3266 gd = (GDrive*)link->data;
3270 device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3271 dvd_devices = g_list_append(dvd_devices, (gpointer)device);
3273 g_object_unref (gd);
3276 g_list_free(drives);
3281 static DBusConnection *dbus_connection = NULL;
3282 static LibHalContext *hal_ctx;
3285 ghb_is_cd(GDrive *gd)
3288 LibHalDrive *halDrive;
3289 LibHalDriveType dtype;
3291 device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3292 halDrive = libhal_drive_from_device_file (hal_ctx, device);
3293 dtype = libhal_drive_get_type(halDrive);
3295 return (dtype == LIBHAL_DRIVE_TYPE_CDROM);
3299 drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
3303 if (ud->current_dvd_device == NULL) return;
3304 if (ud->state != GHB_STATE_IDLE) return;
3305 device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3307 // DVD insertion detected. Scan it.
3308 if (strcmp(device, ud->current_dvd_device) == 0)
3310 if (g_drive_has_media (gd))
3312 GtkProgressBar *progress;
3313 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
3314 gtk_progress_bar_set_text (progress, "Scanning ...");
3315 gtk_progress_bar_set_fraction (progress, 0);
3316 update_source_label(ud, device);
3317 ud->state |= GHB_STATE_SCANNING;
3318 ghb_backend_scan(device, 0);
3322 ud->state |= GHB_STATE_SCANNING;
3323 ghb_backend_scan("/dev/null", 0);
3335 if (dbus_connection != NULL)
3338 dbus_error_init (&error);
3339 if (!(dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) {
3340 g_debug ("could not get system bus: %s\n", error.message);
3341 dbus_error_free (&error);
3345 //dbus_connection_setup_with_g_main (dbus_connection, NULL);
3346 //dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
3347 //dbus_connection_add_filter (dbus_connection, gvm_dbus_filter_function, NULL, NULL);
3362 if (!(hal_ctx = libhal_ctx_new ())) {
3363 g_warning ("failed to create a HAL context!");
3367 libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
3368 dbus_error_init (&error);
3369 if (!libhal_ctx_init (hal_ctx, &error)) {
3370 g_warning ("libhal_ctx_init failed: %s", error.message ? error.message : "unknown");
3371 dbus_error_free (&error);
3372 libhal_ctx_free (hal_ctx);
3377 * Do something to ping the HAL daemon - the above functions will
3378 * succeed even if hald is not running, so long as DBUS is. But we
3379 * want to exit silently if hald is not running, to behave on
3382 if (!(devices = libhal_get_all_devices (hal_ctx, &nr, &error))) {
3383 g_warning ("seems that HAL is not running: %s", error.message ? error.message : "unknown");
3384 dbus_error_free (&error);
3386 libhal_ctx_shutdown (hal_ctx, NULL);
3387 libhal_ctx_free (hal_ctx);
3391 libhal_free_string_array (devices);
3393 //gvm_hal_claim_branch ("/org/freedesktop/Hal/devices/local");