1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
6 * callbacks.c is free software.
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
22 #include <libhal-storage.h>
24 #include <glib/gstdio.h>
27 #include "callbacks.h"
29 #include "hb-backend.h"
32 extern gboolean ghb_autostart;
33 static void update_chapter_list(signal_user_data_t *ud);
34 static void clear_audio_list(signal_user_data_t *ud);
35 static GList* dvd_device_list();
36 static gboolean cancel_encode();
37 static void audio_list_refresh_selected(signal_user_data_t *ud);
38 static GHashTable* get_selected_asettings(signal_user_data_t *ud);
40 // This is a dependency map used for greying widgets
41 // that are dependent on the state of another widget.
42 // The enable_value comes from the values that are
43 // obtained from ghb_widget_value(). For combo boxes
44 // you will have to look further to combo box options
45 // maps in hb-backend.c
48 const gchar *widget_name;
49 const gchar *dep_name;
50 const gchar *enable_value;
51 const gboolean disable_if_equal;
54 static dependency_t dep_map[] =
56 {"title", "queue_add", "none", TRUE},
57 {"title", "queue_add_menu", "none", TRUE},
58 {"title", "preview_button", "none", TRUE},
59 {"title", "show_preview_menu", "none", TRUE},
60 {"title", "preview_frame", "none", TRUE},
61 {"title", "picture_label", "none", TRUE},
62 {"title", "picture_tab", "none", TRUE},
63 {"title", "audio_label", "none", TRUE},
64 {"title", "audio_tab", "none", TRUE},
65 {"title", "chapters_label", "none", TRUE},
66 {"title", "chapters_tab", "none", TRUE},
67 {"title", "title", "none", TRUE},
68 {"title", "start_chapter", "none", TRUE},
69 {"title", "end_chapter", "none", TRUE},
70 {"vquality_type_bitrate", "video_bitrate", "enable", FALSE},
71 {"vquality_type_target", "video_target_size", "enable", FALSE},
72 {"vquality_type_constant", "video_quality", "enable", FALSE},
73 {"vquality_type_constant", "constant_rate_factor", "enable", FALSE},
74 {"vquality_type_constant", "x264_trellis", "enable", TRUE},
75 {"vquality_type_constant", "two_pass", "enable", TRUE},
76 {"vquality_type_constant", "turbo", "enable", TRUE},
77 {"two_pass", "turbo", "enable", FALSE},
78 {"container", "large_mp4", "mp4|m4v", FALSE},
79 {"container", "http_optimize_mp4", "mp4|m4v", FALSE},
80 {"container", "ipod_file", "mp4|m4v", FALSE},
81 {"container", "variable_frame_rate", "avi", TRUE},
82 {"variable_frame_rate", "framerate", "enable", TRUE},
83 {"variable_frame_rate", "detelecine", "enable", TRUE},
84 {"decomb", "deinterlace", "enable", TRUE},
85 {"autocrop", "crop_top", "disable", FALSE},
86 {"autocrop", "crop_bottom", "disable", FALSE},
87 {"autocrop", "crop_left", "disable", FALSE},
88 {"autocrop", "crop_right", "disable", FALSE},
89 {"autoscale", "scale_width", "disable", FALSE},
90 {"autoscale", "scale_height", "disable", FALSE},
91 {"anamorphic", "keep_aspect", "disable", FALSE},
92 {"anamorphic", "scale_height", "disable", FALSE},
93 {"keep_aspect", "scale_height", "disable", FALSE},
94 {"video_codec", "x264_tab", "x264", FALSE},
95 {"video_codec", "x264_tab_label", "x264", FALSE},
96 {"video_codec", "ipod_file", "x264", FALSE},
97 {"audio_track", "audio_add", "none", TRUE},
98 {"audio_track", "audio_codec", "none", TRUE},
99 {"audio_track", "audio_bitrate", "none", TRUE},
100 {"audio_track", "audio_sample_rate", "none", TRUE},
101 {"audio_track", "audio_mix", "none", TRUE},
102 {"audio_track", "audio_drc", "none", TRUE},
103 {"audio_codec", "audio_bitrate", "ac3", TRUE},
104 {"audio_codec", "audio_sample_rate", "ac3", TRUE},
105 {"audio_codec", "audio_mix", "ac3", TRUE},
106 {"audio_codec", "audio_drc", "ac3", TRUE},
107 {"x264_bframes", "x264_weighted_bframes", "0", TRUE},
108 {"x264_bframes", "x264_brdo", "0", TRUE},
109 {"x264_bframes", "x264_bime", "0", TRUE},
110 {"x264_bframes", "x264_bpyramid", "<2", TRUE},
111 {"x264_bframes", "x264_direct", "0", TRUE},
112 {"x264_refs", "x264_mixed_refs", "<2", TRUE},
113 {"x264_cabac", "x264_trellis", "enable", FALSE},
114 {"x264_subme", "x264_brdo", "<6", TRUE},
115 {"x264_analyse", "x264_direct", "none", TRUE},
116 {"x264_me", "x264_merange", "umh|esa", FALSE},
117 {"pref_audio_codec1", "pref_audio_bitrate1", "none", TRUE},
118 {"pref_audio_codec1", "pref_audio_rate1", "none", TRUE},
119 {"pref_audio_codec1", "pref_audio_mix1", "none", TRUE},
120 {"pref_audio_codec1", "pref_audio_codec2", "none", TRUE},
121 {"pref_audio_codec1", "pref_audio_bitrate2", "none", TRUE},
122 {"pref_audio_codec1", "pref_audio_rate2", "none", TRUE},
123 {"pref_audio_codec1", "pref_audio_mix2", "none", TRUE},
124 {"pref_audio_codec2", "pref_audio_bitrate2", "none", TRUE},
125 {"pref_audio_codec2", "pref_audio_rate2", "none", TRUE},
126 {"pref_audio_codec2", "pref_audio_mix2", "none", TRUE},
127 {"chapter_markers", "chapters_list", "enable", FALSE},
131 dep_check(signal_user_data_t *ud, const gchar *name)
137 int count = sizeof(dep_map) / sizeof(dependency_t);
138 gboolean result = TRUE;
140 g_debug("dep_check () %s\n", name);
141 for (ii = 0; ii < count; ii++)
143 if (strcmp(dep_map[ii].dep_name, name) == 0)
145 widget = GHB_WIDGET(ud->builder, dep_map[ii].widget_name);
146 dep_object = gtk_builder_get_object(ud->builder, dep_map[ii].dep_name);
147 value = ghb_widget_short_opt(widget);
148 if (dep_object == NULL || widget == NULL)
150 g_message("Failed to find widget\n");
155 gchar **values = g_strsplit(dep_map[ii].enable_value, "|", 10);
156 gboolean sensitive = FALSE;
158 while (values && values[jj])
160 if (values[jj][0] == '>')
162 gdouble dbl = g_strtod (&values[jj][1], NULL);
163 gdouble dvalue = ghb_widget_dbl (widget);
170 else if (values[jj][0] == '<')
172 gdouble dbl = g_strtod (&values[jj][1], NULL);
173 gdouble dvalue = ghb_widget_dbl (widget);
180 if (strcmp(values[jj], value) == 0)
187 sensitive = dep_map[ii].disable_if_equal ^ sensitive;
188 if (!sensitive) result = FALSE;
198 check_depencency(signal_user_data_t *ud, GtkWidget *widget)
203 int count = sizeof(dep_map) / sizeof(dependency_t);
205 if (ghb_widget_index(widget) < 0) return;
206 name = gtk_widget_get_name(widget);
207 g_debug("check_depencency () %s\n", name);
208 for (ii = 0; ii < count; ii++)
210 if (strcmp(dep_map[ii].widget_name, name) == 0)
214 dep_object = gtk_builder_get_object (ud->builder, dep_map[ii].dep_name);
215 if (dep_object == NULL)
217 g_message("Failed to find dependent widget %s\n", dep_map[ii].dep_name);
220 sensitive = dep_check(ud, dep_map[ii].dep_name);
221 if (GTK_IS_ACTION(dep_object))
222 gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
224 gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
230 ghb_check_all_depencencies(signal_user_data_t *ud)
234 int count = sizeof(dep_map) / sizeof(dependency_t);
236 g_debug("ghb_check_all_depencencies ()\n");
237 for (ii = 0; ii < count; ii++)
240 dep_object = gtk_builder_get_object (ud->builder, dep_map[ii].dep_name);
241 if (dep_object == NULL)
243 g_message("Failed to find dependent widget %s\n", dep_map[ii].dep_name);
246 sensitive = dep_check(ud, dep_map[ii].dep_name);
247 if (GTK_IS_ACTION(dep_object))
248 gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
250 gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
255 clear_presets_selection(signal_user_data_t *ud)
257 GtkTreeView *treeview;
258 GtkTreeSelection *selection;
260 if (ud->dont_clear_presets) return;
261 g_debug("clear_presets_selection()\n");
262 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
263 selection = gtk_tree_view_get_selection (treeview);
264 gtk_tree_selection_unselect_all (selection);
268 expand_tilde(const gchar *path)
270 const gchar *user_home;
273 gchar *expanded_path = NULL;
275 g_debug("expand_tilde ()\n");
278 user_home = g_get_home_dir();
279 home = NULL; // squash warning about home uninitialized
282 home = g_strdup(user_home);
285 else if (path[1] == '/')
287 home = g_strdup(user_home);
292 home = g_path_get_dirname(user_home);
295 expanded_path = g_strdup_printf("%s/%s", home, suffix);
298 return expanded_path;
302 on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud)
304 g_debug("on_quit1_activate ()\n");
305 if (ud->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 ud->state |= GHB_STATE_SCANNING;
604 ghb_hb_cleanup(TRUE);
605 ghb_backend_scan (path, 0);
609 // TODO: error dialog
615 source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
619 const gchar *sourcename;
621 GtkFileChooserAction action;
622 gboolean checkbutton_active;
624 g_debug("source_browse_clicked_cb ()\n");
625 sourcename = ghb_settings_get_string(ud->settings, "source");
626 checkbutton_active = FALSE;
627 if (g_file_test(sourcename, G_FILE_TEST_IS_DIR))
629 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
630 checkbutton_active = TRUE;
634 action = GTK_FILE_CHOOSER_ACTION_OPEN;
636 dialog = gtk_file_chooser_dialog_new ("Select Source",
639 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
640 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
642 widget = source_dialog_extra_widgets(dialog, checkbutton_active);
643 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), widget);
644 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), sourcename);
645 response = gtk_dialog_run(GTK_DIALOG (dialog));
646 gtk_widget_hide(dialog);
647 if (response == GTK_RESPONSE_ACCEPT)
651 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
652 if (filename != NULL)
654 do_scan(ud, filename);
655 if (strcmp(sourcename, filename) != 0)
657 ghb_settings_set_string (ud->settings, "default_source", filename);
658 ghb_pref_save (ud->settings, "default_source");
659 ghb_dvd_set_current (filename, ud);
664 gtk_widget_destroy(dialog);
668 dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
670 const gchar *filename;
671 const gchar *sourcename;
673 sourcename = ghb_settings_get_string(ud->settings, "source");
674 filename = gtk_action_get_name(action);
675 do_scan(ud, filename);
676 if (strcmp(sourcename, filename) != 0)
678 ghb_settings_set_string (ud->settings, "default_source", filename);
679 ghb_pref_save (ud->settings, "default_source");
680 ghb_dvd_set_current (filename, ud);
685 update_destination_extension(signal_user_data_t *ud)
687 static gchar *containers[] = {"mkv", "mp4", "m4v", "avi", "ogm", NULL};
689 const gchar *extension;
693 g_debug("update_destination_extension ()\n");
694 extension = ghb_settings_get_string(ud->settings, "container");
695 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "destination"));
696 filename = g_strdup(gtk_entry_get_text(entry));
697 for (ii = 0; containers[ii] != NULL; ii++)
699 if (g_str_has_suffix(filename, containers[ii]))
704 pos = g_strrstr( filename, "." );
706 if (strcmp(extension, &pos[1]) == 0)
708 // Extension is already correct
711 new_name = g_strjoin(".", filename, extension, NULL);
712 ghb_ui_update(ud, "destination", new_name);
720 static gboolean update_default_destination = FALSE;
723 destination_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
727 g_debug("destination_entry_changed_cb ()\n");
728 if ((dest = expand_tilde(gtk_entry_get_text(entry))) != NULL)
730 gtk_entry_set_text(entry, dest);
733 update_destination_extension(ud);
734 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
735 // This signal goes off with ever keystroke, so I'm putting this
736 // update on the timer.
737 update_default_destination = TRUE;
741 destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
745 const char *destname;
748 g_debug("destination_browse_clicked_cb ()\n");
749 destname = ghb_settings_get_string(ud->settings, "destination");
750 dialog = gtk_file_chooser_dialog_new ("Choose Destination",
752 GTK_FILE_CHOOSER_ACTION_SAVE,
753 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
754 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
756 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), destname);
757 basename = g_path_get_basename(destname);
758 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
760 if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
764 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
765 entry = (GtkEntry*)GHB_WIDGET(ud->builder, "destination");
768 g_debug("Failed to find widget: %s\n", "destination");
772 gtk_entry_set_text(entry, filename);
776 gtk_widget_destroy(dialog);
780 window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
782 g_debug("window_destroy_event_cb ()\n");
783 ghb_hb_cleanup(FALSE);
789 window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
791 g_debug("window_delete_event_cb ()\n");
792 if (ud->state & GHB_STATE_WORKING)
794 if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
796 ghb_hb_cleanup(FALSE);
802 ghb_hb_cleanup(FALSE);
808 update_acodec_combo(signal_user_data_t *ud)
810 ghb_grey_combo_options (ud->builder);
814 container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
816 g_debug("container_changed_cb ()\n");
817 ghb_widget_to_setting(ud->settings, widget);
818 update_destination_extension(ud);
819 check_depencency(ud, widget);
820 update_acodec_combo(ud);
821 clear_presets_selection(ud);
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 text = g_strdup_printf ("%02d:%02d:%02d", tinfo->hours, tinfo->minutes, tinfo->seconds);
858 gtk_label_set_text (GTK_LABEL(widget), text);
860 widget = GHB_WIDGET (ud->builder, "source_dimensions");
861 text = g_strdup_printf ("%d x %d", tinfo->width, tinfo->height);
862 gtk_label_set_text (GTK_LABEL(widget), text);
864 widget = GHB_WIDGET (ud->builder, "source_aspect");
865 text = get_aspect_string(tinfo->aspect_n, tinfo->aspect_d);
866 gtk_label_set_text (GTK_LABEL(widget), text);
869 widget = GHB_WIDGET (ud->builder, "source_frame_rate");
870 text = (gchar*)get_rate_string(tinfo->rate_base, tinfo->rate);
871 gtk_label_set_text (GTK_LABEL(widget), text);
874 ghb_ui_update_int (ud, "scale_width", tinfo->width - tinfo->crop[2] - tinfo->crop[3]);
875 // If anamorphic or keep_aspect, the hight will be automatically calculated
876 gboolean keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
877 gboolean anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
878 if (!(keep_aspect || anamorphic))
879 ghb_ui_update_int (ud, "scale_height", tinfo->height - tinfo->crop[0] - tinfo->crop[1]);
881 // Set the limits of cropping. hb_set_anamorphic_size crashes if
882 // you pass it a cropped width or height == 0.
884 bound = tinfo->height / 2 - 2;
885 widget = GHB_WIDGET (ud->builder, "crop_top");
886 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
887 widget = GHB_WIDGET (ud->builder, "crop_bottom");
888 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
889 bound = tinfo->width / 2 - 2;
890 widget = GHB_WIDGET (ud->builder, "crop_left");
891 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
892 widget = GHB_WIDGET (ud->builder, "crop_right");
893 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
894 if (ghb_settings_get_bool (ud->settings, "autocrop"))
896 ghb_ui_update_int (ud, "crop_top", tinfo->crop[0]);
897 ghb_ui_update_int (ud, "crop_bottom", tinfo->crop[1]);
898 ghb_ui_update_int (ud, "crop_left", tinfo->crop[2]);
899 ghb_ui_update_int (ud, "crop_right", tinfo->crop[3]);
901 g_debug("setting max end chapter %d\n", tinfo->num_chapters);
902 widget = GHB_WIDGET (ud->builder, "end_chapter");
903 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters);
904 gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), tinfo->num_chapters);
905 widget = GHB_WIDGET (ud->builder, "start_chapter");
906 gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1);
910 adjust_audio_rate_combos(signal_user_data_t *ud)
912 gint titleindex, audioindex, acodec;
913 ghb_audio_info_t ainfo;
916 g_debug("adjust_audio_rate_combos ()\n");
917 titleindex = ghb_settings_get_index(ud->settings, "title");
919 widget = GHB_WIDGET(ud->builder, "audio_track");
920 audioindex = ghb_widget_int(widget);
922 widget = GHB_WIDGET(ud->builder, "audio_codec");
923 acodec = ghb_widget_int(widget);
925 if (ghb_get_audio_info (&ainfo, titleindex, audioindex) && ghb_audio_is_passthru (acodec))
927 // Set the values for bitrate and samplerate to the input rates
928 ghb_set_passthru_rate_opts (ud->builder, ainfo.bitrate);
929 ghb_ui_update_int (ud, "audio_bitrate", ainfo.bitrate);
930 ghb_ui_update_int (ud, "audio_sample_rate", 0);
931 ghb_ui_update_int (ud, "audio_mix", 0);
935 ghb_set_default_rate_opts (ud->builder);
940 set_pref_audio(gint titleindex, signal_user_data_t *ud)
942 gint acodec, track, ivalue;
945 ghb_audio_info_t ainfo;
946 gboolean skipped_1st = FALSE;
948 // Clear the audio list
949 clear_audio_list(ud);
951 // Find "best" audio based on audio preferences
952 button = GHB_WIDGET (ud->builder, "audio_add");
953 svalue = ghb_settings_get_short_opt(ud->settings, "pref_source_audio_lang");
954 acodec = ghb_settings_get_int(ud->settings, "pref_source_audio_codec");
955 track = ghb_find_audio_track(titleindex, svalue, acodec);
956 ghb_ui_update_int(ud, "audio_track", track);
957 // Get the resulting track, it may not be what was asked for.
958 track = ghb_settings_get_int(ud->settings, "audio_track");
961 // No audio tracks. Perhaps no source dvd yet
962 // Just initialize the audio controls and do not add anything to
964 acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec1");
965 ghb_ui_update_int(ud, "audio_codec", acodec);
966 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
967 ghb_ui_update_int(ud, "audio_bitrate", ivalue);
968 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
969 ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
970 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
971 ghb_ui_update_int(ud, "audio_mix", ivalue);
972 svalue = ghb_settings_get_string(ud->settings, "pref_audio_drc");
973 ghb_ui_update(ud, "audio_drc", svalue);
976 acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec1");
978 // 1. pref codec is ac3
979 // 2. source codec is not ac3
980 // 3. 2nd pref is enabled
981 if (ghb_get_audio_info (&ainfo, titleindex, track) && ghb_audio_is_passthru (acodec))
983 if (!ghb_audio_is_passthru(ainfo.codec))
985 acodec = ghb_get_default_acodec();
986 if (ghb_settings_get_int(ud->settings, "pref_audio_codec2") != 0)
988 // Skip first pref audio
994 ghb_ui_update_int(ud, "audio_codec", acodec);
995 if (!ghb_audio_is_passthru (acodec))
997 // This gets set autimatically if the codec is passthru
998 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
999 ghb_ui_update_int(ud, "audio_bitrate", ivalue);
1000 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
1001 ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
1002 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
1003 ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1004 ghb_ui_update_int(ud, "audio_mix", ivalue);
1006 svalue = ghb_settings_get_string(ud->settings, "pref_audio_drc");
1007 ghb_ui_update(ud, "audio_drc", svalue);
1008 if (acodec != 0) // 0 is none
1010 // Add to audio list
1011 g_signal_emit_by_name(button, "clicked", ud);
1013 acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec2");
1015 // 1. pref codec is ac3
1016 // 2. source codec is not ac3
1017 if (ghb_audio_is_passthru (acodec))
1019 if (!ghb_audio_is_passthru(ainfo.codec) && skipped_1st)
1021 acodec = ghb_get_default_acodec();
1030 ghb_ui_update_int(ud, "audio_codec", acodec);
1031 // Do the second prefs track
1032 if (!ghb_audio_is_passthru (acodec))
1034 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate2");
1035 ghb_ui_update_int(ud, "audio_bitrate", ivalue);
1036 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate2");
1037 ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
1038 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix2");
1039 ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1040 ghb_ui_update_int(ud, "audio_mix", ivalue);
1042 g_signal_emit_by_name(button, "clicked", ud);
1046 static gint preview_button_width;
1047 static gint preview_button_height;
1048 static gboolean update_preview = FALSE;
1051 set_preview_image(signal_user_data_t *ud)
1054 gint preview_width, preview_height, target_height, width, height;
1056 g_debug("set_preview_button_image ()\n");
1057 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1058 if (titleindex < 0) return;
1059 widget = GHB_WIDGET (ud->builder, "preview_frame");
1060 gint frame = ghb_widget_int(widget) - 1;
1061 GdkPixbuf *preview = ghb_get_preview_image (titleindex, frame, ud->settings, TRUE);
1062 if (preview == NULL) return;
1063 widget = GHB_WIDGET (ud->builder, "preview_image");
1064 gtk_image_set_from_pixbuf(GTK_IMAGE(widget), preview);
1066 preview_width = gdk_pixbuf_get_width(preview);
1067 preview_height = gdk_pixbuf_get_height(preview);
1068 gchar *text = g_strdup_printf("%d x %d", preview_width, preview_height);
1069 widget = GHB_WIDGET (ud->builder, "preview_dims");
1070 gtk_label_set_text(GTK_LABEL(widget), text);
1073 g_debug("preview %d x %d\n", preview_width, preview_height);
1074 target_height = MIN(preview_button_height - 12, 128);
1075 height = target_height;
1076 width = preview_width * height / preview_height;
1078 if ((height >= 16) && (width >= 16))
1080 GdkPixbuf *scaled_preview;
1081 scaled_preview = gdk_pixbuf_scale_simple (preview, width, height, GDK_INTERP_NEAREST);
1082 if (scaled_preview != NULL)
1084 g_object_unref (preview);
1086 widget = GHB_WIDGET (ud->builder, "preview_button_image");
1087 gtk_image_set_from_pixbuf(GTK_IMAGE(widget), scaled_preview);
1088 g_object_unref (scaled_preview);
1094 title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1096 ghb_title_info_t tinfo;
1098 const gchar *preset;
1100 g_debug("title_changed_cb ()\n");
1101 ghb_widget_to_setting(ud->settings, widget);
1102 check_depencency(ud, widget);
1104 titleindex = ghb_settings_get_int(ud->settings, "title");
1105 ghb_update_ui_combo_box (ud->builder, "audio_track", titleindex, FALSE);
1106 ghb_update_ui_combo_box (ud->builder, "subtitle_lang", titleindex, FALSE);
1107 preset = ghb_settings_get_string (ud->settings, "preset");
1108 ghb_update_from_preset(ud, preset, "subtitle_lang");
1109 if (ghb_get_title_info (&tinfo, titleindex))
1111 show_title_info(ud, &tinfo);
1113 update_chapter_list (ud);
1114 adjust_audio_rate_combos(ud);
1115 set_pref_audio(titleindex, ud);
1116 if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
1118 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1119 ghb_ui_update_int (ud, "video_bitrate", bitrate);
1122 // Unfortunately, there is no way to query how many frames were
1123 // actually generated during the scan. It attempts to make 10.
1124 // If I knew how many were generated, I would adjust the spin
1125 // control range here.
1126 ghb_ui_update_int (ud, "preview_frame", 1);
1128 set_preview_image (ud);
1132 audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1134 static gint prev_acodec = 0;
1135 gint acodec, ivalue;
1136 GHashTable *asettings;
1138 g_debug("audio_codec_changed_cb ()\n");
1140 acodec = ghb_widget_int(widget);
1141 if (ghb_audio_is_passthru (prev_acodec) && !ghb_audio_is_passthru (acodec))
1143 // Transition from passthru to not, put some audio settings back to
1145 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1146 gint track = ghb_settings_get_int(ud->settings, "audio_track");
1148 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
1149 ghb_ui_update_int (ud, "audio_bitrate", ivalue);
1150 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
1151 ghb_ui_update_int (ud, "audio_sample_rate", ivalue);
1152 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
1153 ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1154 ghb_ui_update_int (ud, "audio_mix", ivalue);
1156 adjust_audio_rate_combos(ud);
1157 ghb_grey_combo_options (ud->builder);
1158 check_depencency(ud, widget);
1159 prev_acodec = acodec;
1160 asettings = get_selected_asettings(ud);
1161 if (asettings != NULL)
1163 ghb_widget_to_setting(asettings, widget);
1164 audio_list_refresh_selected(ud);
1168 static void audio_list_refresh_selected(signal_user_data_t *ud);
1169 static GHashTable* get_selected_asettings(signal_user_data_t *ud);
1172 audio_track_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1174 GHashTable *asettings;
1176 g_debug("audio_track_changed_cb ()\n");
1177 adjust_audio_rate_combos(ud);
1178 check_depencency(ud, widget);
1179 ghb_grey_combo_options(ud->builder);
1180 asettings = get_selected_asettings(ud);
1181 if (asettings != NULL)
1183 ghb_widget_to_setting(asettings, widget);
1184 audio_list_refresh_selected(ud);
1189 audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1191 GHashTable *asettings;
1193 g_debug("audio_widget_changed_cb ()\n");
1194 check_depencency(ud, widget);
1195 asettings = get_selected_asettings(ud);
1196 if (asettings != NULL)
1198 ghb_widget_to_setting(asettings, widget);
1199 audio_list_refresh_selected(ud);
1204 generic_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1206 g_debug("generic_widget_changed_cb ()\n");
1207 check_depencency(ud, widget);
1211 setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1213 ghb_widget_to_setting(ud->settings, widget);
1214 check_depencency(ud, widget);
1215 clear_presets_selection(ud);
1219 vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1223 ghb_widget_to_setting(ud->settings, widget);
1224 check_depencency(ud, widget);
1225 clear_presets_selection(ud);
1226 ghb_vquality_range(ud, &vqmin, &vqmax);
1227 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1228 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1232 vfr_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1234 //const gchar *name = gtk_widget_get_name(widget);
1235 //g_debug("setting_widget_changed_cb () %s\n", name);
1236 ghb_widget_to_setting(ud->settings, widget);
1237 check_depencency(ud, widget);
1238 clear_presets_selection(ud);
1239 if (ghb_settings_get_bool(ud->settings, "variable_frame_rate"))
1241 ghb_ui_update_int(ud, "framerate", 0);
1246 mirror_cb(GtkWidget *widget, signal_user_data_t *ud)
1248 const gchar *name = gtk_widget_get_name(widget);
1249 if (name == NULL) return;
1251 g_debug("mirror_cb () %s\n", name);
1252 gchar *mirror = g_strdup(name);
1253 gchar *pos = g_strrstr(mirror, "_mirror");
1254 if (pos == NULL) return;
1256 gchar *value = ghb_widget_short_opt (widget);
1257 ghb_ui_update (ud, mirror, value);
1261 // subtitles have their differ from other settings in that
1262 // the selection is updated automaitcally when the title
1263 // changes. I don't want the preset selection changed as
1264 // would happen for regular settings.
1266 subtitle_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1268 const gchar *name = gtk_widget_get_name(widget);
1269 g_debug("subtitle_changed_cb () %s\n", name);
1270 ghb_widget_to_setting(ud->settings, widget);
1271 check_depencency(ud, widget);
1275 target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1277 const gchar *name = gtk_widget_get_name(widget);
1278 g_debug("setting_widget_changed_cb () %s\n", name);
1279 ghb_widget_to_setting(ud->settings, widget);
1280 check_depencency(ud, widget);
1281 clear_presets_selection(ud);
1282 if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
1284 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1285 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1286 ghb_ui_update_int (ud, "video_bitrate", bitrate);
1291 start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1293 const gchar *name = gtk_widget_get_name(widget);
1294 g_debug("start_chapter_changed_cb () %s\n", name);
1295 ghb_widget_to_setting(ud->settings, widget);
1296 GtkWidget *end_ch = GHB_WIDGET (ud->builder, "end_chapter");
1298 gtk_spin_button_get_range (GTK_SPIN_BUTTON(end_ch), &start, &end);
1299 start = ghb_settings_get_int(ud->settings, "start_chapter");
1300 gtk_spin_button_set_range (GTK_SPIN_BUTTON(end_ch), start, end);
1301 check_depencency(ud, widget);
1305 end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1307 const gchar *name = gtk_widget_get_name(widget);
1308 g_debug("end_chapter_changed_cb () %s\n", name);
1309 ghb_widget_to_setting(ud->settings, widget);
1310 GtkWidget *start_ch = GHB_WIDGET (ud->builder, "start_chapter");
1312 gtk_spin_button_get_range (GTK_SPIN_BUTTON(start_ch), &start, &end);
1313 end = ghb_settings_get_int(ud->settings, "end_chapter");
1314 gtk_spin_button_set_range (GTK_SPIN_BUTTON(start_ch), start, end);
1315 check_depencency(ud, widget);
1319 scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1321 g_debug("scale_width_changed_cb ()\n");
1322 ghb_widget_to_setting(ud->settings, widget);
1323 check_depencency(ud, widget);
1324 ghb_set_scale (ud, GHB_SCALE_KEEP_WIDTH);
1325 update_preview = TRUE;
1327 gint width = ghb_settings_get_int(ud->settings, "scale_width");
1328 gint height = ghb_settings_get_int(ud->settings, "scale_height");
1329 widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1330 text = g_strdup_printf ("%d x %d", width, height);
1331 gtk_label_set_text (GTK_LABEL(widget), text);
1336 scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1338 g_debug("scale_height_changed_cb ()\n");
1339 ghb_widget_to_setting(ud->settings, widget);
1340 check_depencency(ud, widget);
1341 ghb_set_scale (ud, GHB_SCALE_KEEP_HEIGHT);
1342 update_preview = TRUE;
1344 gint width = ghb_settings_get_int(ud->settings, "scale_width");
1345 gint height = ghb_settings_get_int(ud->settings, "scale_height");
1346 widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1347 text = g_strdup_printf ("%d x %d", width, height);
1348 gtk_label_set_text (GTK_LABEL(widget), text);
1353 crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1355 gint titleindex, crop[4];
1356 ghb_title_info_t tinfo;
1358 g_debug("crop_changed_cb ()\n");
1359 ghb_widget_to_setting(ud->settings, widget);
1360 check_depencency(ud, widget);
1361 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1363 crop[0] = ghb_settings_get_int(ud->settings, "crop_top");
1364 crop[1] = ghb_settings_get_int(ud->settings, "crop_bottom");
1365 crop[2] = ghb_settings_get_int(ud->settings, "crop_left");
1366 crop[3] = ghb_settings_get_int(ud->settings, "crop_right");
1367 titleindex = ghb_settings_get_index(ud->settings, "title");
1368 if (ghb_get_title_info (&tinfo, titleindex))
1373 width = tinfo.width - crop[2] - crop[3];
1374 height = tinfo.height - crop[0] - crop[1];
1375 widget = GHB_WIDGET (ud->builder, "crop_dimensions");
1376 text = g_strdup_printf ("%d x %d", width, height);
1377 gtk_label_set_text (GTK_LABEL(widget), text);
1381 widget = GHB_WIDGET (ud->builder, "crop_values");
1382 text = g_strdup_printf ("%d:%d:%d:%d", crop[0], crop[1], crop[2], crop[3]);
1383 gtk_label_set_text (GTK_LABEL(widget), text);
1385 update_preview = TRUE;
1389 scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1391 g_debug("scale_changed_cb ()\n");
1392 ghb_widget_to_setting(ud->settings, widget);
1393 check_depencency(ud, widget);
1394 clear_presets_selection(ud);
1395 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1396 update_preview = TRUE;
1400 text = ghb_settings_get_bool(ud->settings, "autocrop") ? "On" : "Off";
1401 widget = GHB_WIDGET (ud->builder, "crop_auto");
1402 gtk_label_set_text (GTK_LABEL(widget), text);
1403 text = ghb_settings_get_bool(ud->settings, "autoscale") ? "On" : "Off";
1404 widget = GHB_WIDGET (ud->builder, "scale_auto");
1405 gtk_label_set_text (GTK_LABEL(widget), text);
1406 text = ghb_settings_get_bool(ud->settings, "anamorphic") ? "On" : "Off";
1407 widget = GHB_WIDGET (ud->builder, "scale_anamorphic");
1408 gtk_label_set_text (GTK_LABEL(widget), text);
1412 generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
1414 // Normally (due to user input) I only want to process the entry
1415 // when editing is done and the focus-out signal is sent.
1416 // But... there's always a but.
1417 // If the entry is changed by software, the focus-out signal is not sent.
1418 // The changed signal is sent ... so here we are.
1419 // I don't want to process upon every keystroke, so I prevent processing
1420 // while the widget has focus.
1421 g_debug("generic_entry_changed_cb ()\n");
1422 if (!GTK_WIDGET_HAS_FOCUS((GtkWidget*)entry))
1424 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
1429 generic_focus_out_cb(GtkWidget *widget, GdkEventFocus *event,
1430 signal_user_data_t *ud)
1432 g_debug("generic_focus_out_cb ()\n");
1433 ghb_widget_to_setting(ud->settings, widget);
1438 clear_audio_list(signal_user_data_t *ud)
1440 GtkTreeView *treeview;
1441 GtkListStore *store;
1444 g_debug("clear_audio_list ()\n");
1445 while (ud->audio_settings != NULL)
1447 link = ud->audio_settings;
1448 ud->audio_settings = g_slist_remove_link(ud->audio_settings, link);
1449 g_hash_table_destroy((GHashTable*)link->data);
1450 g_slist_free_1(link);
1452 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1453 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1454 gtk_list_store_clear (store);
1458 add_to_audio_list(signal_user_data_t *ud, GHashTable *settings)
1460 GtkTreeView *treeview;
1462 GtkListStore *store;
1463 GtkTreeSelection *selection;
1465 g_debug("add_to_audio_list ()\n");
1466 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1467 selection = gtk_tree_view_get_selection (treeview);
1468 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1470 gtk_list_store_append(store, &iter);
1471 gtk_list_store_set(store, &iter,
1472 // These are displayed in list
1473 0, ghb_settings_get_option(settings, "audio_track"),
1474 1, ghb_settings_get_option(settings, "audio_codec"),
1475 2, ghb_settings_get_option(settings, "audio_bitrate"),
1476 3, ghb_settings_get_option(settings, "audio_sample_rate"),
1477 4, ghb_settings_get_option(settings, "audio_mix"),
1478 // These are used to set combo box values when a list item is selected
1479 5, ghb_settings_get_string(settings, "audio_drc"),
1480 6, ghb_settings_get_short_opt(settings, "audio_track"),
1481 7, ghb_settings_get_short_opt(settings, "audio_codec"),
1482 8, ghb_settings_get_short_opt(settings, "audio_bitrate"),
1483 9, ghb_settings_get_short_opt(settings, "audio_sample_rate"),
1484 10, ghb_settings_get_short_opt(settings, "audio_mix"),
1486 gtk_tree_selection_select_iter(selection, &iter);
1490 audio_list_refresh_selected(signal_user_data_t *ud)
1492 GtkTreeView *treeview;
1493 GtkTreePath *treepath;
1494 GtkTreeSelection *selection;
1495 GtkTreeModel *store;
1500 GHashTable *asettings = NULL;
1502 g_debug("get_selected_asettings ()\n");
1503 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1504 selection = gtk_tree_view_get_selection (treeview);
1505 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1507 // Get the row number
1508 treepath = gtk_tree_model_get_path (store, &iter);
1509 indices = gtk_tree_path_get_indices (treepath);
1512 // find audio settings
1513 if (row < 0) return;
1514 link = g_slist_nth(ud->audio_settings, row);
1515 if (link == NULL) return;
1516 asettings = (GHashTable*)link->data;
1517 gtk_list_store_set(GTK_LIST_STORE(store), &iter,
1518 // These are displayed in list
1519 0, ghb_settings_get_option(asettings, "audio_track"),
1520 1, ghb_settings_get_option(asettings, "audio_codec"),
1521 2, ghb_settings_get_option(asettings, "audio_bitrate"),
1522 3, ghb_settings_get_option(asettings, "audio_sample_rate"),
1523 4, ghb_settings_get_option(asettings, "audio_mix"),
1524 // These are used to set combo box values when a list item is selected
1525 5, ghb_settings_get_string(asettings, "audio_drc"),
1526 6, ghb_settings_get_short_opt(asettings, "audio_track"),
1527 7, ghb_settings_get_short_opt(asettings, "audio_codec"),
1528 8, ghb_settings_get_short_opt(asettings, "audio_bitrate"),
1529 9, ghb_settings_get_short_opt(asettings, "audio_sample_rate"),
1530 10, ghb_settings_get_short_opt(asettings, "audio_mix"),
1536 get_selected_asettings(signal_user_data_t *ud)
1538 GtkTreeView *treeview;
1539 GtkTreePath *treepath;
1540 GtkTreeSelection *selection;
1541 GtkTreeModel *store;
1546 GHashTable *asettings = NULL;
1548 g_debug("get_selected_asettings ()\n");
1549 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1550 selection = gtk_tree_view_get_selection (treeview);
1551 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1553 // Get the row number
1554 treepath = gtk_tree_model_get_path (store, &iter);
1555 indices = gtk_tree_path_get_indices (treepath);
1558 // find audio settings
1559 if (row < 0) return NULL;
1560 link = g_slist_nth(ud->audio_settings, row);
1561 if (link == NULL) return NULL;
1562 asettings = (GHashTable*)link->data;
1568 audio_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
1570 GtkTreeModel *store;
1574 g_debug("audio_list_selection_changed_cb ()\n");
1575 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1577 const gchar *track, *codec, *bitrate, *sample_rate, *mix, *drc;
1578 gtk_tree_model_get(store, &iter,
1586 ghb_ui_update(ud, "audio_track", track);
1587 ghb_ui_update(ud, "audio_codec", codec);
1588 ghb_ui_update(ud, "audio_bitrate", bitrate);
1589 ghb_ui_update(ud, "audio_sample_rate", sample_rate);
1590 ghb_ui_update(ud, "audio_mix", mix);
1591 ghb_ui_update(ud, "audio_drc", drc);
1592 widget = GHB_WIDGET (ud->builder, "audio_remove");
1593 gtk_widget_set_sensitive(widget, TRUE);
1594 //widget = GHB_WIDGET (ud->builder, "audio_update");
1595 //gtk_widget_set_sensitive(widget, TRUE);
1599 widget = GHB_WIDGET (ud->builder, "audio_remove");
1600 gtk_widget_set_sensitive(widget, FALSE);
1601 //widget = GHB_WIDGET (ud->builder, "audio_update");
1602 //gtk_widget_set_sensitive(widget, FALSE);
1607 audio_add_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1609 // Add the current audio settings to the list.
1610 GHashTable *asettings;
1614 g_debug("audio_add_clicked_cb ()\n");
1615 // Only allow up to 8 audio entries
1616 asettings = ghb_settings_new();
1617 widget = GHB_WIDGET(ud->builder, "audio_track");
1618 ghb_settings_set(asettings, "audio_track", ghb_widget_value(widget));
1619 widget = GHB_WIDGET(ud->builder, "audio_codec");
1620 ghb_settings_set(asettings, "audio_codec", ghb_widget_value(widget));
1621 widget = GHB_WIDGET(ud->builder, "audio_bitrate");
1622 ghb_settings_set(asettings, "audio_bitrate", ghb_widget_value(widget));
1623 widget = GHB_WIDGET(ud->builder, "audio_sample_rate");
1624 ghb_settings_set(asettings, "audio_sample_rate", ghb_widget_value(widget));
1625 widget = GHB_WIDGET(ud->builder, "audio_mix");
1626 ghb_settings_set(asettings, "audio_mix", ghb_widget_value(widget));
1627 widget = GHB_WIDGET(ud->builder, "audio_drc");
1628 ghb_settings_set(asettings, "audio_drc", ghb_widget_value(widget));
1630 ud->audio_settings = g_slist_append(ud->audio_settings, asettings);
1631 add_to_audio_list(ud, asettings);
1632 count = g_slist_length(ud->audio_settings);
1635 gtk_widget_set_sensitive(xwidget, FALSE);
1640 audio_remove_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
1642 GtkTreeView *treeview;
1643 GtkTreePath *treepath;
1644 GtkTreeSelection *selection;
1645 GtkTreeModel *store;
1646 GtkTreeIter iter, nextIter;
1651 g_debug("audio_remove_clicked_cb ()\n");
1652 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1653 selection = gtk_tree_view_get_selection (treeview);
1654 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1657 if (!gtk_tree_model_iter_next(store, &nextIter))
1660 if (gtk_tree_model_get_iter_first(store, &nextIter))
1662 gtk_tree_selection_select_iter (selection, &nextIter);
1667 gtk_tree_selection_select_iter (selection, &nextIter);
1669 // Get the row number
1670 treepath = gtk_tree_model_get_path (store, &iter);
1671 indices = gtk_tree_path_get_indices (treepath);
1674 // Remove the selected item
1675 gtk_list_store_remove (GTK_LIST_STORE(store), &iter);
1676 // remove from audio settings list
1677 if (row < 0) return;
1678 link = g_slist_nth(ud->audio_settings, row);
1679 if (link == NULL) return;
1680 ud->audio_settings = g_slist_remove_link(ud->audio_settings, link);
1681 g_hash_table_destroy((GHashTable*)link->data);
1682 g_slist_free_1(link);
1683 widget = GHB_WIDGET (ud->builder, "audio_add");
1684 gtk_widget_set_sensitive(widget, TRUE);
1689 audio_list_refresh(signal_user_data_t *ud)
1691 GtkTreeView *treeview;
1693 GtkListStore *store;
1696 g_debug("audio_list_refresh ()\n");
1697 GSList *link = ud->audio_settings;
1698 if (link == NULL) return;
1699 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1700 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1701 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1705 GHashTable *asettings;
1707 asettings = (GHashTable*)link->data;
1708 gtk_list_store_set(GTK_LIST_STORE(store), &iter,
1709 // These are displayed in list
1710 0, ghb_settings_get_option(asettings, "audio_track"),
1711 1, ghb_settings_get_option(asettings, "audio_codec"),
1712 2, ghb_settings_get_option(asettings, "audio_bitrate"),
1713 3, ghb_settings_get_option(asettings, "audio_sample_rate"),
1714 4, ghb_settings_get_option(asettings, "audio_mix"),
1715 // These are used to set combo box values when a list item is selected
1716 5, ghb_settings_get_string(asettings, "audio_drc"),
1717 6, ghb_settings_get_short_opt(asettings, "audio_track"),
1718 7, ghb_settings_get_short_opt(asettings, "audio_codec"),
1719 8, ghb_settings_get_short_opt(asettings, "audio_bitrate"),
1720 9, ghb_settings_get_short_opt(asettings, "audio_sample_rate"),
1721 10, ghb_settings_get_short_opt(asettings, "audio_mix"),
1723 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1725 } while (!done && link);
1730 ghb_presets_list_update(signal_user_data_t *ud)
1732 GtkTreeView *treeview;
1734 GtkListStore *store;
1739 gchar **descriptions;
1740 gint flags, custom, def;
1742 g_debug("ghb_presets_list_update ()\n");
1743 presets = ghb_presets_get_names();
1744 descriptions = ghb_presets_get_descriptions();
1745 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1746 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1747 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1751 if ((presets != NULL) && (presets[ii] != NULL))
1753 // Update row with settings data
1754 g_debug("Updating row\n");
1755 flags = ghb_preset_flags(presets[ii], &index);
1756 def = flags & PRESET_DEFAULT;
1757 custom = flags & PRESET_CUSTOM;
1758 gtk_list_store_set(store, &iter,
1762 3, custom ? "black" : "blue",
1763 4, descriptions[ii],
1766 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1770 // No more settings data, remove row
1771 g_debug("Removing row\n");
1772 done = !gtk_list_store_remove(store, &iter);
1776 while ((presets != NULL) && (presets[ii] != NULL))
1778 // Additional settings, add row
1779 g_debug("Adding row %s\n", presets[ii]);
1780 gtk_list_store_append(store, &iter);
1781 flags = ghb_preset_flags(presets[ii], &index);
1782 def = flags & PRESET_DEFAULT;
1783 custom = flags & PRESET_CUSTOM;
1784 gtk_list_store_set(store, &iter, 0, presets[ii],
1787 3, custom ? "black" : "blue",
1788 4, descriptions[ii],
1792 g_strfreev (presets);
1796 ghb_select_preset(GtkBuilder *builder, const gchar *preset)
1798 GtkTreeView *treeview;
1799 GtkTreeSelection *selection;
1800 GtkTreeModel *store;
1805 g_debug("select_preset()\n");
1806 if (preset == NULL) return;
1807 treeview = GTK_TREE_VIEW(GHB_WIDGET(builder, "presets_list"));
1808 selection = gtk_tree_view_get_selection (treeview);
1809 store = gtk_tree_view_get_model (treeview);
1810 if (gtk_tree_model_get_iter_first(store, &iter))
1814 gtk_tree_model_get(store, &iter, 0, &tpreset, -1);
1815 if (strcmp(preset, tpreset) == 0)
1817 gtk_tree_selection_select_iter (selection, &iter);
1820 done = !gtk_tree_model_iter_next(store, &iter);
1826 presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1831 GtkResponseType response;
1832 const gchar *preset = "";
1834 g_debug("presets_save_clicked_cb ()\n");
1835 preset = ghb_settings_get_string (ud->settings, "preset");
1836 // Clear the description
1837 desc = GTK_TEXT_VIEW(GHB_WIDGET(ud->builder, "preset_description"));
1838 //gtk_entry_set_text(desc, "");
1839 dialog = GHB_WIDGET(ud->builder, "preset_save_dialog");
1840 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "preset_name"));
1841 gtk_entry_set_text(entry, preset);
1842 response = gtk_dialog_run(GTK_DIALOG(dialog));
1843 gtk_widget_hide(dialog);
1844 if (response == GTK_RESPONSE_OK)
1847 const gchar *name = gtk_entry_get_text(entry);
1848 g_debug("description to settings\n");
1849 ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
1850 ghb_settings_save(ud, name);
1851 ghb_presets_list_update(ud);
1852 // Make the new preset the selected item
1853 ghb_select_preset(ud->builder, name);
1858 prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1861 GtkResponseType response;
1863 g_debug("prefs_dialog_cb ()\n");
1864 dialog = GHB_WIDGET(ud->builder, "prefs_dialog");
1865 response = gtk_dialog_run(GTK_DIALOG(dialog));
1866 gtk_widget_hide(dialog);
1870 presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1872 GtkTreeView *treeview;
1873 GtkTreeSelection *selection;
1874 GtkTreeModel *store;
1877 GtkResponseType response;
1879 g_debug("presets_remove_clicked_cb ()\n");
1880 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1881 selection = gtk_tree_view_get_selection (treeview);
1882 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1886 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1887 if (!ghb_presets_is_standard(preset))
1889 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1890 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1891 "Confirm deletion of preset %s.", preset);
1892 response = gtk_dialog_run(GTK_DIALOG(dialog));
1893 gtk_widget_destroy (dialog);
1894 if (response == GTK_RESPONSE_YES)
1896 GtkTreeIter nextIter = iter;
1897 gchar *nextPreset = NULL;
1898 if (!gtk_tree_model_iter_next(store, &nextIter))
1900 if (gtk_tree_model_get_iter_first(store, &nextIter))
1902 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1907 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1909 // Remove the selected item
1910 // First unselect it so that selecting the new item works properly
1911 gtk_tree_selection_unselect_iter (selection, &iter);
1912 ghb_presets_remove(ud->settings, preset);
1913 ghb_presets_list_update(ud);
1914 ghb_select_preset(ud->builder, nextPreset);
1919 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1920 GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
1921 "Can not delete standard preset %s.", preset);
1922 response = gtk_dialog_run(GTK_DIALOG(dialog));
1923 gtk_widget_destroy (dialog);
1929 preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
1933 ghb_ui_update_int (ud, "scale_width", tinfo->width - tinfo->crop[2] - tinfo->crop[3]);
1934 // If anamorphic or keep_aspect, the hight will be automatically calculated
1935 gboolean keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
1936 gboolean anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
1937 if (!(keep_aspect || anamorphic))
1938 ghb_ui_update_int (ud, "scale_height", tinfo->height - tinfo->crop[0] - tinfo->crop[1]);
1940 // Set the limits of cropping. hb_set_anamorphic_size crashes if
1941 // you pass it a cropped width or height == 0.
1943 bound = tinfo->height / 2 - 2;
1944 widget = GHB_WIDGET (ud->builder, "crop_top");
1945 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1946 widget = GHB_WIDGET (ud->builder, "crop_bottom");
1947 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1948 bound = tinfo->width / 2 - 2;
1949 widget = GHB_WIDGET (ud->builder, "crop_left");
1950 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1951 widget = GHB_WIDGET (ud->builder, "crop_right");
1952 gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1953 if (ghb_settings_get_bool (ud->settings, "autocrop"))
1955 ghb_ui_update_int (ud, "crop_top", tinfo->crop[0]);
1956 ghb_ui_update_int (ud, "crop_bottom", tinfo->crop[1]);
1957 ghb_ui_update_int (ud, "crop_left", tinfo->crop[2]);
1958 ghb_ui_update_int (ud, "crop_right", tinfo->crop[3]);
1963 presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
1965 GtkTreeModel *store;
1969 gboolean sensitive = FALSE;
1970 ghb_title_info_t tinfo;
1972 g_debug("presets_list_selection_changed_cb ()\n");
1973 if (gtk_tree_selection_get_selected(selection, &store, &iter))
1975 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1976 if (!ghb_presets_is_standard(preset))
1980 ud->dont_clear_presets = TRUE;
1981 // Temporarily set the video_quality range to (0,100)
1982 // This is needed so the video_quality value does not get
1983 // truncated when set. The range will be readjusted below
1984 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1985 gtk_range_set_range (GTK_RANGE(qp), 0, 100);
1986 ghb_set_preset(ud, preset);
1987 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1988 set_pref_audio(titleindex, ud);
1989 ud->dont_clear_presets = FALSE;
1990 if (ghb_get_title_info (&tinfo, titleindex))
1992 preset_update_title_deps(ud, &tinfo);
1994 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1997 ghb_vquality_range(ud, &vqmin, &vqmax);
1998 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
2002 g_debug("No selection??? Perhaps unselected.\n");
2004 widget = GHB_WIDGET (ud->builder, "presets_remove");
2005 gtk_widget_set_sensitive(widget, sensitive);
2009 queue_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
2011 GtkTreeModel *store;
2012 GtkTreeIter iter, piter;
2014 g_debug("queue_list_selection_changed_cb ()\n");
2015 // A queue entry is made up of a parent and multiple
2016 // children that are visible when expanded. When and entry
2017 // is selected, I want the parent to be selected.
2018 // This is purely cosmetic.
2019 if (gtk_tree_selection_get_selected(selection, &store, &iter))
2021 if (gtk_tree_model_iter_parent (store, &piter, &iter))
2024 GtkTreeView *treeview;
2026 gtk_tree_selection_select_iter (selection, &piter);
2027 path = gtk_tree_model_get_path (store, &piter);
2028 treeview = gtk_tree_selection_get_tree_view (selection);
2029 // Make the parent visible in scroll window if it is not.
2030 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
2037 add_to_queue_list(signal_user_data_t *ud, job_settings_t *item)
2039 GtkTreeView *treeview;
2041 GtkTreeStore *store;
2047 g_debug("update_queue_list ()\n");
2048 if (item == NULL) return;
2049 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2050 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2052 gint title = ghb_settings_get_int(item->settings, "title");
2053 gint start_chapter = ghb_settings_get_int(item->settings, "start_chapter");
2054 gint end_chapter = ghb_settings_get_int(item->settings, "end_chapter");
2055 gboolean pass2 = ghb_settings_get_bool(item->settings, "two_pass");
2056 const gchar *vol_name = ghb_settings_get_string(item->settings, "volume_label");
2057 if (vol_name == NULL)
2058 vol_name = "No Title";
2059 info = g_strdup_printf
2061 "<big><b>%s</b></big> (Title %d, Chapters %d through %d, %d Video %s)",
2062 vol_name, title+1, start_chapter, end_chapter,
2063 pass2 ? 2:1, pass2 ? "Passes":"Pass");
2065 gtk_tree_store_append(store, &iter, NULL);
2066 gtk_tree_store_set(store, &iter, 0, "hb-queue-job", 1, info, 2, "hb-queue-delete", -1);
2069 const gchar *vcodec = ghb_settings_get_option(item->settings, "video_codec");
2070 const gchar *container = ghb_settings_get_option(item->settings, "container");
2071 const gchar *acodec = ghb_settings_get_option(item->settings, "audio_codec");
2072 const gchar *dest = ghb_settings_get_string(item->settings, "destination");
2073 const gchar *preset = ghb_settings_get_string(item->settings, "preset");
2074 info = g_strdup_printf
2076 "<b>Preset:</b> %s\n"
2077 "<b>Format:</b> %s Container, %s Video + %s Audio\n"
2078 "<b>Destination:</b> %s",
2079 preset, container, vcodec, acodec, dest);
2081 gtk_tree_store_append(store, &citer, &iter);
2082 gtk_tree_store_set(store, &citer, 1, info, -1);
2085 gint width = ghb_settings_get_int(item->settings, "scale_width");
2086 gint height = ghb_settings_get_int(item->settings, "scale_height");
2087 gboolean anamorphic = ghb_settings_get_bool(item->settings, "anamorphic");
2088 gboolean round_dim = ghb_settings_get_bool(item->settings, "round_dimensions");
2089 gboolean keep_aspect = ghb_settings_get_bool(item->settings, "keep_aspect");
2095 aspect_desc = "(Anamorphic)";
2099 aspect_desc = "(Strict Anamorphic)";
2106 aspect_desc = "(Aspect Preserved)";
2110 aspect_desc = "(Aspect Lost)";
2113 gboolean vqtype = ghb_settings_get_bool(item->settings, "vquality_type_constant");
2115 gchar *vq_desc = "Error";
2118 vqtype = ghb_settings_get_bool(item->settings, "vquality_type_target");
2121 // Has to be bitrate
2122 vqvalue = ghb_settings_get_int(item->settings, "video_bitrate");
2128 vqvalue = ghb_settings_get_int(item->settings, "video_target");
2135 vqvalue = ghb_settings_get_int(item->settings, "video_quality");
2136 vq_desc = "% Constant Quality";
2138 const gchar *fps = ghb_settings_get_string(item->settings, "framerate");
2139 const gchar *vcodec_abbr = ghb_settings_get_short_opt(item->settings, "video_codec");
2141 if (strcmp(vcodec_abbr, "x264") == 0)
2143 gchar *x264opts = ghb_build_x264opts_string(item->settings);
2144 g_debug("xopts (%s)\n", x264opts);
2145 extra_opts = g_strdup_printf ("\n<b>x264 Options:</b> %s", x264opts);
2150 extra_opts = g_strdup("");
2152 gboolean turbo = ghb_settings_get_bool (item->settings, "turbo");
2153 gchar *turbo_desc = "\n<b>Turbo:</b> Off";;
2156 turbo_desc = "\n<b>Turbo:</b> On";
2158 num_pass = pass2 ? 2 : 1;
2159 for (ii = 0; ii < num_pass; ii++)
2161 gboolean final = (ii == (num_pass - 1));
2162 GString *pass = g_string_new("");
2163 g_string_append_printf( pass,
2165 "<b>Picture:</b> %d x %d %s\n"
2166 "<b>Video:</b> %s, %d %s, %s fps"
2168 ii ? "2nd":"1st", width, height, aspect_desc,
2169 vcodec, vqvalue, vq_desc, fps,
2170 final ? extra_opts : turbo_desc);
2175 GSList *link = item->audio_settings;
2178 GHashTable *asettings = (GHashTable*)link->data;
2179 const gchar *acodec = ghb_settings_get_option(asettings, "audio_codec");
2180 const gchar *bitrate = ghb_settings_get_string(asettings, "audio_bitrate");
2181 const gchar *samplerate = ghb_settings_get_string(asettings, "audio_sample_rate");
2182 gint track = ghb_settings_get_int(asettings, "audio_track");
2183 const gchar *mix = ghb_settings_get_option(asettings, "audio_mix");
2184 g_string_append_printf(pass,
2185 "\n<b>Audio:</b> %s, %s kbps, %s kHz, Track %d: %s",
2186 acodec, bitrate, samplerate, track+1, mix);
2190 info = g_string_free(pass, FALSE);
2191 gtk_tree_store_append(store, &citer, &iter);
2192 gtk_tree_store_set(store, &citer, 0, ii ? "hb-queue-pass2" : "hb-queue-pass1", 1, info, -1);
2199 ghb_message_dialog(GtkMessageType type, const gchar *message, const gchar *no, const gchar *yes)
2202 GtkResponseType response;
2204 // Toss up a warning dialog
2205 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2206 type, GTK_BUTTONS_NONE,
2208 gtk_dialog_add_buttons( GTK_DIALOG(dialog),
2209 no, GTK_RESPONSE_NO,
2210 yes, GTK_RESPONSE_YES, NULL);
2211 response = gtk_dialog_run(GTK_DIALOG(dialog));
2212 gtk_widget_destroy (dialog);
2213 if (response == GTK_RESPONSE_NO)
2221 estimate_file_size(signal_user_data_t *ud)
2223 ghb_title_info_t tinfo;
2227 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2228 if (titleindex < 0) return 0;
2230 if (!ghb_get_title_info(&tinfo, titleindex)) return 0;
2231 duration = ((tinfo.hours*60)+tinfo.minutes)*60+tinfo.seconds;
2232 bitrate = ghb_guess_bitrate(ud->settings);
2233 size = (gint64)duration * (gint64)bitrate/8;
2237 #define DISK_FREE_THRESH (1024L*1024L*1024L*3)
2240 validate_settings(signal_user_data_t *ud)
2242 // Check to see if the dest file exists or is
2243 // already in the queue
2245 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2246 if (titleindex < 0) return FALSE;
2247 const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
2248 GSList *link = ud->queue;
2249 while (link != NULL)
2251 job_settings_t *item;
2252 const gchar *filename;
2253 item = (job_settings_t*)link->data;
2254 filename = ghb_settings_get_string(item->settings, "destination");
2255 if (strcmp(dest, filename) == 0)
2257 message = g_strdup_printf(
2258 "Destination: %s\n\n"
2259 "Another queued job has specified the same destination.\n"
2260 "Do you want to overwrite?",
2262 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
2272 gchar *destdir = g_path_get_dirname(dest);
2273 if (!g_file_test(destdir, G_FILE_TEST_IS_DIR))
2275 message = g_strdup_printf(
2276 "Destination: %s\n\n"
2277 "This is not a valid directory.",
2279 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2284 if (g_access(destdir, R_OK|W_OK) != 0)
2286 message = g_strdup_printf(
2287 "Destination: %s\n\n"
2288 "Can not read or write the directory.",
2290 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2298 gchar *resolved = ghb_resolve_symlink(destdir);
2300 gfile = g_file_new_for_path(resolved);
2301 info = g_file_query_filesystem_info(gfile,
2302 G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, NULL);
2305 if (g_file_info_has_attribute(info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE))
2307 size = g_file_info_get_attribute_uint64(info,
2308 G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
2310 gint64 fsize = estimate_file_size(ud);
2313 message = g_strdup_printf(
2314 "Destination filesystem is almost full: %uM free\n\n"
2315 "Encode may be incomplete if you proceed.\n",
2316 (guint)(size / (1024L*1024L)));
2317 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Proceed"))
2325 g_object_unref(info);
2327 g_object_unref(gfile);
2330 if (g_file_test(dest, G_FILE_TEST_EXISTS))
2332 message = g_strdup_printf(
2333 "Destination: %s\n\n"
2334 "File already exhists.\n"
2335 "Do you want to overwrite?",
2337 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
2345 // Validate video quality is in a reasonable range
2346 if (!ghb_validate_vquality(ud->settings))
2350 // Validate audio settings
2351 if (!ghb_validate_audio(ud))
2355 // Validate video settings
2356 if (!ghb_validate_video(ud))
2360 audio_list_refresh(ud);
2365 queue_add(signal_user_data_t *ud)
2367 // Add settings to the queue
2368 job_settings_t *queue_item;
2370 static gint unique_id = 0;
2372 g_debug("queue_add ()\n");
2373 if (!validate_settings(ud))
2377 // Make a copy of current settings to be used for the new job
2378 queue_item = g_malloc(sizeof(job_settings_t));
2379 queue_item->settings = ghb_settings_dup(ud->settings);
2380 queue_item->audio_settings = NULL;
2381 link = ud->audio_settings;
2382 while (link != NULL)
2384 GHashTable *asettings;
2385 asettings = ghb_settings_dup((GHashTable*)link->data);
2386 queue_item->audio_settings =
2387 g_slist_append(queue_item->audio_settings, asettings);
2388 link = g_slist_next(link);
2390 queue_item->chapter_list = g_strdupv(ud->chapter_list);
2391 ud->queue = g_slist_append(ud->queue, queue_item);
2392 add_to_queue_list(ud, queue_item);
2393 ghb_add_job (queue_item, unique_id);
2394 queue_item->unique_id = unique_id;
2395 queue_item->status = GHB_QUEUE_PENDING;
2401 queue_add_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
2403 g_debug("queue_add_clicked_cb ()\n");
2408 cancel_encode(const gchar *extra_msg)
2411 GtkResponseType response;
2413 if (extra_msg == NULL) extra_msg = "";
2414 // Toss up a warning dialog
2415 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2416 GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
2417 "%sYour movie will be lost if you don't continue encoding.",
2419 gtk_dialog_add_buttons( GTK_DIALOG(dialog),
2420 "Continue Encoding", GTK_RESPONSE_NO,
2421 "Stop Encoding", GTK_RESPONSE_YES, NULL);
2422 response = gtk_dialog_run(GTK_DIALOG(dialog));
2423 gtk_widget_destroy (dialog);
2424 if (response == GTK_RESPONSE_NO) return FALSE;
2430 queue_remove_clicked_cb(GtkWidget *widget, gchar *path, signal_user_data_t *ud)
2432 GtkTreeView *treeview;
2433 GtkTreePath *treepath;
2434 GtkTreeModel *store;
2439 job_settings_t *queue_item;
2442 g_debug("queue_remove_clicked_cb ()\n");
2443 g_debug("ud %p\n", ud);
2444 g_debug("ud->builder %p\n", ud->builder);
2446 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2447 store = gtk_tree_view_get_model(treeview);
2448 treepath = gtk_tree_path_new_from_string (path);
2449 if (gtk_tree_model_get_iter(store, &iter, treepath))
2451 // Find the entry in the queue
2452 indices = gtk_tree_path_get_indices (treepath);
2454 // Can only free the treepath After getting what I need from
2455 // indices since this points into treepath somewhere.
2456 gtk_tree_path_free (treepath);
2457 if (row < 0) return;
2458 link = g_slist_nth(ud->queue, row);
2459 if (link == NULL) return;
2460 queue_item = (job_settings_t*)link->data;
2461 if (queue_item->status == GHB_QUEUE_RUNNING)
2463 // Ask if wants to stop encode.
2464 if (!cancel_encode(NULL))
2469 // Remove the selected item
2470 g_debug(" should be removing from treestore\n");
2471 gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
2472 // Remove the corresponding item from the queue list
2473 ud->queue = g_slist_remove_link(ud->queue, link);
2474 g_slist_free_1(link);
2475 g_hash_table_destroy(queue_item->settings);
2476 link = queue_item->audio_settings;
2477 while (link != NULL)
2480 g_hash_table_destroy((GHashTable*)link->data);
2481 nextlink = g_slist_next(link);
2482 g_slist_free_1(link);
2485 g_strfreev (queue_item->chapter_list);
2486 unique_id = queue_item->unique_id;
2488 ghb_remove_job(unique_id);
2492 gtk_tree_path_free (treepath);
2497 find_queue_item(GSList *queue, gint unique_id, job_settings_t **job)
2502 while (queue != NULL)
2505 js = (job_settings_t*)queue->data;
2506 if (js->unique_id == unique_id)
2511 queue = queue->next;
2518 queue_buttons_grey(signal_user_data_t *ud, gboolean working)
2522 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2523 gboolean title_ok = (titleindex >= 0);
2524 widget = GHB_WIDGET (ud->builder, "queue_start1");
2525 gtk_widget_set_sensitive (widget, !working && title_ok);
2526 widget = GHB_WIDGET (ud->builder, "queue_start2");
2527 gtk_widget_set_sensitive (widget, !working && title_ok);
2528 action = GHB_ACTION (ud->builder, "queue_start_menu");
2529 gtk_action_set_sensitive (action, !working && title_ok);
2530 widget = GHB_WIDGET (ud->builder, "queue_pause1");
2531 gtk_widget_set_sensitive (widget, working);
2532 widget = GHB_WIDGET (ud->builder, "queue_pause2");
2533 gtk_widget_set_sensitive (widget, working);
2534 action = GHB_ACTION (ud->builder, "queue_pause_menu");
2535 gtk_action_set_sensitive (action, working);
2536 widget = GHB_WIDGET (ud->builder, "queue_stop");
2537 gtk_widget_set_sensitive (widget, working);
2538 action = GHB_ACTION (ud->builder, "queue_stop_menu");
2539 gtk_action_set_sensitive (action, working);
2542 void queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud);
2544 static gint autostart_timeout = -1;
2547 autostart_timer_cb(gpointer data)
2550 GtkProgressBar *progress;
2551 signal_user_data_t *ud = (signal_user_data_t*)data;
2553 if (autostart_timeout < 0) return FALSE;
2554 gchar *remaining = g_strdup_printf("Encoding will start in %d second%c",
2555 (autostart_timeout-1) / 40 + 1, autostart_timeout <= 40 ? ' ':'s');
2556 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "autostart_countdown"));
2557 gtk_progress_bar_set_fraction (progress, (gdouble)autostart_timeout / 800);
2558 gtk_progress_bar_set_text(progress, remaining);
2560 autostart_timeout--;
2561 if (autostart_timeout == 0)
2563 widget = GHB_WIDGET(ud->builder, "autostart_dialog");
2564 gtk_widget_hide(widget);
2565 queue_start_clicked_cb(NULL, ud);
2572 ghb_timer_cb(gpointer data)
2574 static gint ticks = 0;
2578 static gint current_id = -1;
2580 GtkTreeView *treeview;
2581 GtkTreeStore *store;
2583 static gint working = 0;
2584 static gboolean work_started = FALSE;
2586 signal_user_data_t *ud = (signal_user_data_t*)data;
2587 switch (ghb_backend_events (ud, &unique_id))
2589 case GHB_EVENT_WORKING:
2593 work_started = TRUE;
2594 queue_buttons_grey(ud, TRUE);
2596 if (unique_id != current_id)
2598 index = find_queue_item(ud->queue, current_id, &js);
2601 js->status = GHB_QUEUE_DONE;
2602 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2603 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2604 gchar *path = g_strdup_printf ("%d", index);
2605 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2607 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
2612 index = find_queue_item(ud->queue, unique_id, &js);
2615 js->status = GHB_QUEUE_RUNNING;
2616 current_id = unique_id;
2619 index = find_queue_item(ud->queue, unique_id, &js);
2622 gchar working_icon[] = "hb-working0";
2623 working_icon[10] = '0' + working;
2624 working = (working+1) % 6;
2625 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2626 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2627 gchar *path = g_strdup_printf ("%d", index);
2628 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2630 gtk_tree_store_set(store, &iter, 0, working_icon, -1);
2635 case GHB_EVENT_PAUSED:
2638 case GHB_EVENT_WORK_DONE:
2640 ud->state &= ~GHB_STATE_WORKING;
2641 work_started = FALSE;
2642 queue_buttons_grey(ud, FALSE);
2643 index = find_queue_item(ud->queue, current_id, &js);
2646 js->status = GHB_QUEUE_DONE;
2647 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2648 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2649 gchar *path = g_strdup_printf ("%d", index);
2650 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2652 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
2659 ghb_hb_cleanup(FALSE);
2663 case GHB_EVENT_WORK_CANCELED:
2665 work_started = FALSE;
2666 queue_buttons_grey(ud, FALSE);
2667 index = find_queue_item(ud->queue, current_id, &js);
2670 js->status = GHB_QUEUE_CANCELED;
2671 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2672 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2673 gchar *path = g_strdup_printf ("%d", index);
2674 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2676 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
2682 case GHB_EVENT_SCAN_DONE:
2684 ghb_title_info_t tinfo;
2686 ud->state &= ~GHB_STATE_SCANNING;
2687 ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE);
2688 titleindex = ghb_longest_title();
2689 ghb_ui_update_int(ud, "title", titleindex);
2690 queue_buttons_grey(ud, FALSE);
2692 // Are there really any titles.
2693 if (ghb_get_title_info(&tinfo, titleindex))
2699 gint title = ghb_settings_get_int(ud->settings, "title");
2700 gint start_chapter = ghb_settings_get_int(ud->settings, "start_chapter");
2701 gint end_chapter = ghb_settings_get_int(ud->settings, "end_chapter");
2702 gboolean pass2 = ghb_settings_get_bool(ud->settings, "two_pass");
2703 const gchar *vol_name = ghb_settings_get_string(ud->settings, "volume_label");
2704 if (vol_name == NULL)
2705 vol_name = "No Title";
2706 const gchar *vcodec = ghb_settings_get_option(ud->settings, "video_codec");
2707 const gchar *container = ghb_settings_get_option(ud->settings, "container");
2708 const gchar *acodec = ghb_settings_get_option(ud->settings, "audio_codec");
2709 const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
2710 const gchar *preset = ghb_settings_get_string(ud->settings, "preset");
2711 gchar *info = g_strdup_printf
2713 "<big><b>%s</b></big> (Title %d, Chapters %d through %d, %d Video %s)"
2714 "\n<b>Preset:</b> %s"
2715 "\n<b>Format:</b> %s Container, %s Video + %s Audio"
2716 "\n<b>Destination:</b> %s",
2717 vol_name, title+1, start_chapter, end_chapter,
2718 pass2 ? 2:1, pass2 ? "Passes":"Pass",
2719 preset, container, vcodec, acodec, dest);
2721 widget = GHB_WIDGET (ud->builder, "autostart_summary");
2722 gtk_label_set_markup (GTK_LABEL(widget), info);
2724 widget = GHB_WIDGET(ud->builder, "autostart_dialog");
2725 gtk_widget_show_now(widget);
2726 g_timeout_add (25, autostart_timer_cb, (gpointer)ud);
2727 autostart_timeout = 800;
2732 GtkProgressBar *progress;
2733 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2734 gtk_progress_bar_set_fraction (progress, 0);
2735 gtk_progress_bar_set_text (progress, "No Source");
2742 work_started = FALSE;
2743 queue_buttons_grey(ud, FALSE);
2747 if (update_default_destination)
2749 const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
2750 gchar *dest_dir = g_path_get_dirname (dest);
2751 const gchar *def_dest = ghb_settings_get_string(ud->settings, "destination_dir");
2752 if (strcmp(dest_dir, def_dest) != 0)
2754 ghb_settings_set_string (ud->settings, "destination_dir", dest_dir);
2755 ghb_pref_save (ud->settings, "destination_dir");
2757 update_default_destination = FALSE;
2761 set_preview_image (ud);
2762 update_preview = FALSE;
2764 if (ticks == 3 && ghb_autostart)
2766 // Make sure this doesn't happen twice
2767 const gchar *source = ghb_settings_get_string(ud->settings, "source");
2768 if (update_source_label(ud, source))
2770 GtkProgressBar *progress;
2771 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2772 const gchar *path = ghb_settings_get_string( ud->settings, "source");
2773 gtk_progress_bar_set_fraction (progress, 0);
2774 gtk_progress_bar_set_text (progress, "Scanning ...");
2775 ud->state |= GHB_STATE_SCANNING;
2776 ghb_hb_cleanup(TRUE);
2777 ghb_backend_scan (path, 0);
2785 autostart_ok_cb(GtkWidget *widget, signal_user_data_t *ud)
2787 widget = GHB_WIDGET(ud->builder, "autostart_dialog");
2788 gtk_widget_hide(widget);
2789 queue_start_clicked_cb(NULL, ud);
2790 autostart_timeout = -1;
2794 autostart_cancel_cb(GtkWidget *widget, signal_user_data_t *ud)
2796 widget = GHB_WIDGET(ud->builder, "autostart_dialog");
2797 gtk_widget_hide(widget);
2798 autostart_timeout = -1;
2802 ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
2806 GtkTextView *textview;
2807 GtkTextBuffer *buffer;
2809 GError *gerror = NULL;
2812 signal_user_data_t *ud = (signal_user_data_t*)data;
2814 status = g_io_channel_read_line (source, &text, &length, NULL, &gerror);
2817 textview = GTK_TEXT_VIEW(GHB_WIDGET (ud->builder, "activity_view"));
2818 buffer = gtk_text_view_get_buffer (textview);
2819 mark = gtk_text_buffer_get_insert (buffer);
2820 gtk_text_view_scroll_mark_onscreen(textview, mark);
2821 gtk_text_buffer_insert_at_cursor (buffer, text, -1);
2822 g_io_channel_write_chars (ud->activity_log, text, length, &length, NULL);
2825 if (status != G_IO_STATUS_NORMAL)
2827 // This should never happen, but if it does I would get into an
2828 // infinite loop. Returning false removes this callback.
2829 g_warning("Error while reading activity from pipe\n");
2832 g_warning("%s\n", gerror->message);
2833 g_error_free (gerror);
2838 g_error_free (gerror);
2843 about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2845 GtkWidget *widget = GHB_WIDGET (ud->builder, "hb_about");
2846 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(widget), ghb_version());
2847 gtk_widget_show (widget);
2851 guide_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2855 {"xdg-open","http://trac.handbrake.fr/wiki/HandBrakeGuide",NULL,NULL};
2856 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2860 argv[0] = "gnome-open";
2861 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2865 argv[0] = "kfmclient";
2867 argv[2] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2868 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2872 argv[0] = "firefox";
2873 argv[1] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2875 result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2881 hb_about_response_cb(GtkWidget *widget, gint response, signal_user_data_t *ud)
2883 gtk_widget_hide (widget);
2887 show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2889 GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
2890 gtk_widget_show (widget);
2894 show_queue_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2896 GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
2897 gtk_widget_show (widget);
2901 show_presets_toggled_cb(GtkToggleButton *button, signal_user_data_t *ud)
2904 GtkWindow *hb_window;
2906 g_debug("show_presets_clicked_cb ()\n");
2907 widget = GHB_WIDGET (ud->builder, "presets_frame");
2908 if (gtk_toggle_button_get_active(button))
2910 gtk_widget_show_now(widget);
2914 gtk_widget_hide(widget);
2915 hb_window = GTK_WINDOW(GHB_WIDGET (ud->builder, "hb_window"));
2916 gtk_window_resize(hb_window, 16, 16);
2918 ghb_widget_to_setting(ud->settings, GTK_WIDGET(button));
2919 ghb_pref_save(ud->settings, "show_presets");
2923 presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
2925 GtkTreeView *treeview;
2926 GtkTreeSelection *selection;
2927 GtkTreeModel *store;
2930 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
2931 selection = gtk_tree_view_get_selection(treeview);
2932 if (gtk_tree_selection_get_selected(selection, &store, &iter))
2935 path = gtk_tree_model_get_path (store, &iter);
2936 // Make the parent visible in scroll window if it is not.
2937 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
2943 update_chapter_list(signal_user_data_t *ud)
2945 GtkTreeView *treeview;
2947 GtkListStore *store;
2950 gint titleindex, ii;
2952 g_debug("update_chapter_list ()\n");
2953 titleindex = ghb_settings_get_index(ud->settings, "title");
2954 chapters = ghb_get_chapters(titleindex);
2955 if (ud->chapter_list != NULL)
2956 g_strfreev (ud->chapter_list);
2957 ud->chapter_list = chapters;
2959 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
2960 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
2962 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
2966 if (chapters != NULL && chapters[ii])
2968 // Update row with settings data
2969 g_debug("Updating row\n");
2970 gtk_list_store_set(store, &iter,
2976 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
2980 // No more settings data, remove row
2981 g_debug("Removing row\n");
2982 done = !gtk_list_store_remove(store, &iter);
2986 while (chapters != NULL && chapters[ii])
2988 // Additional settings, add row
2989 g_debug("Adding row\n");
2990 g_debug("%d -- %s\n", ii, chapters[ii]);
2991 gtk_list_store_append(store, &iter);
2992 gtk_list_store_set(store, &iter,
3002 chapter_edited_cb(GtkCellRendererText *cell, gchar *path, gchar *text, signal_user_data_t *ud)
3004 GtkTreePath *treepath;
3005 GtkListStore *store;
3006 GtkTreeView *treeview;
3007 GtkTreeViewColumn *column;
3011 g_debug("chapter_edited_cb ()\n");
3012 g_debug("path (%s)\n", path);
3013 g_debug("text (%s)\n", text);
3014 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
3015 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
3016 treepath = gtk_tree_path_new_from_string (path);
3017 gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
3018 gtk_tree_path_free (treepath);
3019 gtk_list_store_set(store, &iter,
3023 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &index, -1);
3024 g_free(ud->chapter_list[index-1]);
3025 ud->chapter_list[index-1] = g_strdup(text);
3026 if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
3028 column = gtk_tree_view_get_column(treeview, 1);
3029 treepath = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
3030 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
3031 gtk_tree_path_free (treepath);
3036 chapter_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
3038 GtkTreeModel *store;
3041 g_debug("chapter_list_selection_changed_cb ()\n");
3042 if (gtk_tree_selection_get_selected(selection, &store, &iter))
3049 queue_list_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, GtkCellRenderer *cell)
3051 GtkTreeViewColumn *column;
3054 column = gtk_tree_view_get_column (GTK_TREE_VIEW(widget), 0);
3055 width = gtk_tree_view_column_get_width(column);
3056 g_debug("col width %d alloc width %d\n", width, allocation->width);
3057 // Set new wrap-width. Shave a little off to accomidate the icons
3058 // that share this column.
3059 if (width >= 564) // Don't allow below a certain size
3060 g_object_set(cell, "wrap-width", width-70, NULL);
3064 preview_button_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3066 gint titleindex = ghb_settings_get_int(ud->settings, "title");
3067 if (titleindex < 0) return;
3068 g_debug("titleindex %d\n", titleindex);
3070 GtkWidget *widget = GHB_WIDGET (ud->builder, "preview_window");
3071 gtk_widget_show (widget);
3075 preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3077 set_preview_image(ud);
3081 preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
3083 g_debug("-------------------------------allocate %d x %d\n", allocation->width, allocation->height);
3084 if (preview_button_width == allocation->width &&
3085 preview_button_height == allocation->height)
3087 // Nothing to do. Bug out.
3088 g_debug("nothing to do\n");
3091 g_debug("-------------------------------prev allocate %d x %d\n", preview_button_width, preview_button_height);
3092 preview_button_width = allocation->width;
3093 preview_button_height = allocation->height;
3094 set_preview_image(ud);
3098 queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3100 GSList *link = ud->queue;
3101 job_settings_t *job;
3102 gboolean running = FALSE;
3103 while (link != NULL)
3105 job = (job_settings_t*)link->data;
3106 if ((job->status == GHB_QUEUE_RUNNING) ||
3107 (job->status == GHB_QUEUE_PENDING))
3116 // The queue has no running or pending jobs.
3117 // Add current settings to the queue, then run.
3121 ud->state |= GHB_STATE_WORKING;
3126 queue_stop_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3128 cancel_encode(NULL);
3132 queue_pause_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3138 presets_default_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3140 ghb_set_preset_default(ud->settings);
3141 ghb_presets_list_update(ud);
3145 debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data)
3147 signal_user_data_t *ud = (signal_user_data_t*)data;
3151 printf("%s: %s\n", domain, msg);
3156 set_visible(GtkWidget *widget, gboolean visible)
3160 gtk_widget_show_now(widget);
3164 gtk_widget_hide(widget);
3169 ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
3172 g_debug("ghb_hbfd\n");
3173 widget = GHB_WIDGET(ud->builder, "queue_pause1");
3174 set_visible(widget, !hbfd);
3175 widget = GHB_WIDGET(ud->builder, "queue_add");
3176 set_visible(widget, !hbfd);
3177 widget = GHB_WIDGET(ud->builder, "show_queue");
3178 set_visible(widget, !hbfd);
3179 widget = GHB_WIDGET(ud->builder, "show_activity");
3180 set_visible(widget, !hbfd);
3182 widget = GHB_WIDGET(ud->builder, "chapter_box");
3183 set_visible(widget, !hbfd);
3184 widget = GHB_WIDGET(ud->builder, "container_box");
3185 set_visible(widget, !hbfd);
3186 widget = GHB_WIDGET(ud->builder, "settings_box");
3187 set_visible(widget, !hbfd);
3188 widget = GHB_WIDGET(ud->builder, "presets_save");
3189 set_visible(widget, !hbfd);
3190 widget = GHB_WIDGET(ud->builder, "presets_remove");
3191 set_visible(widget, !hbfd);
3192 widget = GHB_WIDGET(ud->builder, "presets_default");
3193 set_visible(widget, !hbfd);
3194 widget = GHB_WIDGET (ud->builder, "hb_window");
3195 gtk_window_resize(GTK_WINDOW(widget), 16, 16);
3200 hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
3202 g_debug("hbfd_toggled_cb\n");
3203 ghb_widget_to_setting (ud->settings, widget);
3204 gboolean hbfd = ghb_settings_get_bool(ud->settings, "hbfd");
3206 ghb_pref_save(ud->settings, "hbfd");
3210 pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3212 g_debug("pref_changed_cb\n");
3213 ghb_widget_to_setting (ud->settings, widget);
3214 const gchar *name = gtk_widget_get_name(widget);
3215 ghb_pref_save(ud->settings, name);
3219 ghb_file_menu_add_dvd(signal_user_data_t *ud)
3221 GList *link, *drives;
3223 GtkActionGroup *agroup = GTK_ACTION_GROUP(
3224 gtk_builder_get_object(ud->builder, "actiongroup1"));
3225 GtkUIManager *ui = GTK_UI_MANAGER(
3226 gtk_builder_get_object(ud->builder, "uimanager1"));
3227 guint merge_id = gtk_ui_manager_new_merge_id(ui);
3229 link = drives = dvd_device_list();
3230 while (link != NULL)
3232 gchar *name = (gchar*)link->data;
3233 // Create action for this drive
3234 GtkAction *action = gtk_action_new(name, name,
3235 "Scan this DVD source", "gtk-cdrom");
3236 // Add action to action group
3237 gtk_action_group_add_action_with_accel(agroup, action, "");
3238 // Add to ui manager
3239 gtk_ui_manager_add_ui(ui, merge_id,
3240 "ui/menubar1/menuitem1/quit1", name, name,
3241 GTK_UI_MANAGER_AUTO, TRUE);
3242 // Connect signal to action (menu item)
3243 g_signal_connect(action, "activate",
3244 (GCallback)dvd_source_activate_cb, ud);
3248 g_list_free(drives);
3251 gtk_ui_manager_add_ui(ui, merge_id,
3252 "ui/menubar1/menuitem1/quit1", "", NULL,
3253 GTK_UI_MANAGER_AUTO, TRUE);
3256 gboolean ghb_is_cd(GDrive *gd);
3261 GVolumeMonitor *gvm;
3262 GList *drives, *link;
3263 GList *dvd_devices = NULL;
3265 gvm = g_volume_monitor_get ();
3266 drives = g_volume_monitor_get_connected_drives (gvm);
3268 while (link != NULL)
3272 gd = (GDrive*)link->data;
3276 device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3277 dvd_devices = g_list_append(dvd_devices, (gpointer)device);
3279 g_object_unref (gd);
3282 g_list_free(drives);
3287 static DBusConnection *dbus_connection = NULL;
3288 static LibHalContext *hal_ctx;
3291 ghb_is_cd(GDrive *gd)
3294 LibHalDrive *halDrive;
3295 LibHalDriveType dtype;
3297 device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3298 halDrive = libhal_drive_from_device_file (hal_ctx, device);
3299 dtype = libhal_drive_get_type(halDrive);
3301 return (dtype == LIBHAL_DRIVE_TYPE_CDROM);
3305 drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
3309 if (ud->current_dvd_device == NULL) return;
3310 if (ud->state != GHB_STATE_IDLE) return;
3311 device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3313 // DVD insertion detected. Scan it.
3314 if (strcmp(device, ud->current_dvd_device) == 0)
3316 if (g_drive_has_media (gd))
3318 GtkProgressBar *progress;
3319 progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
3320 gtk_progress_bar_set_text (progress, "Scanning ...");
3321 gtk_progress_bar_set_fraction (progress, 0);
3322 update_source_label(ud, device);
3323 ud->state |= GHB_STATE_SCANNING;
3324 ghb_hb_cleanup(TRUE);
3325 ghb_backend_scan(device, 0);
3329 ud->state |= GHB_STATE_SCANNING;
3330 ghb_hb_cleanup(TRUE);
3331 ghb_backend_scan("/dev/null", 0);
3343 if (dbus_connection != NULL)
3346 dbus_error_init (&error);
3347 if (!(dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) {
3348 g_debug ("could not get system bus: %s\n", error.message);
3349 dbus_error_free (&error);
3353 //dbus_connection_setup_with_g_main (dbus_connection, NULL);
3354 //dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
3355 //dbus_connection_add_filter (dbus_connection, gvm_dbus_filter_function, NULL, NULL);
3370 if (!(hal_ctx = libhal_ctx_new ())) {
3371 g_warning ("failed to create a HAL context!");
3375 libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
3376 dbus_error_init (&error);
3377 if (!libhal_ctx_init (hal_ctx, &error)) {
3378 g_warning ("libhal_ctx_init failed: %s", error.message ? error.message : "unknown");
3379 dbus_error_free (&error);
3380 libhal_ctx_free (hal_ctx);
3385 * Do something to ping the HAL daemon - the above functions will
3386 * succeed even if hald is not running, so long as DBUS is. But we
3387 * want to exit silently if hald is not running, to behave on
3390 if (!(devices = libhal_get_all_devices (hal_ctx, &nr, &error))) {
3391 g_warning ("seems that HAL is not running: %s", error.message ? error.message : "unknown");
3392 dbus_error_free (&error);
3394 libhal_ctx_shutdown (hal_ctx, NULL);
3395 libhal_ctx_free (hal_ctx);
3399 libhal_free_string_array (devices);
3401 //gvm_hal_claim_branch ("/org/freedesktop/Hal/devices/local");