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 static void update_chapter_list(signal_user_data_t *ud);
33 static void clear_audio_list(signal_user_data_t *ud);
34 static GList* dvd_device_list();
35 static gboolean cancel_encode();
36 static void audio_list_refresh_selected(signal_user_data_t *ud);
37 static GHashTable* get_selected_asettings(signal_user_data_t *ud);
39 // This is a dependency map used for greying widgets
40 // that are dependent on the state of another widget.
41 // The enable_value comes from the values that are
42 // obtained from ghb_widget_value(). For combo boxes
43 // you will have to look further to combo box options
44 // maps in hb-backend.c
47 const gchar *widget_name;
48 const gchar *dep_name;
49 const gchar *enable_value;
50 const gboolean disable_if_equal;
53 static dependency_t dep_map[] =
55 {"title", "queue_add", "none", TRUE},
56 {"title", "queue_add_menu", "none", TRUE},
57 {"title", "preview_button", "none", TRUE},
58 {"title", "show_preview_menu", "none", TRUE},
59 {"title", "preview_frame", "none", TRUE},
60 {"title", "picture_label", "none", TRUE},
61 {"title", "picture_tab", "none", TRUE},
62 {"title", "chapters_label", "none", TRUE},
63 {"title", "chapters_tab", "none", TRUE},
64 {"title", "title", "none", TRUE},
65 {"title", "start_chapter", "none", TRUE},
66 {"title", "end_chapter", "none", TRUE},
67 {"vquality_type_bitrate", "video_bitrate", "enable", FALSE},
68 {"vquality_type_target", "video_target_size", "enable", FALSE},
69 {"vquality_type_constant", "video_quality", "enable", FALSE},
70 {"vquality_type_constant", "constant_rate_factor", "enable", FALSE},
71 {"vquality_type_constant", "two_pass", "enable", TRUE},
72 {"vquality_type_constant", "turbo", "enable", TRUE},
73 {"two_pass", "turbo", "enable", FALSE},
74 {"container", "large_mp4", "mp4|m4v", FALSE},
75 {"container", "http_optimize_mp4", "mp4|m4v", FALSE},
76 {"container", "ipod_file", "mp4|m4v", FALSE},
77 {"container", "variable_frame_rate", "avi", TRUE},
78 {"variable_frame_rate", "framerate", "enable", TRUE},
79 {"variable_frame_rate", "detelecine", "enable", TRUE},
80 {"decomb", "deinterlace", "enable", TRUE},
81 {"autocrop", "crop_top", "disable", FALSE},
82 {"autocrop", "crop_bottom", "disable", FALSE},
83 {"autocrop", "crop_left", "disable", FALSE},
84 {"autocrop", "crop_right", "disable", FALSE},
85 {"autoscale", "scale_width", "disable", FALSE},
86 {"autoscale", "scale_height", "disable", FALSE},
87 {"anamorphic", "keep_aspect", "disable", FALSE},
88 {"anamorphic", "scale_height", "disable", FALSE},
89 {"keep_aspect", "scale_height", "disable", FALSE},
90 {"video_codec", "x264_tab", "x264", FALSE},
91 {"video_codec", "x264_tab_label", "x264", FALSE},
92 {"video_codec", "ipod_file", "x264", FALSE},
93 {"audio_codec", "audio_bitrate", "ac3", TRUE},
94 {"audio_codec", "audio_rate", "ac3", TRUE},
95 {"audio_codec", "audio_mix", "ac3", TRUE},
96 {"audio_codec", "audio_drc", "ac3", TRUE},
97 {"x264_bframes", "x264_weighted_bframes", "0", TRUE},
98 {"x264_bframes", "x264_brdo", "0", TRUE},
99 {"x264_bframes", "x264_bime", "0", TRUE},
100 {"x264_bframes", "x264_bpyramid", "<2", TRUE},
101 {"x264_bframes", "x264_direct", "0", TRUE},
102 {"x264_refs", "x264_mixed_refs", "<2", TRUE},
103 {"x264_cabac", "x264_trellis", "enable", FALSE},
104 {"x264_subme", "x264_brdo", "<6", TRUE},
105 {"x264_analyse", "x264_direct", "none", TRUE},
106 {"x264_me", "x264_merange", "umh|esa", FALSE},
107 {"chapter_markers", "chapters_list", "enable", FALSE},
111 dep_check(signal_user_data_t *ud, const gchar *name)
116 int count = sizeof(dep_map) / sizeof(dependency_t);
117 gboolean result = TRUE;
119 g_debug("dep_check () %s\n", name);
120 for (ii = 0; ii < count; ii++)
122 if (strcmp(dep_map[ii].dep_name, name) == 0)
124 widget = GHB_WIDGET(ud->builder, dep_map[ii].widget_name);
125 dep_object = gtk_builder_get_object(ud->builder, dep_map[ii].dep_name);
126 if (dep_object == NULL)
128 g_message("Failed to find widget\n");
134 gchar **values = g_strsplit(dep_map[ii].enable_value, "|", 10);
135 gboolean sensitive = FALSE;
138 value = ghb_widget_short_opt(widget);
140 value = g_strdup( ghb_settings_get_short_opt(
141 ud->settings, dep_map[ii].widget_name));
142 while (values && values[jj])
144 if (values[jj][0] == '>')
146 gdouble dbl = g_strtod (&values[jj][1], NULL);
147 gdouble dvalue = ghb_widget_dbl (widget);
154 else if (values[jj][0] == '<')
156 gdouble dbl = g_strtod (&values[jj][1], NULL);
157 gdouble dvalue = ghb_widget_dbl (widget);
164 if (strcmp(values[jj], value) == 0)
171 sensitive = dep_map[ii].disable_if_equal ^ sensitive;
172 if (!sensitive) result = FALSE;
182 check_depencency(signal_user_data_t *ud, GtkWidget *widget)
187 int count = sizeof(dep_map) / sizeof(dependency_t);
189 if (ghb_widget_index(widget) < 0) return;
190 name = gtk_widget_get_name(widget);
191 g_debug("check_depencency () %s\n", name);
192 for (ii = 0; ii < count; ii++)
194 if (strcmp(dep_map[ii].widget_name, name) == 0)
198 dep_object = gtk_builder_get_object (ud->builder, dep_map[ii].dep_name);
199 if (dep_object == NULL)
201 g_message("Failed to find dependent widget %s\n", dep_map[ii].dep_name);
204 sensitive = dep_check(ud, dep_map[ii].dep_name);
205 if (GTK_IS_ACTION(dep_object))
206 gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
208 gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
214 ghb_check_all_depencencies(signal_user_data_t *ud)
218 int count = sizeof(dep_map) / sizeof(dependency_t);
220 g_debug("ghb_check_all_depencencies ()\n");
221 for (ii = 0; ii < count; ii++)
224 dep_object = gtk_builder_get_object (ud->builder, dep_map[ii].dep_name);
225 if (dep_object == NULL)
227 g_message("Failed to find dependent widget %s\n", dep_map[ii].dep_name);
230 sensitive = dep_check(ud, dep_map[ii].dep_name);
231 if (GTK_IS_ACTION(dep_object))
232 gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
234 gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
239 clear_presets_selection(signal_user_data_t *ud)
241 GtkTreeView *treeview;
242 GtkTreeSelection *selection;
244 if (ud->dont_clear_presets) return;
245 g_debug("clear_presets_selection()\n");
246 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
247 selection = gtk_tree_view_get_selection (treeview);
248 gtk_tree_selection_unselect_all (selection);
252 expand_tilde(const gchar *path)
254 const gchar *user_home;
257 gchar *expanded_path = NULL;
259 g_debug("expand_tilde ()\n");
262 user_home = g_get_home_dir();
263 home = NULL; // squash warning about home uninitialized
266 home = g_strdup(user_home);
269 else if (path[1] == '/')
271 home = g_strdup(user_home);
276 home = g_path_get_dirname(user_home);
279 expanded_path = g_strdup_printf("%s/%s", home, suffix);
282 return expanded_path;
286 on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud)
288 gint state = ghb_get_state();
289 g_debug("on_quit1_activate ()\n");
290 if (state & GHB_STATE_WORKING)
292 if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
294 ghb_hb_cleanup(FALSE);
300 ghb_hb_cleanup(FALSE);
305 set_destination(signal_user_data_t *ud)
307 if (ghb_settings_get_bool(ud->settings, "use_source_name"))
309 const gchar *vol_name, *filename, *extension;
310 gchar *dir, *new_name;
312 filename = ghb_settings_get_string(ud->settings, "destination");
313 extension = ghb_settings_get_string(ud->settings, "container");
314 dir = g_path_get_dirname (filename);
315 vol_name = ghb_settings_get_string(ud->settings, "volume_label");
316 g_debug("volume_label (%s)\n", vol_name);
317 if (vol_name == NULL)
319 vol_name = "new_video";
321 new_name = g_strdup_printf("%s/%s.%s", dir, vol_name, extension);
322 ghb_ui_update(ud, "destination", new_name);
329 uppers_and_unders(const gchar *str)
331 if (str == NULL) return FALSE;
338 if (*str >= 'a' && *str <= 'z')
354 camel_convert(gchar *str)
356 gint state = CAMEL_OTHER;
358 if (str == NULL) return;
361 if (*str == '_') *str = ' ';
366 if (*str >= 'A' && *str <= 'Z')
367 state = CAMEL_FIRST_UPPER;
372 case CAMEL_FIRST_UPPER:
374 if (*str >= 'A' && *str <= 'Z')
375 *str = *str - 'A' + 'a';
385 update_source_label(signal_user_data_t *ud, const gchar *source)
390 gchar *filename = g_strdup(source);
392 len = strlen(filename);
393 if (filename[len-1] == '/') filename[len-1] = 0;
394 if (g_file_test(filename, G_FILE_TEST_IS_DIR))
396 path = g_strsplit(filename, "/", -1);
397 len = g_strv_length (path);
398 if ((len > 1) && (strcmp("VIDEO_TS", path[len-1]) == 0))
400 label = g_strdup(path[len-2]);
404 label = g_strdup(path[len-1]);
410 // Is regular file or block dev.
411 // Check to see if it is a dvd image
412 label = ghb_dvd_volname (filename);
415 path = g_strsplit(filename, "/", -1);
416 len = g_strv_length (path);
417 // Just use the last combonent of the path
418 label = g_strdup(path[len-1]);
423 if (uppers_and_unders(label))
425 camel_convert(label);
430 GtkWidget *widget = GHB_WIDGET (ud->builder, "source_title");
433 gtk_label_set_text (GTK_LABEL(widget), label);
434 ghb_settings_set_string(ud->settings, "volume_label", label);
440 label = "No Title Found";
441 gtk_label_set_text (GTK_LABEL(widget), label);
442 ghb_settings_set_string(ud->settings, "volume_label", label);
448 static GtkWidget *dvd_device_combo = NULL;
451 chooser_file_selected_cb(GtkFileChooser *dialog, GtkComboBox *combo)
453 const gchar *name = gtk_file_chooser_get_filename (dialog);
457 gboolean foundit = FALSE;
459 if (name == NULL) return;
460 store = gtk_combo_box_get_model(combo);
461 if (gtk_tree_model_get_iter_first(store, &iter))
465 gtk_tree_model_get(store, &iter, 0, &device, -1);
466 if (strcmp(name, device) == 0)
471 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
474 gtk_combo_box_set_active_iter (combo, &iter);
476 gtk_combo_box_set_active (combo, 0);
480 dvd_device_changed_cb(GtkComboBox *combo, GtkWidget *dialog)
482 gint ii = gtk_combo_box_get_active (combo);
485 const gchar *device = gtk_combo_box_get_active_text (combo);
486 const gchar *name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog));
487 if (name == NULL || strcmp(name, device) != 0)
488 gtk_file_chooser_select_filename (GTK_FILE_CHOOSER(dialog), device);
494 source_type_changed_cb(GtkToggleButton *toggle, GtkFileChooser *chooser)
498 g_debug("source_type_changed_cb ()\n");
499 if (gtk_toggle_button_get_active (toggle))
501 filename = gtk_file_chooser_get_filename (chooser);
502 gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
503 if (filename != NULL)
505 gtk_file_chooser_set_filename(chooser, filename);
508 gtk_widget_set_sensitive (dvd_device_combo, FALSE);
509 gtk_combo_box_set_active (GTK_COMBO_BOX(dvd_device_combo), 0);
513 filename = gtk_file_chooser_get_filename (chooser);
514 gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_OPEN);
515 if (filename != NULL)
517 gtk_file_chooser_set_filename(chooser, filename);
520 gtk_widget_set_sensitive (dvd_device_combo, TRUE);
525 source_dialog_extra_widgets(GtkWidget *dialog, gboolean checkbutton_active)
528 GtkWidget *checkbutton;
530 vbox = GTK_BOX(gtk_vbox_new (FALSE, 2));
531 checkbutton = gtk_check_button_new_with_label ("Open VIDEO_TS folder");
532 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), checkbutton_active);
533 gtk_box_pack_start (vbox, checkbutton, FALSE, FALSE, 1);
534 gtk_widget_show(checkbutton);
538 GList *drives, *link;
539 GtkWidget *label, *blank;
541 hbox = GTK_BOX(gtk_hbox_new (FALSE, 2));
542 combo = gtk_combo_box_new_text();
543 label = gtk_label_new("Detected DVD devices:");
544 blank = gtk_label_new("");
545 link = drives = dvd_device_list();
546 gtk_combo_box_append_text (GTK_COMBO_BOX(combo), "Not Selected");
549 gchar *name = (gchar*)link->data;
550 gtk_combo_box_append_text (GTK_COMBO_BOX(combo), name);
555 gtk_combo_box_set_active (GTK_COMBO_BOX(combo), 0);
556 gtk_box_pack_start (vbox, GTK_WIDGET(hbox), FALSE, FALSE, 1);
557 gtk_widget_show(GTK_WIDGET(hbox));
558 gtk_box_pack_start (hbox, label, FALSE, FALSE, 1);
559 gtk_widget_show(label);
560 gtk_box_pack_start (hbox, combo, FALSE, FALSE, 2);
561 gtk_widget_show(combo);
562 gtk_box_pack_start (hbox, blank, TRUE, TRUE, 1);
563 gtk_widget_show(blank);
565 // Ugly hackish global alert
566 dvd_device_combo = combo;
567 g_signal_connect(combo, "changed", (GCallback)dvd_device_changed_cb, dialog);
568 g_signal_connect(dialog, "selection-changed", (GCallback)chooser_file_selected_cb, combo);
570 g_signal_connect(checkbutton, "toggled", (GCallback)source_type_changed_cb, dialog);
571 return GTK_WIDGET(vbox);
575 do_scan(signal_user_data_t *ud, const gchar *filename)
577 if (filename != NULL)
579 ghb_settings_set_string(ud->settings, "source", filename);
580 if (update_source_label(ud, filename))
582 GtkProgressBar *progress;
583 progress = GTK_PROGRESS_BAR(GHB_WIDGET(ud->builder, "progressbar"));
585 path = ghb_settings_get_string( ud->settings, "source");
586 gtk_progress_bar_set_fraction (progress, 0);
587 gtk_progress_bar_set_text (progress, "Scanning ...");
588 ghb_hb_cleanup(TRUE);
589 ghb_backend_scan (path, 0);
593 // TODO: error dialog
599 source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
603 const gchar *sourcename;
605 GtkFileChooserAction action;
606 gboolean checkbutton_active;
608 g_debug("source_browse_clicked_cb ()\n");
609 sourcename = ghb_settings_get_string(ud->settings, "source");
610 checkbutton_active = FALSE;
611 if (g_file_test(sourcename, G_FILE_TEST_IS_DIR))
613 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
614 checkbutton_active = TRUE;
618 action = GTK_FILE_CHOOSER_ACTION_OPEN;
620 dialog = gtk_file_chooser_dialog_new ("Select Source",
623 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
624 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
626 widget = source_dialog_extra_widgets(dialog, checkbutton_active);
627 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), widget);
628 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), sourcename);
629 response = gtk_dialog_run(GTK_DIALOG (dialog));
630 gtk_widget_hide(dialog);
631 if (response == GTK_RESPONSE_ACCEPT)
635 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
636 if (filename != NULL)
638 do_scan(ud, filename);
639 if (strcmp(sourcename, filename) != 0)
641 ghb_settings_set_string (ud->settings, "default_source", filename);
642 ghb_pref_save (ud->settings, "default_source");
643 ghb_dvd_set_current (filename, ud);
648 gtk_widget_destroy(dialog);
652 dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
654 const gchar *filename;
655 const gchar *sourcename;
657 sourcename = ghb_settings_get_string(ud->settings, "source");
658 filename = gtk_action_get_name(action);
659 do_scan(ud, filename);
660 if (strcmp(sourcename, filename) != 0)
662 ghb_settings_set_string (ud->settings, "default_source", filename);
663 ghb_pref_save (ud->settings, "default_source");
664 ghb_dvd_set_current (filename, ud);
669 update_destination_extension(signal_user_data_t *ud)
671 static gchar *containers[] = {".mkv", ".mp4", ".m4v", ".avi", ".ogm", NULL};
673 const gchar *extension;
677 g_debug("update_destination_extension ()\n");
678 extension = ghb_settings_get_string(ud->settings, "container");
679 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "destination"));
680 filename = g_strdup(gtk_entry_get_text(entry));
681 for (ii = 0; containers[ii] != NULL; ii++)
683 if (g_str_has_suffix(filename, containers[ii]))
688 pos = g_strrstr( filename, "." );
691 // No period? shouldn't happen
695 if (strcmp(extension, &pos[1]) == 0)
697 // Extension is already correct
700 new_name = g_strjoin(".", filename, extension, NULL);
701 ghb_ui_update(ud, "destination", new_name);
709 static gboolean update_default_destination = FALSE;
712 destination_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
716 g_debug("destination_entry_changed_cb ()\n");
717 if ((dest = expand_tilde(gtk_entry_get_text(entry))) != NULL)
719 gtk_entry_set_text(entry, dest);
722 update_destination_extension(ud);
723 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
724 // This signal goes off with ever keystroke, so I'm putting this
725 // update on the timer.
726 update_default_destination = TRUE;
730 destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
734 const char *destname;
737 g_debug("destination_browse_clicked_cb ()\n");
738 destname = ghb_settings_get_string(ud->settings, "destination");
739 dialog = gtk_file_chooser_dialog_new ("Choose Destination",
741 GTK_FILE_CHOOSER_ACTION_SAVE,
742 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
743 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
745 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), destname);
746 basename = g_path_get_basename(destname);
747 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
749 if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
753 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
754 entry = (GtkEntry*)GHB_WIDGET(ud->builder, "destination");
757 g_debug("Failed to find widget: %s\n", "destination");
761 gtk_entry_set_text(entry, filename);
765 gtk_widget_destroy(dialog);
769 window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
771 g_debug("window_destroy_event_cb ()\n");
772 ghb_hb_cleanup(FALSE);
778 window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
780 gint state = ghb_get_state();
781 g_debug("window_delete_event_cb ()\n");
782 if (state & GHB_STATE_WORKING)
784 if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
786 ghb_hb_cleanup(FALSE);
792 ghb_hb_cleanup(FALSE);
798 update_acodec_combo(signal_user_data_t *ud)
800 ghb_grey_combo_options (ud->builder);
804 container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
806 g_debug("container_changed_cb ()\n");
807 ghb_widget_to_setting(ud->settings, widget);
808 update_destination_extension(ud);
809 check_depencency(ud, widget);
810 update_acodec_combo(ud);
811 clear_presets_selection(ud);
812 if (ghb_ac3_in_audio_list (ud->audio_settings))
814 const gchar *container;
816 container = ghb_settings_get_string(ud->settings, "container");
817 if (strcmp(container, "mp4") == 0)
819 ghb_ui_update(ud, "container", "m4v");
825 get_aspect_string(gint aspect_n, gint aspect_d)
831 aspect = g_strdup_printf("%d:%d", aspect_n, aspect_d);
835 gdouble aspect_nf = (gdouble)aspect_n / aspect_d;
836 aspect = g_strdup_printf("%.2f:1", aspect_nf);
842 get_rate_string(gint rate_base, gint rate)
844 gdouble rate_f = (gdouble)rate / rate_base;
847 rate_s = g_strdup_printf("%.6g", rate_f);
851 show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
856 widget = GHB_WIDGET (ud->builder, "title_duration");
857 if (tinfo->duration != 0)
859 text = g_strdup_printf ("%02d:%02d:%02d", tinfo->hours,
860 tinfo->minutes, tinfo->seconds);
864 text = g_strdup_printf ("Unknown");
866 gtk_label_set_text (GTK_LABEL(widget), text);
868 widget = GHB_WIDGET (ud->builder, "source_dimensions");
869 text = g_strdup_printf ("%d x %d", tinfo->width, tinfo->height);
870 gtk_label_set_text (GTK_LABEL(widget), text);
872 widget = GHB_WIDGET (ud->builder, "source_aspect");
873 text = get_aspect_string(tinfo->aspect_n, tinfo->aspect_d);
874 gtk_label_set_text (GTK_LABEL(widget), text);
877 widget = GHB_WIDGET (ud->builder, "source_frame_rate");
878 text = (gchar*)get_rate_string(tinfo->rate_base, tinfo->rate);
879 gtk_label_set_text (GTK_LABEL(widget), text);
882 ghb_ui_update_int (ud, "scale_width", tinfo->width - tinfo->crop[2] - tinfo->crop[3]);
883 // If anamorphic or keep_aspect, the hight will be automatically calculated
884 gboolean keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
885 gboolean anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
886 if (!(keep_aspect || anamorphic))
887 ghb_ui_update_int (ud, "scale_height", tinfo->height - tinfo->crop[0] - tinfo->crop[1]);
889 // Set the limits of cropping. hb_set_anamorphic_size crashes if
890 // you pass it a cropped width or height == 0.
892 bound = tinfo->height / 2 - 2;
893 widget = GHB_WIDGET (ud->builder, "crop_top");
894 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
895 widget = GHB_WIDGET (ud->builder, "crop_bottom");
896 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
897 bound = tinfo->width / 2 - 2;
898 widget = GHB_WIDGET (ud->builder, "crop_left");
899 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
900 widget = GHB_WIDGET (ud->builder, "crop_right");
901 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
902 if (ghb_settings_get_bool (ud->settings, "autocrop"))
904 ghb_ui_update_int (ud, "crop_top", tinfo->crop[0]);
905 ghb_ui_update_int (ud, "crop_bottom", tinfo->crop[1]);
906 ghb_ui_update_int (ud, "crop_left", tinfo->crop[2]);
907 ghb_ui_update_int (ud, "crop_right", tinfo->crop[3]);
909 g_debug("setting max end chapter %d\n", tinfo->num_chapters);
910 widget = GHB_WIDGET (ud->builder, "end_chapter");
911 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters);
912 gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), tinfo->num_chapters);
913 widget = GHB_WIDGET (ud->builder, "start_chapter");
914 gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1);
918 adjust_audio_rate_combos(signal_user_data_t *ud)
920 gint titleindex, audioindex, acodec;
921 ghb_audio_info_t ainfo;
924 g_debug("adjust_audio_rate_combos ()\n");
925 titleindex = ghb_settings_get_index(ud->settings, "title");
927 widget = GHB_WIDGET(ud->builder, "audio_track");
928 audioindex = ghb_widget_int(widget);
930 widget = GHB_WIDGET(ud->builder, "audio_codec");
931 acodec = ghb_widget_int(widget);
933 if (ghb_get_audio_info (&ainfo, titleindex, audioindex) && ghb_audio_is_passthru (acodec))
935 // Set the values for bitrate and samplerate to the input rates
936 ghb_set_passthru_rate_opts (ud->builder, ainfo.bitrate);
937 ghb_ui_update_int (ud, "audio_bitrate", ainfo.bitrate);
938 ghb_ui_update_int (ud, "audio_rate", 0);
939 ghb_ui_update_int (ud, "audio_mix", 0);
943 ghb_set_default_rate_opts (ud->builder);
948 set_pref_audio(gint titleindex, signal_user_data_t *ud)
950 gint acodec, track, ivalue;
953 ghb_audio_info_t ainfo;
956 GHashTable *track_indicies;
959 track_indicies = g_hash_table_new(g_int_hash, g_int_equal);
960 // Clear the audio list
961 clear_audio_list(ud);
962 // Find "best" audio based on audio preferences
963 button = GHB_WIDGET (ud->builder, "audio_add");
964 svalue = ghb_settings_get_short_opt(ud->settings, "source_audio_lang");
965 gint acount = ghb_pref_acount();
968 for (ii = 0; ii < acount; ii++)
970 acodec = ghb_pref_acodec(ii);
971 iptr = g_hash_table_lookup(track_indicies, &acodec);
975 index = *(gint*)iptr;
977 track = ghb_find_audio_track(titleindex, svalue, index);
979 // 1. pref codec is ac3
980 // 2. source codec is not ac3
981 // 3. next pref is enabled
982 if (ghb_get_audio_info (&ainfo, titleindex, track) &&
983 ghb_audio_is_passthru (acodec))
985 if (!ghb_audio_is_passthru(ainfo.codec))
987 acodec = ghb_get_default_acodec();
988 if ((ii + 1 < acount) || (list_count != 0))
995 if (titleindex >= 0 && track < 0)
1000 g_signal_emit_by_name(button, "clicked", ud);
1002 ghb_ui_update_int(ud, "audio_track", track);
1003 ghb_ui_update_int(ud, "audio_codec", acodec);
1004 if (!ghb_audio_is_passthru (acodec))
1006 // This gets set autimatically if the codec is passthru
1007 ivalue = ghb_pref_bitrate(ii);
1008 ghb_ui_update_int(ud, "audio_bitrate", ivalue);
1009 ivalue = ghb_pref_rate(ii);
1010 ghb_ui_update_int(ud, "audio_rate", ivalue);
1011 ivalue = ghb_pref_mix(ii);
1012 ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1013 ghb_ui_update_int(ud, "audio_mix", ivalue);
1015 drcstr = g_strdup_printf("%.2g", ghb_pref_drc(ii));
1016 ghb_ui_update(ud, "audio_drc", drcstr);
1019 g_hash_table_insert(track_indicies, &acodec, &index);
1022 g_hash_table_destroy(track_indicies);
1025 static gint preview_button_width;
1026 static gint preview_button_height;
1027 static gboolean update_preview = FALSE;
1030 set_preview_image(signal_user_data_t *ud)
1033 gint preview_width, preview_height, target_height, width, height;
1035 g_debug("set_preview_button_image ()\n");
1036 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1037 if (titleindex < 0) return;
1038 widget = GHB_WIDGET (ud->builder, "preview_frame");
1039 gint frame = ghb_widget_int(widget) - 1;
1040 GdkPixbuf *preview = ghb_get_preview_image (titleindex, frame, ud->settings, TRUE);
1041 if (preview == NULL) return;
1042 widget = GHB_WIDGET (ud->builder, "preview_image");
1043 gtk_image_set_from_pixbuf(GTK_IMAGE(widget), preview);
1045 preview_width = gdk_pixbuf_get_width(preview);
1046 preview_height = gdk_pixbuf_get_height(preview);
1047 gchar *text = g_strdup_printf("%d x %d", preview_width, preview_height);
1048 widget = GHB_WIDGET (ud->builder, "preview_dims");
1049 gtk_label_set_text(GTK_LABEL(widget), text);
1052 g_debug("preview %d x %d\n", preview_width, preview_height);
1053 target_height = MIN(preview_button_height - 12, 128);
1054 height = target_height;
1055 width = preview_width * height / preview_height;
1057 if ((height >= 16) && (width >= 16))
1059 GdkPixbuf *scaled_preview;
1060 scaled_preview = gdk_pixbuf_scale_simple (preview, width, height, GDK_INTERP_NEAREST);
1061 if (scaled_preview != NULL)
1063 g_object_unref (preview);
1065 widget = GHB_WIDGET (ud->builder, "preview_button_image");
1066 gtk_image_set_from_pixbuf(GTK_IMAGE(widget), scaled_preview);
1067 g_object_unref (scaled_preview);
1073 title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1075 ghb_title_info_t tinfo;
1077 const gchar *preset;
1079 g_debug("title_changed_cb ()\n");
1080 ghb_widget_to_setting(ud->settings, widget);
1081 check_depencency(ud, widget);
1083 titleindex = ghb_settings_get_int(ud->settings, "title");
1084 ghb_update_ui_combo_box (ud->builder, "audio_track", titleindex, FALSE);
1085 ghb_update_ui_combo_box (ud->builder, "subtitle_lang", titleindex, FALSE);
1086 preset = ghb_settings_get_string (ud->settings, "preset");
1087 ghb_update_from_preset(ud, preset, "subtitle_lang");
1088 if (ghb_get_title_info (&tinfo, titleindex))
1090 show_title_info(ud, &tinfo);
1092 update_chapter_list (ud);
1093 adjust_audio_rate_combos(ud);
1094 set_pref_audio(titleindex, ud);
1095 if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
1097 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1098 ghb_ui_update_int (ud, "video_bitrate", bitrate);
1101 // Unfortunately, there is no way to query how many frames were
1102 // actually generated during the scan. It attempts to make 10.
1103 // If I knew how many were generated, I would adjust the spin
1104 // control range here.
1105 ghb_ui_update_int (ud, "preview_frame", 1);
1107 set_preview_image (ud);
1111 audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1113 static gint prev_acodec = 0;
1114 gint acodec, ivalue;
1115 GHashTable *asettings;
1117 g_debug("audio_codec_changed_cb ()\n");
1119 acodec = ghb_widget_int(widget);
1120 if (ghb_audio_is_passthru (prev_acodec) && !ghb_audio_is_passthru (acodec))
1122 // Transition from passthru to not, put some audio settings back to
1124 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1125 gint track = ghb_settings_get_int(ud->settings, "audio_track");
1127 ivalue = ghb_pref_bitrate(0);
1128 ghb_ui_update_int (ud, "audio_bitrate", ivalue);
1129 ivalue = ghb_pref_rate(0);
1130 ghb_ui_update_int (ud, "audio_rate", ivalue);
1131 ivalue = ghb_pref_mix(0);
1132 ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1133 ghb_ui_update_int (ud, "audio_mix", ivalue);
1135 adjust_audio_rate_combos(ud);
1136 ghb_grey_combo_options (ud->builder);
1137 check_depencency(ud, widget);
1138 prev_acodec = acodec;
1139 asettings = get_selected_asettings(ud);
1140 if (asettings != NULL)
1142 ghb_widget_to_setting(asettings, widget);
1143 audio_list_refresh_selected(ud);
1145 if (ghb_ac3_in_audio_list (ud->audio_settings))
1147 const gchar *container;
1149 container = ghb_settings_get_string(ud->settings, "container");
1150 if (strcmp(container, "mp4") == 0)
1152 ghb_ui_update(ud, "container", "m4v");
1157 static void audio_list_refresh_selected(signal_user_data_t *ud);
1158 static GHashTable* get_selected_asettings(signal_user_data_t *ud);
1161 audio_track_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1163 GHashTable *asettings;
1165 g_debug("audio_track_changed_cb ()\n");
1166 adjust_audio_rate_combos(ud);
1167 check_depencency(ud, widget);
1168 ghb_grey_combo_options(ud->builder);
1169 asettings = get_selected_asettings(ud);
1170 if (asettings != NULL)
1172 ghb_widget_to_setting(asettings, widget);
1173 audio_list_refresh_selected(ud);
1178 audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1180 GHashTable *asettings;
1182 g_debug("audio_widget_changed_cb ()\n");
1183 check_depencency(ud, widget);
1184 asettings = get_selected_asettings(ud);
1185 if (asettings != NULL)
1187 ghb_widget_to_setting(asettings, widget);
1188 audio_list_refresh_selected(ud);
1193 generic_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1195 g_debug("generic_widget_changed_cb ()\n");
1196 check_depencency(ud, widget);
1200 setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1202 ghb_widget_to_setting(ud->settings, widget);
1203 check_depencency(ud, widget);
1204 clear_presets_selection(ud);
1208 http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1210 ghb_widget_to_setting(ud->settings, widget);
1211 check_depencency(ud, widget);
1212 clear_presets_selection(ud);
1213 ghb_grey_combo_options (ud->builder);
1217 vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1221 ghb_widget_to_setting(ud->settings, widget);
1222 check_depencency(ud, widget);
1223 clear_presets_selection(ud);
1224 ghb_vquality_range(ud, &vqmin, &vqmax);
1225 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1226 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1230 vfr_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1232 //const gchar *name = gtk_widget_get_name(widget);
1233 //g_debug("setting_widget_changed_cb () %s\n", name);
1234 ghb_widget_to_setting(ud->settings, widget);
1235 check_depencency(ud, widget);
1236 clear_presets_selection(ud);
1237 if (ghb_settings_get_bool(ud->settings, "variable_frame_rate"))
1239 ghb_ui_update_int(ud, "framerate", 0);
1244 mirror_cb(GtkWidget *widget, signal_user_data_t *ud)
1246 const gchar *name = gtk_widget_get_name(widget);
1247 if (name == NULL) return;
1249 g_debug("mirror_cb () %s\n", name);
1250 gchar *mirror = g_strdup(name);
1251 gchar *pos = g_strrstr(mirror, "_mirror");
1252 if (pos == NULL) return;
1254 gchar *value = ghb_widget_short_opt (widget);
1255 ghb_ui_update (ud, mirror, value);
1259 // subtitles have their differ from other settings in that
1260 // the selection is updated automaitcally when the title
1261 // changes. I don't want the preset selection changed as
1262 // would happen for regular settings.
1264 subtitle_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1266 const gchar *name = gtk_widget_get_name(widget);
1267 g_debug("subtitle_changed_cb () %s\n", name);
1268 ghb_widget_to_setting(ud->settings, widget);
1269 check_depencency(ud, widget);
1273 target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1275 const gchar *name = gtk_widget_get_name(widget);
1276 g_debug("setting_widget_changed_cb () %s\n", name);
1277 ghb_widget_to_setting(ud->settings, widget);
1278 check_depencency(ud, widget);
1279 clear_presets_selection(ud);
1280 if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
1282 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1283 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1284 ghb_ui_update_int (ud, "video_bitrate", bitrate);
1289 start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1291 const gchar *name = gtk_widget_get_name(widget);
1292 g_debug("start_chapter_changed_cb () %s\n", name);
1293 ghb_widget_to_setting(ud->settings, widget);
1294 GtkWidget *end_ch = GHB_WIDGET (ud->builder, "end_chapter");
1296 gtk_spin_button_get_range (GTK_SPIN_BUTTON(end_ch), &start, &end);
1297 start = ghb_settings_get_int(ud->settings, "start_chapter");
1298 gtk_spin_button_set_range (GTK_SPIN_BUTTON(end_ch), start, end);
1299 check_depencency(ud, widget);
1303 end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1305 const gchar *name = gtk_widget_get_name(widget);
1306 g_debug("end_chapter_changed_cb () %s\n", name);
1307 ghb_widget_to_setting(ud->settings, widget);
1308 GtkWidget *start_ch = GHB_WIDGET (ud->builder, "start_chapter");
1310 gtk_spin_button_get_range (GTK_SPIN_BUTTON(start_ch), &start, &end);
1311 end = ghb_settings_get_int(ud->settings, "end_chapter");
1312 gtk_spin_button_set_range (GTK_SPIN_BUTTON(start_ch), start, end);
1313 check_depencency(ud, widget);
1317 scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1319 g_debug("scale_width_changed_cb ()\n");
1320 ghb_widget_to_setting(ud->settings, widget);
1321 check_depencency(ud, widget);
1322 ghb_set_scale (ud, GHB_SCALE_KEEP_WIDTH);
1323 update_preview = TRUE;
1325 gint width = ghb_settings_get_int(ud->settings, "scale_width");
1326 gint height = ghb_settings_get_int(ud->settings, "scale_height");
1327 widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1328 text = g_strdup_printf ("%d x %d", width, height);
1329 gtk_label_set_text (GTK_LABEL(widget), text);
1334 scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1336 g_debug("scale_height_changed_cb ()\n");
1337 ghb_widget_to_setting(ud->settings, widget);
1338 check_depencency(ud, widget);
1339 ghb_set_scale (ud, GHB_SCALE_KEEP_HEIGHT);
1340 update_preview = TRUE;
1342 gint width = ghb_settings_get_int(ud->settings, "scale_width");
1343 gint height = ghb_settings_get_int(ud->settings, "scale_height");
1344 widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1345 text = g_strdup_printf ("%d x %d", width, height);
1346 gtk_label_set_text (GTK_LABEL(widget), text);
1351 crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1353 gint titleindex, crop[4];
1354 ghb_title_info_t tinfo;
1356 g_debug("crop_changed_cb ()\n");
1357 ghb_widget_to_setting(ud->settings, widget);
1358 check_depencency(ud, widget);
1359 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1361 crop[0] = ghb_settings_get_int(ud->settings, "crop_top");
1362 crop[1] = ghb_settings_get_int(ud->settings, "crop_bottom");
1363 crop[2] = ghb_settings_get_int(ud->settings, "crop_left");
1364 crop[3] = ghb_settings_get_int(ud->settings, "crop_right");
1365 titleindex = ghb_settings_get_index(ud->settings, "title");
1366 if (ghb_get_title_info (&tinfo, titleindex))
1371 width = tinfo.width - crop[2] - crop[3];
1372 height = tinfo.height - crop[0] - crop[1];
1373 widget = GHB_WIDGET (ud->builder, "crop_dimensions");
1374 text = g_strdup_printf ("%d x %d", width, height);
1375 gtk_label_set_text (GTK_LABEL(widget), text);
1379 widget = GHB_WIDGET (ud->builder, "crop_values");
1380 text = g_strdup_printf ("%d:%d:%d:%d", crop[0], crop[1], crop[2], crop[3]);
1381 gtk_label_set_text (GTK_LABEL(widget), text);
1383 update_preview = TRUE;
1387 scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1389 g_debug("scale_changed_cb ()\n");
1390 ghb_widget_to_setting(ud->settings, widget);
1391 check_depencency(ud, widget);
1392 clear_presets_selection(ud);
1393 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1394 update_preview = TRUE;
1398 text = ghb_settings_get_bool(ud->settings, "autocrop") ? "On" : "Off";
1399 widget = GHB_WIDGET (ud->builder, "crop_auto");
1400 gtk_label_set_text (GTK_LABEL(widget), text);
1401 text = ghb_settings_get_bool(ud->settings, "autoscale") ? "On" : "Off";
1402 widget = GHB_WIDGET (ud->builder, "scale_auto");
1403 gtk_label_set_text (GTK_LABEL(widget), text);
1404 text = ghb_settings_get_bool(ud->settings, "anamorphic") ? "On" : "Off";
1405 widget = GHB_WIDGET (ud->builder, "scale_anamorphic");
1406 gtk_label_set_text (GTK_LABEL(widget), text);
1410 generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
1412 // Normally (due to user input) I only want to process the entry
1413 // when editing is done and the focus-out signal is sent.
1414 // But... there's always a but.
1415 // If the entry is changed by software, the focus-out signal is not sent.
1416 // The changed signal is sent ... so here we are.
1417 // I don't want to process upon every keystroke, so I prevent processing
1418 // while the widget has focus.
1419 g_debug("generic_entry_changed_cb ()\n");
1420 if (!GTK_WIDGET_HAS_FOCUS((GtkWidget*)entry))
1422 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
1427 generic_focus_out_cb(GtkWidget *widget, GdkEventFocus *event,
1428 signal_user_data_t *ud)
1430 g_debug("generic_focus_out_cb ()\n");
1431 ghb_widget_to_setting(ud->settings, widget);
1435 // Flag needed to prevent x264 options processing from chasing its tail
1436 static gboolean ignore_options_update = FALSE;
1439 x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1441 ghb_widget_to_setting(ud->settings, widget);
1442 if (!ignore_options_update)
1444 ignore_options_update = TRUE;
1445 ghb_x264_opt_update(ud, widget);
1446 ignore_options_update = FALSE;
1448 check_depencency(ud, widget);
1449 clear_presets_selection(ud);
1453 x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1455 g_debug("x264_entry_changed_cb ()\n");
1456 if (!ignore_options_update)
1458 GtkWidget *textview;
1459 textview = GTK_WIDGET(GHB_WIDGET(ud->builder, "x264_options"));
1460 ghb_widget_to_setting(ud->settings, textview);
1462 options = (gchar*)ghb_settings_get_string(ud->settings, "x264_options");
1463 ignore_options_update = TRUE;
1464 ghb_x264_parse_options(ud, options);
1465 if (!GTK_WIDGET_HAS_FOCUS(textview))
1467 options = ghb_sanitize_x264opts(ud, options);
1468 ghb_ui_update(ud, "x264_options", options);
1469 ghb_x264_parse_options(ud, options);
1472 ignore_options_update = FALSE;
1477 x264_focus_out_cb(GtkWidget *widget, GdkEventFocus *event,
1478 signal_user_data_t *ud)
1480 ghb_widget_to_setting(ud->settings, widget);
1482 options = (gchar*)ghb_settings_get_string(ud->settings, "x264_options");
1483 options = ghb_sanitize_x264opts(ud, options);
1484 ignore_options_update = TRUE;
1485 if (options != NULL)
1487 ghb_ui_update(ud, "x264_options", options);
1488 ghb_x264_parse_options(ud, options);
1491 ignore_options_update = FALSE;
1496 clear_audio_list(signal_user_data_t *ud)
1498 GtkTreeView *treeview;
1499 GtkListStore *store;
1502 g_debug("clear_audio_list ()\n");
1503 while (ud->audio_settings != NULL)
1505 link = ud->audio_settings;
1506 ud->audio_settings = g_slist_remove_link(ud->audio_settings, link);
1507 g_hash_table_destroy((GHashTable*)link->data);
1508 g_slist_free_1(link);
1510 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1511 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1512 gtk_list_store_clear (store);
1516 add_to_audio_list(signal_user_data_t *ud, GHashTable *settings)
1518 GtkTreeView *treeview;
1520 GtkListStore *store;
1521 GtkTreeSelection *selection;
1523 g_debug("add_to_audio_list ()\n");
1524 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1525 selection = gtk_tree_view_get_selection (treeview);
1526 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1528 gtk_list_store_append(store, &iter);
1529 gtk_list_store_set(store, &iter,
1530 // These are displayed in list
1531 0, ghb_settings_get_option(settings, "audio_track"),
1532 1, ghb_settings_get_option(settings, "audio_codec"),
1533 2, ghb_settings_get_option(settings, "audio_bitrate"),
1534 3, ghb_settings_get_option(settings, "audio_rate"),
1535 4, ghb_settings_get_option(settings, "audio_mix"),
1536 // These are used to set combo box values when a list item is selected
1537 5, ghb_settings_get_string(settings, "audio_drc"),
1538 6, ghb_settings_get_short_opt(settings, "audio_track"),
1539 7, ghb_settings_get_short_opt(settings, "audio_codec"),
1540 8, ghb_settings_get_short_opt(settings, "audio_bitrate"),
1541 9, ghb_settings_get_short_opt(settings, "audio_rate"),
1542 10, ghb_settings_get_short_opt(settings, "audio_mix"),
1544 gtk_tree_selection_select_iter(selection, &iter);
1548 audio_list_refresh_selected(signal_user_data_t *ud)
1550 GtkTreeView *treeview;
1551 GtkTreePath *treepath;
1552 GtkTreeSelection *selection;
1553 GtkTreeModel *store;
1558 GHashTable *asettings = NULL;
1560 g_debug("get_selected_asettings ()\n");
1561 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1562 selection = gtk_tree_view_get_selection (treeview);
1563 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1565 // Get the row number
1566 treepath = gtk_tree_model_get_path (store, &iter);
1567 indices = gtk_tree_path_get_indices (treepath);
1570 // find audio settings
1571 if (row < 0) return;
1572 link = g_slist_nth(ud->audio_settings, row);
1573 if (link == NULL) return;
1574 asettings = (GHashTable*)link->data;
1575 gtk_list_store_set(GTK_LIST_STORE(store), &iter,
1576 // These are displayed in list
1577 0, ghb_settings_get_option(asettings, "audio_track"),
1578 1, ghb_settings_get_option(asettings, "audio_codec"),
1579 2, ghb_settings_get_option(asettings, "audio_bitrate"),
1580 3, ghb_settings_get_option(asettings, "audio_rate"),
1581 4, ghb_settings_get_option(asettings, "audio_mix"),
1582 // These are used to set combo box values when a list item is selected
1583 5, ghb_settings_get_string(asettings, "audio_drc"),
1584 6, ghb_settings_get_short_opt(asettings, "audio_track"),
1585 7, ghb_settings_get_short_opt(asettings, "audio_codec"),
1586 8, ghb_settings_get_short_opt(asettings, "audio_bitrate"),
1587 9, ghb_settings_get_short_opt(asettings, "audio_rate"),
1588 10, ghb_settings_get_short_opt(asettings, "audio_mix"),
1594 get_selected_asettings(signal_user_data_t *ud)
1596 GtkTreeView *treeview;
1597 GtkTreePath *treepath;
1598 GtkTreeSelection *selection;
1599 GtkTreeModel *store;
1604 GHashTable *asettings = NULL;
1606 g_debug("get_selected_asettings ()\n");
1607 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1608 selection = gtk_tree_view_get_selection (treeview);
1609 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1611 // Get the row number
1612 treepath = gtk_tree_model_get_path (store, &iter);
1613 indices = gtk_tree_path_get_indices (treepath);
1616 // find audio settings
1617 if (row < 0) return NULL;
1618 link = g_slist_nth(ud->audio_settings, row);
1619 if (link == NULL) return NULL;
1620 asettings = (GHashTable*)link->data;
1626 audio_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
1628 GtkTreeModel *store;
1632 g_debug("audio_list_selection_changed_cb ()\n");
1633 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1635 const gchar *track, *codec, *bitrate, *sample_rate, *mix, *drc;
1636 gtk_tree_model_get(store, &iter,
1644 ghb_ui_update(ud, "audio_track", track);
1645 ghb_ui_update(ud, "audio_codec", codec);
1646 ghb_ui_update(ud, "audio_bitrate", bitrate);
1647 ghb_ui_update(ud, "audio_rate", sample_rate);
1648 ghb_ui_update(ud, "audio_mix", mix);
1649 ghb_ui_update(ud, "audio_drc", drc);
1650 widget = GHB_WIDGET (ud->builder, "audio_remove");
1651 gtk_widget_set_sensitive(widget, TRUE);
1652 //widget = GHB_WIDGET (ud->builder, "audio_update");
1653 //gtk_widget_set_sensitive(widget, TRUE);
1657 widget = GHB_WIDGET (ud->builder, "audio_remove");
1658 gtk_widget_set_sensitive(widget, FALSE);
1659 //widget = GHB_WIDGET (ud->builder, "audio_update");
1660 //gtk_widget_set_sensitive(widget, FALSE);
1665 audio_add_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1667 // Add the current audio settings to the list.
1668 GHashTable *asettings;
1672 g_debug("audio_add_clicked_cb ()\n");
1673 // Only allow up to 8 audio entries
1674 asettings = ghb_settings_new();
1675 widget = GHB_WIDGET(ud->builder, "audio_track");
1676 ghb_settings_set(asettings, "audio_track", ghb_widget_value(widget));
1677 widget = GHB_WIDGET(ud->builder, "audio_codec");
1678 ghb_settings_set(asettings, "audio_codec", ghb_widget_value(widget));
1679 widget = GHB_WIDGET(ud->builder, "audio_bitrate");
1680 ghb_settings_set(asettings, "audio_bitrate", ghb_widget_value(widget));
1681 widget = GHB_WIDGET(ud->builder, "audio_rate");
1682 ghb_settings_set(asettings, "audio_rate", ghb_widget_value(widget));
1683 widget = GHB_WIDGET(ud->builder, "audio_mix");
1684 ghb_settings_set(asettings, "audio_mix", ghb_widget_value(widget));
1685 widget = GHB_WIDGET(ud->builder, "audio_drc");
1686 ghb_settings_set(asettings, "audio_drc", ghb_widget_value(widget));
1688 ud->audio_settings = g_slist_append(ud->audio_settings, asettings);
1689 add_to_audio_list(ud, asettings);
1690 count = g_slist_length(ud->audio_settings);
1693 gtk_widget_set_sensitive(xwidget, FALSE);
1698 audio_remove_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
1700 GtkTreeView *treeview;
1701 GtkTreePath *treepath;
1702 GtkTreeSelection *selection;
1703 GtkTreeModel *store;
1704 GtkTreeIter iter, nextIter;
1709 g_debug("audio_remove_clicked_cb ()\n");
1710 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1711 selection = gtk_tree_view_get_selection (treeview);
1712 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1715 if (!gtk_tree_model_iter_next(store, &nextIter))
1718 if (gtk_tree_model_get_iter_first(store, &nextIter))
1720 gtk_tree_selection_select_iter (selection, &nextIter);
1725 gtk_tree_selection_select_iter (selection, &nextIter);
1727 // Get the row number
1728 treepath = gtk_tree_model_get_path (store, &iter);
1729 indices = gtk_tree_path_get_indices (treepath);
1732 // Remove the selected item
1733 gtk_list_store_remove (GTK_LIST_STORE(store), &iter);
1734 // remove from audio settings list
1735 if (row < 0) return;
1736 link = g_slist_nth(ud->audio_settings, row);
1737 if (link == NULL) return;
1738 ud->audio_settings = g_slist_remove_link(ud->audio_settings, link);
1739 g_hash_table_destroy((GHashTable*)link->data);
1740 g_slist_free_1(link);
1741 widget = GHB_WIDGET (ud->builder, "audio_add");
1742 gtk_widget_set_sensitive(widget, TRUE);
1747 audio_list_refresh(signal_user_data_t *ud)
1749 GtkTreeView *treeview;
1751 GtkListStore *store;
1754 g_debug("audio_list_refresh ()\n");
1755 GSList *link = ud->audio_settings;
1756 if (link == NULL) return;
1757 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1758 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1759 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1763 GHashTable *asettings;
1765 asettings = (GHashTable*)link->data;
1766 gtk_list_store_set(GTK_LIST_STORE(store), &iter,
1767 // These are displayed in list
1768 0, ghb_settings_get_option(asettings, "audio_track"),
1769 1, ghb_settings_get_option(asettings, "audio_codec"),
1770 2, ghb_settings_get_option(asettings, "audio_bitrate"),
1771 3, ghb_settings_get_option(asettings, "audio_rate"),
1772 4, ghb_settings_get_option(asettings, "audio_mix"),
1773 // These are used to set combo box values when a list item is selected
1774 5, ghb_settings_get_string(asettings, "audio_drc"),
1775 6, ghb_settings_get_short_opt(asettings, "audio_track"),
1776 7, ghb_settings_get_short_opt(asettings, "audio_codec"),
1777 8, ghb_settings_get_short_opt(asettings, "audio_bitrate"),
1778 9, ghb_settings_get_short_opt(asettings, "audio_rate"),
1779 10, ghb_settings_get_short_opt(asettings, "audio_mix"),
1781 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1783 } while (!done && link);
1788 ghb_presets_list_update(signal_user_data_t *ud)
1790 GtkTreeView *treeview;
1792 GtkListStore *store;
1797 gchar **descriptions;
1798 gint flags, custom, def;
1800 g_debug("ghb_presets_list_update ()\n");
1801 presets = ghb_presets_get_names();
1802 descriptions = ghb_presets_get_descriptions();
1803 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1804 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1805 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1809 if ((presets != NULL) && (presets[ii] != NULL))
1811 // Update row with settings data
1812 g_debug("Updating row\n");
1813 flags = ghb_preset_flags(presets[ii], &index);
1814 def = flags & PRESET_DEFAULT;
1815 custom = flags & PRESET_CUSTOM;
1816 gtk_list_store_set(store, &iter,
1820 3, custom ? "black" : "blue",
1821 4, descriptions[ii],
1824 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1828 // No more settings data, remove row
1829 g_debug("Removing row\n");
1830 done = !gtk_list_store_remove(store, &iter);
1834 while ((presets != NULL) && (presets[ii] != NULL))
1836 // Additional settings, add row
1837 g_debug("Adding row %s\n", presets[ii]);
1838 gtk_list_store_append(store, &iter);
1839 flags = ghb_preset_flags(presets[ii], &index);
1840 def = flags & PRESET_DEFAULT;
1841 custom = flags & PRESET_CUSTOM;
1842 gtk_list_store_set(store, &iter, 0, presets[ii],
1845 3, custom ? "black" : "blue",
1846 4, descriptions[ii],
1850 g_strfreev (presets);
1854 ghb_select_preset(GtkBuilder *builder, const gchar *preset)
1856 GtkTreeView *treeview;
1857 GtkTreeSelection *selection;
1858 GtkTreeModel *store;
1863 g_debug("select_preset()\n");
1864 if (preset == NULL) return;
1865 treeview = GTK_TREE_VIEW(GHB_WIDGET(builder, "presets_list"));
1866 selection = gtk_tree_view_get_selection (treeview);
1867 store = gtk_tree_view_get_model (treeview);
1868 if (gtk_tree_model_get_iter_first(store, &iter))
1872 gtk_tree_model_get(store, &iter, 0, &tpreset, -1);
1873 if (strcmp(preset, tpreset) == 0)
1875 gtk_tree_selection_select_iter (selection, &iter);
1878 done = !gtk_tree_model_iter_next(store, &iter);
1884 update_audio_presets(signal_user_data_t *ud)
1886 GSList *link = ud->audio_settings;
1887 GHashTable *asettings;
1888 gchar *acodec, *bitrate, *rate, *mix, *drc;
1889 GString *pref_acodec, *pref_bitrate, *pref_rate, *pref_mix, *pref_drc;
1890 pref_acodec = g_string_new("");
1891 pref_bitrate = g_string_new("");
1892 pref_rate = g_string_new("");
1893 pref_mix = g_string_new("");
1894 pref_drc = g_string_new("");
1897 gchar *format = link->next ? "%s," : "%s";
1898 asettings = (GHashTable*)link->data;
1899 acodec = (gchar*)ghb_settings_get_short_opt(asettings, "audio_codec");
1900 g_string_append_printf( pref_acodec, format, acodec);
1901 bitrate = (gchar*)ghb_settings_get_string(asettings, "audio_bitrate");
1902 g_string_append_printf( pref_bitrate, format, bitrate);
1903 rate = (gchar*)ghb_settings_get_string(asettings, "audio_rate");
1904 g_string_append_printf( pref_rate, format, rate);
1905 mix = (gchar*)ghb_settings_get_short_opt(asettings, "audio_mix");
1906 g_string_append_printf( pref_mix, format, mix);
1907 drc = (gchar*)ghb_settings_get_string(asettings, "audio_drc");
1908 g_string_append_printf( pref_drc, format, drc);
1911 acodec = g_string_free(pref_acodec, FALSE);
1912 bitrate = g_string_free(pref_bitrate, FALSE);
1913 rate = g_string_free(pref_rate, FALSE);
1914 mix = g_string_free(pref_mix, FALSE);
1915 drc = g_string_free(pref_drc, FALSE);
1916 ghb_settings_set_string(ud->settings, "pref_audio_codec", acodec);
1917 ghb_settings_set_string(ud->settings, "pref_audio_bitrate", bitrate);
1918 ghb_settings_set_string(ud->settings, "pref_audio_rate", rate);
1919 ghb_settings_set_string(ud->settings, "pref_audio_mix", mix);
1920 ghb_settings_set_string(ud->settings, "pref_audio_drc", drc);
1929 presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1934 GtkResponseType response;
1935 const gchar *preset = "";
1937 g_debug("presets_save_clicked_cb ()\n");
1938 // Construct the audio settings presets from the current audio list
1939 preset = ghb_settings_get_string (ud->settings, "preset");
1940 // Clear the description
1941 desc = GTK_TEXT_VIEW(GHB_WIDGET(ud->builder, "preset_description"));
1942 //gtk_entry_set_text(desc, "");
1943 dialog = GHB_WIDGET(ud->builder, "preset_save_dialog");
1944 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "preset_name"));
1945 gtk_entry_set_text(entry, preset);
1946 response = gtk_dialog_run(GTK_DIALOG(dialog));
1947 gtk_widget_hide(dialog);
1948 if (response == GTK_RESPONSE_OK)
1951 const gchar *name = gtk_entry_get_text(entry);
1952 g_debug("description to settings\n");
1953 ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
1954 update_audio_presets(ud);
1955 ghb_settings_save(ud, name);
1956 ghb_presets_list_update(ud);
1957 // Make the new preset the selected item
1958 ghb_select_preset(ud->builder, name);
1963 prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1966 GtkResponseType response;
1968 g_debug("prefs_dialog_cb ()\n");
1969 dialog = GHB_WIDGET(ud->builder, "prefs_dialog");
1970 response = gtk_dialog_run(GTK_DIALOG(dialog));
1971 gtk_widget_hide(dialog);
1975 presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1977 GtkTreeView *treeview;
1978 GtkTreeSelection *selection;
1979 GtkTreeModel *store;
1982 GtkResponseType response;
1984 g_debug("presets_remove_clicked_cb ()\n");
1985 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1986 selection = gtk_tree_view_get_selection (treeview);
1987 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1991 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1992 if (!ghb_presets_is_standard(preset))
1994 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1995 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1996 "Confirm deletion of preset %s.", preset);
1997 response = gtk_dialog_run(GTK_DIALOG(dialog));
1998 gtk_widget_destroy (dialog);
1999 if (response == GTK_RESPONSE_YES)
2001 GtkTreeIter nextIter = iter;
2002 gchar *nextPreset = NULL;
2003 if (!gtk_tree_model_iter_next(store, &nextIter))
2005 if (gtk_tree_model_get_iter_first(store, &nextIter))
2007 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
2012 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
2014 // Remove the selected item
2015 // First unselect it so that selecting the new item works properly
2016 gtk_tree_selection_unselect_iter (selection, &iter);
2017 ghb_presets_remove(ud->settings, preset);
2018 ghb_presets_list_update(ud);
2019 ghb_select_preset(ud->builder, nextPreset);
2024 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2025 GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
2026 "Can not delete standard preset %s.", preset);
2027 response = gtk_dialog_run(GTK_DIALOG(dialog));
2028 gtk_widget_destroy (dialog);
2034 preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
2038 ghb_ui_update_int (ud, "scale_width", tinfo->width - tinfo->crop[2] - tinfo->crop[3]);
2039 // If anamorphic or keep_aspect, the hight will be automatically calculated
2040 gboolean keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
2041 gboolean anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
2042 if (!(keep_aspect || anamorphic))
2043 ghb_ui_update_int (ud, "scale_height", tinfo->height - tinfo->crop[0] - tinfo->crop[1]);
2045 // Set the limits of cropping. hb_set_anamorphic_size crashes if
2046 // you pass it a cropped width or height == 0.
2048 bound = tinfo->height / 2 - 2;
2049 widget = GHB_WIDGET (ud->builder, "crop_top");
2050 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
2051 widget = GHB_WIDGET (ud->builder, "crop_bottom");
2052 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
2053 bound = tinfo->width / 2 - 2;
2054 widget = GHB_WIDGET (ud->builder, "crop_left");
2055 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
2056 widget = GHB_WIDGET (ud->builder, "crop_right");
2057 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
2058 if (ghb_settings_get_bool (ud->settings, "autocrop"))
2060 ghb_ui_update_int (ud, "crop_top", tinfo->crop[0]);
2061 ghb_ui_update_int (ud, "crop_bottom", tinfo->crop[1]);
2062 ghb_ui_update_int (ud, "crop_left", tinfo->crop[2]);
2063 ghb_ui_update_int (ud, "crop_right", tinfo->crop[3]);
2068 presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
2070 GtkTreeModel *store;
2074 gboolean sensitive = FALSE;
2075 ghb_title_info_t tinfo;
2077 g_debug("presets_list_selection_changed_cb ()\n");
2078 if (gtk_tree_selection_get_selected(selection, &store, &iter))
2080 gtk_tree_model_get(store, &iter, 0, &preset, -1);
2081 if (!ghb_presets_is_standard(preset))
2085 ud->dont_clear_presets = TRUE;
2086 // Temporarily set the video_quality range to (0,100)
2087 // This is needed so the video_quality value does not get
2088 // truncated when set. The range will be readjusted below
2089 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
2090 gtk_range_set_range (GTK_RANGE(qp), 0, 100);
2091 // Clear the audio list prior to changing the preset. Existing audio
2092 // can cause the container extension to be automatically changed when
2094 clear_audio_list(ud);
2095 ghb_set_preset(ud, preset);
2096 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2097 set_pref_audio(titleindex, ud);
2098 ud->dont_clear_presets = FALSE;
2099 if (ghb_get_title_info (&tinfo, titleindex))
2101 preset_update_title_deps(ud, &tinfo);
2103 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
2106 ghb_vquality_range(ud, &vqmin, &vqmax);
2107 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
2111 g_debug("No selection??? Perhaps unselected.\n");
2113 widget = GHB_WIDGET (ud->builder, "presets_remove");
2114 gtk_widget_set_sensitive(widget, sensitive);
2118 queue_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
2120 GtkTreeModel *store;
2121 GtkTreeIter iter, piter;
2123 g_debug("queue_list_selection_changed_cb ()\n");
2124 // A queue entry is made up of a parent and multiple
2125 // children that are visible when expanded. When and entry
2126 // is selected, I want the parent to be selected.
2127 // This is purely cosmetic.
2128 if (gtk_tree_selection_get_selected(selection, &store, &iter))
2130 if (gtk_tree_model_iter_parent (store, &piter, &iter))
2133 GtkTreeView *treeview;
2135 gtk_tree_selection_select_iter (selection, &piter);
2136 path = gtk_tree_model_get_path (store, &piter);
2137 treeview = gtk_tree_selection_get_tree_view (selection);
2138 // Make the parent visible in scroll window if it is not.
2139 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
2146 add_to_queue_list(signal_user_data_t *ud, job_settings_t *item)
2148 GtkTreeView *treeview;
2150 GtkTreeStore *store;
2156 g_debug("update_queue_list ()\n");
2157 if (item == NULL) return;
2158 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2159 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2161 gint title = ghb_settings_get_int(item->settings, "title");
2162 gint start_chapter = ghb_settings_get_int(item->settings, "start_chapter");
2163 gint end_chapter = ghb_settings_get_int(item->settings, "end_chapter");
2164 gboolean pass2 = ghb_settings_get_bool(item->settings, "two_pass");
2165 const gchar *vol_name = ghb_settings_get_string(item->settings, "volume_label");
2166 if (vol_name == NULL)
2167 vol_name = "No Title";
2168 info = g_strdup_printf
2170 "<big><b>%s</b></big> (Title %d, Chapters %d through %d, %d Video %s)",
2171 vol_name, title+1, start_chapter, end_chapter,
2172 pass2 ? 2:1, pass2 ? "Passes":"Pass");
2174 gtk_tree_store_append(store, &iter, NULL);
2175 gtk_tree_store_set(store, &iter, 0, "hb-queue-job", 1, info, 2, "hb-queue-delete", -1);
2178 const gchar *vcodec = ghb_settings_get_option(item->settings, "video_codec");
2179 const gchar *container = ghb_settings_get_option(item->settings, "container");
2180 const gchar *acodec = ghb_settings_get_option(item->settings, "audio_codec");
2181 const gchar *dest = ghb_settings_get_string(item->settings, "destination");
2182 const gchar *preset = ghb_settings_get_string(item->settings, "preset");
2183 info = g_strdup_printf
2185 "<b>Preset:</b> %s\n"
2186 "<b>Format:</b> %s Container, %s Video + %s Audio\n"
2187 "<b>Destination:</b> %s",
2188 preset, container, vcodec, acodec, dest);
2190 gtk_tree_store_append(store, &citer, &iter);
2191 gtk_tree_store_set(store, &citer, 1, info, -1);
2194 gint width = ghb_settings_get_int(item->settings, "scale_width");
2195 gint height = ghb_settings_get_int(item->settings, "scale_height");
2196 gboolean anamorphic = ghb_settings_get_bool(item->settings, "anamorphic");
2197 gboolean round_dim = ghb_settings_get_bool(item->settings, "round_dimensions");
2198 gboolean keep_aspect = ghb_settings_get_bool(item->settings, "keep_aspect");
2204 aspect_desc = "(Anamorphic)";
2208 aspect_desc = "(Strict Anamorphic)";
2215 aspect_desc = "(Aspect Preserved)";
2219 aspect_desc = "(Aspect Lost)";
2222 gboolean vqtype = ghb_settings_get_bool(item->settings, "vquality_type_constant");
2224 gchar *vq_desc = "Error";
2227 vqtype = ghb_settings_get_bool(item->settings, "vquality_type_target");
2230 // Has to be bitrate
2231 vqvalue = ghb_settings_get_int(item->settings, "video_bitrate");
2237 vqvalue = ghb_settings_get_int(item->settings, "video_target");
2244 vqvalue = ghb_settings_get_int(item->settings, "video_quality");
2245 vq_desc = "% Constant Quality";
2247 const gchar *fps = ghb_settings_get_string(item->settings, "framerate");
2248 const gchar *vcodec_abbr = ghb_settings_get_short_opt(item->settings, "video_codec");
2250 if (strcmp(vcodec_abbr, "x264") == 0)
2252 gchar *x264opts = ghb_build_x264opts_string(item->settings);
2253 g_debug("xopts (%s)\n", x264opts);
2254 extra_opts = g_strdup_printf ("\n<b>x264 Options:</b> %s", x264opts);
2259 extra_opts = g_strdup("");
2261 gboolean turbo = ghb_settings_get_bool (item->settings, "turbo");
2262 gchar *turbo_desc = "\n<b>Turbo:</b> Off";;
2265 turbo_desc = "\n<b>Turbo:</b> On";
2267 num_pass = pass2 ? 2 : 1;
2268 for (ii = 0; ii < num_pass; ii++)
2270 gboolean final = (ii == (num_pass - 1));
2271 GString *pass = g_string_new("");
2272 g_string_append_printf( pass,
2274 "<b>Picture:</b> %d x %d %s\n"
2275 "<b>Video:</b> %s, %d %s, %s fps"
2277 ii ? "2nd":"1st", width, height, aspect_desc,
2278 vcodec, vqvalue, vq_desc, fps,
2279 final ? extra_opts : turbo_desc);
2284 GSList *link = item->audio_settings;
2287 GHashTable *asettings = (GHashTable*)link->data;
2288 const gchar *acodec = ghb_settings_get_option(asettings, "audio_codec");
2289 const gchar *bitrate = ghb_settings_get_string(asettings, "audio_bitrate");
2290 const gchar *samplerate = ghb_settings_get_string(asettings, "audio_rate");
2291 gint track = ghb_settings_get_int(asettings, "audio_track");
2292 const gchar *mix = ghb_settings_get_option(asettings, "audio_mix");
2293 g_string_append_printf(pass,
2294 "\n<b>Audio:</b> %s, %s kbps, %s kHz, Track %d: %s",
2295 acodec, bitrate, samplerate, track+1, mix);
2299 info = g_string_free(pass, FALSE);
2300 gtk_tree_store_append(store, &citer, &iter);
2301 gtk_tree_store_set(store, &citer, 0, ii ? "hb-queue-pass2" : "hb-queue-pass1", 1, info, -1);
2308 ghb_message_dialog(GtkMessageType type, const gchar *message, const gchar *no, const gchar *yes)
2311 GtkResponseType response;
2313 // Toss up a warning dialog
2314 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2315 type, GTK_BUTTONS_NONE,
2317 gtk_dialog_add_buttons( GTK_DIALOG(dialog),
2318 no, GTK_RESPONSE_NO,
2319 yes, GTK_RESPONSE_YES, NULL);
2320 response = gtk_dialog_run(GTK_DIALOG(dialog));
2321 gtk_widget_destroy (dialog);
2322 if (response == GTK_RESPONSE_NO)
2330 estimate_file_size(signal_user_data_t *ud)
2332 ghb_title_info_t tinfo;
2336 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2337 if (titleindex < 0) return 0;
2339 if (!ghb_get_title_info(&tinfo, titleindex)) return 0;
2340 duration = ((tinfo.hours*60)+tinfo.minutes)*60+tinfo.seconds;
2341 bitrate = ghb_guess_bitrate(ud->settings);
2342 size = (gint64)duration * (gint64)bitrate/8;
2346 #define DISK_FREE_THRESH (1024L*1024L*1024L*3)
2349 validate_settings(signal_user_data_t *ud)
2351 // Check to see if the dest file exists or is
2352 // already in the queue
2354 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2355 if (titleindex < 0) return FALSE;
2356 const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
2357 GSList *link = ud->queue;
2358 while (link != NULL)
2360 job_settings_t *item;
2361 const gchar *filename;
2362 item = (job_settings_t*)link->data;
2363 filename = ghb_settings_get_string(item->settings, "destination");
2364 if (strcmp(dest, filename) == 0)
2366 message = g_strdup_printf(
2367 "Destination: %s\n\n"
2368 "Another queued job has specified the same destination.\n"
2369 "Do you want to overwrite?",
2371 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
2381 gchar *destdir = g_path_get_dirname(dest);
2382 if (!g_file_test(destdir, G_FILE_TEST_IS_DIR))
2384 message = g_strdup_printf(
2385 "Destination: %s\n\n"
2386 "This is not a valid directory.",
2388 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2393 if (g_access(destdir, R_OK|W_OK) != 0)
2395 message = g_strdup_printf(
2396 "Destination: %s\n\n"
2397 "Can not read or write the directory.",
2399 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2407 gchar *resolved = ghb_resolve_symlink(destdir);
2409 gfile = g_file_new_for_path(resolved);
2410 info = g_file_query_filesystem_info(gfile,
2411 G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, NULL);
2414 if (g_file_info_has_attribute(info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE))
2416 size = g_file_info_get_attribute_uint64(info,
2417 G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
2419 gint64 fsize = estimate_file_size(ud);
2422 message = g_strdup_printf(
2423 "Destination filesystem is almost full: %uM free\n\n"
2424 "Encode may be incomplete if you proceed.\n",
2425 (guint)(size / (1024L*1024L)));
2426 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Proceed"))
2434 g_object_unref(info);
2436 g_object_unref(gfile);
2439 if (g_file_test(dest, G_FILE_TEST_EXISTS))
2441 message = g_strdup_printf(
2442 "Destination: %s\n\n"
2443 "File already exhists.\n"
2444 "Do you want to overwrite?",
2446 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
2454 // Validate video quality is in a reasonable range
2455 if (!ghb_validate_vquality(ud->settings))
2459 // Validate audio settings
2460 if (!ghb_validate_audio(ud))
2464 // Validate video settings
2465 if (!ghb_validate_video(ud))
2469 // Validate container settings
2470 if (!ghb_validate_container(ud))
2474 // Validate filter settings
2475 if (!ghb_validate_filters(ud))
2479 audio_list_refresh(ud);
2484 queue_add(signal_user_data_t *ud)
2486 // Add settings to the queue
2487 job_settings_t *queue_item;
2489 static gint unique_id = 0;
2491 g_debug("queue_add ()\n");
2492 if (!validate_settings(ud))
2496 // Make a copy of current settings to be used for the new job
2497 queue_item = g_malloc(sizeof(job_settings_t));
2498 queue_item->settings = ghb_settings_dup(ud->settings);
2499 queue_item->audio_settings = NULL;
2500 link = ud->audio_settings;
2501 while (link != NULL)
2503 GHashTable *asettings;
2504 asettings = ghb_settings_dup((GHashTable*)link->data);
2505 queue_item->audio_settings =
2506 g_slist_append(queue_item->audio_settings, asettings);
2507 link = g_slist_next(link);
2509 queue_item->chapter_list = g_strdupv(ud->chapter_list);
2510 ud->queue = g_slist_append(ud->queue, queue_item);
2511 add_to_queue_list(ud, queue_item);
2512 ghb_add_job (queue_item, unique_id);
2513 queue_item->unique_id = unique_id;
2514 queue_item->status = GHB_QUEUE_PENDING;
2520 queue_add_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
2522 g_debug("queue_add_clicked_cb ()\n");
2527 cancel_encode(const gchar *extra_msg)
2530 GtkResponseType response;
2532 if (extra_msg == NULL) extra_msg = "";
2533 // Toss up a warning dialog
2534 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2535 GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
2536 "%sYour movie will be lost if you don't continue encoding.",
2538 gtk_dialog_add_buttons( GTK_DIALOG(dialog),
2539 "Continue Encoding", GTK_RESPONSE_NO,
2540 "Stop Encoding", GTK_RESPONSE_YES, NULL);
2541 response = gtk_dialog_run(GTK_DIALOG(dialog));
2542 gtk_widget_destroy (dialog);
2543 if (response == GTK_RESPONSE_NO) return FALSE;
2549 queue_remove_clicked_cb(GtkWidget *widget, gchar *path, signal_user_data_t *ud)
2551 GtkTreeView *treeview;
2552 GtkTreePath *treepath;
2553 GtkTreeModel *store;
2558 job_settings_t *queue_item;
2561 g_debug("queue_remove_clicked_cb ()\n");
2562 g_debug("ud %p\n", ud);
2563 g_debug("ud->builder %p\n", ud->builder);
2565 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2566 store = gtk_tree_view_get_model(treeview);
2567 treepath = gtk_tree_path_new_from_string (path);
2568 if (gtk_tree_model_get_iter(store, &iter, treepath))
2570 // Find the entry in the queue
2571 indices = gtk_tree_path_get_indices (treepath);
2573 // Can only free the treepath After getting what I need from
2574 // indices since this points into treepath somewhere.
2575 gtk_tree_path_free (treepath);
2576 if (row < 0) return;
2577 link = g_slist_nth(ud->queue, row);
2578 if (link == NULL) return;
2579 queue_item = (job_settings_t*)link->data;
2580 if (queue_item->status == GHB_QUEUE_RUNNING)
2582 // Ask if wants to stop encode.
2583 if (!cancel_encode(NULL))
2588 // Remove the selected item
2589 g_debug(" should be removing from treestore\n");
2590 gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
2591 // Remove the corresponding item from the queue list
2592 ud->queue = g_slist_remove_link(ud->queue, link);
2593 g_slist_free_1(link);
2594 g_hash_table_destroy(queue_item->settings);
2595 link = queue_item->audio_settings;
2596 while (link != NULL)
2599 g_hash_table_destroy((GHashTable*)link->data);
2600 nextlink = g_slist_next(link);
2601 g_slist_free_1(link);
2604 g_strfreev (queue_item->chapter_list);
2605 unique_id = queue_item->unique_id;
2607 ghb_remove_job(unique_id);
2611 gtk_tree_path_free (treepath);
2616 find_queue_item(GSList *queue, gint unique_id, job_settings_t **job)
2621 while (queue != NULL)
2624 js = (job_settings_t*)queue->data;
2625 if (js->unique_id == unique_id)
2630 queue = queue->next;
2637 queue_buttons_grey(signal_user_data_t *ud, gboolean working)
2641 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2642 gboolean title_ok = (titleindex >= 0);
2643 widget = GHB_WIDGET (ud->builder, "queue_start1");
2644 gtk_widget_set_sensitive (widget, !working && title_ok);
2645 widget = GHB_WIDGET (ud->builder, "queue_start2");
2646 gtk_widget_set_sensitive (widget, !working && title_ok);
2647 action = GHB_ACTION (ud->builder, "queue_start_menu");
2648 gtk_action_set_sensitive (action, !working && title_ok);
2649 widget = GHB_WIDGET (ud->builder, "queue_pause1");
2650 gtk_widget_set_sensitive (widget, working);
2651 widget = GHB_WIDGET (ud->builder, "queue_pause2");
2652 gtk_widget_set_sensitive (widget, working);
2653 action = GHB_ACTION (ud->builder, "queue_pause_menu");
2654 gtk_action_set_sensitive (action, working);
2655 widget = GHB_WIDGET (ud->builder, "queue_stop");
2656 gtk_widget_set_sensitive (widget, working);
2657 action = GHB_ACTION (ud->builder, "queue_stop_menu");
2658 gtk_action_set_sensitive (action, working);
2661 void queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud);
2664 ghb_backend_events(signal_user_data_t *ud)
2666 ghb_status_t status;
2668 GtkProgressBar *progress;
2671 static gint current_id = -1;
2673 GtkTreeView *treeview;
2674 GtkTreeStore *store;
2676 static gint working = 0;
2677 static gboolean work_started = FALSE;
2680 ghb_get_status(&status);
2681 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2682 if (status.state & GHB_STATE_SCANNING)
2684 status_str = g_strdup_printf ("Scanning title %d of %d...",
2685 status.title_cur, status.title_count );
2686 gtk_progress_bar_set_text (progress, status_str);
2688 if (status.title_count > 0)
2690 gtk_progress_bar_set_fraction (progress,
2691 (gdouble)status.title_cur / status.title_count);
2694 else if (status.state & GHB_STATE_SCANDONE)
2696 status_str = g_strdup_printf ("Scan done");
2697 gtk_progress_bar_set_text (progress, status_str);
2699 gtk_progress_bar_set_fraction (progress, 1.0);
2701 ghb_title_info_t tinfo;
2703 ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE);
2704 titleindex = ghb_longest_title();
2705 ghb_ui_update_int(ud, "title", titleindex);
2707 // Are there really any titles.
2708 if (!ghb_get_title_info(&tinfo, titleindex))
2710 GtkProgressBar *progress;
2711 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2712 gtk_progress_bar_set_fraction (progress, 0);
2713 gtk_progress_bar_set_text (progress, "No Source");
2715 ghb_clear_state(GHB_STATE_SCANDONE);
2716 queue_buttons_grey(ud, (0 != (status.state & GHB_STATE_WORKING)));
2718 else if (status.state & GHB_STATE_WORKING)
2720 if(status.seconds > -1)
2722 status_str= g_strdup_printf(
2723 "Encoding: task %d of %d, %.2f %%"
2724 " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)",
2725 status.job_cur, status.job_count,
2726 100.0 * status.progress,
2727 status.rate_cur, status.rate_avg, status.hours,
2728 status.minutes, status.seconds );
2732 status_str= g_strdup_printf(
2733 "Encoding: task %d of %d, %.2f %%",
2734 status.job_cur, status.job_count,
2735 100.0 * status.progress );
2737 gtk_progress_bar_set_text (progress, status_str);
2738 gtk_progress_bar_set_fraction (progress, status.progress);
2741 else if (status.state & GHB_STATE_WORKDONE)
2743 work_started = FALSE;
2744 queue_buttons_grey(ud, FALSE);
2745 index = find_queue_item(ud->queue, current_id, &js);
2746 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2747 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2748 switch( status.error )
2750 case GHB_ERROR_NONE:
2751 gtk_progress_bar_set_text( progress, "Rip done!" );
2754 js->status = GHB_QUEUE_DONE;
2755 gchar *path = g_strdup_printf ("%d", index);
2756 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2758 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
2763 case GHB_ERROR_CANCELED:
2764 gtk_progress_bar_set_text( progress, "Rip canceled." );
2767 js->status = GHB_QUEUE_CANCELED;
2768 gchar *path = g_strdup_printf ("%d", index);
2769 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2771 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
2777 gtk_progress_bar_set_text( progress, "Rip failed.");
2780 js->status = GHB_QUEUE_CANCELED;
2781 gchar *path = g_strdup_printf ("%d", index);
2782 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2784 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
2790 gtk_progress_bar_set_fraction (progress, 1.0);
2791 ghb_clear_state(GHB_STATE_WORKDONE);
2793 else if (status.state & GHB_STATE_PAUSED)
2795 status_str = g_strdup_printf ("Paused");
2796 gtk_progress_bar_set_text (progress, status_str);
2799 else if (status.state & GHB_STATE_MUXING)
2801 gtk_progress_bar_set_text(progress, "Muxing: this may take awhile...");
2803 if (status.state & GHB_STATE_WORKING)
2807 work_started = TRUE;
2808 queue_buttons_grey(ud, TRUE);
2810 if (status.unique_id != current_id)
2812 index = find_queue_item(ud->queue, current_id, &js);
2815 js->status = GHB_QUEUE_DONE;
2816 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2817 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2818 gchar *path = g_strdup_printf ("%d", index);
2819 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2821 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
2826 index = find_queue_item(ud->queue, status.unique_id, &js);
2829 js->status = GHB_QUEUE_RUNNING;
2830 current_id = status.unique_id;
2833 index = find_queue_item(ud->queue, status.unique_id, &js);
2836 gchar working_icon[] = "hb-working0";
2837 working_icon[10] = '0' + working;
2838 working = (working+1) % 6;
2839 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2840 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2841 gchar *path = g_strdup_printf ("%d", index);
2842 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2844 gtk_tree_store_set(store, &iter, 0, working_icon, -1);
2852 ghb_timer_cb(gpointer data)
2854 signal_user_data_t *ud = (signal_user_data_t*)data;
2856 ghb_backend_events(ud);
2857 if (update_default_destination)
2859 const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
2860 gchar *dest_dir = g_path_get_dirname (dest);
2861 const gchar *def_dest = ghb_settings_get_string(ud->settings, "destination_dir");
2862 if (strcmp(dest_dir, def_dest) != 0)
2864 ghb_settings_set_string (ud->settings, "destination_dir", dest_dir);
2865 ghb_pref_save (ud->settings, "destination_dir");
2867 update_default_destination = FALSE;
2871 set_preview_image (ud);
2872 update_preview = FALSE;
2878 ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
2882 GtkTextView *textview;
2883 GtkTextBuffer *buffer;
2886 GError *gerror = NULL;
2889 signal_user_data_t *ud = (signal_user_data_t*)data;
2891 status = g_io_channel_read_line (source, &text, &length, NULL, &gerror);
2897 gboolean bottom = FALSE;
2899 textview = GTK_TEXT_VIEW(GHB_WIDGET (ud->builder, "activity_view"));
2900 buffer = gtk_text_view_get_buffer (textview);
2901 // I would like to auto-scroll the window when the scrollbar
2902 // is at the bottom,
2903 // must determining whether the insert point is at
2904 // the bottom of the window
2905 window = gtk_text_view_get_window(textview, GTK_TEXT_WINDOW_TEXT);
2908 gdk_drawable_get_size(GDK_DRAWABLE(window), &width, &height);
2909 gtk_text_view_window_to_buffer_coords(textview,
2910 GTK_TEXT_WINDOW_TEXT, width, height, &x, &y);
2911 gtk_text_view_get_iter_at_location(textview, &iter, x, y);
2912 if (gtk_text_iter_is_end(&iter))
2919 // If the window isn't available, assume bottom
2922 gtk_text_buffer_get_end_iter(buffer, &iter);
2923 gtk_text_buffer_insert(buffer, &iter, text, -1);
2926 //gtk_text_view_scroll_to_iter(textview, &iter, 0, FALSE, 0, 0);
2927 mark = gtk_text_buffer_get_insert (buffer);
2928 gtk_text_view_scroll_mark_onscreen(textview, mark);
2930 g_io_channel_write_chars (ud->activity_log, text, length, &length, NULL);
2933 if (status != G_IO_STATUS_NORMAL)
2935 // This should never happen, but if it does I would get into an
2936 // infinite loop. Returning false removes this callback.
2937 g_warning("Error while reading activity from pipe\n");
2940 g_warning("%s\n", gerror->message);
2941 g_error_free (gerror);
2946 g_error_free (gerror);
2951 about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2953 GtkWidget *widget = GHB_WIDGET (ud->builder, "hb_about");
2954 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(widget), ghb_version());
2955 gtk_widget_show (widget);
2959 guide_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2963 {"xdg-open","http://trac.handbrake.fr/wiki/HandBrakeGuide",NULL,NULL};
2964 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2968 argv[0] = "gnome-open";
2969 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2973 argv[0] = "kfmclient";
2975 argv[2] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2976 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2980 argv[0] = "firefox";
2981 argv[1] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2983 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2989 hb_about_response_cb(GtkWidget *widget, gint response, signal_user_data_t *ud)
2991 gtk_widget_hide (widget);
2995 show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2997 GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
2998 gtk_widget_show (widget);
3002 show_queue_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3004 GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
3005 gtk_widget_show (widget);
3009 show_presets_toggled_cb(GtkToggleButton *button, signal_user_data_t *ud)
3012 GtkWindow *hb_window;
3014 g_debug("show_presets_clicked_cb ()\n");
3015 widget = GHB_WIDGET (ud->builder, "presets_frame");
3016 if (gtk_toggle_button_get_active(button))
3018 gtk_widget_show_now(widget);
3022 gtk_widget_hide(widget);
3023 hb_window = GTK_WINDOW(GHB_WIDGET (ud->builder, "hb_window"));
3024 gtk_window_resize(hb_window, 16, 16);
3026 ghb_widget_to_setting(ud->settings, GTK_WIDGET(button));
3027 ghb_pref_save(ud->settings, "show_presets");
3031 presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
3033 GtkTreeView *treeview;
3034 GtkTreeSelection *selection;
3035 GtkTreeModel *store;
3038 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
3039 selection = gtk_tree_view_get_selection(treeview);
3040 if (gtk_tree_selection_get_selected(selection, &store, &iter))
3043 path = gtk_tree_model_get_path (store, &iter);
3044 // Make the parent visible in scroll window if it is not.
3045 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
3051 update_chapter_list(signal_user_data_t *ud)
3053 GtkTreeView *treeview;
3055 GtkListStore *store;
3058 gint titleindex, ii;
3060 g_debug("update_chapter_list ()\n");
3061 titleindex = ghb_settings_get_index(ud->settings, "title");
3062 chapters = ghb_get_chapters(titleindex);
3063 if (ud->chapter_list != NULL)
3064 g_strfreev (ud->chapter_list);
3065 ud->chapter_list = chapters;
3067 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
3068 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
3070 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
3074 if (chapters != NULL && chapters[ii])
3076 // Update row with settings data
3077 g_debug("Updating row\n");
3078 gtk_list_store_set(store, &iter,
3084 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
3088 // No more settings data, remove row
3089 g_debug("Removing row\n");
3090 done = !gtk_list_store_remove(store, &iter);
3094 while (chapters != NULL && chapters[ii])
3096 // Additional settings, add row
3097 g_debug("Adding row\n");
3098 g_debug("%d -- %s\n", ii, chapters[ii]);
3099 gtk_list_store_append(store, &iter);
3100 gtk_list_store_set(store, &iter,
3110 chapter_edited_cb(GtkCellRendererText *cell, gchar *path, gchar *text, signal_user_data_t *ud)
3112 GtkTreePath *treepath;
3113 GtkListStore *store;
3114 GtkTreeView *treeview;
3115 GtkTreeViewColumn *column;
3119 g_debug("chapter_edited_cb ()\n");
3120 g_debug("path (%s)\n", path);
3121 g_debug("text (%s)\n", text);
3122 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
3123 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
3124 treepath = gtk_tree_path_new_from_string (path);
3125 gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
3126 gtk_tree_path_free (treepath);
3127 gtk_list_store_set(store, &iter,
3131 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &index, -1);
3132 g_free(ud->chapter_list[index-1]);
3133 ud->chapter_list[index-1] = g_strdup(text);
3134 if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
3136 column = gtk_tree_view_get_column(treeview, 1);
3137 treepath = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
3138 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
3139 gtk_tree_path_free (treepath);
3144 chapter_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
3146 GtkTreeModel *store;
3149 g_debug("chapter_list_selection_changed_cb ()\n");
3150 if (gtk_tree_selection_get_selected(selection, &store, &iter))
3157 queue_list_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, GtkCellRenderer *cell)
3159 GtkTreeViewColumn *column;
3162 column = gtk_tree_view_get_column (GTK_TREE_VIEW(widget), 0);
3163 width = gtk_tree_view_column_get_width(column);
3164 g_debug("col width %d alloc width %d\n", width, allocation->width);
3165 // Set new wrap-width. Shave a little off to accomidate the icons
3166 // that share this column.
3167 if (width >= 564) // Don't allow below a certain size
3168 g_object_set(cell, "wrap-width", width-70, NULL);
3172 preview_button_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3174 gint titleindex = ghb_settings_get_int(ud->settings, "title");
3175 if (titleindex < 0) return;
3176 g_debug("titleindex %d\n", titleindex);
3178 GtkWidget *widget = GHB_WIDGET (ud->builder, "preview_window");
3179 gtk_widget_show (widget);
3183 preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3185 set_preview_image(ud);
3189 preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
3191 g_debug("-------------------------------allocate %d x %d\n", allocation->width, allocation->height);
3192 if (preview_button_width == allocation->width &&
3193 preview_button_height == allocation->height)
3195 // Nothing to do. Bug out.
3196 g_debug("nothing to do\n");
3199 g_debug("-------------------------------prev allocate %d x %d\n", preview_button_width, preview_button_height);
3200 preview_button_width = allocation->width;
3201 preview_button_height = allocation->height;
3202 set_preview_image(ud);
3206 queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3208 GSList *link = ud->queue;
3209 job_settings_t *job;
3210 gboolean running = FALSE;
3211 while (link != NULL)
3213 job = (job_settings_t*)link->data;
3214 if ((job->status == GHB_QUEUE_RUNNING) ||
3215 (job->status == GHB_QUEUE_PENDING))
3224 // The queue has no running or pending jobs.
3225 // Add current settings to the queue, then run.
3233 queue_stop_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3235 cancel_encode(NULL);
3239 queue_pause_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3245 presets_default_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3247 ghb_set_preset_default(ud->settings);
3248 ghb_presets_list_update(ud);
3252 debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data)
3254 signal_user_data_t *ud = (signal_user_data_t*)data;
3258 printf("%s: %s\n", domain, msg);
3263 set_visible(GtkWidget *widget, gboolean visible)
3267 gtk_widget_show_now(widget);
3271 gtk_widget_hide(widget);
3276 ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
3279 g_debug("ghb_hbfd\n");
3280 widget = GHB_WIDGET(ud->builder, "queue_pause1");
3281 set_visible(widget, !hbfd);
3282 widget = GHB_WIDGET(ud->builder, "queue_add");
3283 set_visible(widget, !hbfd);
3284 widget = GHB_WIDGET(ud->builder, "show_queue");
3285 set_visible(widget, !hbfd);
3286 widget = GHB_WIDGET(ud->builder, "show_activity");
3287 set_visible(widget, !hbfd);
3289 widget = GHB_WIDGET(ud->builder, "chapter_box");
3290 set_visible(widget, !hbfd);
3291 widget = GHB_WIDGET(ud->builder, "container_box");
3292 set_visible(widget, !hbfd);
3293 widget = GHB_WIDGET(ud->builder, "settings_box");
3294 set_visible(widget, !hbfd);
3295 widget = GHB_WIDGET(ud->builder, "presets_save");
3296 set_visible(widget, !hbfd);
3297 widget = GHB_WIDGET(ud->builder, "presets_remove");
3298 set_visible(widget, !hbfd);
3299 widget = GHB_WIDGET(ud->builder, "presets_default");
3300 set_visible(widget, !hbfd);
3301 widget = GHB_WIDGET (ud->builder, "hb_window");
3302 gtk_window_resize(GTK_WINDOW(widget), 16, 16);
3307 hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
3309 g_debug("hbfd_toggled_cb\n");
3310 ghb_widget_to_setting (ud->settings, widget);
3311 gboolean hbfd = ghb_settings_get_bool(ud->settings, "hbfd");
3313 ghb_pref_save(ud->settings, "hbfd");
3317 pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3319 g_debug("pref_changed_cb\n");
3320 ghb_widget_to_setting (ud->settings, widget);
3321 const gchar *name = gtk_widget_get_name(widget);
3322 ghb_pref_save(ud->settings, name);
3326 ghb_file_menu_add_dvd(signal_user_data_t *ud)
3328 GList *link, *drives;
3330 GtkActionGroup *agroup = GTK_ACTION_GROUP(
3331 gtk_builder_get_object(ud->builder, "actiongroup1"));
3332 GtkUIManager *ui = GTK_UI_MANAGER(
3333 gtk_builder_get_object(ud->builder, "uimanager1"));
3334 guint merge_id = gtk_ui_manager_new_merge_id(ui);
3336 link = drives = dvd_device_list();
3337 while (link != NULL)
3339 gchar *name = (gchar*)link->data;
3340 // Create action for this drive
3341 GtkAction *action = gtk_action_new(name, name,
3342 "Scan this DVD source", "gtk-cdrom");
3343 // Add action to action group
3344 gtk_action_group_add_action_with_accel(agroup, action, "");
3345 // Add to ui manager
3346 gtk_ui_manager_add_ui(ui, merge_id,
3347 "ui/menubar1/menuitem1/quit1", name, name,
3348 GTK_UI_MANAGER_AUTO, TRUE);
3349 // Connect signal to action (menu item)
3350 g_signal_connect(action, "activate",
3351 (GCallback)dvd_source_activate_cb, ud);
3355 g_list_free(drives);
3358 gtk_ui_manager_add_ui(ui, merge_id,
3359 "ui/menubar1/menuitem1/quit1", "", NULL,
3360 GTK_UI_MANAGER_AUTO, TRUE);
3363 gboolean ghb_is_cd(GDrive *gd);
3368 GVolumeMonitor *gvm;
3369 GList *drives, *link;
3370 GList *dvd_devices = NULL;
3372 gvm = g_volume_monitor_get ();
3373 drives = g_volume_monitor_get_connected_drives (gvm);
3375 while (link != NULL)
3379 gd = (GDrive*)link->data;
3383 device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3384 dvd_devices = g_list_append(dvd_devices, (gpointer)device);
3386 g_object_unref (gd);
3389 g_list_free(drives);
3394 static DBusConnection *dbus_connection = NULL;
3395 static LibHalContext *hal_ctx;
3398 ghb_is_cd(GDrive *gd)
3401 LibHalDrive *halDrive;
3402 LibHalDriveType dtype;
3404 device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3405 halDrive = libhal_drive_from_device_file (hal_ctx, device);
3406 dtype = libhal_drive_get_type(halDrive);
3408 return (dtype == LIBHAL_DRIVE_TYPE_CDROM);
3412 drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
3415 gint state = ghb_get_state();
3416 static gboolean first_time = TRUE;
3418 if (ud->current_dvd_device == NULL) return;
3419 // A drive change event happens when the program initially starts
3420 // and I don't want to automatically scan at that time.
3426 if (state != GHB_STATE_IDLE) return;
3427 device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3429 // DVD insertion detected. Scan it.
3430 if (strcmp(device, ud->current_dvd_device) == 0)
3432 if (g_drive_has_media (gd))
3434 GtkProgressBar *progress;
3435 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
3436 gtk_progress_bar_set_text (progress, "Scanning ...");
3437 gtk_progress_bar_set_fraction (progress, 0);
3438 update_source_label(ud, device);
3439 ghb_hb_cleanup(TRUE);
3440 ghb_backend_scan(device, 0);
3444 ghb_hb_cleanup(TRUE);
3445 ghb_backend_scan("/dev/null", 0);
3457 if (dbus_connection != NULL)
3460 dbus_error_init (&error);
3461 if (!(dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) {
3462 g_debug ("could not get system bus: %s\n", error.message);
3463 dbus_error_free (&error);
3467 //dbus_connection_setup_with_g_main (dbus_connection, NULL);
3468 //dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
3469 //dbus_connection_add_filter (dbus_connection, gvm_dbus_filter_function, NULL, NULL);
3484 if (!(hal_ctx = libhal_ctx_new ())) {
3485 g_warning ("failed to create a HAL context!");
3489 libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
3490 dbus_error_init (&error);
3491 if (!libhal_ctx_init (hal_ctx, &error)) {
3492 g_warning ("libhal_ctx_init failed: %s", error.message ? error.message : "unknown");
3493 dbus_error_free (&error);
3494 libhal_ctx_free (hal_ctx);
3499 * Do something to ping the HAL daemon - the above functions will
3500 * succeed even if hald is not running, so long as DBUS is. But we
3501 * want to exit silently if hald is not running, to behave on
3504 if (!(devices = libhal_get_all_devices (hal_ctx, &nr, &error))) {
3505 g_warning ("seems that HAL is not running: %s", error.message ? error.message : "unknown");
3506 dbus_error_free (&error);
3508 libhal_ctx_shutdown (hal_ctx, NULL);
3509 libhal_ctx_free (hal_ctx);
3513 libhal_free_string_array (devices);
3515 //gvm_hal_claim_branch ("/org/freedesktop/Hal/devices/local");
3521 GdkEventButton *event,
3522 signal_user_data_t *ud)
3526 gboolean ret = FALSE;
3527 gboolean allow_tweaks;
3529 g_debug("press %d %d", event->type, event->button);
3530 allow_tweaks = ghb_settings_get_bool (ud->settings, "allow_tweaks");
3531 if (allow_tweaks && event->type == GDK_BUTTON_PRESS && event->button == 3)
3532 { // Its a right mouse click
3535 GtkResponseType response;
3536 const gchar *tweak = NULL;
3538 name = gtk_widget_get_name(widget);
3539 if (g_str_has_prefix(name, "tweak_"))
3541 tweak_name = g_strdup(name);
3545 tweak_name = g_strdup_printf("tweak_%s", name);
3548 tweak = ghb_settings_get_string (ud->settings, tweak_name);
3549 dialog = GHB_WIDGET(ud->builder, "tweak_dialog");
3550 gtk_window_set_title(GTK_WINDOW(dialog), tweak_name);
3551 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "tweak_setting"));
3553 gtk_entry_set_text(entry, tweak);
3554 response = gtk_dialog_run(GTK_DIALOG(dialog));
3555 gtk_widget_hide(dialog);
3556 if (response == GTK_RESPONSE_OK)
3558 tweak = gtk_entry_get_text(entry);
3559 if (ghb_validate_filter_string(tweak, -1))
3560 ghb_settings_set_string(ud->settings, tweak_name, tweak);
3564 message = g_strdup_printf(
3565 "Invalid Settings:\n%s",
3567 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);