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", "audio_label", "none", TRUE},
63 {"title", "audio_tab", "none", TRUE},
64 {"title", "chapters_label", "none", TRUE},
65 {"title", "chapters_tab", "none", TRUE},
66 {"title", "title", "none", TRUE},
67 {"title", "start_chapter", "none", TRUE},
68 {"title", "end_chapter", "none", TRUE},
69 {"vquality_type_bitrate", "video_bitrate", "enable", FALSE},
70 {"vquality_type_target", "video_target_size", "enable", FALSE},
71 {"vquality_type_constant", "video_quality", "enable", FALSE},
72 {"vquality_type_constant", "constant_rate_factor", "enable", FALSE},
73 {"vquality_type_constant", "x264_trellis", "enable", TRUE},
74 {"vquality_type_constant", "two_pass", "enable", TRUE},
75 {"vquality_type_constant", "turbo", "enable", TRUE},
76 {"two_pass", "turbo", "enable", FALSE},
77 {"container", "large_mp4", "mp4|m4v", FALSE},
78 {"container", "http_optimize_mp4", "mp4|m4v", FALSE},
79 {"container", "ipod_file", "mp4|m4v", FALSE},
80 {"container", "variable_frame_rate", "avi", TRUE},
81 {"variable_frame_rate", "framerate", "enable", TRUE},
82 {"variable_frame_rate", "detelecine", "enable", TRUE},
83 {"decomb", "deinterlace", "enable", TRUE},
84 {"autocrop", "crop_top", "disable", FALSE},
85 {"autocrop", "crop_bottom", "disable", FALSE},
86 {"autocrop", "crop_left", "disable", FALSE},
87 {"autocrop", "crop_right", "disable", FALSE},
88 {"autoscale", "scale_width", "disable", FALSE},
89 {"autoscale", "scale_height", "disable", FALSE},
90 {"anamorphic", "keep_aspect", "disable", FALSE},
91 {"anamorphic", "scale_height", "disable", FALSE},
92 {"keep_aspect", "scale_height", "disable", FALSE},
93 {"video_codec", "x264_tab", "x264", FALSE},
94 {"video_codec", "x264_tab_label", "x264", FALSE},
95 {"video_codec", "ipod_file", "x264", FALSE},
96 {"audio_track", "audio_add", "none", TRUE},
97 {"audio_track", "audio_codec", "none", TRUE},
98 {"audio_track", "audio_bitrate", "none", TRUE},
99 {"audio_track", "audio_sample_rate", "none", TRUE},
100 {"audio_track", "audio_mix", "none", TRUE},
101 {"audio_track", "audio_drc", "none", TRUE},
102 {"audio_codec", "audio_bitrate", "ac3", TRUE},
103 {"audio_codec", "audio_sample_rate", "ac3", TRUE},
104 {"audio_codec", "audio_mix", "ac3", TRUE},
105 {"audio_codec", "audio_drc", "ac3", TRUE},
106 {"x264_bframes", "x264_weighted_bframes", "0", TRUE},
107 {"x264_bframes", "x264_brdo", "0", TRUE},
108 {"x264_bframes", "x264_bime", "0", TRUE},
109 {"x264_bframes", "x264_bpyramid", "<2", TRUE},
110 {"x264_bframes", "x264_direct", "0", TRUE},
111 {"x264_refs", "x264_mixed_refs", "<2", TRUE},
112 {"x264_cabac", "x264_trellis", "enable", FALSE},
113 {"x264_subme", "x264_brdo", "<6", TRUE},
114 {"x264_analyse", "x264_direct", "none", TRUE},
115 {"x264_me", "x264_merange", "umh|esa", FALSE},
116 {"pref_audio_codec1", "pref_audio_bitrate1", "none", TRUE},
117 {"pref_audio_codec1", "pref_audio_rate1", "none", TRUE},
118 {"pref_audio_codec1", "pref_audio_mix1", "none", TRUE},
119 {"pref_audio_codec1", "pref_audio_codec2", "none", TRUE},
120 {"pref_audio_codec1", "pref_audio_bitrate2", "none", TRUE},
121 {"pref_audio_codec1", "pref_audio_rate2", "none", TRUE},
122 {"pref_audio_codec1", "pref_audio_mix2", "none", TRUE},
123 {"pref_audio_codec2", "pref_audio_bitrate2", "none", TRUE},
124 {"pref_audio_codec2", "pref_audio_rate2", "none", TRUE},
125 {"pref_audio_codec2", "pref_audio_mix2", "none", TRUE},
126 {"chapter_markers", "chapters_list", "enable", FALSE},
130 dep_check(signal_user_data_t *ud, const gchar *name)
136 int count = sizeof(dep_map) / sizeof(dependency_t);
137 gboolean result = TRUE;
139 g_debug("dep_check () %s\n", name);
140 for (ii = 0; ii < count; ii++)
142 if (strcmp(dep_map[ii].dep_name, name) == 0)
144 widget = GHB_WIDGET(ud->builder, dep_map[ii].widget_name);
145 dep_object = gtk_builder_get_object(ud->builder, dep_map[ii].dep_name);
146 value = ghb_widget_short_opt(widget);
147 if (dep_object == NULL || widget == NULL)
149 g_message("Failed to find widget\n");
154 gchar **values = g_strsplit(dep_map[ii].enable_value, "|", 10);
155 gboolean sensitive = FALSE;
157 while (values && values[jj])
159 if (values[jj][0] == '>')
161 gdouble dbl = g_strtod (&values[jj][1], NULL);
162 gdouble dvalue = ghb_widget_dbl (widget);
169 else if (values[jj][0] == '<')
171 gdouble dbl = g_strtod (&values[jj][1], NULL);
172 gdouble dvalue = ghb_widget_dbl (widget);
179 if (strcmp(values[jj], value) == 0)
186 sensitive = dep_map[ii].disable_if_equal ^ sensitive;
187 if (!sensitive) result = FALSE;
197 check_depencency(signal_user_data_t *ud, GtkWidget *widget)
202 int count = sizeof(dep_map) / sizeof(dependency_t);
204 if (ghb_widget_index(widget) < 0) return;
205 name = gtk_widget_get_name(widget);
206 g_debug("check_depencency () %s\n", name);
207 for (ii = 0; ii < count; ii++)
209 if (strcmp(dep_map[ii].widget_name, name) == 0)
213 dep_object = gtk_builder_get_object (ud->builder, dep_map[ii].dep_name);
214 if (dep_object == NULL)
216 g_message("Failed to find dependent widget %s\n", dep_map[ii].dep_name);
219 sensitive = dep_check(ud, dep_map[ii].dep_name);
220 if (GTK_IS_ACTION(dep_object))
221 gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
223 gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
229 ghb_check_all_depencencies(signal_user_data_t *ud)
233 int count = sizeof(dep_map) / sizeof(dependency_t);
235 g_debug("ghb_check_all_depencencies ()\n");
236 for (ii = 0; ii < count; ii++)
239 dep_object = gtk_builder_get_object (ud->builder, dep_map[ii].dep_name);
240 if (dep_object == NULL)
242 g_message("Failed to find dependent widget %s\n", dep_map[ii].dep_name);
245 sensitive = dep_check(ud, dep_map[ii].dep_name);
246 if (GTK_IS_ACTION(dep_object))
247 gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
249 gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
254 clear_presets_selection(signal_user_data_t *ud)
256 GtkTreeView *treeview;
257 GtkTreeSelection *selection;
259 if (ud->dont_clear_presets) return;
260 g_debug("clear_presets_selection()\n");
261 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
262 selection = gtk_tree_view_get_selection (treeview);
263 gtk_tree_selection_unselect_all (selection);
267 expand_tilde(const gchar *path)
269 const gchar *user_home;
272 gchar *expanded_path = NULL;
274 g_debug("expand_tilde ()\n");
277 user_home = g_get_home_dir();
278 home = NULL; // squash warning about home uninitialized
281 home = g_strdup(user_home);
284 else if (path[1] == '/')
286 home = g_strdup(user_home);
291 home = g_path_get_dirname(user_home);
294 expanded_path = g_strdup_printf("%s/%s", home, suffix);
297 return expanded_path;
301 on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud)
303 gint state = ghb_get_state();
304 g_debug("on_quit1_activate ()\n");
305 if (state & GHB_STATE_WORKING)
307 if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
309 ghb_hb_cleanup(FALSE);
315 ghb_hb_cleanup(FALSE);
320 set_destination(signal_user_data_t *ud)
322 if (ghb_settings_get_bool(ud->settings, "use_source_name"))
324 const gchar *vol_name, *filename, *extension;
325 gchar *dir, *new_name;
327 filename = ghb_settings_get_string(ud->settings, "destination");
328 extension = ghb_settings_get_string(ud->settings, "container");
329 dir = g_path_get_dirname (filename);
330 vol_name = ghb_settings_get_string(ud->settings, "volume_label");
331 g_debug("volume_label (%s)\n", vol_name);
332 if (vol_name == NULL)
334 vol_name = "new_video";
336 new_name = g_strdup_printf("%s/%s.%s", dir, vol_name, extension);
337 ghb_ui_update(ud, "destination", new_name);
344 uppers_and_unders(const gchar *str)
346 if (str == NULL) return FALSE;
353 if (*str >= 'a' && *str <= 'z')
369 camel_convert(gchar *str)
371 gint state = CAMEL_OTHER;
373 if (str == NULL) return;
376 if (*str == '_') *str = ' ';
381 if (*str >= 'A' && *str <= 'Z')
382 state = CAMEL_FIRST_UPPER;
387 case CAMEL_FIRST_UPPER:
389 if (*str >= 'A' && *str <= 'Z')
390 *str = *str - 'A' + 'a';
400 update_source_label(signal_user_data_t *ud, const gchar *source)
405 gchar *filename = g_strdup(source);
407 len = strlen(filename);
408 if (filename[len-1] == '/') filename[len-1] = 0;
409 if (g_file_test(filename, G_FILE_TEST_IS_DIR))
411 path = g_strsplit(filename, "/", -1);
412 len = g_strv_length (path);
413 if ((len > 1) && (strcmp("VIDEO_TS", path[len-1]) == 0))
415 label = g_strdup(path[len-2]);
419 label = g_strdup(path[len-1]);
425 // Is regular file or block dev.
426 // Check to see if it is a dvd image
427 label = ghb_dvd_volname (filename);
430 path = g_strsplit(filename, "/", -1);
431 len = g_strv_length (path);
432 // Just use the last combonent of the path
433 label = g_strdup(path[len-1]);
438 if (uppers_and_unders(label))
440 camel_convert(label);
445 GtkWidget *widget = GHB_WIDGET (ud->builder, "source_title");
448 gtk_label_set_text (GTK_LABEL(widget), label);
449 ghb_settings_set_string(ud->settings, "volume_label", label);
455 label = "No Title Found";
456 gtk_label_set_text (GTK_LABEL(widget), label);
457 ghb_settings_set_string(ud->settings, "volume_label", label);
463 static GtkWidget *dvd_device_combo = NULL;
466 chooser_file_selected_cb(GtkFileChooser *dialog, GtkComboBox *combo)
468 const gchar *name = gtk_file_chooser_get_filename (dialog);
472 gboolean foundit = FALSE;
474 if (name == NULL) return;
475 store = gtk_combo_box_get_model(combo);
476 if (gtk_tree_model_get_iter_first(store, &iter))
480 gtk_tree_model_get(store, &iter, 0, &device, -1);
481 if (strcmp(name, device) == 0)
486 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
489 gtk_combo_box_set_active_iter (combo, &iter);
491 gtk_combo_box_set_active (combo, 0);
495 dvd_device_changed_cb(GtkComboBox *combo, GtkWidget *dialog)
497 gint ii = gtk_combo_box_get_active (combo);
500 const gchar *device = gtk_combo_box_get_active_text (combo);
501 const gchar *name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog));
502 if (name == NULL || strcmp(name, device) != 0)
503 gtk_file_chooser_select_filename (GTK_FILE_CHOOSER(dialog), device);
509 source_type_changed_cb(GtkToggleButton *toggle, GtkFileChooser *chooser)
513 g_debug("source_type_changed_cb ()\n");
514 if (gtk_toggle_button_get_active (toggle))
516 filename = gtk_file_chooser_get_filename (chooser);
517 gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
518 if (filename != NULL)
520 gtk_file_chooser_set_filename(chooser, filename);
523 gtk_widget_set_sensitive (dvd_device_combo, FALSE);
524 gtk_combo_box_set_active (GTK_COMBO_BOX(dvd_device_combo), 0);
528 filename = gtk_file_chooser_get_filename (chooser);
529 gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_OPEN);
530 if (filename != NULL)
532 gtk_file_chooser_set_filename(chooser, filename);
535 gtk_widget_set_sensitive (dvd_device_combo, TRUE);
540 source_dialog_extra_widgets(GtkWidget *dialog, gboolean checkbutton_active)
543 GtkWidget *checkbutton;
545 vbox = GTK_BOX(gtk_vbox_new (FALSE, 2));
546 checkbutton = gtk_check_button_new_with_label ("Open VIDEO_TS folder");
547 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), checkbutton_active);
548 gtk_box_pack_start (vbox, checkbutton, FALSE, FALSE, 1);
549 gtk_widget_show(checkbutton);
553 GList *drives, *link;
554 GtkWidget *label, *blank;
556 hbox = GTK_BOX(gtk_hbox_new (FALSE, 2));
557 combo = gtk_combo_box_new_text();
558 label = gtk_label_new("Detected DVD devices:");
559 blank = gtk_label_new("");
560 link = drives = dvd_device_list();
561 gtk_combo_box_append_text (GTK_COMBO_BOX(combo), "Not Selected");
564 gchar *name = (gchar*)link->data;
565 gtk_combo_box_append_text (GTK_COMBO_BOX(combo), name);
570 gtk_combo_box_set_active (GTK_COMBO_BOX(combo), 0);
571 gtk_box_pack_start (vbox, GTK_WIDGET(hbox), FALSE, FALSE, 1);
572 gtk_widget_show(GTK_WIDGET(hbox));
573 gtk_box_pack_start (hbox, label, FALSE, FALSE, 1);
574 gtk_widget_show(label);
575 gtk_box_pack_start (hbox, combo, FALSE, FALSE, 2);
576 gtk_widget_show(combo);
577 gtk_box_pack_start (hbox, blank, TRUE, TRUE, 1);
578 gtk_widget_show(blank);
580 // Ugly hackish global alert
581 dvd_device_combo = combo;
582 g_signal_connect(combo, "changed", (GCallback)dvd_device_changed_cb, dialog);
583 g_signal_connect(dialog, "selection-changed", (GCallback)chooser_file_selected_cb, combo);
585 g_signal_connect(checkbutton, "toggled", (GCallback)source_type_changed_cb, dialog);
586 return GTK_WIDGET(vbox);
590 do_scan(signal_user_data_t *ud, const gchar *filename)
592 if (filename != NULL)
594 ghb_settings_set_string(ud->settings, "source", filename);
595 if (update_source_label(ud, filename))
597 GtkProgressBar *progress;
598 progress = GTK_PROGRESS_BAR(GHB_WIDGET(ud->builder, "progressbar"));
600 path = ghb_settings_get_string( ud->settings, "source");
601 gtk_progress_bar_set_fraction (progress, 0);
602 gtk_progress_bar_set_text (progress, "Scanning ...");
603 ghb_hb_cleanup(TRUE);
604 ghb_backend_scan (path, 0);
608 // TODO: error dialog
614 source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
618 const gchar *sourcename;
620 GtkFileChooserAction action;
621 gboolean checkbutton_active;
623 g_debug("source_browse_clicked_cb ()\n");
624 sourcename = ghb_settings_get_string(ud->settings, "source");
625 checkbutton_active = FALSE;
626 if (g_file_test(sourcename, G_FILE_TEST_IS_DIR))
628 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
629 checkbutton_active = TRUE;
633 action = GTK_FILE_CHOOSER_ACTION_OPEN;
635 dialog = gtk_file_chooser_dialog_new ("Select Source",
638 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
639 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
641 widget = source_dialog_extra_widgets(dialog, checkbutton_active);
642 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), widget);
643 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), sourcename);
644 response = gtk_dialog_run(GTK_DIALOG (dialog));
645 gtk_widget_hide(dialog);
646 if (response == GTK_RESPONSE_ACCEPT)
650 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
651 if (filename != NULL)
653 do_scan(ud, filename);
654 if (strcmp(sourcename, filename) != 0)
656 ghb_settings_set_string (ud->settings, "default_source", filename);
657 ghb_pref_save (ud->settings, "default_source");
658 ghb_dvd_set_current (filename, ud);
663 gtk_widget_destroy(dialog);
667 dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
669 const gchar *filename;
670 const gchar *sourcename;
672 sourcename = ghb_settings_get_string(ud->settings, "source");
673 filename = gtk_action_get_name(action);
674 do_scan(ud, filename);
675 if (strcmp(sourcename, filename) != 0)
677 ghb_settings_set_string (ud->settings, "default_source", filename);
678 ghb_pref_save (ud->settings, "default_source");
679 ghb_dvd_set_current (filename, ud);
684 update_destination_extension(signal_user_data_t *ud)
686 static gchar *containers[] = {".mkv", ".mp4", ".m4v", ".avi", ".ogm", NULL};
688 const gchar *extension;
692 g_debug("update_destination_extension ()\n");
693 extension = ghb_settings_get_string(ud->settings, "container");
694 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "destination"));
695 filename = g_strdup(gtk_entry_get_text(entry));
696 for (ii = 0; containers[ii] != NULL; ii++)
698 if (g_str_has_suffix(filename, containers[ii]))
703 pos = g_strrstr( filename, "." );
706 // No period? shouldn't happen
710 if (strcmp(extension, &pos[1]) == 0)
712 // Extension is already correct
715 new_name = g_strjoin(".", filename, extension, NULL);
716 ghb_ui_update(ud, "destination", new_name);
724 static gboolean update_default_destination = FALSE;
727 destination_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
731 g_debug("destination_entry_changed_cb ()\n");
732 if ((dest = expand_tilde(gtk_entry_get_text(entry))) != NULL)
734 gtk_entry_set_text(entry, dest);
737 update_destination_extension(ud);
738 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
739 // This signal goes off with ever keystroke, so I'm putting this
740 // update on the timer.
741 update_default_destination = TRUE;
745 destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
749 const char *destname;
752 g_debug("destination_browse_clicked_cb ()\n");
753 destname = ghb_settings_get_string(ud->settings, "destination");
754 dialog = gtk_file_chooser_dialog_new ("Choose Destination",
756 GTK_FILE_CHOOSER_ACTION_SAVE,
757 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
758 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
760 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), destname);
761 basename = g_path_get_basename(destname);
762 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
764 if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
768 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
769 entry = (GtkEntry*)GHB_WIDGET(ud->builder, "destination");
772 g_debug("Failed to find widget: %s\n", "destination");
776 gtk_entry_set_text(entry, filename);
780 gtk_widget_destroy(dialog);
784 window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
786 g_debug("window_destroy_event_cb ()\n");
787 ghb_hb_cleanup(FALSE);
793 window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
795 gint state = ghb_get_state();
796 g_debug("window_delete_event_cb ()\n");
797 if (state & GHB_STATE_WORKING)
799 if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
801 ghb_hb_cleanup(FALSE);
807 ghb_hb_cleanup(FALSE);
813 update_acodec_combo(signal_user_data_t *ud)
815 ghb_grey_combo_options (ud->builder);
819 container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
821 g_debug("container_changed_cb ()\n");
822 ghb_widget_to_setting(ud->settings, widget);
823 update_destination_extension(ud);
824 check_depencency(ud, widget);
825 update_acodec_combo(ud);
826 clear_presets_selection(ud);
827 if (ghb_ac3_in_audio_list (ud->audio_settings))
829 const gchar *container;
831 container = ghb_settings_get_string(ud->settings, "container");
832 if (strcmp(container, "mp4") == 0)
834 ghb_ui_update(ud, "container", "m4v");
840 get_aspect_string(gint aspect_n, gint aspect_d)
846 aspect = g_strdup_printf("%d:%d", aspect_n, aspect_d);
850 gdouble aspect_nf = (gdouble)aspect_n / aspect_d;
851 aspect = g_strdup_printf("%.2f:1", aspect_nf);
857 get_rate_string(gint rate_base, gint rate)
859 gdouble rate_f = (gdouble)rate / rate_base;
862 rate_s = g_strdup_printf("%.6g", rate_f);
866 show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
871 widget = GHB_WIDGET (ud->builder, "title_duration");
872 if (tinfo->duration != 0)
874 text = g_strdup_printf ("%02d:%02d:%02d", tinfo->hours,
875 tinfo->minutes, tinfo->seconds);
879 text = g_strdup_printf ("Unknown");
881 gtk_label_set_text (GTK_LABEL(widget), text);
883 widget = GHB_WIDGET (ud->builder, "source_dimensions");
884 text = g_strdup_printf ("%d x %d", tinfo->width, tinfo->height);
885 gtk_label_set_text (GTK_LABEL(widget), text);
887 widget = GHB_WIDGET (ud->builder, "source_aspect");
888 text = get_aspect_string(tinfo->aspect_n, tinfo->aspect_d);
889 gtk_label_set_text (GTK_LABEL(widget), text);
892 widget = GHB_WIDGET (ud->builder, "source_frame_rate");
893 text = (gchar*)get_rate_string(tinfo->rate_base, tinfo->rate);
894 gtk_label_set_text (GTK_LABEL(widget), text);
897 ghb_ui_update_int (ud, "scale_width", tinfo->width - tinfo->crop[2] - tinfo->crop[3]);
898 // If anamorphic or keep_aspect, the hight will be automatically calculated
899 gboolean keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
900 gboolean anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
901 if (!(keep_aspect || anamorphic))
902 ghb_ui_update_int (ud, "scale_height", tinfo->height - tinfo->crop[0] - tinfo->crop[1]);
904 // Set the limits of cropping. hb_set_anamorphic_size crashes if
905 // you pass it a cropped width or height == 0.
907 bound = tinfo->height / 2 - 2;
908 widget = GHB_WIDGET (ud->builder, "crop_top");
909 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
910 widget = GHB_WIDGET (ud->builder, "crop_bottom");
911 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
912 bound = tinfo->width / 2 - 2;
913 widget = GHB_WIDGET (ud->builder, "crop_left");
914 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
915 widget = GHB_WIDGET (ud->builder, "crop_right");
916 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
917 if (ghb_settings_get_bool (ud->settings, "autocrop"))
919 ghb_ui_update_int (ud, "crop_top", tinfo->crop[0]);
920 ghb_ui_update_int (ud, "crop_bottom", tinfo->crop[1]);
921 ghb_ui_update_int (ud, "crop_left", tinfo->crop[2]);
922 ghb_ui_update_int (ud, "crop_right", tinfo->crop[3]);
924 g_debug("setting max end chapter %d\n", tinfo->num_chapters);
925 widget = GHB_WIDGET (ud->builder, "end_chapter");
926 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters);
927 gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), tinfo->num_chapters);
928 widget = GHB_WIDGET (ud->builder, "start_chapter");
929 gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1);
933 adjust_audio_rate_combos(signal_user_data_t *ud)
935 gint titleindex, audioindex, acodec;
936 ghb_audio_info_t ainfo;
939 g_debug("adjust_audio_rate_combos ()\n");
940 titleindex = ghb_settings_get_index(ud->settings, "title");
942 widget = GHB_WIDGET(ud->builder, "audio_track");
943 audioindex = ghb_widget_int(widget);
945 widget = GHB_WIDGET(ud->builder, "audio_codec");
946 acodec = ghb_widget_int(widget);
948 if (ghb_get_audio_info (&ainfo, titleindex, audioindex) && ghb_audio_is_passthru (acodec))
950 // Set the values for bitrate and samplerate to the input rates
951 ghb_set_passthru_rate_opts (ud->builder, ainfo.bitrate);
952 ghb_ui_update_int (ud, "audio_bitrate", ainfo.bitrate);
953 ghb_ui_update_int (ud, "audio_sample_rate", 0);
954 ghb_ui_update_int (ud, "audio_mix", 0);
958 ghb_set_default_rate_opts (ud->builder);
963 set_pref_audio(gint titleindex, signal_user_data_t *ud)
965 gint acodec, track, ivalue;
968 ghb_audio_info_t ainfo;
969 gboolean skipped_1st = FALSE;
971 // Clear the audio list
972 clear_audio_list(ud);
974 // Find "best" audio based on audio preferences
975 button = GHB_WIDGET (ud->builder, "audio_add");
976 svalue = ghb_settings_get_short_opt(ud->settings, "pref_source_audio_lang");
977 acodec = ghb_settings_get_int(ud->settings, "pref_source_audio_codec");
978 track = ghb_find_audio_track(titleindex, svalue, acodec);
979 ghb_ui_update_int(ud, "audio_track", track);
980 // Get the resulting track, it may not be what was asked for.
981 track = ghb_settings_get_int(ud->settings, "audio_track");
984 // No audio tracks. Perhaps no source dvd yet
985 // Just initialize the audio controls and do not add anything to
987 acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec1");
988 ghb_ui_update_int(ud, "audio_codec", acodec);
989 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
990 ghb_ui_update_int(ud, "audio_bitrate", ivalue);
991 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
992 ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
993 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
994 ghb_ui_update_int(ud, "audio_mix", ivalue);
995 svalue = ghb_settings_get_string(ud->settings, "pref_audio_drc");
996 ghb_ui_update(ud, "audio_drc", svalue);
999 acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec1");
1001 // 1. pref codec is ac3
1002 // 2. source codec is not ac3
1003 // 3. 2nd pref is enabled
1004 if (ghb_get_audio_info (&ainfo, titleindex, track) && ghb_audio_is_passthru (acodec))
1006 if (!ghb_audio_is_passthru(ainfo.codec))
1008 acodec = ghb_get_default_acodec();
1009 if (ghb_settings_get_int(ud->settings, "pref_audio_codec2") != 0)
1011 // Skip first pref audio
1017 ghb_ui_update_int(ud, "audio_codec", acodec);
1018 if (!ghb_audio_is_passthru (acodec))
1020 // This gets set autimatically if the codec is passthru
1021 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
1022 ghb_ui_update_int(ud, "audio_bitrate", ivalue);
1023 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
1024 ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
1025 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
1026 ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1027 ghb_ui_update_int(ud, "audio_mix", ivalue);
1029 svalue = ghb_settings_get_string(ud->settings, "pref_audio_drc");
1030 ghb_ui_update(ud, "audio_drc", svalue);
1031 if (acodec != 0) // 0 is none
1033 // Add to audio list
1034 g_signal_emit_by_name(button, "clicked", ud);
1036 acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec2");
1038 // 1. pref codec is ac3
1039 // 2. source codec is not ac3
1040 if (ghb_audio_is_passthru (acodec))
1042 if (!ghb_audio_is_passthru(ainfo.codec) && skipped_1st)
1044 acodec = ghb_get_default_acodec();
1053 ghb_ui_update_int(ud, "audio_codec", acodec);
1054 // Do the second prefs track
1055 if (!ghb_audio_is_passthru (acodec))
1057 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate2");
1058 ghb_ui_update_int(ud, "audio_bitrate", ivalue);
1059 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate2");
1060 ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
1061 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix2");
1062 ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1063 ghb_ui_update_int(ud, "audio_mix", ivalue);
1065 g_signal_emit_by_name(button, "clicked", ud);
1069 static gint preview_button_width;
1070 static gint preview_button_height;
1071 static gboolean update_preview = FALSE;
1074 set_preview_image(signal_user_data_t *ud)
1077 gint preview_width, preview_height, target_height, width, height;
1079 g_debug("set_preview_button_image ()\n");
1080 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1081 if (titleindex < 0) return;
1082 widget = GHB_WIDGET (ud->builder, "preview_frame");
1083 gint frame = ghb_widget_int(widget) - 1;
1084 GdkPixbuf *preview = ghb_get_preview_image (titleindex, frame, ud->settings, TRUE);
1085 if (preview == NULL) return;
1086 widget = GHB_WIDGET (ud->builder, "preview_image");
1087 gtk_image_set_from_pixbuf(GTK_IMAGE(widget), preview);
1089 preview_width = gdk_pixbuf_get_width(preview);
1090 preview_height = gdk_pixbuf_get_height(preview);
1091 gchar *text = g_strdup_printf("%d x %d", preview_width, preview_height);
1092 widget = GHB_WIDGET (ud->builder, "preview_dims");
1093 gtk_label_set_text(GTK_LABEL(widget), text);
1096 g_debug("preview %d x %d\n", preview_width, preview_height);
1097 target_height = MIN(preview_button_height - 12, 128);
1098 height = target_height;
1099 width = preview_width * height / preview_height;
1101 if ((height >= 16) && (width >= 16))
1103 GdkPixbuf *scaled_preview;
1104 scaled_preview = gdk_pixbuf_scale_simple (preview, width, height, GDK_INTERP_NEAREST);
1105 if (scaled_preview != NULL)
1107 g_object_unref (preview);
1109 widget = GHB_WIDGET (ud->builder, "preview_button_image");
1110 gtk_image_set_from_pixbuf(GTK_IMAGE(widget), scaled_preview);
1111 g_object_unref (scaled_preview);
1117 title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1119 ghb_title_info_t tinfo;
1121 const gchar *preset;
1123 g_debug("title_changed_cb ()\n");
1124 ghb_widget_to_setting(ud->settings, widget);
1125 check_depencency(ud, widget);
1127 titleindex = ghb_settings_get_int(ud->settings, "title");
1128 ghb_update_ui_combo_box (ud->builder, "audio_track", titleindex, FALSE);
1129 ghb_update_ui_combo_box (ud->builder, "subtitle_lang", titleindex, FALSE);
1130 preset = ghb_settings_get_string (ud->settings, "preset");
1131 ghb_update_from_preset(ud, preset, "subtitle_lang");
1132 if (ghb_get_title_info (&tinfo, titleindex))
1134 show_title_info(ud, &tinfo);
1136 update_chapter_list (ud);
1137 adjust_audio_rate_combos(ud);
1138 set_pref_audio(titleindex, ud);
1139 if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
1141 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1142 ghb_ui_update_int (ud, "video_bitrate", bitrate);
1145 // Unfortunately, there is no way to query how many frames were
1146 // actually generated during the scan. It attempts to make 10.
1147 // If I knew how many were generated, I would adjust the spin
1148 // control range here.
1149 ghb_ui_update_int (ud, "preview_frame", 1);
1151 set_preview_image (ud);
1155 audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1157 static gint prev_acodec = 0;
1158 gint acodec, ivalue;
1159 GHashTable *asettings;
1161 g_debug("audio_codec_changed_cb ()\n");
1163 acodec = ghb_widget_int(widget);
1164 if (ghb_audio_is_passthru (prev_acodec) && !ghb_audio_is_passthru (acodec))
1166 // Transition from passthru to not, put some audio settings back to
1168 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1169 gint track = ghb_settings_get_int(ud->settings, "audio_track");
1171 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
1172 ghb_ui_update_int (ud, "audio_bitrate", ivalue);
1173 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
1174 ghb_ui_update_int (ud, "audio_sample_rate", ivalue);
1175 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
1176 ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1177 ghb_ui_update_int (ud, "audio_mix", ivalue);
1179 adjust_audio_rate_combos(ud);
1180 ghb_grey_combo_options (ud->builder);
1181 check_depencency(ud, widget);
1182 prev_acodec = acodec;
1183 asettings = get_selected_asettings(ud);
1184 if (asettings != NULL)
1186 ghb_widget_to_setting(asettings, widget);
1187 audio_list_refresh_selected(ud);
1189 if (ghb_ac3_in_audio_list (ud->audio_settings))
1191 const gchar *container;
1193 container = ghb_settings_get_string(ud->settings, "container");
1194 if (strcmp(container, "mp4") == 0)
1196 ghb_ui_update(ud, "container", "m4v");
1201 static void audio_list_refresh_selected(signal_user_data_t *ud);
1202 static GHashTable* get_selected_asettings(signal_user_data_t *ud);
1205 audio_track_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1207 GHashTable *asettings;
1209 g_debug("audio_track_changed_cb ()\n");
1210 adjust_audio_rate_combos(ud);
1211 check_depencency(ud, widget);
1212 ghb_grey_combo_options(ud->builder);
1213 asettings = get_selected_asettings(ud);
1214 if (asettings != NULL)
1216 ghb_widget_to_setting(asettings, widget);
1217 audio_list_refresh_selected(ud);
1222 audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1224 GHashTable *asettings;
1226 g_debug("audio_widget_changed_cb ()\n");
1227 check_depencency(ud, widget);
1228 asettings = get_selected_asettings(ud);
1229 if (asettings != NULL)
1231 ghb_widget_to_setting(asettings, widget);
1232 audio_list_refresh_selected(ud);
1237 generic_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1239 g_debug("generic_widget_changed_cb ()\n");
1240 check_depencency(ud, widget);
1244 setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1246 ghb_widget_to_setting(ud->settings, widget);
1247 check_depencency(ud, widget);
1248 clear_presets_selection(ud);
1252 http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1254 ghb_widget_to_setting(ud->settings, widget);
1255 check_depencency(ud, widget);
1256 clear_presets_selection(ud);
1257 ghb_grey_combo_options (ud->builder);
1261 vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1265 ghb_widget_to_setting(ud->settings, widget);
1266 check_depencency(ud, widget);
1267 clear_presets_selection(ud);
1268 ghb_vquality_range(ud, &vqmin, &vqmax);
1269 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1270 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1274 vfr_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1276 //const gchar *name = gtk_widget_get_name(widget);
1277 //g_debug("setting_widget_changed_cb () %s\n", name);
1278 ghb_widget_to_setting(ud->settings, widget);
1279 check_depencency(ud, widget);
1280 clear_presets_selection(ud);
1281 if (ghb_settings_get_bool(ud->settings, "variable_frame_rate"))
1283 ghb_ui_update_int(ud, "framerate", 0);
1288 mirror_cb(GtkWidget *widget, signal_user_data_t *ud)
1290 const gchar *name = gtk_widget_get_name(widget);
1291 if (name == NULL) return;
1293 g_debug("mirror_cb () %s\n", name);
1294 gchar *mirror = g_strdup(name);
1295 gchar *pos = g_strrstr(mirror, "_mirror");
1296 if (pos == NULL) return;
1298 gchar *value = ghb_widget_short_opt (widget);
1299 ghb_ui_update (ud, mirror, value);
1303 // subtitles have their differ from other settings in that
1304 // the selection is updated automaitcally when the title
1305 // changes. I don't want the preset selection changed as
1306 // would happen for regular settings.
1308 subtitle_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1310 const gchar *name = gtk_widget_get_name(widget);
1311 g_debug("subtitle_changed_cb () %s\n", name);
1312 ghb_widget_to_setting(ud->settings, widget);
1313 check_depencency(ud, widget);
1317 target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1319 const gchar *name = gtk_widget_get_name(widget);
1320 g_debug("setting_widget_changed_cb () %s\n", name);
1321 ghb_widget_to_setting(ud->settings, widget);
1322 check_depencency(ud, widget);
1323 clear_presets_selection(ud);
1324 if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
1326 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1327 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1328 ghb_ui_update_int (ud, "video_bitrate", bitrate);
1333 start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1335 const gchar *name = gtk_widget_get_name(widget);
1336 g_debug("start_chapter_changed_cb () %s\n", name);
1337 ghb_widget_to_setting(ud->settings, widget);
1338 GtkWidget *end_ch = GHB_WIDGET (ud->builder, "end_chapter");
1340 gtk_spin_button_get_range (GTK_SPIN_BUTTON(end_ch), &start, &end);
1341 start = ghb_settings_get_int(ud->settings, "start_chapter");
1342 gtk_spin_button_set_range (GTK_SPIN_BUTTON(end_ch), start, end);
1343 check_depencency(ud, widget);
1347 end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1349 const gchar *name = gtk_widget_get_name(widget);
1350 g_debug("end_chapter_changed_cb () %s\n", name);
1351 ghb_widget_to_setting(ud->settings, widget);
1352 GtkWidget *start_ch = GHB_WIDGET (ud->builder, "start_chapter");
1354 gtk_spin_button_get_range (GTK_SPIN_BUTTON(start_ch), &start, &end);
1355 end = ghb_settings_get_int(ud->settings, "end_chapter");
1356 gtk_spin_button_set_range (GTK_SPIN_BUTTON(start_ch), start, end);
1357 check_depencency(ud, widget);
1361 scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1363 g_debug("scale_width_changed_cb ()\n");
1364 ghb_widget_to_setting(ud->settings, widget);
1365 check_depencency(ud, widget);
1366 ghb_set_scale (ud, GHB_SCALE_KEEP_WIDTH);
1367 update_preview = TRUE;
1369 gint width = ghb_settings_get_int(ud->settings, "scale_width");
1370 gint height = ghb_settings_get_int(ud->settings, "scale_height");
1371 widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1372 text = g_strdup_printf ("%d x %d", width, height);
1373 gtk_label_set_text (GTK_LABEL(widget), text);
1378 scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1380 g_debug("scale_height_changed_cb ()\n");
1381 ghb_widget_to_setting(ud->settings, widget);
1382 check_depencency(ud, widget);
1383 ghb_set_scale (ud, GHB_SCALE_KEEP_HEIGHT);
1384 update_preview = TRUE;
1386 gint width = ghb_settings_get_int(ud->settings, "scale_width");
1387 gint height = ghb_settings_get_int(ud->settings, "scale_height");
1388 widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1389 text = g_strdup_printf ("%d x %d", width, height);
1390 gtk_label_set_text (GTK_LABEL(widget), text);
1395 crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1397 gint titleindex, crop[4];
1398 ghb_title_info_t tinfo;
1400 g_debug("crop_changed_cb ()\n");
1401 ghb_widget_to_setting(ud->settings, widget);
1402 check_depencency(ud, widget);
1403 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1405 crop[0] = ghb_settings_get_int(ud->settings, "crop_top");
1406 crop[1] = ghb_settings_get_int(ud->settings, "crop_bottom");
1407 crop[2] = ghb_settings_get_int(ud->settings, "crop_left");
1408 crop[3] = ghb_settings_get_int(ud->settings, "crop_right");
1409 titleindex = ghb_settings_get_index(ud->settings, "title");
1410 if (ghb_get_title_info (&tinfo, titleindex))
1415 width = tinfo.width - crop[2] - crop[3];
1416 height = tinfo.height - crop[0] - crop[1];
1417 widget = GHB_WIDGET (ud->builder, "crop_dimensions");
1418 text = g_strdup_printf ("%d x %d", width, height);
1419 gtk_label_set_text (GTK_LABEL(widget), text);
1423 widget = GHB_WIDGET (ud->builder, "crop_values");
1424 text = g_strdup_printf ("%d:%d:%d:%d", crop[0], crop[1], crop[2], crop[3]);
1425 gtk_label_set_text (GTK_LABEL(widget), text);
1427 update_preview = TRUE;
1431 scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1433 g_debug("scale_changed_cb ()\n");
1434 ghb_widget_to_setting(ud->settings, widget);
1435 check_depencency(ud, widget);
1436 clear_presets_selection(ud);
1437 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1438 update_preview = TRUE;
1442 text = ghb_settings_get_bool(ud->settings, "autocrop") ? "On" : "Off";
1443 widget = GHB_WIDGET (ud->builder, "crop_auto");
1444 gtk_label_set_text (GTK_LABEL(widget), text);
1445 text = ghb_settings_get_bool(ud->settings, "autoscale") ? "On" : "Off";
1446 widget = GHB_WIDGET (ud->builder, "scale_auto");
1447 gtk_label_set_text (GTK_LABEL(widget), text);
1448 text = ghb_settings_get_bool(ud->settings, "anamorphic") ? "On" : "Off";
1449 widget = GHB_WIDGET (ud->builder, "scale_anamorphic");
1450 gtk_label_set_text (GTK_LABEL(widget), text);
1454 generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
1456 // Normally (due to user input) I only want to process the entry
1457 // when editing is done and the focus-out signal is sent.
1458 // But... there's always a but.
1459 // If the entry is changed by software, the focus-out signal is not sent.
1460 // The changed signal is sent ... so here we are.
1461 // I don't want to process upon every keystroke, so I prevent processing
1462 // while the widget has focus.
1463 g_debug("generic_entry_changed_cb ()\n");
1464 if (!GTK_WIDGET_HAS_FOCUS((GtkWidget*)entry))
1466 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
1471 generic_focus_out_cb(GtkWidget *widget, GdkEventFocus *event,
1472 signal_user_data_t *ud)
1474 g_debug("generic_focus_out_cb ()\n");
1475 ghb_widget_to_setting(ud->settings, widget);
1480 clear_audio_list(signal_user_data_t *ud)
1482 GtkTreeView *treeview;
1483 GtkListStore *store;
1486 g_debug("clear_audio_list ()\n");
1487 while (ud->audio_settings != NULL)
1489 link = ud->audio_settings;
1490 ud->audio_settings = g_slist_remove_link(ud->audio_settings, link);
1491 g_hash_table_destroy((GHashTable*)link->data);
1492 g_slist_free_1(link);
1494 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1495 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1496 gtk_list_store_clear (store);
1500 add_to_audio_list(signal_user_data_t *ud, GHashTable *settings)
1502 GtkTreeView *treeview;
1504 GtkListStore *store;
1505 GtkTreeSelection *selection;
1507 g_debug("add_to_audio_list ()\n");
1508 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1509 selection = gtk_tree_view_get_selection (treeview);
1510 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1512 gtk_list_store_append(store, &iter);
1513 gtk_list_store_set(store, &iter,
1514 // These are displayed in list
1515 0, ghb_settings_get_option(settings, "audio_track"),
1516 1, ghb_settings_get_option(settings, "audio_codec"),
1517 2, ghb_settings_get_option(settings, "audio_bitrate"),
1518 3, ghb_settings_get_option(settings, "audio_sample_rate"),
1519 4, ghb_settings_get_option(settings, "audio_mix"),
1520 // These are used to set combo box values when a list item is selected
1521 5, ghb_settings_get_string(settings, "audio_drc"),
1522 6, ghb_settings_get_short_opt(settings, "audio_track"),
1523 7, ghb_settings_get_short_opt(settings, "audio_codec"),
1524 8, ghb_settings_get_short_opt(settings, "audio_bitrate"),
1525 9, ghb_settings_get_short_opt(settings, "audio_sample_rate"),
1526 10, ghb_settings_get_short_opt(settings, "audio_mix"),
1528 gtk_tree_selection_select_iter(selection, &iter);
1532 audio_list_refresh_selected(signal_user_data_t *ud)
1534 GtkTreeView *treeview;
1535 GtkTreePath *treepath;
1536 GtkTreeSelection *selection;
1537 GtkTreeModel *store;
1542 GHashTable *asettings = NULL;
1544 g_debug("get_selected_asettings ()\n");
1545 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1546 selection = gtk_tree_view_get_selection (treeview);
1547 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1549 // Get the row number
1550 treepath = gtk_tree_model_get_path (store, &iter);
1551 indices = gtk_tree_path_get_indices (treepath);
1554 // find audio settings
1555 if (row < 0) return;
1556 link = g_slist_nth(ud->audio_settings, row);
1557 if (link == NULL) return;
1558 asettings = (GHashTable*)link->data;
1559 gtk_list_store_set(GTK_LIST_STORE(store), &iter,
1560 // These are displayed in list
1561 0, ghb_settings_get_option(asettings, "audio_track"),
1562 1, ghb_settings_get_option(asettings, "audio_codec"),
1563 2, ghb_settings_get_option(asettings, "audio_bitrate"),
1564 3, ghb_settings_get_option(asettings, "audio_sample_rate"),
1565 4, ghb_settings_get_option(asettings, "audio_mix"),
1566 // These are used to set combo box values when a list item is selected
1567 5, ghb_settings_get_string(asettings, "audio_drc"),
1568 6, ghb_settings_get_short_opt(asettings, "audio_track"),
1569 7, ghb_settings_get_short_opt(asettings, "audio_codec"),
1570 8, ghb_settings_get_short_opt(asettings, "audio_bitrate"),
1571 9, ghb_settings_get_short_opt(asettings, "audio_sample_rate"),
1572 10, ghb_settings_get_short_opt(asettings, "audio_mix"),
1578 get_selected_asettings(signal_user_data_t *ud)
1580 GtkTreeView *treeview;
1581 GtkTreePath *treepath;
1582 GtkTreeSelection *selection;
1583 GtkTreeModel *store;
1588 GHashTable *asettings = NULL;
1590 g_debug("get_selected_asettings ()\n");
1591 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1592 selection = gtk_tree_view_get_selection (treeview);
1593 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1595 // Get the row number
1596 treepath = gtk_tree_model_get_path (store, &iter);
1597 indices = gtk_tree_path_get_indices (treepath);
1600 // find audio settings
1601 if (row < 0) return NULL;
1602 link = g_slist_nth(ud->audio_settings, row);
1603 if (link == NULL) return NULL;
1604 asettings = (GHashTable*)link->data;
1610 audio_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
1612 GtkTreeModel *store;
1616 g_debug("audio_list_selection_changed_cb ()\n");
1617 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1619 const gchar *track, *codec, *bitrate, *sample_rate, *mix, *drc;
1620 gtk_tree_model_get(store, &iter,
1628 ghb_ui_update(ud, "audio_track", track);
1629 ghb_ui_update(ud, "audio_codec", codec);
1630 ghb_ui_update(ud, "audio_bitrate", bitrate);
1631 ghb_ui_update(ud, "audio_sample_rate", sample_rate);
1632 ghb_ui_update(ud, "audio_mix", mix);
1633 ghb_ui_update(ud, "audio_drc", drc);
1634 widget = GHB_WIDGET (ud->builder, "audio_remove");
1635 gtk_widget_set_sensitive(widget, TRUE);
1636 //widget = GHB_WIDGET (ud->builder, "audio_update");
1637 //gtk_widget_set_sensitive(widget, TRUE);
1641 widget = GHB_WIDGET (ud->builder, "audio_remove");
1642 gtk_widget_set_sensitive(widget, FALSE);
1643 //widget = GHB_WIDGET (ud->builder, "audio_update");
1644 //gtk_widget_set_sensitive(widget, FALSE);
1649 audio_add_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1651 // Add the current audio settings to the list.
1652 GHashTable *asettings;
1656 g_debug("audio_add_clicked_cb ()\n");
1657 // Only allow up to 8 audio entries
1658 asettings = ghb_settings_new();
1659 widget = GHB_WIDGET(ud->builder, "audio_track");
1660 ghb_settings_set(asettings, "audio_track", ghb_widget_value(widget));
1661 widget = GHB_WIDGET(ud->builder, "audio_codec");
1662 ghb_settings_set(asettings, "audio_codec", ghb_widget_value(widget));
1663 widget = GHB_WIDGET(ud->builder, "audio_bitrate");
1664 ghb_settings_set(asettings, "audio_bitrate", ghb_widget_value(widget));
1665 widget = GHB_WIDGET(ud->builder, "audio_sample_rate");
1666 ghb_settings_set(asettings, "audio_sample_rate", ghb_widget_value(widget));
1667 widget = GHB_WIDGET(ud->builder, "audio_mix");
1668 ghb_settings_set(asettings, "audio_mix", ghb_widget_value(widget));
1669 widget = GHB_WIDGET(ud->builder, "audio_drc");
1670 ghb_settings_set(asettings, "audio_drc", ghb_widget_value(widget));
1672 ud->audio_settings = g_slist_append(ud->audio_settings, asettings);
1673 add_to_audio_list(ud, asettings);
1674 count = g_slist_length(ud->audio_settings);
1677 gtk_widget_set_sensitive(xwidget, FALSE);
1682 audio_remove_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
1684 GtkTreeView *treeview;
1685 GtkTreePath *treepath;
1686 GtkTreeSelection *selection;
1687 GtkTreeModel *store;
1688 GtkTreeIter iter, nextIter;
1693 g_debug("audio_remove_clicked_cb ()\n");
1694 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1695 selection = gtk_tree_view_get_selection (treeview);
1696 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1699 if (!gtk_tree_model_iter_next(store, &nextIter))
1702 if (gtk_tree_model_get_iter_first(store, &nextIter))
1704 gtk_tree_selection_select_iter (selection, &nextIter);
1709 gtk_tree_selection_select_iter (selection, &nextIter);
1711 // Get the row number
1712 treepath = gtk_tree_model_get_path (store, &iter);
1713 indices = gtk_tree_path_get_indices (treepath);
1716 // Remove the selected item
1717 gtk_list_store_remove (GTK_LIST_STORE(store), &iter);
1718 // remove from audio settings list
1719 if (row < 0) return;
1720 link = g_slist_nth(ud->audio_settings, row);
1721 if (link == NULL) return;
1722 ud->audio_settings = g_slist_remove_link(ud->audio_settings, link);
1723 g_hash_table_destroy((GHashTable*)link->data);
1724 g_slist_free_1(link);
1725 widget = GHB_WIDGET (ud->builder, "audio_add");
1726 gtk_widget_set_sensitive(widget, TRUE);
1731 audio_list_refresh(signal_user_data_t *ud)
1733 GtkTreeView *treeview;
1735 GtkListStore *store;
1738 g_debug("audio_list_refresh ()\n");
1739 GSList *link = ud->audio_settings;
1740 if (link == NULL) return;
1741 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1742 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1743 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1747 GHashTable *asettings;
1749 asettings = (GHashTable*)link->data;
1750 gtk_list_store_set(GTK_LIST_STORE(store), &iter,
1751 // These are displayed in list
1752 0, ghb_settings_get_option(asettings, "audio_track"),
1753 1, ghb_settings_get_option(asettings, "audio_codec"),
1754 2, ghb_settings_get_option(asettings, "audio_bitrate"),
1755 3, ghb_settings_get_option(asettings, "audio_sample_rate"),
1756 4, ghb_settings_get_option(asettings, "audio_mix"),
1757 // These are used to set combo box values when a list item is selected
1758 5, ghb_settings_get_string(asettings, "audio_drc"),
1759 6, ghb_settings_get_short_opt(asettings, "audio_track"),
1760 7, ghb_settings_get_short_opt(asettings, "audio_codec"),
1761 8, ghb_settings_get_short_opt(asettings, "audio_bitrate"),
1762 9, ghb_settings_get_short_opt(asettings, "audio_sample_rate"),
1763 10, ghb_settings_get_short_opt(asettings, "audio_mix"),
1765 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1767 } while (!done && link);
1772 ghb_presets_list_update(signal_user_data_t *ud)
1774 GtkTreeView *treeview;
1776 GtkListStore *store;
1781 gchar **descriptions;
1782 gint flags, custom, def;
1784 g_debug("ghb_presets_list_update ()\n");
1785 presets = ghb_presets_get_names();
1786 descriptions = ghb_presets_get_descriptions();
1787 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1788 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1789 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1793 if ((presets != NULL) && (presets[ii] != NULL))
1795 // Update row with settings data
1796 g_debug("Updating row\n");
1797 flags = ghb_preset_flags(presets[ii], &index);
1798 def = flags & PRESET_DEFAULT;
1799 custom = flags & PRESET_CUSTOM;
1800 gtk_list_store_set(store, &iter,
1804 3, custom ? "black" : "blue",
1805 4, descriptions[ii],
1808 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1812 // No more settings data, remove row
1813 g_debug("Removing row\n");
1814 done = !gtk_list_store_remove(store, &iter);
1818 while ((presets != NULL) && (presets[ii] != NULL))
1820 // Additional settings, add row
1821 g_debug("Adding row %s\n", presets[ii]);
1822 gtk_list_store_append(store, &iter);
1823 flags = ghb_preset_flags(presets[ii], &index);
1824 def = flags & PRESET_DEFAULT;
1825 custom = flags & PRESET_CUSTOM;
1826 gtk_list_store_set(store, &iter, 0, presets[ii],
1829 3, custom ? "black" : "blue",
1830 4, descriptions[ii],
1834 g_strfreev (presets);
1838 ghb_select_preset(GtkBuilder *builder, const gchar *preset)
1840 GtkTreeView *treeview;
1841 GtkTreeSelection *selection;
1842 GtkTreeModel *store;
1847 g_debug("select_preset()\n");
1848 if (preset == NULL) return;
1849 treeview = GTK_TREE_VIEW(GHB_WIDGET(builder, "presets_list"));
1850 selection = gtk_tree_view_get_selection (treeview);
1851 store = gtk_tree_view_get_model (treeview);
1852 if (gtk_tree_model_get_iter_first(store, &iter))
1856 gtk_tree_model_get(store, &iter, 0, &tpreset, -1);
1857 if (strcmp(preset, tpreset) == 0)
1859 gtk_tree_selection_select_iter (selection, &iter);
1862 done = !gtk_tree_model_iter_next(store, &iter);
1868 presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1873 GtkResponseType response;
1874 const gchar *preset = "";
1876 g_debug("presets_save_clicked_cb ()\n");
1877 preset = ghb_settings_get_string (ud->settings, "preset");
1878 // Clear the description
1879 desc = GTK_TEXT_VIEW(GHB_WIDGET(ud->builder, "preset_description"));
1880 //gtk_entry_set_text(desc, "");
1881 dialog = GHB_WIDGET(ud->builder, "preset_save_dialog");
1882 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "preset_name"));
1883 gtk_entry_set_text(entry, preset);
1884 response = gtk_dialog_run(GTK_DIALOG(dialog));
1885 gtk_widget_hide(dialog);
1886 if (response == GTK_RESPONSE_OK)
1889 const gchar *name = gtk_entry_get_text(entry);
1890 g_debug("description to settings\n");
1891 ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
1892 ghb_settings_save(ud, name);
1893 ghb_presets_list_update(ud);
1894 // Make the new preset the selected item
1895 ghb_select_preset(ud->builder, name);
1900 prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1903 GtkResponseType response;
1905 g_debug("prefs_dialog_cb ()\n");
1906 dialog = GHB_WIDGET(ud->builder, "prefs_dialog");
1907 response = gtk_dialog_run(GTK_DIALOG(dialog));
1908 gtk_widget_hide(dialog);
1912 presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1914 GtkTreeView *treeview;
1915 GtkTreeSelection *selection;
1916 GtkTreeModel *store;
1919 GtkResponseType response;
1921 g_debug("presets_remove_clicked_cb ()\n");
1922 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1923 selection = gtk_tree_view_get_selection (treeview);
1924 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1928 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1929 if (!ghb_presets_is_standard(preset))
1931 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1932 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1933 "Confirm deletion of preset %s.", preset);
1934 response = gtk_dialog_run(GTK_DIALOG(dialog));
1935 gtk_widget_destroy (dialog);
1936 if (response == GTK_RESPONSE_YES)
1938 GtkTreeIter nextIter = iter;
1939 gchar *nextPreset = NULL;
1940 if (!gtk_tree_model_iter_next(store, &nextIter))
1942 if (gtk_tree_model_get_iter_first(store, &nextIter))
1944 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1949 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1951 // Remove the selected item
1952 // First unselect it so that selecting the new item works properly
1953 gtk_tree_selection_unselect_iter (selection, &iter);
1954 ghb_presets_remove(ud->settings, preset);
1955 ghb_presets_list_update(ud);
1956 ghb_select_preset(ud->builder, nextPreset);
1961 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1962 GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
1963 "Can not delete standard preset %s.", preset);
1964 response = gtk_dialog_run(GTK_DIALOG(dialog));
1965 gtk_widget_destroy (dialog);
1971 preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
1975 ghb_ui_update_int (ud, "scale_width", tinfo->width - tinfo->crop[2] - tinfo->crop[3]);
1976 // If anamorphic or keep_aspect, the hight will be automatically calculated
1977 gboolean keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
1978 gboolean anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
1979 if (!(keep_aspect || anamorphic))
1980 ghb_ui_update_int (ud, "scale_height", tinfo->height - tinfo->crop[0] - tinfo->crop[1]);
1982 // Set the limits of cropping. hb_set_anamorphic_size crashes if
1983 // you pass it a cropped width or height == 0.
1985 bound = tinfo->height / 2 - 2;
1986 widget = GHB_WIDGET (ud->builder, "crop_top");
1987 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1988 widget = GHB_WIDGET (ud->builder, "crop_bottom");
1989 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1990 bound = tinfo->width / 2 - 2;
1991 widget = GHB_WIDGET (ud->builder, "crop_left");
1992 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1993 widget = GHB_WIDGET (ud->builder, "crop_right");
1994 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1995 if (ghb_settings_get_bool (ud->settings, "autocrop"))
1997 ghb_ui_update_int (ud, "crop_top", tinfo->crop[0]);
1998 ghb_ui_update_int (ud, "crop_bottom", tinfo->crop[1]);
1999 ghb_ui_update_int (ud, "crop_left", tinfo->crop[2]);
2000 ghb_ui_update_int (ud, "crop_right", tinfo->crop[3]);
2005 presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
2007 GtkTreeModel *store;
2011 gboolean sensitive = FALSE;
2012 ghb_title_info_t tinfo;
2014 g_debug("presets_list_selection_changed_cb ()\n");
2015 if (gtk_tree_selection_get_selected(selection, &store, &iter))
2017 gtk_tree_model_get(store, &iter, 0, &preset, -1);
2018 if (!ghb_presets_is_standard(preset))
2022 ud->dont_clear_presets = TRUE;
2023 // Temporarily set the video_quality range to (0,100)
2024 // This is needed so the video_quality value does not get
2025 // truncated when set. The range will be readjusted below
2026 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
2027 gtk_range_set_range (GTK_RANGE(qp), 0, 100);
2028 // Clear the audio list prior to changing the preset. Existing audio
2029 // can cause the container extension to be automatically changed when
2031 clear_audio_list(ud);
2032 ghb_set_preset(ud, preset);
2033 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2034 set_pref_audio(titleindex, ud);
2035 ud->dont_clear_presets = FALSE;
2036 if (ghb_get_title_info (&tinfo, titleindex))
2038 preset_update_title_deps(ud, &tinfo);
2040 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
2043 ghb_vquality_range(ud, &vqmin, &vqmax);
2044 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
2048 g_debug("No selection??? Perhaps unselected.\n");
2050 widget = GHB_WIDGET (ud->builder, "presets_remove");
2051 gtk_widget_set_sensitive(widget, sensitive);
2055 queue_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
2057 GtkTreeModel *store;
2058 GtkTreeIter iter, piter;
2060 g_debug("queue_list_selection_changed_cb ()\n");
2061 // A queue entry is made up of a parent and multiple
2062 // children that are visible when expanded. When and entry
2063 // is selected, I want the parent to be selected.
2064 // This is purely cosmetic.
2065 if (gtk_tree_selection_get_selected(selection, &store, &iter))
2067 if (gtk_tree_model_iter_parent (store, &piter, &iter))
2070 GtkTreeView *treeview;
2072 gtk_tree_selection_select_iter (selection, &piter);
2073 path = gtk_tree_model_get_path (store, &piter);
2074 treeview = gtk_tree_selection_get_tree_view (selection);
2075 // Make the parent visible in scroll window if it is not.
2076 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
2083 add_to_queue_list(signal_user_data_t *ud, job_settings_t *item)
2085 GtkTreeView *treeview;
2087 GtkTreeStore *store;
2093 g_debug("update_queue_list ()\n");
2094 if (item == NULL) return;
2095 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2096 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2098 gint title = ghb_settings_get_int(item->settings, "title");
2099 gint start_chapter = ghb_settings_get_int(item->settings, "start_chapter");
2100 gint end_chapter = ghb_settings_get_int(item->settings, "end_chapter");
2101 gboolean pass2 = ghb_settings_get_bool(item->settings, "two_pass");
2102 const gchar *vol_name = ghb_settings_get_string(item->settings, "volume_label");
2103 if (vol_name == NULL)
2104 vol_name = "No Title";
2105 info = g_strdup_printf
2107 "<big><b>%s</b></big> (Title %d, Chapters %d through %d, %d Video %s)",
2108 vol_name, title+1, start_chapter, end_chapter,
2109 pass2 ? 2:1, pass2 ? "Passes":"Pass");
2111 gtk_tree_store_append(store, &iter, NULL);
2112 gtk_tree_store_set(store, &iter, 0, "hb-queue-job", 1, info, 2, "hb-queue-delete", -1);
2115 const gchar *vcodec = ghb_settings_get_option(item->settings, "video_codec");
2116 const gchar *container = ghb_settings_get_option(item->settings, "container");
2117 const gchar *acodec = ghb_settings_get_option(item->settings, "audio_codec");
2118 const gchar *dest = ghb_settings_get_string(item->settings, "destination");
2119 const gchar *preset = ghb_settings_get_string(item->settings, "preset");
2120 info = g_strdup_printf
2122 "<b>Preset:</b> %s\n"
2123 "<b>Format:</b> %s Container, %s Video + %s Audio\n"
2124 "<b>Destination:</b> %s",
2125 preset, container, vcodec, acodec, dest);
2127 gtk_tree_store_append(store, &citer, &iter);
2128 gtk_tree_store_set(store, &citer, 1, info, -1);
2131 gint width = ghb_settings_get_int(item->settings, "scale_width");
2132 gint height = ghb_settings_get_int(item->settings, "scale_height");
2133 gboolean anamorphic = ghb_settings_get_bool(item->settings, "anamorphic");
2134 gboolean round_dim = ghb_settings_get_bool(item->settings, "round_dimensions");
2135 gboolean keep_aspect = ghb_settings_get_bool(item->settings, "keep_aspect");
2141 aspect_desc = "(Anamorphic)";
2145 aspect_desc = "(Strict Anamorphic)";
2152 aspect_desc = "(Aspect Preserved)";
2156 aspect_desc = "(Aspect Lost)";
2159 gboolean vqtype = ghb_settings_get_bool(item->settings, "vquality_type_constant");
2161 gchar *vq_desc = "Error";
2164 vqtype = ghb_settings_get_bool(item->settings, "vquality_type_target");
2167 // Has to be bitrate
2168 vqvalue = ghb_settings_get_int(item->settings, "video_bitrate");
2174 vqvalue = ghb_settings_get_int(item->settings, "video_target");
2181 vqvalue = ghb_settings_get_int(item->settings, "video_quality");
2182 vq_desc = "% Constant Quality";
2184 const gchar *fps = ghb_settings_get_string(item->settings, "framerate");
2185 const gchar *vcodec_abbr = ghb_settings_get_short_opt(item->settings, "video_codec");
2187 if (strcmp(vcodec_abbr, "x264") == 0)
2189 gchar *x264opts = ghb_build_x264opts_string(item->settings);
2190 g_debug("xopts (%s)\n", x264opts);
2191 extra_opts = g_strdup_printf ("\n<b>x264 Options:</b> %s", x264opts);
2196 extra_opts = g_strdup("");
2198 gboolean turbo = ghb_settings_get_bool (item->settings, "turbo");
2199 gchar *turbo_desc = "\n<b>Turbo:</b> Off";;
2202 turbo_desc = "\n<b>Turbo:</b> On";
2204 num_pass = pass2 ? 2 : 1;
2205 for (ii = 0; ii < num_pass; ii++)
2207 gboolean final = (ii == (num_pass - 1));
2208 GString *pass = g_string_new("");
2209 g_string_append_printf( pass,
2211 "<b>Picture:</b> %d x %d %s\n"
2212 "<b>Video:</b> %s, %d %s, %s fps"
2214 ii ? "2nd":"1st", width, height, aspect_desc,
2215 vcodec, vqvalue, vq_desc, fps,
2216 final ? extra_opts : turbo_desc);
2221 GSList *link = item->audio_settings;
2224 GHashTable *asettings = (GHashTable*)link->data;
2225 const gchar *acodec = ghb_settings_get_option(asettings, "audio_codec");
2226 const gchar *bitrate = ghb_settings_get_string(asettings, "audio_bitrate");
2227 const gchar *samplerate = ghb_settings_get_string(asettings, "audio_sample_rate");
2228 gint track = ghb_settings_get_int(asettings, "audio_track");
2229 const gchar *mix = ghb_settings_get_option(asettings, "audio_mix");
2230 g_string_append_printf(pass,
2231 "\n<b>Audio:</b> %s, %s kbps, %s kHz, Track %d: %s",
2232 acodec, bitrate, samplerate, track+1, mix);
2236 info = g_string_free(pass, FALSE);
2237 gtk_tree_store_append(store, &citer, &iter);
2238 gtk_tree_store_set(store, &citer, 0, ii ? "hb-queue-pass2" : "hb-queue-pass1", 1, info, -1);
2245 ghb_message_dialog(GtkMessageType type, const gchar *message, const gchar *no, const gchar *yes)
2248 GtkResponseType response;
2250 // Toss up a warning dialog
2251 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2252 type, GTK_BUTTONS_NONE,
2254 gtk_dialog_add_buttons( GTK_DIALOG(dialog),
2255 no, GTK_RESPONSE_NO,
2256 yes, GTK_RESPONSE_YES, NULL);
2257 response = gtk_dialog_run(GTK_DIALOG(dialog));
2258 gtk_widget_destroy (dialog);
2259 if (response == GTK_RESPONSE_NO)
2267 estimate_file_size(signal_user_data_t *ud)
2269 ghb_title_info_t tinfo;
2273 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2274 if (titleindex < 0) return 0;
2276 if (!ghb_get_title_info(&tinfo, titleindex)) return 0;
2277 duration = ((tinfo.hours*60)+tinfo.minutes)*60+tinfo.seconds;
2278 bitrate = ghb_guess_bitrate(ud->settings);
2279 size = (gint64)duration * (gint64)bitrate/8;
2283 #define DISK_FREE_THRESH (1024L*1024L*1024L*3)
2286 validate_settings(signal_user_data_t *ud)
2288 // Check to see if the dest file exists or is
2289 // already in the queue
2291 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2292 if (titleindex < 0) return FALSE;
2293 const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
2294 GSList *link = ud->queue;
2295 while (link != NULL)
2297 job_settings_t *item;
2298 const gchar *filename;
2299 item = (job_settings_t*)link->data;
2300 filename = ghb_settings_get_string(item->settings, "destination");
2301 if (strcmp(dest, filename) == 0)
2303 message = g_strdup_printf(
2304 "Destination: %s\n\n"
2305 "Another queued job has specified the same destination.\n"
2306 "Do you want to overwrite?",
2308 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
2318 gchar *destdir = g_path_get_dirname(dest);
2319 if (!g_file_test(destdir, G_FILE_TEST_IS_DIR))
2321 message = g_strdup_printf(
2322 "Destination: %s\n\n"
2323 "This is not a valid directory.",
2325 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2330 if (g_access(destdir, R_OK|W_OK) != 0)
2332 message = g_strdup_printf(
2333 "Destination: %s\n\n"
2334 "Can not read or write the directory.",
2336 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2344 gchar *resolved = ghb_resolve_symlink(destdir);
2346 gfile = g_file_new_for_path(resolved);
2347 info = g_file_query_filesystem_info(gfile,
2348 G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, NULL);
2351 if (g_file_info_has_attribute(info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE))
2353 size = g_file_info_get_attribute_uint64(info,
2354 G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
2356 gint64 fsize = estimate_file_size(ud);
2359 message = g_strdup_printf(
2360 "Destination filesystem is almost full: %uM free\n\n"
2361 "Encode may be incomplete if you proceed.\n",
2362 (guint)(size / (1024L*1024L)));
2363 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Proceed"))
2371 g_object_unref(info);
2373 g_object_unref(gfile);
2376 if (g_file_test(dest, G_FILE_TEST_EXISTS))
2378 message = g_strdup_printf(
2379 "Destination: %s\n\n"
2380 "File already exhists.\n"
2381 "Do you want to overwrite?",
2383 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
2391 // Validate video quality is in a reasonable range
2392 if (!ghb_validate_vquality(ud->settings))
2396 // Validate audio settings
2397 if (!ghb_validate_audio(ud))
2401 // Validate video settings
2402 if (!ghb_validate_video(ud))
2406 // Validate container settings
2407 if (!ghb_validate_container(ud))
2411 audio_list_refresh(ud);
2416 queue_add(signal_user_data_t *ud)
2418 // Add settings to the queue
2419 job_settings_t *queue_item;
2421 static gint unique_id = 0;
2423 g_debug("queue_add ()\n");
2424 if (!validate_settings(ud))
2428 // Make a copy of current settings to be used for the new job
2429 queue_item = g_malloc(sizeof(job_settings_t));
2430 queue_item->settings = ghb_settings_dup(ud->settings);
2431 queue_item->audio_settings = NULL;
2432 link = ud->audio_settings;
2433 while (link != NULL)
2435 GHashTable *asettings;
2436 asettings = ghb_settings_dup((GHashTable*)link->data);
2437 queue_item->audio_settings =
2438 g_slist_append(queue_item->audio_settings, asettings);
2439 link = g_slist_next(link);
2441 queue_item->chapter_list = g_strdupv(ud->chapter_list);
2442 ud->queue = g_slist_append(ud->queue, queue_item);
2443 add_to_queue_list(ud, queue_item);
2444 ghb_add_job (queue_item, unique_id);
2445 queue_item->unique_id = unique_id;
2446 queue_item->status = GHB_QUEUE_PENDING;
2452 queue_add_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
2454 g_debug("queue_add_clicked_cb ()\n");
2459 cancel_encode(const gchar *extra_msg)
2462 GtkResponseType response;
2464 if (extra_msg == NULL) extra_msg = "";
2465 // Toss up a warning dialog
2466 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2467 GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
2468 "%sYour movie will be lost if you don't continue encoding.",
2470 gtk_dialog_add_buttons( GTK_DIALOG(dialog),
2471 "Continue Encoding", GTK_RESPONSE_NO,
2472 "Stop Encoding", GTK_RESPONSE_YES, NULL);
2473 response = gtk_dialog_run(GTK_DIALOG(dialog));
2474 gtk_widget_destroy (dialog);
2475 if (response == GTK_RESPONSE_NO) return FALSE;
2481 queue_remove_clicked_cb(GtkWidget *widget, gchar *path, signal_user_data_t *ud)
2483 GtkTreeView *treeview;
2484 GtkTreePath *treepath;
2485 GtkTreeModel *store;
2490 job_settings_t *queue_item;
2493 g_debug("queue_remove_clicked_cb ()\n");
2494 g_debug("ud %p\n", ud);
2495 g_debug("ud->builder %p\n", ud->builder);
2497 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2498 store = gtk_tree_view_get_model(treeview);
2499 treepath = gtk_tree_path_new_from_string (path);
2500 if (gtk_tree_model_get_iter(store, &iter, treepath))
2502 // Find the entry in the queue
2503 indices = gtk_tree_path_get_indices (treepath);
2505 // Can only free the treepath After getting what I need from
2506 // indices since this points into treepath somewhere.
2507 gtk_tree_path_free (treepath);
2508 if (row < 0) return;
2509 link = g_slist_nth(ud->queue, row);
2510 if (link == NULL) return;
2511 queue_item = (job_settings_t*)link->data;
2512 if (queue_item->status == GHB_QUEUE_RUNNING)
2514 // Ask if wants to stop encode.
2515 if (!cancel_encode(NULL))
2520 // Remove the selected item
2521 g_debug(" should be removing from treestore\n");
2522 gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
2523 // Remove the corresponding item from the queue list
2524 ud->queue = g_slist_remove_link(ud->queue, link);
2525 g_slist_free_1(link);
2526 g_hash_table_destroy(queue_item->settings);
2527 link = queue_item->audio_settings;
2528 while (link != NULL)
2531 g_hash_table_destroy((GHashTable*)link->data);
2532 nextlink = g_slist_next(link);
2533 g_slist_free_1(link);
2536 g_strfreev (queue_item->chapter_list);
2537 unique_id = queue_item->unique_id;
2539 ghb_remove_job(unique_id);
2543 gtk_tree_path_free (treepath);
2548 find_queue_item(GSList *queue, gint unique_id, job_settings_t **job)
2553 while (queue != NULL)
2556 js = (job_settings_t*)queue->data;
2557 if (js->unique_id == unique_id)
2562 queue = queue->next;
2569 queue_buttons_grey(signal_user_data_t *ud, gboolean working)
2573 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2574 gboolean title_ok = (titleindex >= 0);
2575 widget = GHB_WIDGET (ud->builder, "queue_start1");
2576 gtk_widget_set_sensitive (widget, !working && title_ok);
2577 widget = GHB_WIDGET (ud->builder, "queue_start2");
2578 gtk_widget_set_sensitive (widget, !working && title_ok);
2579 action = GHB_ACTION (ud->builder, "queue_start_menu");
2580 gtk_action_set_sensitive (action, !working && title_ok);
2581 widget = GHB_WIDGET (ud->builder, "queue_pause1");
2582 gtk_widget_set_sensitive (widget, working);
2583 widget = GHB_WIDGET (ud->builder, "queue_pause2");
2584 gtk_widget_set_sensitive (widget, working);
2585 action = GHB_ACTION (ud->builder, "queue_pause_menu");
2586 gtk_action_set_sensitive (action, working);
2587 widget = GHB_WIDGET (ud->builder, "queue_stop");
2588 gtk_widget_set_sensitive (widget, working);
2589 action = GHB_ACTION (ud->builder, "queue_stop_menu");
2590 gtk_action_set_sensitive (action, working);
2593 void queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud);
2596 ghb_backend_events(signal_user_data_t *ud)
2598 ghb_status_t status;
2600 GtkProgressBar *progress;
2603 static gint current_id = -1;
2605 GtkTreeView *treeview;
2606 GtkTreeStore *store;
2608 static gint working = 0;
2609 static gboolean work_started = FALSE;
2612 ghb_get_status(&status);
2613 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2614 if (status.state & GHB_STATE_SCANNING)
2616 status_str = g_strdup_printf ("Scanning title %d of %d...",
2617 status.title_cur, status.title_count );
2618 gtk_progress_bar_set_text (progress, status_str);
2620 if (status.title_count > 0)
2622 gtk_progress_bar_set_fraction (progress,
2623 (gdouble)status.title_cur / status.title_count);
2626 else if (status.state & GHB_STATE_SCANDONE)
2628 status_str = g_strdup_printf ("Scan done");
2629 gtk_progress_bar_set_text (progress, status_str);
2631 gtk_progress_bar_set_fraction (progress, 1.0);
2633 ghb_title_info_t tinfo;
2635 ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE);
2636 titleindex = ghb_longest_title();
2637 ghb_ui_update_int(ud, "title", titleindex);
2639 // Are there really any titles.
2640 if (!ghb_get_title_info(&tinfo, titleindex))
2642 GtkProgressBar *progress;
2643 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2644 gtk_progress_bar_set_fraction (progress, 0);
2645 gtk_progress_bar_set_text (progress, "No Source");
2647 ghb_clear_state(GHB_STATE_SCANDONE);
2648 queue_buttons_grey(ud, (0 != (status.state & GHB_STATE_WORKING)));
2650 else if (status.state & GHB_STATE_WORKING)
2652 if(status.seconds > -1)
2654 status_str= g_strdup_printf(
2655 "Encoding: task %d of %d, %.2f %%"
2656 " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)",
2657 status.job_cur, status.job_count,
2658 100.0 * status.progress,
2659 status.rate_cur, status.rate_avg, status.hours,
2660 status.minutes, status.seconds );
2664 status_str= g_strdup_printf(
2665 "Encoding: task %d of %d, %.2f %%",
2666 status.job_cur, status.job_count,
2667 100.0 * status.progress );
2669 gtk_progress_bar_set_text (progress, status_str);
2670 gtk_progress_bar_set_fraction (progress, status.progress);
2673 else if (status.state & GHB_STATE_WORKDONE)
2675 work_started = FALSE;
2676 queue_buttons_grey(ud, FALSE);
2677 index = find_queue_item(ud->queue, current_id, &js);
2678 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2679 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2680 switch( status.error )
2682 case GHB_ERROR_NONE:
2683 gtk_progress_bar_set_text( progress, "Rip done!" );
2686 js->status = GHB_QUEUE_DONE;
2687 gchar *path = g_strdup_printf ("%d", index);
2688 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2690 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
2695 case GHB_ERROR_CANCELED:
2696 gtk_progress_bar_set_text( progress, "Rip canceled." );
2699 js->status = GHB_QUEUE_CANCELED;
2700 gchar *path = g_strdup_printf ("%d", index);
2701 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2703 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
2709 gtk_progress_bar_set_text( progress, "Rip failed.");
2712 js->status = GHB_QUEUE_CANCELED;
2713 gchar *path = g_strdup_printf ("%d", index);
2714 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2716 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
2722 gtk_progress_bar_set_fraction (progress, 1.0);
2723 ghb_clear_state(GHB_STATE_WORKDONE);
2725 else if (status.state & GHB_STATE_PAUSED)
2727 status_str = g_strdup_printf ("Paused");
2728 gtk_progress_bar_set_text (progress, status_str);
2731 else if (status.state & GHB_STATE_MUXING)
2733 gtk_progress_bar_set_text(progress, "Muxing: this may take awhile...");
2735 if (status.state & GHB_STATE_WORKING)
2739 work_started = TRUE;
2740 queue_buttons_grey(ud, TRUE);
2742 if (status.unique_id != current_id)
2744 index = find_queue_item(ud->queue, current_id, &js);
2747 js->status = GHB_QUEUE_DONE;
2748 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2749 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2750 gchar *path = g_strdup_printf ("%d", index);
2751 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2753 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
2758 index = find_queue_item(ud->queue, status.unique_id, &js);
2761 js->status = GHB_QUEUE_RUNNING;
2762 current_id = status.unique_id;
2765 index = find_queue_item(ud->queue, status.unique_id, &js);
2768 gchar working_icon[] = "hb-working0";
2769 working_icon[10] = '0' + working;
2770 working = (working+1) % 6;
2771 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2772 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2773 gchar *path = g_strdup_printf ("%d", index);
2774 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2776 gtk_tree_store_set(store, &iter, 0, working_icon, -1);
2784 ghb_timer_cb(gpointer data)
2786 signal_user_data_t *ud = (signal_user_data_t*)data;
2788 ghb_backend_events(ud);
2789 if (update_default_destination)
2791 const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
2792 gchar *dest_dir = g_path_get_dirname (dest);
2793 const gchar *def_dest = ghb_settings_get_string(ud->settings, "destination_dir");
2794 if (strcmp(dest_dir, def_dest) != 0)
2796 ghb_settings_set_string (ud->settings, "destination_dir", dest_dir);
2797 ghb_pref_save (ud->settings, "destination_dir");
2799 update_default_destination = FALSE;
2803 set_preview_image (ud);
2804 update_preview = FALSE;
2810 ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
2814 GtkTextView *textview;
2815 GtkTextBuffer *buffer;
2817 //GtkTextMark *mark;
2818 GError *gerror = NULL;
2821 signal_user_data_t *ud = (signal_user_data_t*)data;
2823 status = g_io_channel_read_line (source, &text, &length, NULL, &gerror);
2826 textview = GTK_TEXT_VIEW(GHB_WIDGET (ud->builder, "activity_view"));
2827 buffer = gtk_text_view_get_buffer (textview);
2828 // I would like to auto-scroll the window when the scrollbar
2829 // is at the bottom, but I'm having difficulty finding a way
2830 // to reliably detect that the scrollbar is at the bottom
2831 //mark = gtk_text_buffer_get_insert (buffer);
2832 //gtk_text_view_scroll_mark_onscreen(textview, mark);
2833 gtk_text_buffer_get_end_iter(buffer, &iter);
2834 gtk_text_buffer_insert(buffer, &iter, text, -1);
2835 g_io_channel_write_chars (ud->activity_log, text, length, &length, NULL);
2838 if (status != G_IO_STATUS_NORMAL)
2840 // This should never happen, but if it does I would get into an
2841 // infinite loop. Returning false removes this callback.
2842 g_warning("Error while reading activity from pipe\n");
2845 g_warning("%s\n", gerror->message);
2846 g_error_free (gerror);
2851 g_error_free (gerror);
2856 about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2858 GtkWidget *widget = GHB_WIDGET (ud->builder, "hb_about");
2859 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(widget), ghb_version());
2860 gtk_widget_show (widget);
2864 guide_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2868 {"xdg-open","http://trac.handbrake.fr/wiki/HandBrakeGuide",NULL,NULL};
2869 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2873 argv[0] = "gnome-open";
2874 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2878 argv[0] = "kfmclient";
2880 argv[2] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2881 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2885 argv[0] = "firefox";
2886 argv[1] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2888 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2894 hb_about_response_cb(GtkWidget *widget, gint response, signal_user_data_t *ud)
2896 gtk_widget_hide (widget);
2900 show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2902 GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
2903 gtk_widget_show (widget);
2907 show_queue_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2909 GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
2910 gtk_widget_show (widget);
2914 show_presets_toggled_cb(GtkToggleButton *button, signal_user_data_t *ud)
2917 GtkWindow *hb_window;
2919 g_debug("show_presets_clicked_cb ()\n");
2920 widget = GHB_WIDGET (ud->builder, "presets_frame");
2921 if (gtk_toggle_button_get_active(button))
2923 gtk_widget_show_now(widget);
2927 gtk_widget_hide(widget);
2928 hb_window = GTK_WINDOW(GHB_WIDGET (ud->builder, "hb_window"));
2929 gtk_window_resize(hb_window, 16, 16);
2931 ghb_widget_to_setting(ud->settings, GTK_WIDGET(button));
2932 ghb_pref_save(ud->settings, "show_presets");
2936 presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
2938 GtkTreeView *treeview;
2939 GtkTreeSelection *selection;
2940 GtkTreeModel *store;
2943 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
2944 selection = gtk_tree_view_get_selection(treeview);
2945 if (gtk_tree_selection_get_selected(selection, &store, &iter))
2948 path = gtk_tree_model_get_path (store, &iter);
2949 // Make the parent visible in scroll window if it is not.
2950 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
2956 update_chapter_list(signal_user_data_t *ud)
2958 GtkTreeView *treeview;
2960 GtkListStore *store;
2963 gint titleindex, ii;
2965 g_debug("update_chapter_list ()\n");
2966 titleindex = ghb_settings_get_index(ud->settings, "title");
2967 chapters = ghb_get_chapters(titleindex);
2968 if (ud->chapter_list != NULL)
2969 g_strfreev (ud->chapter_list);
2970 ud->chapter_list = chapters;
2972 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
2973 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
2975 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
2979 if (chapters != NULL && chapters[ii])
2981 // Update row with settings data
2982 g_debug("Updating row\n");
2983 gtk_list_store_set(store, &iter,
2989 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
2993 // No more settings data, remove row
2994 g_debug("Removing row\n");
2995 done = !gtk_list_store_remove(store, &iter);
2999 while (chapters != NULL && chapters[ii])
3001 // Additional settings, add row
3002 g_debug("Adding row\n");
3003 g_debug("%d -- %s\n", ii, chapters[ii]);
3004 gtk_list_store_append(store, &iter);
3005 gtk_list_store_set(store, &iter,
3015 chapter_edited_cb(GtkCellRendererText *cell, gchar *path, gchar *text, signal_user_data_t *ud)
3017 GtkTreePath *treepath;
3018 GtkListStore *store;
3019 GtkTreeView *treeview;
3020 GtkTreeViewColumn *column;
3024 g_debug("chapter_edited_cb ()\n");
3025 g_debug("path (%s)\n", path);
3026 g_debug("text (%s)\n", text);
3027 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
3028 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
3029 treepath = gtk_tree_path_new_from_string (path);
3030 gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
3031 gtk_tree_path_free (treepath);
3032 gtk_list_store_set(store, &iter,
3036 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &index, -1);
3037 g_free(ud->chapter_list[index-1]);
3038 ud->chapter_list[index-1] = g_strdup(text);
3039 if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
3041 column = gtk_tree_view_get_column(treeview, 1);
3042 treepath = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
3043 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
3044 gtk_tree_path_free (treepath);
3049 chapter_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
3051 GtkTreeModel *store;
3054 g_debug("chapter_list_selection_changed_cb ()\n");
3055 if (gtk_tree_selection_get_selected(selection, &store, &iter))
3062 queue_list_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, GtkCellRenderer *cell)
3064 GtkTreeViewColumn *column;
3067 column = gtk_tree_view_get_column (GTK_TREE_VIEW(widget), 0);
3068 width = gtk_tree_view_column_get_width(column);
3069 g_debug("col width %d alloc width %d\n", width, allocation->width);
3070 // Set new wrap-width. Shave a little off to accomidate the icons
3071 // that share this column.
3072 if (width >= 564) // Don't allow below a certain size
3073 g_object_set(cell, "wrap-width", width-70, NULL);
3077 preview_button_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3079 gint titleindex = ghb_settings_get_int(ud->settings, "title");
3080 if (titleindex < 0) return;
3081 g_debug("titleindex %d\n", titleindex);
3083 GtkWidget *widget = GHB_WIDGET (ud->builder, "preview_window");
3084 gtk_widget_show (widget);
3088 preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3090 set_preview_image(ud);
3094 preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
3096 g_debug("-------------------------------allocate %d x %d\n", allocation->width, allocation->height);
3097 if (preview_button_width == allocation->width &&
3098 preview_button_height == allocation->height)
3100 // Nothing to do. Bug out.
3101 g_debug("nothing to do\n");
3104 g_debug("-------------------------------prev allocate %d x %d\n", preview_button_width, preview_button_height);
3105 preview_button_width = allocation->width;
3106 preview_button_height = allocation->height;
3107 set_preview_image(ud);
3111 queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3113 GSList *link = ud->queue;
3114 job_settings_t *job;
3115 gboolean running = FALSE;
3116 while (link != NULL)
3118 job = (job_settings_t*)link->data;
3119 if ((job->status == GHB_QUEUE_RUNNING) ||
3120 (job->status == GHB_QUEUE_PENDING))
3129 // The queue has no running or pending jobs.
3130 // Add current settings to the queue, then run.
3138 queue_stop_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3140 cancel_encode(NULL);
3144 queue_pause_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3150 presets_default_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3152 ghb_set_preset_default(ud->settings);
3153 ghb_presets_list_update(ud);
3157 debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data)
3159 signal_user_data_t *ud = (signal_user_data_t*)data;
3163 printf("%s: %s\n", domain, msg);
3168 set_visible(GtkWidget *widget, gboolean visible)
3172 gtk_widget_show_now(widget);
3176 gtk_widget_hide(widget);
3181 ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
3184 g_debug("ghb_hbfd\n");
3185 widget = GHB_WIDGET(ud->builder, "queue_pause1");
3186 set_visible(widget, !hbfd);
3187 widget = GHB_WIDGET(ud->builder, "queue_add");
3188 set_visible(widget, !hbfd);
3189 widget = GHB_WIDGET(ud->builder, "show_queue");
3190 set_visible(widget, !hbfd);
3191 widget = GHB_WIDGET(ud->builder, "show_activity");
3192 set_visible(widget, !hbfd);
3194 widget = GHB_WIDGET(ud->builder, "chapter_box");
3195 set_visible(widget, !hbfd);
3196 widget = GHB_WIDGET(ud->builder, "container_box");
3197 set_visible(widget, !hbfd);
3198 widget = GHB_WIDGET(ud->builder, "settings_box");
3199 set_visible(widget, !hbfd);
3200 widget = GHB_WIDGET(ud->builder, "presets_save");
3201 set_visible(widget, !hbfd);
3202 widget = GHB_WIDGET(ud->builder, "presets_remove");
3203 set_visible(widget, !hbfd);
3204 widget = GHB_WIDGET(ud->builder, "presets_default");
3205 set_visible(widget, !hbfd);
3206 widget = GHB_WIDGET (ud->builder, "hb_window");
3207 gtk_window_resize(GTK_WINDOW(widget), 16, 16);
3212 hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
3214 g_debug("hbfd_toggled_cb\n");
3215 ghb_widget_to_setting (ud->settings, widget);
3216 gboolean hbfd = ghb_settings_get_bool(ud->settings, "hbfd");
3218 ghb_pref_save(ud->settings, "hbfd");
3222 pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3224 g_debug("pref_changed_cb\n");
3225 ghb_widget_to_setting (ud->settings, widget);
3226 const gchar *name = gtk_widget_get_name(widget);
3227 ghb_pref_save(ud->settings, name);
3231 ghb_file_menu_add_dvd(signal_user_data_t *ud)
3233 GList *link, *drives;
3235 GtkActionGroup *agroup = GTK_ACTION_GROUP(
3236 gtk_builder_get_object(ud->builder, "actiongroup1"));
3237 GtkUIManager *ui = GTK_UI_MANAGER(
3238 gtk_builder_get_object(ud->builder, "uimanager1"));
3239 guint merge_id = gtk_ui_manager_new_merge_id(ui);
3241 link = drives = dvd_device_list();
3242 while (link != NULL)
3244 gchar *name = (gchar*)link->data;
3245 // Create action for this drive
3246 GtkAction *action = gtk_action_new(name, name,
3247 "Scan this DVD source", "gtk-cdrom");
3248 // Add action to action group
3249 gtk_action_group_add_action_with_accel(agroup, action, "");
3250 // Add to ui manager
3251 gtk_ui_manager_add_ui(ui, merge_id,
3252 "ui/menubar1/menuitem1/quit1", name, name,
3253 GTK_UI_MANAGER_AUTO, TRUE);
3254 // Connect signal to action (menu item)
3255 g_signal_connect(action, "activate",
3256 (GCallback)dvd_source_activate_cb, ud);
3260 g_list_free(drives);
3263 gtk_ui_manager_add_ui(ui, merge_id,
3264 "ui/menubar1/menuitem1/quit1", "", NULL,
3265 GTK_UI_MANAGER_AUTO, TRUE);
3268 gboolean ghb_is_cd(GDrive *gd);
3273 GVolumeMonitor *gvm;
3274 GList *drives, *link;
3275 GList *dvd_devices = NULL;
3277 gvm = g_volume_monitor_get ();
3278 drives = g_volume_monitor_get_connected_drives (gvm);
3280 while (link != NULL)
3284 gd = (GDrive*)link->data;
3288 device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3289 dvd_devices = g_list_append(dvd_devices, (gpointer)device);
3291 g_object_unref (gd);
3294 g_list_free(drives);
3299 static DBusConnection *dbus_connection = NULL;
3300 static LibHalContext *hal_ctx;
3303 ghb_is_cd(GDrive *gd)
3306 LibHalDrive *halDrive;
3307 LibHalDriveType dtype;
3309 device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3310 halDrive = libhal_drive_from_device_file (hal_ctx, device);
3311 dtype = libhal_drive_get_type(halDrive);
3313 return (dtype == LIBHAL_DRIVE_TYPE_CDROM);
3317 drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
3320 gint state = ghb_get_state();
3321 static gboolean first_time = TRUE;
3323 if (ud->current_dvd_device == NULL) return;
3324 // A drive change event happens when the program initially starts
3325 // and I don't want to automatically scan at that time.
3331 if (state != GHB_STATE_IDLE) return;
3332 device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3334 // DVD insertion detected. Scan it.
3335 if (strcmp(device, ud->current_dvd_device) == 0)
3337 if (g_drive_has_media (gd))
3339 GtkProgressBar *progress;
3340 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
3341 gtk_progress_bar_set_text (progress, "Scanning ...");
3342 gtk_progress_bar_set_fraction (progress, 0);
3343 update_source_label(ud, device);
3344 ghb_hb_cleanup(TRUE);
3345 ghb_backend_scan(device, 0);
3349 ghb_hb_cleanup(TRUE);
3350 ghb_backend_scan("/dev/null", 0);
3362 if (dbus_connection != NULL)
3365 dbus_error_init (&error);
3366 if (!(dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) {
3367 g_debug ("could not get system bus: %s\n", error.message);
3368 dbus_error_free (&error);
3372 //dbus_connection_setup_with_g_main (dbus_connection, NULL);
3373 //dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
3374 //dbus_connection_add_filter (dbus_connection, gvm_dbus_filter_function, NULL, NULL);
3389 if (!(hal_ctx = libhal_ctx_new ())) {
3390 g_warning ("failed to create a HAL context!");
3394 libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
3395 dbus_error_init (&error);
3396 if (!libhal_ctx_init (hal_ctx, &error)) {
3397 g_warning ("libhal_ctx_init failed: %s", error.message ? error.message : "unknown");
3398 dbus_error_free (&error);
3399 libhal_ctx_free (hal_ctx);
3404 * Do something to ping the HAL daemon - the above functions will
3405 * succeed even if hald is not running, so long as DBUS is. But we
3406 * want to exit silently if hald is not running, to behave on
3409 if (!(devices = libhal_get_all_devices (hal_ctx, &nr, &error))) {
3410 g_warning ("seems that HAL is not running: %s", error.message ? error.message : "unknown");
3411 dbus_error_free (&error);
3413 libhal_ctx_shutdown (hal_ctx, NULL);
3414 libhal_ctx_free (hal_ctx);
3418 libhal_free_string_array (devices);
3420 //gvm_hal_claim_branch ("/org/freedesktop/Hal/devices/local");