OSDN Git Service

LinGui: change how x264 options are handled
[handbrake-jp/handbrake-jp-git.git] / gtk / src / callbacks.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * callbacks.c
4  * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
5  * 
6  * callbacks.c is free software.
7  * 
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)
11  * any later version.
12  */
13
14 #ifdef HAVE_CONFIG_H
15 #  include <config.h>
16 #endif
17
18 #include <string.h>
19 #include <poll.h>
20 #include <fcntl.h>
21 #include <sys/stat.h>
22 #include <libhal-storage.h>
23 #include <gtk/gtk.h>
24 #include <glib/gstdio.h>
25 #include <gio/gio.h>
26
27 #include "callbacks.h"
28 #include "settings.h"
29 #include "hb-backend.h"
30 #include "ghb-dvd.h"
31
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);
38
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
45 typedef struct
46 {
47         const gchar *widget_name;
48         const gchar *dep_name;
49         const gchar *enable_value;
50         const gboolean disable_if_equal;
51 } dependency_t;
52
53 static dependency_t dep_map[] =
54 {
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", "two_pass", "enable", TRUE},
74         {"vquality_type_constant", "turbo", "enable", TRUE},
75         {"two_pass", "turbo", "enable", FALSE},
76         {"container", "large_mp4", "mp4|m4v", FALSE},
77         {"container", "http_optimize_mp4", "mp4|m4v", FALSE},
78         {"container", "ipod_file", "mp4|m4v", FALSE},
79         {"container", "variable_frame_rate", "avi", TRUE},
80         {"variable_frame_rate", "framerate", "enable", TRUE},
81         {"variable_frame_rate", "detelecine", "enable", TRUE},
82         {"decomb", "deinterlace", "enable", TRUE},
83         {"autocrop", "crop_top", "disable", FALSE},
84         {"autocrop", "crop_bottom", "disable", FALSE},
85         {"autocrop", "crop_left", "disable", FALSE},
86         {"autocrop", "crop_right", "disable", FALSE},
87         {"autoscale", "scale_width", "disable", FALSE},
88         {"autoscale", "scale_height", "disable", FALSE},
89         {"anamorphic", "keep_aspect", "disable", FALSE},
90         {"anamorphic", "scale_height", "disable", FALSE},
91         {"keep_aspect", "scale_height", "disable", FALSE},
92         {"video_codec", "x264_tab", "x264", FALSE},
93         {"video_codec", "x264_tab_label", "x264", FALSE},
94         {"video_codec", "ipod_file", "x264", FALSE},
95         {"audio_track", "audio_add", "none", TRUE},
96         {"audio_track", "audio_codec", "none", TRUE},
97         {"audio_track", "audio_bitrate", "none", TRUE},
98         {"audio_track", "audio_sample_rate", "none", TRUE},
99         {"audio_track", "audio_mix", "none", TRUE},
100         {"audio_track", "audio_drc", "none", TRUE},
101         {"audio_codec", "audio_bitrate", "ac3", TRUE},
102         {"audio_codec", "audio_sample_rate", "ac3", TRUE},
103         {"audio_codec", "audio_mix", "ac3", TRUE},
104         {"audio_codec", "audio_drc", "ac3", TRUE},
105         {"x264_bframes", "x264_weighted_bframes", "0", TRUE},
106         {"x264_bframes", "x264_brdo", "0", TRUE},
107         {"x264_bframes", "x264_bime", "0", TRUE},
108         {"x264_bframes", "x264_bpyramid", "<2", TRUE},
109         {"x264_bframes", "x264_direct", "0", TRUE},
110         {"x264_refs", "x264_mixed_refs", "<2", TRUE},
111         {"x264_cabac", "x264_trellis", "enable", FALSE},
112         {"x264_subme", "x264_brdo", "<6", TRUE},
113         {"x264_analyse", "x264_direct", "none", TRUE},
114         {"x264_me", "x264_merange", "umh|esa", FALSE},
115         {"pref_audio_codec1", "pref_audio_bitrate1", "none", TRUE},
116         {"pref_audio_codec1", "pref_audio_rate1", "none", TRUE},
117         {"pref_audio_codec1", "pref_audio_mix1", "none", TRUE},
118         {"pref_audio_codec1", "pref_audio_codec2", "none", TRUE},
119         {"pref_audio_codec1", "pref_audio_bitrate2", "none", TRUE},
120         {"pref_audio_codec1", "pref_audio_rate2", "none", TRUE},
121         {"pref_audio_codec1", "pref_audio_mix2", "none", TRUE},
122         {"pref_audio_codec2", "pref_audio_bitrate2", "none", TRUE},
123         {"pref_audio_codec2", "pref_audio_rate2", "none", TRUE},
124         {"pref_audio_codec2", "pref_audio_mix2", "none", TRUE},
125         {"chapter_markers", "chapters_list", "enable", FALSE},
126 };
127
128 static gboolean
129 dep_check(signal_user_data_t *ud, const gchar *name)
130 {
131         GtkWidget *widget;
132         GObject *dep_object;
133         int ii;
134         int count = sizeof(dep_map) / sizeof(dependency_t);
135         gboolean result = TRUE;
136         
137         g_debug("dep_check () %s\n", name);
138         for (ii = 0; ii < count; ii++)
139         {
140                 if (strcmp(dep_map[ii].dep_name, name) == 0)
141                 {
142                         widget = GHB_WIDGET(ud->builder, dep_map[ii].widget_name);
143                         dep_object = gtk_builder_get_object(ud->builder, dep_map[ii].dep_name);
144                         if (dep_object == NULL)
145                         {
146                                 g_message("Failed to find widget\n");
147                         }
148                         else
149                         {
150                                 gchar *value;
151                                 gint jj = 0;
152                                 gchar **values = g_strsplit(dep_map[ii].enable_value, "|", 10);
153                                 gboolean sensitive = FALSE;
154
155                                 if (widget)
156                                         value = ghb_widget_short_opt(widget);
157                                 else
158                                         value = g_strdup( ghb_settings_get_short_opt(
159                                                 ud->settings, dep_map[ii].widget_name));
160                                 while (values && values[jj])
161                                 {
162                                         if (values[jj][0] == '>')
163                                         {
164                                                 gdouble dbl = g_strtod (&values[jj][1], NULL);
165                                                 gdouble dvalue = ghb_widget_dbl (widget);
166                                                 if (dvalue > dbl)
167                                                 {
168                                                         sensitive = TRUE;
169                                                         break;
170                                                 }
171                                         }
172                                         else if (values[jj][0] == '<')
173                                         {
174                                                 gdouble dbl = g_strtod (&values[jj][1], NULL);
175                                                 gdouble dvalue = ghb_widget_dbl (widget);
176                                                 if (dvalue < dbl)
177                                                 {
178                                                         sensitive = TRUE;
179                                                         break;
180                                                 }
181                                         }
182                                         if (strcmp(values[jj], value) == 0)
183                                         {
184                                                 sensitive = TRUE;
185                                                 break;
186                                         }
187                                         jj++;
188                                 }
189                                 sensitive = dep_map[ii].disable_if_equal ^ sensitive;
190                                 if (!sensitive) result = FALSE;
191                                 g_strfreev (values);
192                                 g_free(value);
193                         }
194                 }
195         }
196         return result;
197 }
198
199 static void
200 check_depencency(signal_user_data_t *ud, GtkWidget *widget)
201 {
202         GObject *dep_object;
203         const gchar *name;
204         int ii;
205         int count = sizeof(dep_map) / sizeof(dependency_t);
206
207         if (ghb_widget_index(widget) < 0) return;
208         name = gtk_widget_get_name(widget);
209         g_debug("check_depencency () %s\n", name);
210         for (ii = 0; ii < count; ii++)
211         {
212                 if (strcmp(dep_map[ii].widget_name, name) == 0)
213                 {
214                         gboolean sensitive;
215
216                         dep_object = gtk_builder_get_object (ud->builder, dep_map[ii].dep_name);
217                         if (dep_object == NULL)
218                         {
219                                 g_message("Failed to find dependent widget %s\n", dep_map[ii].dep_name);
220                                 continue;
221                         }
222                         sensitive = dep_check(ud, dep_map[ii].dep_name);
223                         if (GTK_IS_ACTION(dep_object))
224                                 gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
225                         else
226                                 gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
227                 }
228         }
229 }
230
231 void
232 ghb_check_all_depencencies(signal_user_data_t *ud)
233 {
234         GObject *dep_object;
235         int ii;
236         int count = sizeof(dep_map) / sizeof(dependency_t);
237
238         g_debug("ghb_check_all_depencencies ()\n");
239         for (ii = 0; ii < count; ii++)
240         {
241                 gboolean sensitive;
242                 dep_object = gtk_builder_get_object (ud->builder, dep_map[ii].dep_name);
243                 if (dep_object == NULL)
244                 {
245                         g_message("Failed to find dependent widget %s\n", dep_map[ii].dep_name);
246                         continue;
247                 }
248                 sensitive = dep_check(ud, dep_map[ii].dep_name);
249                 if (GTK_IS_ACTION(dep_object))
250                         gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
251                 else
252                         gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
253         }
254 }
255
256 static void
257 clear_presets_selection(signal_user_data_t *ud)
258 {
259         GtkTreeView *treeview;
260         GtkTreeSelection *selection;
261         
262         if (ud->dont_clear_presets) return;
263         g_debug("clear_presets_selection()\n");
264         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
265         selection = gtk_tree_view_get_selection (treeview);
266         gtk_tree_selection_unselect_all (selection);
267 }
268
269 static gchar*
270 expand_tilde(const gchar *path)
271 {
272         const gchar *user_home;
273         gchar *home;
274         const gchar *suffix;
275         gchar *expanded_path = NULL;
276         
277         g_debug("expand_tilde ()\n");
278         if (path[0] == '~')
279         {
280                 user_home = g_get_home_dir();
281                 home = NULL; // squash warning about home uninitialized
282                 if (path[1] == 0)
283                 {
284                         home = g_strdup(user_home);
285                         suffix = "";
286                 }
287                 else if (path[1] == '/')
288                 {
289                         home = g_strdup(user_home);
290                         suffix = &path[2];
291                 }
292                 else
293                 {
294                         home = g_path_get_dirname(user_home);
295                         suffix = &path[1];
296                 }
297                 expanded_path = g_strdup_printf("%s/%s", home, suffix);
298                 g_free(home);
299         }
300         return expanded_path;
301 }
302
303 void
304 on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud)
305 {
306         gint state = ghb_get_state();
307         g_debug("on_quit1_activate ()\n");
308     if (state & GHB_STATE_WORKING)
309     {
310         if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
311         {
312                         ghb_hb_cleanup(FALSE);
313                 gtk_main_quit();
314             return;
315         }
316         return;
317     }
318         ghb_hb_cleanup(FALSE);
319         gtk_main_quit();
320 }
321
322 static void
323 set_destination(signal_user_data_t *ud)
324 {
325         if (ghb_settings_get_bool(ud->settings, "use_source_name"))
326         {
327                 const gchar *vol_name, *filename, *extension;
328                 gchar *dir, *new_name;
329                 
330                 filename = ghb_settings_get_string(ud->settings, "destination");
331                 extension = ghb_settings_get_string(ud->settings, "container");
332                 dir = g_path_get_dirname (filename);
333                 vol_name = ghb_settings_get_string(ud->settings, "volume_label");
334                 g_debug("volume_label (%s)\n", vol_name);
335                 if (vol_name == NULL)
336                 {
337                         vol_name = "new_video";
338                 }
339                 new_name = g_strdup_printf("%s/%s.%s", dir, vol_name, extension);
340                 ghb_ui_update(ud, "destination", new_name);
341                 g_free(dir);
342                 g_free(new_name);
343         }
344 }
345
346 gboolean
347 uppers_and_unders(const gchar *str)
348 {
349         if (str == NULL) return FALSE;
350         while (*str)
351         {
352                 if (*str == ' ')
353                 {
354                         return FALSE;
355                 }
356                 if (*str >= 'a' && *str <= 'z')
357                 {
358                         return FALSE;
359                 }
360                 str++;
361         }
362         return TRUE;
363 }
364
365 enum
366 {
367         CAMEL_FIRST_UPPER,
368         CAMEL_OTHER
369 };
370
371 void
372 camel_convert(gchar *str)
373 {
374         gint state = CAMEL_OTHER;
375         
376         if (str == NULL) return;
377         while (*str)
378         {
379                 if (*str == '_') *str = ' ';
380                 switch (state)
381                 {
382                         case CAMEL_OTHER:
383                         {
384                                 if (*str >= 'A' && *str <= 'Z')
385                                         state = CAMEL_FIRST_UPPER;
386                                 else
387                                         state = CAMEL_OTHER;
388                                 
389                         } break;
390                         case CAMEL_FIRST_UPPER:
391                         {
392                                 if (*str >= 'A' && *str <= 'Z')
393                                         *str = *str - 'A' + 'a';
394                                 else
395                                         state = CAMEL_OTHER;
396                         } break;
397                 }
398                 str++;
399         }
400 }
401
402 static gboolean
403 update_source_label(signal_user_data_t *ud, const gchar *source)
404 {
405         gchar *label = NULL;
406         gint len;
407         gchar **path;
408         gchar *filename = g_strdup(source);
409         
410         len = strlen(filename);
411         if (filename[len-1] == '/') filename[len-1] = 0;
412         if (g_file_test(filename, G_FILE_TEST_IS_DIR))
413         {
414                 path = g_strsplit(filename, "/", -1);
415                 len = g_strv_length (path);
416                 if ((len > 1) && (strcmp("VIDEO_TS", path[len-1]) == 0))
417                 {
418                         label = g_strdup(path[len-2]);
419                 }
420                 else
421                 {
422                         label = g_strdup(path[len-1]);
423                 }
424                 g_strfreev (path);
425         }
426         else
427         {
428                 // Is regular file or block dev.
429                 // Check to see if it is a dvd image
430                 label = ghb_dvd_volname (filename);
431                 if (label == NULL)
432                 {
433                         path = g_strsplit(filename, "/", -1);
434                         len = g_strv_length (path);
435                         // Just use the last combonent of the path
436                         label = g_strdup(path[len-1]);
437                         g_strfreev (path);
438                 }
439                 else
440                 {
441                         if (uppers_and_unders(label))
442                         {
443                                 camel_convert(label);
444                         }
445                 }
446         }
447         g_free(filename);
448         GtkWidget *widget = GHB_WIDGET (ud->builder, "source_title");
449         if (label != NULL)
450         {
451                 gtk_label_set_text (GTK_LABEL(widget), label);
452                 ghb_settings_set_string(ud->settings, "volume_label", label);
453                 g_free(label);
454                 set_destination(ud);
455         }
456         else
457         {
458                 label = "No Title Found";
459                 gtk_label_set_text (GTK_LABEL(widget), label);
460                 ghb_settings_set_string(ud->settings, "volume_label", label);
461                 return FALSE;
462         }
463         return TRUE;
464 }
465
466 static GtkWidget *dvd_device_combo = NULL;
467
468 void
469 chooser_file_selected_cb(GtkFileChooser *dialog, GtkComboBox *combo)
470 {
471         const gchar *name = gtk_file_chooser_get_filename (dialog);
472         GtkTreeModel *store;
473         GtkTreeIter iter;
474         const gchar *device;
475         gboolean foundit = FALSE;
476         
477         if (name == NULL) return;
478         store = gtk_combo_box_get_model(combo);
479         if (gtk_tree_model_get_iter_first(store, &iter))
480         {
481                 do
482                 {
483                         gtk_tree_model_get(store, &iter, 0, &device, -1);
484                         if (strcmp(name, device) == 0)
485                         {
486                                 foundit = TRUE;
487                                 break;
488                         }
489                 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
490         }
491         if (foundit)
492                 gtk_combo_box_set_active_iter (combo, &iter);
493         else
494                 gtk_combo_box_set_active (combo, 0);
495 }
496
497 void
498 dvd_device_changed_cb(GtkComboBox *combo, GtkWidget *dialog)
499 {
500         gint ii = gtk_combo_box_get_active (combo);
501         if (ii != 0)
502         {
503                 const gchar *device = gtk_combo_box_get_active_text (combo);
504                 const gchar *name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog));
505                 if (name == NULL || strcmp(name, device) != 0)
506                         gtk_file_chooser_select_filename (GTK_FILE_CHOOSER(dialog), device);
507         }
508 }
509
510
511 void
512 source_type_changed_cb(GtkToggleButton *toggle, GtkFileChooser *chooser)
513 {
514         gchar *filename;
515         
516         g_debug("source_type_changed_cb ()\n");
517         if (gtk_toggle_button_get_active (toggle))
518         {
519                 filename = gtk_file_chooser_get_filename (chooser);
520                 gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
521                 if (filename != NULL)
522                 {
523                         gtk_file_chooser_set_filename(chooser, filename);
524                         g_free(filename);
525                 }
526                 gtk_widget_set_sensitive (dvd_device_combo, FALSE);
527                 gtk_combo_box_set_active (GTK_COMBO_BOX(dvd_device_combo), 0);
528         }
529         else
530         {
531                 filename = gtk_file_chooser_get_filename (chooser);
532                 gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_OPEN);
533                 if (filename != NULL)
534                 {
535                         gtk_file_chooser_set_filename(chooser, filename);
536                         g_free(filename);
537                 }
538                 gtk_widget_set_sensitive (dvd_device_combo, TRUE);
539         }
540 }
541
542 static GtkWidget*
543 source_dialog_extra_widgets(GtkWidget *dialog, gboolean checkbutton_active)
544 {
545         GtkBox *vbox;
546         GtkWidget *checkbutton;
547         
548         vbox = GTK_BOX(gtk_vbox_new (FALSE, 2));
549         checkbutton = gtk_check_button_new_with_label ("Open VIDEO_TS folder");
550         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), checkbutton_active);
551         gtk_box_pack_start (vbox, checkbutton, FALSE, FALSE, 1);
552         gtk_widget_show(checkbutton);
553
554         GtkWidget *combo;
555         GtkBox *hbox;
556         GList *drives, *link;
557         GtkWidget *label, *blank;
558
559         hbox = GTK_BOX(gtk_hbox_new (FALSE, 2));
560         combo = gtk_combo_box_new_text();
561         label = gtk_label_new("Detected DVD devices:");
562         blank = gtk_label_new("");
563         link = drives = dvd_device_list();
564         gtk_combo_box_append_text (GTK_COMBO_BOX(combo), "Not Selected");
565         while (link != NULL)
566         {
567                 gchar *name = (gchar*)link->data;
568                 gtk_combo_box_append_text (GTK_COMBO_BOX(combo), name);
569                 g_free(name);
570                 link = link->next;
571         }
572         g_list_free(drives);
573         gtk_combo_box_set_active (GTK_COMBO_BOX(combo), 0);
574         gtk_box_pack_start (vbox, GTK_WIDGET(hbox), FALSE, FALSE, 1);
575         gtk_widget_show(GTK_WIDGET(hbox));
576         gtk_box_pack_start (hbox, label, FALSE, FALSE, 1);
577         gtk_widget_show(label);
578         gtk_box_pack_start (hbox, combo, FALSE, FALSE, 2);
579         gtk_widget_show(combo);
580         gtk_box_pack_start (hbox, blank, TRUE, TRUE, 1);
581         gtk_widget_show(blank);
582  
583         // Ugly hackish global alert
584         dvd_device_combo = combo;
585         g_signal_connect(combo, "changed", (GCallback)dvd_device_changed_cb, dialog);
586         g_signal_connect(dialog, "selection-changed", (GCallback)chooser_file_selected_cb, combo);
587
588         g_signal_connect(checkbutton, "toggled", (GCallback)source_type_changed_cb, dialog);
589         return GTK_WIDGET(vbox);
590 }
591
592 static void
593 do_scan(signal_user_data_t *ud, const gchar *filename)
594 {
595         if (filename != NULL)
596         {
597                 ghb_settings_set_string(ud->settings, "source", filename);
598                 if (update_source_label(ud, filename))
599                 {
600                         GtkProgressBar *progress;
601                         progress = GTK_PROGRESS_BAR(GHB_WIDGET(ud->builder, "progressbar"));
602                         const gchar *path;
603                         path = ghb_settings_get_string( ud->settings, "source");
604                         gtk_progress_bar_set_fraction (progress, 0);
605                         gtk_progress_bar_set_text (progress, "Scanning ...");
606                         ghb_hb_cleanup(TRUE);
607                         ghb_backend_scan (path, 0);
608                 }
609                 else
610                 {
611                         // TODO: error dialog
612                 }
613         }
614 }
615
616 void
617 source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
618 {
619         GtkWidget *dialog;
620         GtkWidget *widget;
621         const gchar *sourcename;
622         gint    response;
623         GtkFileChooserAction action;
624         gboolean checkbutton_active;
625
626         g_debug("source_browse_clicked_cb ()\n");
627         sourcename = ghb_settings_get_string(ud->settings, "source");
628         checkbutton_active = FALSE;
629         if (g_file_test(sourcename, G_FILE_TEST_IS_DIR))
630         {
631                 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
632                 checkbutton_active = TRUE;
633         }
634         else
635         {
636                 action = GTK_FILE_CHOOSER_ACTION_OPEN;
637         }
638         dialog = gtk_file_chooser_dialog_new ("Select Source",
639                                                                 NULL,
640                                                                 action,
641                                                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
642                                                                 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
643                                                                 NULL);
644         widget = source_dialog_extra_widgets(dialog, checkbutton_active);
645         gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), widget);
646         gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), sourcename);
647         response = gtk_dialog_run(GTK_DIALOG (dialog));
648         gtk_widget_hide(dialog);
649         if (response == GTK_RESPONSE_ACCEPT)
650         {
651                 char *filename;
652
653                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
654                 if (filename != NULL)
655                 {
656                         do_scan(ud, filename);
657                         if (strcmp(sourcename, filename) != 0)
658                         {
659                                 ghb_settings_set_string (ud->settings, "default_source", filename);
660                                 ghb_pref_save (ud->settings, "default_source");
661                                 ghb_dvd_set_current (filename, ud);
662                         }
663                         g_free(filename);
664                 }
665         }
666         gtk_widget_destroy(dialog);
667 }
668
669 void
670 dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
671 {
672         const gchar *filename;
673         const gchar *sourcename;
674
675         sourcename = ghb_settings_get_string(ud->settings, "source");
676         filename = gtk_action_get_name(action);
677         do_scan(ud, filename);
678         if (strcmp(sourcename, filename) != 0)
679         {
680                 ghb_settings_set_string (ud->settings, "default_source", filename);
681                 ghb_pref_save (ud->settings, "default_source");
682                 ghb_dvd_set_current (filename, ud);
683         }
684 }
685
686 static void
687 update_destination_extension(signal_user_data_t *ud)
688 {
689         static gchar *containers[] = {".mkv", ".mp4", ".m4v", ".avi", ".ogm", NULL};
690         gchar *filename;
691         const gchar *extension;
692         gint ii;
693         GtkEntry *entry;
694
695         g_debug("update_destination_extension ()\n");
696         extension = ghb_settings_get_string(ud->settings, "container");
697         entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "destination"));
698         filename = g_strdup(gtk_entry_get_text(entry));
699         for (ii = 0; containers[ii] != NULL; ii++)
700         {
701                 if (g_str_has_suffix(filename, containers[ii]))
702                 {
703                         gchar *pos;
704                         gchar *new_name;
705                         
706                         pos = g_strrstr( filename, "." );
707                         if (pos == NULL)
708                         {
709                                 // No period? shouldn't happen
710                                 break;
711                         }
712                         *pos = 0;
713                         if (strcmp(extension, &pos[1]) == 0)
714                         {
715                                 // Extension is already correct
716                                 break;
717                         }
718                         new_name = g_strjoin(".", filename, extension, NULL); 
719                         ghb_ui_update(ud, "destination", new_name);
720                         g_free(new_name);
721                         break;
722                 }
723         }
724         g_free(filename);
725 }
726
727 static gboolean update_default_destination = FALSE;
728
729 void
730 destination_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
731 {
732         gchar *dest;
733         
734         g_debug("destination_entry_changed_cb ()\n");
735         if ((dest = expand_tilde(gtk_entry_get_text(entry))) != NULL)
736         {
737                 gtk_entry_set_text(entry, dest);
738                 g_free(dest);
739         }
740         update_destination_extension(ud);
741         ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
742         // This signal goes off with ever keystroke, so I'm putting this
743         // update on the timer.
744         update_default_destination = TRUE;
745 }
746
747 void
748 destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
749 {
750         GtkWidget *dialog;
751         GtkEntry *entry;
752         const char *destname;
753         gchar *basename;
754
755         g_debug("destination_browse_clicked_cb ()\n");
756         destname = ghb_settings_get_string(ud->settings, "destination");
757         dialog = gtk_file_chooser_dialog_new ("Choose Destination",
758                       NULL,
759                       GTK_FILE_CHOOSER_ACTION_SAVE,
760                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
761                       GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
762                       NULL);
763         gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), destname);
764         basename = g_path_get_basename(destname);
765         gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
766         g_free(basename);
767         if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
768         {
769                 char *filename;
770                 
771                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
772                 entry = (GtkEntry*)GHB_WIDGET(ud->builder, "destination");
773                 if (entry == NULL)
774                 {
775                         g_debug("Failed to find widget: %s\n", "destination");
776                 }
777                 else
778                 {
779                         gtk_entry_set_text(entry, filename);
780                 }
781                 g_free (filename);
782         }
783         gtk_widget_destroy(dialog);
784 }
785
786 gboolean
787 window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
788 {
789         g_debug("window_destroy_event_cb ()\n");
790         ghb_hb_cleanup(FALSE);
791         gtk_main_quit();
792     return FALSE;
793 }
794
795 gboolean
796 window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
797 {
798         gint state = ghb_get_state();
799         g_debug("window_delete_event_cb ()\n");
800     if (state & GHB_STATE_WORKING)
801     {
802         if (cancel_encode("Closing HandBrake will terminate encoding.\n"))
803         {
804                         ghb_hb_cleanup(FALSE);
805                 gtk_main_quit();
806             return FALSE;
807         }
808         return TRUE;
809     }
810         ghb_hb_cleanup(FALSE);
811         gtk_main_quit();
812     return FALSE;
813 }
814
815 static void
816 update_acodec_combo(signal_user_data_t *ud)
817 {
818         ghb_grey_combo_options (ud->builder);
819 }
820
821 void
822 container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
823 {
824         g_debug("container_changed_cb ()\n");
825         ghb_widget_to_setting(ud->settings, widget);
826         update_destination_extension(ud);
827         check_depencency(ud, widget);
828         update_acodec_combo(ud);
829         clear_presets_selection(ud);
830         if (ghb_ac3_in_audio_list (ud->audio_settings))
831         {
832                 const gchar *container;
833
834                 container = ghb_settings_get_string(ud->settings, "container");
835                 if (strcmp(container, "mp4") == 0)
836                 {
837                         ghb_ui_update(ud, "container", "m4v");
838                 }
839         }
840 }
841
842 static gchar*
843 get_aspect_string(gint aspect_n, gint aspect_d)
844 {
845         gchar *aspect;
846
847         if (aspect_d < 10)
848         {
849                 aspect = g_strdup_printf("%d:%d", aspect_n, aspect_d);
850         }
851         else
852         {
853                 gdouble aspect_nf = (gdouble)aspect_n / aspect_d;
854                 aspect = g_strdup_printf("%.2f:1", aspect_nf);
855         }
856         return aspect;
857 }
858
859 static gchar*
860 get_rate_string(gint rate_base, gint rate)
861 {
862         gdouble rate_f = (gdouble)rate / rate_base;
863         gchar *rate_s;
864
865         rate_s = g_strdup_printf("%.6g", rate_f);
866         return rate_s;
867 }
868 static void
869 show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
870 {
871         GtkWidget *widget;
872         gchar *text;
873
874         widget = GHB_WIDGET (ud->builder, "title_duration");
875         if (tinfo->duration != 0)
876         {
877                 text = g_strdup_printf ("%02d:%02d:%02d", tinfo->hours, 
878                                 tinfo->minutes, tinfo->seconds);
879         }
880         else
881         {
882                 text = g_strdup_printf ("Unknown");
883         }
884         gtk_label_set_text (GTK_LABEL(widget), text);
885         g_free(text);
886         widget = GHB_WIDGET (ud->builder, "source_dimensions");
887         text = g_strdup_printf ("%d x %d", tinfo->width, tinfo->height);
888         gtk_label_set_text (GTK_LABEL(widget), text);
889         g_free(text);
890         widget = GHB_WIDGET (ud->builder, "source_aspect");
891         text = get_aspect_string(tinfo->aspect_n, tinfo->aspect_d);
892         gtk_label_set_text (GTK_LABEL(widget), text);
893         g_free(text);
894
895         widget = GHB_WIDGET (ud->builder, "source_frame_rate");
896         text = (gchar*)get_rate_string(tinfo->rate_base, tinfo->rate);
897         gtk_label_set_text (GTK_LABEL(widget), text);
898         g_free(text);
899
900         ghb_ui_update_int (ud, "scale_width", tinfo->width - tinfo->crop[2] - tinfo->crop[3]);
901         // If anamorphic or keep_aspect, the hight will be automatically calculated
902         gboolean keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
903         gboolean anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
904         if (!(keep_aspect || anamorphic))
905                 ghb_ui_update_int (ud, "scale_height", tinfo->height - tinfo->crop[0] - tinfo->crop[1]);
906
907         // Set the limits of cropping.  hb_set_anamorphic_size crashes if
908         // you pass it a cropped width or height == 0.
909         gint bound;
910         bound = tinfo->height / 2 - 2;
911         widget = GHB_WIDGET (ud->builder, "crop_top");
912         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
913         widget = GHB_WIDGET (ud->builder, "crop_bottom");
914         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
915         bound = tinfo->width / 2 - 2;
916         widget = GHB_WIDGET (ud->builder, "crop_left");
917         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
918         widget = GHB_WIDGET (ud->builder, "crop_right");
919         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
920         if (ghb_settings_get_bool (ud->settings, "autocrop"))
921         {
922                 ghb_ui_update_int (ud, "crop_top", tinfo->crop[0]);
923                 ghb_ui_update_int (ud, "crop_bottom", tinfo->crop[1]);
924                 ghb_ui_update_int (ud, "crop_left", tinfo->crop[2]);
925                 ghb_ui_update_int (ud, "crop_right", tinfo->crop[3]);
926         }
927         g_debug("setting max end chapter %d\n", tinfo->num_chapters);
928         widget = GHB_WIDGET (ud->builder, "end_chapter");
929         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters);
930         gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), tinfo->num_chapters);
931         widget = GHB_WIDGET (ud->builder, "start_chapter");
932         gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1);
933 }
934
935 static void
936 adjust_audio_rate_combos(signal_user_data_t *ud)
937 {
938         gint titleindex, audioindex, acodec;
939         ghb_audio_info_t ainfo;
940         GtkWidget *widget;
941         
942         g_debug("adjust_audio_rate_combos ()\n");
943         titleindex = ghb_settings_get_index(ud->settings, "title");
944
945         widget = GHB_WIDGET(ud->builder, "audio_track");
946         audioindex = ghb_widget_int(widget);
947
948         widget = GHB_WIDGET(ud->builder, "audio_codec");
949         acodec = ghb_widget_int(widget);
950
951         if (ghb_get_audio_info (&ainfo, titleindex, audioindex) && ghb_audio_is_passthru (acodec))
952         {
953                 // Set the values for bitrate and samplerate to the input rates
954                 ghb_set_passthru_rate_opts (ud->builder, ainfo.bitrate);
955                 ghb_ui_update_int (ud, "audio_bitrate", ainfo.bitrate);
956                 ghb_ui_update_int (ud, "audio_sample_rate", 0);
957                 ghb_ui_update_int (ud, "audio_mix", 0);
958         }
959         else
960         {
961                 ghb_set_default_rate_opts (ud->builder);
962         }
963 }
964
965 static void
966 set_pref_audio(gint titleindex, signal_user_data_t *ud)
967 {
968         gint acodec, track, ivalue;
969         const gchar *svalue;
970         GtkWidget *button;
971         ghb_audio_info_t ainfo;
972         gboolean skipped_1st = FALSE;
973         
974         // Clear the audio list
975         clear_audio_list(ud);
976
977         // Find "best" audio based on audio preferences
978         button = GHB_WIDGET (ud->builder, "audio_add");
979         svalue = ghb_settings_get_short_opt(ud->settings, "pref_source_audio_lang");
980         acodec = ghb_settings_get_int(ud->settings, "pref_source_audio_codec");
981         track = ghb_find_audio_track(titleindex, svalue, acodec);
982         ghb_ui_update_int(ud, "audio_track", track);
983         // Get the resulting track, it may not be what was asked for.
984         track = ghb_settings_get_int(ud->settings, "audio_track");
985         if (track == -1)
986         {
987                 // No audio tracks. Perhaps no source dvd yet
988                 // Just initialize the audio controls and do not add anything to
989                 // the audio list
990                 acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec1");
991                 ghb_ui_update_int(ud, "audio_codec", acodec);
992                 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
993                 ghb_ui_update_int(ud, "audio_bitrate", ivalue);
994                 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
995                 ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
996                 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
997                 ghb_ui_update_int(ud, "audio_mix", ivalue);
998                 svalue = ghb_settings_get_string(ud->settings, "pref_audio_drc");
999                 ghb_ui_update(ud, "audio_drc", svalue);
1000                 return;
1001         }
1002         acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec1");
1003         // Check to see if:
1004         // 1. pref codec is ac3
1005         // 2. source codec is not ac3
1006         // 3. 2nd pref is enabled
1007         if (ghb_get_audio_info (&ainfo, titleindex, track) && ghb_audio_is_passthru (acodec))
1008         {
1009                 if (!ghb_audio_is_passthru(ainfo.codec))
1010                 {
1011                         acodec = ghb_get_default_acodec();
1012                         if (ghb_settings_get_int(ud->settings, "pref_audio_codec2") != 0)
1013                         {
1014                                 // Skip first pref audio
1015                                 acodec = 0;
1016                                 skipped_1st = TRUE;
1017                         }
1018                 }
1019         }
1020         ghb_ui_update_int(ud, "audio_codec", acodec);
1021         if (!ghb_audio_is_passthru (acodec))
1022         {
1023                 // This gets set autimatically if the codec is passthru
1024                 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
1025                 ghb_ui_update_int(ud, "audio_bitrate", ivalue);
1026                 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
1027                 ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
1028                 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
1029                 ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1030                 ghb_ui_update_int(ud, "audio_mix", ivalue);
1031         }
1032         svalue = ghb_settings_get_string(ud->settings, "pref_audio_drc");
1033         ghb_ui_update(ud, "audio_drc", svalue);
1034         if (acodec != 0) // 0 is none
1035         {
1036                 // Add to audio list
1037                 g_signal_emit_by_name(button, "clicked", ud);
1038         }
1039         acodec = ghb_settings_get_int(ud->settings, "pref_audio_codec2");
1040         // Check to see if:
1041         // 1. pref codec is ac3
1042         // 2. source codec is not ac3
1043         if (ghb_audio_is_passthru (acodec))
1044         {
1045                 if (!ghb_audio_is_passthru(ainfo.codec) && skipped_1st)
1046                 {
1047                         acodec = ghb_get_default_acodec();
1048                 }
1049                 else
1050                 {
1051                         acodec = 0;
1052                 }
1053         }
1054         if (acodec != 0)
1055         {
1056                 ghb_ui_update_int(ud, "audio_codec", acodec);
1057                 // Do the second prefs track
1058                 if (!ghb_audio_is_passthru (acodec))
1059                 {
1060                         ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate2");
1061                         ghb_ui_update_int(ud, "audio_bitrate", ivalue);
1062                         ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate2");
1063                         ghb_ui_update_int(ud, "audio_sample_rate", ivalue);
1064                         ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix2");
1065                         ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1066                         ghb_ui_update_int(ud, "audio_mix", ivalue);
1067                 }
1068                 g_signal_emit_by_name(button, "clicked", ud);
1069         }
1070 }
1071
1072 static gint preview_button_width;
1073 static gint preview_button_height;
1074 static gboolean update_preview = FALSE;
1075
1076 static void
1077 set_preview_image(signal_user_data_t *ud)
1078 {
1079         GtkWidget *widget;
1080         gint preview_width, preview_height, target_height, width, height;
1081
1082         g_debug("set_preview_button_image ()\n");
1083         gint titleindex = ghb_settings_get_int(ud->settings, "title");
1084         if (titleindex < 0) return;
1085         widget = GHB_WIDGET (ud->builder, "preview_frame");
1086         gint frame = ghb_widget_int(widget) - 1;
1087         GdkPixbuf *preview = ghb_get_preview_image (titleindex, frame, ud->settings, TRUE);
1088         if (preview == NULL) return;
1089         widget = GHB_WIDGET (ud->builder, "preview_image");
1090         gtk_image_set_from_pixbuf(GTK_IMAGE(widget), preview);
1091
1092         preview_width = gdk_pixbuf_get_width(preview);
1093         preview_height = gdk_pixbuf_get_height(preview);
1094         gchar *text = g_strdup_printf("%d x %d", preview_width, preview_height);
1095         widget = GHB_WIDGET (ud->builder, "preview_dims");
1096         gtk_label_set_text(GTK_LABEL(widget), text);
1097         g_free(text);
1098         
1099         g_debug("preview %d x %d\n", preview_width, preview_height);
1100         target_height = MIN(preview_button_height - 12, 128);
1101         height = target_height;
1102         width = preview_width * height / preview_height;
1103
1104         if ((height >= 16) && (width >= 16))
1105         {
1106                 GdkPixbuf *scaled_preview;
1107                 scaled_preview = gdk_pixbuf_scale_simple (preview, width, height, GDK_INTERP_NEAREST);
1108                 if (scaled_preview != NULL)
1109                 {
1110                         g_object_unref (preview);
1111                         
1112                         widget = GHB_WIDGET (ud->builder, "preview_button_image");
1113                         gtk_image_set_from_pixbuf(GTK_IMAGE(widget), scaled_preview);
1114                         g_object_unref (scaled_preview);
1115                 }
1116         }
1117 }
1118
1119 void
1120 title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1121 {
1122         ghb_title_info_t tinfo;
1123         gint titleindex;
1124         const gchar *preset;
1125         
1126         g_debug("title_changed_cb ()\n");
1127         ghb_widget_to_setting(ud->settings, widget);
1128         check_depencency(ud, widget);
1129
1130         titleindex = ghb_settings_get_int(ud->settings, "title");
1131         ghb_update_ui_combo_box (ud->builder, "audio_track", titleindex, FALSE);
1132         ghb_update_ui_combo_box (ud->builder, "subtitle_lang", titleindex, FALSE);
1133         preset = ghb_settings_get_string (ud->settings, "preset");
1134         ghb_update_from_preset(ud, preset, "subtitle_lang");
1135         if (ghb_get_title_info (&tinfo, titleindex))
1136         {
1137                 show_title_info(ud, &tinfo);
1138         }
1139         update_chapter_list (ud);
1140         adjust_audio_rate_combos(ud);
1141         set_pref_audio(titleindex, ud);
1142         if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
1143         {
1144                 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1145                 ghb_ui_update_int (ud, "video_bitrate", bitrate);
1146         }
1147
1148         // Unfortunately, there is no way to query how many frames were
1149         // actually generated during the scan.  It attempts to make 10.
1150         // If I knew how many were generated, I would adjust the spin
1151         // control range here.
1152         ghb_ui_update_int (ud, "preview_frame", 1);
1153
1154         set_preview_image (ud);
1155 }
1156
1157 void
1158 audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1159 {
1160         static gint prev_acodec = 0;
1161         gint acodec, ivalue;
1162         GHashTable *asettings;
1163         
1164         g_debug("audio_codec_changed_cb ()\n");
1165         
1166         acodec = ghb_widget_int(widget);
1167         if (ghb_audio_is_passthru (prev_acodec) && !ghb_audio_is_passthru (acodec))
1168         {
1169                 // Transition from passthru to not, put some audio settings back to 
1170                 // pref settings
1171                 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1172                 gint track = ghb_settings_get_int(ud->settings, "audio_track");
1173
1174                 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_bitrate1");
1175                 ghb_ui_update_int (ud, "audio_bitrate", ivalue);
1176                 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_rate1");
1177                 ghb_ui_update_int (ud, "audio_sample_rate", ivalue);
1178                 ivalue = ghb_settings_get_int(ud->settings, "pref_audio_mix1");
1179                 ivalue = ghb_get_best_mix(titleindex, track, acodec, ivalue);
1180                 ghb_ui_update_int (ud, "audio_mix", ivalue);
1181         }
1182         adjust_audio_rate_combos(ud);
1183         ghb_grey_combo_options (ud->builder);
1184         check_depencency(ud, widget);
1185         prev_acodec = acodec;
1186         asettings = get_selected_asettings(ud);
1187         if (asettings != NULL)
1188         {
1189                 ghb_widget_to_setting(asettings, widget);
1190                 audio_list_refresh_selected(ud);
1191         }
1192         if (ghb_ac3_in_audio_list (ud->audio_settings))
1193         {
1194                 const gchar *container;
1195
1196                 container = ghb_settings_get_string(ud->settings, "container");
1197                 if (strcmp(container, "mp4") == 0)
1198                 {
1199                         ghb_ui_update(ud, "container", "m4v");
1200                 }
1201         }
1202 }
1203
1204 static void audio_list_refresh_selected(signal_user_data_t *ud);
1205 static GHashTable* get_selected_asettings(signal_user_data_t *ud);
1206
1207 void
1208 audio_track_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1209 {
1210         GHashTable *asettings;
1211
1212         g_debug("audio_track_changed_cb ()\n");
1213         adjust_audio_rate_combos(ud);
1214         check_depencency(ud, widget);
1215         ghb_grey_combo_options(ud->builder);
1216         asettings = get_selected_asettings(ud);
1217         if (asettings != NULL)
1218         {
1219                 ghb_widget_to_setting(asettings, widget);
1220                 audio_list_refresh_selected(ud);
1221         }
1222 }
1223
1224 void
1225 audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1226 {
1227         GHashTable *asettings;
1228
1229         g_debug("audio_widget_changed_cb ()\n");
1230         check_depencency(ud, widget);
1231         asettings = get_selected_asettings(ud);
1232         if (asettings != NULL)
1233         {
1234                 ghb_widget_to_setting(asettings, widget);
1235                 audio_list_refresh_selected(ud);
1236         }
1237 }
1238
1239 void
1240 generic_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1241 {
1242         g_debug("generic_widget_changed_cb ()\n");
1243         check_depencency(ud, widget);
1244 }
1245
1246 void
1247 setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1248 {
1249         ghb_widget_to_setting(ud->settings, widget);
1250         check_depencency(ud, widget);
1251         clear_presets_selection(ud);
1252 }
1253
1254 void
1255 http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1256 {
1257         ghb_widget_to_setting(ud->settings, widget);
1258         check_depencency(ud, widget);
1259         clear_presets_selection(ud);
1260         ghb_grey_combo_options (ud->builder);
1261 }
1262
1263 void
1264 vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1265 {
1266         gint vqmin, vqmax;
1267
1268         ghb_widget_to_setting(ud->settings, widget);
1269         check_depencency(ud, widget);
1270         clear_presets_selection(ud);
1271         ghb_vquality_range(ud, &vqmin, &vqmax);
1272         GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1273         gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1274 }
1275
1276 void
1277 vfr_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1278 {
1279         //const gchar *name = gtk_widget_get_name(widget);
1280         //g_debug("setting_widget_changed_cb () %s\n", name);
1281         ghb_widget_to_setting(ud->settings, widget);
1282         check_depencency(ud, widget);
1283         clear_presets_selection(ud);
1284         if (ghb_settings_get_bool(ud->settings, "variable_frame_rate"))
1285         {
1286                 ghb_ui_update_int(ud, "framerate", 0);
1287         }
1288 }
1289
1290 void
1291 mirror_cb(GtkWidget *widget, signal_user_data_t *ud)
1292 {
1293         const gchar *name = gtk_widget_get_name(widget);
1294         if (name == NULL) return;
1295         
1296         g_debug("mirror_cb () %s\n", name);
1297         gchar *mirror = g_strdup(name);
1298         gchar *pos = g_strrstr(mirror, "_mirror");
1299         if (pos == NULL) return;
1300         *pos = 0;
1301         gchar *value = ghb_widget_short_opt (widget);
1302         ghb_ui_update (ud, mirror, value);
1303         g_free(mirror);
1304 }
1305
1306 // subtitles have their differ from other settings in that
1307 // the selection is updated automaitcally when the title
1308 // changes.  I don't want the preset selection changed as
1309 // would happen for regular settings.
1310 void
1311 subtitle_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1312 {
1313         const gchar *name = gtk_widget_get_name(widget);
1314         g_debug("subtitle_changed_cb () %s\n", name);
1315         ghb_widget_to_setting(ud->settings, widget);
1316         check_depencency(ud, widget);
1317 }
1318
1319 void
1320 target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1321 {
1322         const gchar *name = gtk_widget_get_name(widget);
1323         g_debug("setting_widget_changed_cb () %s\n", name);
1324         ghb_widget_to_setting(ud->settings, widget);
1325         check_depencency(ud, widget);
1326         clear_presets_selection(ud);
1327         if (ghb_settings_get_bool (ud->settings, "vquality_type_target"))
1328         {
1329                 gint titleindex = ghb_settings_get_int(ud->settings, "title");
1330                 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1331                 ghb_ui_update_int (ud, "video_bitrate", bitrate);
1332         }
1333 }
1334
1335 void
1336 start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1337 {
1338         const gchar *name = gtk_widget_get_name(widget);
1339         g_debug("start_chapter_changed_cb () %s\n", name);
1340         ghb_widget_to_setting(ud->settings, widget);
1341         GtkWidget *end_ch = GHB_WIDGET (ud->builder, "end_chapter");
1342         gdouble start, end;
1343         gtk_spin_button_get_range (GTK_SPIN_BUTTON(end_ch), &start, &end);
1344         start = ghb_settings_get_int(ud->settings, "start_chapter");
1345         gtk_spin_button_set_range (GTK_SPIN_BUTTON(end_ch), start, end);
1346         check_depencency(ud, widget);
1347 }
1348
1349 void
1350 end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1351 {
1352         const gchar *name = gtk_widget_get_name(widget);
1353         g_debug("end_chapter_changed_cb () %s\n", name);
1354         ghb_widget_to_setting(ud->settings, widget);
1355         GtkWidget *start_ch = GHB_WIDGET (ud->builder, "start_chapter");
1356         gdouble start, end;
1357         gtk_spin_button_get_range (GTK_SPIN_BUTTON(start_ch), &start, &end);
1358         end = ghb_settings_get_int(ud->settings, "end_chapter");
1359         gtk_spin_button_set_range (GTK_SPIN_BUTTON(start_ch), start, end);
1360         check_depencency(ud, widget);
1361 }
1362
1363 void
1364 scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1365 {
1366         g_debug("scale_width_changed_cb ()\n");
1367         ghb_widget_to_setting(ud->settings, widget);
1368         check_depencency(ud, widget);
1369         ghb_set_scale (ud, GHB_SCALE_KEEP_WIDTH);
1370         update_preview = TRUE;
1371         gchar *text;
1372         gint width = ghb_settings_get_int(ud->settings, "scale_width");
1373         gint height = ghb_settings_get_int(ud->settings, "scale_height");
1374         widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1375         text = g_strdup_printf ("%d x %d", width, height);
1376         gtk_label_set_text (GTK_LABEL(widget), text);
1377         g_free(text);
1378 }
1379
1380 void
1381 scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1382 {
1383         g_debug("scale_height_changed_cb ()\n");
1384         ghb_widget_to_setting(ud->settings, widget);
1385         check_depencency(ud, widget);
1386         ghb_set_scale (ud, GHB_SCALE_KEEP_HEIGHT);
1387         update_preview = TRUE;
1388         gchar *text;
1389         gint width = ghb_settings_get_int(ud->settings, "scale_width");
1390         gint height = ghb_settings_get_int(ud->settings, "scale_height");
1391         widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1392         text = g_strdup_printf ("%d x %d", width, height);
1393         gtk_label_set_text (GTK_LABEL(widget), text);
1394         g_free(text);
1395 }
1396
1397 void
1398 crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1399 {
1400         gint titleindex, crop[4];
1401         ghb_title_info_t tinfo;
1402         
1403         g_debug("crop_changed_cb ()\n");
1404         ghb_widget_to_setting(ud->settings, widget);
1405         check_depencency(ud, widget);
1406         ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1407
1408         crop[0] = ghb_settings_get_int(ud->settings, "crop_top");
1409         crop[1] = ghb_settings_get_int(ud->settings, "crop_bottom");
1410         crop[2] = ghb_settings_get_int(ud->settings, "crop_left");
1411         crop[3] = ghb_settings_get_int(ud->settings, "crop_right");
1412         titleindex = ghb_settings_get_index(ud->settings, "title");
1413         if (ghb_get_title_info (&tinfo, titleindex))
1414         {
1415                 gint width, height;
1416                 gchar *text;
1417                 
1418                 width = tinfo.width - crop[2] - crop[3];
1419                 height = tinfo.height - crop[0] - crop[1];
1420                 widget = GHB_WIDGET (ud->builder, "crop_dimensions");
1421                 text = g_strdup_printf ("%d x %d", width, height);
1422                 gtk_label_set_text (GTK_LABEL(widget), text);
1423                 g_free(text);
1424         }
1425         gchar *text;
1426         widget = GHB_WIDGET (ud->builder, "crop_values");
1427         text = g_strdup_printf ("%d:%d:%d:%d", crop[0], crop[1], crop[2], crop[3]);
1428         gtk_label_set_text (GTK_LABEL(widget), text);
1429         g_free(text);
1430         update_preview = TRUE;
1431 }
1432
1433 void
1434 scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1435 {
1436         g_debug("scale_changed_cb ()\n");
1437         ghb_widget_to_setting(ud->settings, widget);
1438         check_depencency(ud, widget);
1439         clear_presets_selection(ud);
1440         ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1441         update_preview = TRUE;
1442         
1443         gchar *text;
1444         
1445         text = ghb_settings_get_bool(ud->settings, "autocrop") ? "On" : "Off";
1446         widget = GHB_WIDGET (ud->builder, "crop_auto");
1447         gtk_label_set_text (GTK_LABEL(widget), text);
1448         text = ghb_settings_get_bool(ud->settings, "autoscale") ? "On" : "Off";
1449         widget = GHB_WIDGET (ud->builder, "scale_auto");
1450         gtk_label_set_text (GTK_LABEL(widget), text);
1451         text = ghb_settings_get_bool(ud->settings, "anamorphic") ? "On" : "Off";
1452         widget = GHB_WIDGET (ud->builder, "scale_anamorphic");
1453         gtk_label_set_text (GTK_LABEL(widget), text);
1454 }
1455
1456 void
1457 generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
1458 {
1459         // Normally (due to user input) I only want to process the entry
1460         // when editing is done and the focus-out signal is sent.
1461         // But... there's always a but.
1462         // If the entry is changed by software, the focus-out signal is not sent.
1463         // The changed signal is sent ... so here we are.
1464         // I don't want to process upon every keystroke, so I prevent processing
1465         // while the widget has focus.
1466         g_debug("generic_entry_changed_cb ()\n");
1467         if (!GTK_WIDGET_HAS_FOCUS((GtkWidget*)entry))
1468         {
1469                 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
1470         }
1471 }
1472
1473 gboolean
1474 generic_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
1475     signal_user_data_t *ud)
1476 {
1477         g_debug("generic_focus_out_cb ()\n");
1478         ghb_widget_to_setting(ud->settings, widget);
1479         return FALSE;
1480 }
1481
1482 // Flag needed to prevent x264 options processing from chasing its tail
1483 static gboolean ignore_options_update = FALSE;
1484
1485 void
1486 x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1487 {
1488         ghb_widget_to_setting(ud->settings, widget);
1489         if (!ignore_options_update)
1490         {
1491                 ignore_options_update = TRUE;
1492                 ghb_x264_opt_update(ud, widget);
1493                 ignore_options_update = FALSE;
1494         }
1495         check_depencency(ud, widget);
1496         clear_presets_selection(ud);
1497 }
1498
1499 void
1500 x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1501 {
1502         g_debug("x264_entry_changed_cb ()\n");
1503         if (!ignore_options_update)
1504         {
1505                 GtkWidget *textview;
1506                 textview = GTK_WIDGET(GHB_WIDGET(ud->builder, "x264_options"));
1507                 ghb_widget_to_setting(ud->settings, textview);
1508                 const gchar *options;
1509                 options = ghb_settings_get_string(ud->settings, "x264_options");
1510                 ignore_options_update = TRUE;
1511                 ghb_x264_parse_options(ud, options);
1512                 ignore_options_update = FALSE;
1513         }
1514 }
1515
1516 gboolean
1517 x264_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
1518     signal_user_data_t *ud)
1519 {
1520         ghb_widget_to_setting(ud->settings, widget);
1521         gchar *options;
1522         options = (gchar*)ghb_settings_get_string(ud->settings, "x264_options");
1523         options = ghb_sanitize_x264opts(ud, options);
1524         ignore_options_update = TRUE;
1525         if (options != NULL)
1526         {
1527                 ghb_ui_update(ud, "x264_options", options);
1528                 ghb_x264_parse_options(ud, options);
1529                 g_free(options);
1530         }
1531         ignore_options_update = FALSE;
1532         return FALSE;
1533 }
1534
1535 static void
1536 clear_audio_list(signal_user_data_t *ud)
1537 {
1538         GtkTreeView *treeview;
1539         GtkListStore *store;
1540         GSList *link;
1541         
1542         g_debug("clear_audio_list ()\n");
1543         while (ud->audio_settings != NULL)
1544         {
1545                 link = ud->audio_settings;
1546                 ud->audio_settings = g_slist_remove_link(ud->audio_settings, link);
1547                 g_hash_table_destroy((GHashTable*)link->data);
1548                 g_slist_free_1(link);
1549         }
1550         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1551         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1552         gtk_list_store_clear (store);
1553 }
1554
1555 static void
1556 add_to_audio_list(signal_user_data_t *ud, GHashTable *settings)
1557 {
1558         GtkTreeView *treeview;
1559         GtkTreeIter iter;
1560         GtkListStore *store;
1561         GtkTreeSelection *selection;
1562         
1563         g_debug("add_to_audio_list ()\n");
1564         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1565         selection = gtk_tree_view_get_selection (treeview);
1566         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1567
1568         gtk_list_store_append(store, &iter);
1569         gtk_list_store_set(store, &iter, 
1570                 // These are displayed in list
1571                 0, ghb_settings_get_option(settings, "audio_track"),
1572                 1, ghb_settings_get_option(settings, "audio_codec"),
1573                 2, ghb_settings_get_option(settings, "audio_bitrate"),
1574                 3, ghb_settings_get_option(settings, "audio_sample_rate"),
1575                 4, ghb_settings_get_option(settings, "audio_mix"),
1576                 // These are used to set combo box values when a list item is selected
1577                 5, ghb_settings_get_string(settings, "audio_drc"),
1578                 6, ghb_settings_get_short_opt(settings, "audio_track"),
1579                 7, ghb_settings_get_short_opt(settings, "audio_codec"),
1580                 8, ghb_settings_get_short_opt(settings, "audio_bitrate"),
1581                 9, ghb_settings_get_short_opt(settings, "audio_sample_rate"),
1582                 10, ghb_settings_get_short_opt(settings, "audio_mix"),
1583                 -1);
1584         gtk_tree_selection_select_iter(selection, &iter);
1585 }
1586
1587 static void
1588 audio_list_refresh_selected(signal_user_data_t *ud)
1589 {
1590         GtkTreeView *treeview;
1591         GtkTreePath *treepath;
1592         GtkTreeSelection *selection;
1593         GtkTreeModel *store;
1594         GtkTreeIter iter;
1595         gint *indices;
1596         gint row;
1597         GSList *link;
1598         GHashTable *asettings = NULL;
1599         
1600         g_debug("get_selected_asettings ()\n");
1601         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1602         selection = gtk_tree_view_get_selection (treeview);
1603         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1604         {
1605         // Get the row number
1606                 treepath = gtk_tree_model_get_path (store, &iter);
1607                 indices = gtk_tree_path_get_indices (treepath);
1608                 g_free(treepath);
1609                 row = indices[0];
1610                 // find audio settings
1611                 if (row < 0) return;
1612                 link = g_slist_nth(ud->audio_settings, row);
1613                 if (link == NULL) return;
1614                 asettings = (GHashTable*)link->data;
1615                 gtk_list_store_set(GTK_LIST_STORE(store), &iter, 
1616                         // These are displayed in list
1617                         0, ghb_settings_get_option(asettings, "audio_track"),
1618                         1, ghb_settings_get_option(asettings, "audio_codec"),
1619                         2, ghb_settings_get_option(asettings, "audio_bitrate"),
1620                         3, ghb_settings_get_option(asettings, "audio_sample_rate"),
1621                         4, ghb_settings_get_option(asettings, "audio_mix"),
1622                         // These are used to set combo box values when a list item is selected
1623                         5, ghb_settings_get_string(asettings, "audio_drc"),
1624                         6, ghb_settings_get_short_opt(asettings, "audio_track"),
1625                         7, ghb_settings_get_short_opt(asettings, "audio_codec"),
1626                         8, ghb_settings_get_short_opt(asettings, "audio_bitrate"),
1627                         9, ghb_settings_get_short_opt(asettings, "audio_sample_rate"),
1628                         10, ghb_settings_get_short_opt(asettings, "audio_mix"),
1629                         -1);
1630         }
1631 }
1632
1633 static GHashTable*
1634 get_selected_asettings(signal_user_data_t *ud)
1635 {
1636         GtkTreeView *treeview;
1637         GtkTreePath *treepath;
1638         GtkTreeSelection *selection;
1639         GtkTreeModel *store;
1640         GtkTreeIter iter;
1641         gint *indices;
1642         gint row;
1643         GSList *link;
1644         GHashTable *asettings = NULL;
1645         
1646         g_debug("get_selected_asettings ()\n");
1647         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1648         selection = gtk_tree_view_get_selection (treeview);
1649         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1650         {
1651         // Get the row number
1652                 treepath = gtk_tree_model_get_path (store, &iter);
1653                 indices = gtk_tree_path_get_indices (treepath);
1654                 g_free(treepath);
1655                 row = indices[0];
1656                 // find audio settings
1657                 if (row < 0) return NULL;
1658                 link = g_slist_nth(ud->audio_settings, row);
1659                 if (link == NULL) return NULL;
1660                 asettings = (GHashTable*)link->data;
1661         }
1662         return asettings;
1663 }
1664
1665 void
1666 audio_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
1667 {
1668         GtkTreeModel *store;
1669         GtkTreeIter iter;
1670         GtkWidget *widget;
1671         
1672         g_debug("audio_list_selection_changed_cb ()\n");
1673         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1674         {
1675                 const gchar *track, *codec, *bitrate, *sample_rate, *mix, *drc;
1676                 gtk_tree_model_get(store, &iter,
1677                                                    6, &track,
1678                                                    7, &codec,
1679                                                    8, &bitrate,
1680                                                    9, &sample_rate,
1681                                                    10, &mix,
1682                                                    5, &drc,
1683                                                    -1);
1684                 ghb_ui_update(ud, "audio_track", track);
1685                 ghb_ui_update(ud, "audio_codec", codec);
1686                 ghb_ui_update(ud, "audio_bitrate", bitrate);
1687                 ghb_ui_update(ud, "audio_sample_rate", sample_rate);
1688                 ghb_ui_update(ud, "audio_mix", mix);
1689                 ghb_ui_update(ud, "audio_drc", drc);
1690                 widget = GHB_WIDGET (ud->builder, "audio_remove");
1691                 gtk_widget_set_sensitive(widget, TRUE);
1692                 //widget = GHB_WIDGET (ud->builder, "audio_update");
1693                 //gtk_widget_set_sensitive(widget, TRUE);
1694         }
1695         else
1696         {
1697                 widget = GHB_WIDGET (ud->builder, "audio_remove");
1698                 gtk_widget_set_sensitive(widget, FALSE);
1699                 //widget = GHB_WIDGET (ud->builder, "audio_update");
1700                 //gtk_widget_set_sensitive(widget, FALSE);
1701         }
1702 }
1703
1704 void
1705 audio_add_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1706 {
1707         // Add the current audio settings to the list.
1708         GHashTable *asettings;
1709         GtkWidget *widget;
1710         gint count;
1711         
1712         g_debug("audio_add_clicked_cb ()\n");
1713         // Only allow up to 8 audio entries
1714         asettings = ghb_settings_new();
1715         widget = GHB_WIDGET(ud->builder, "audio_track");
1716         ghb_settings_set(asettings,     "audio_track", ghb_widget_value(widget));
1717         widget = GHB_WIDGET(ud->builder, "audio_codec");
1718         ghb_settings_set(asettings,     "audio_codec", ghb_widget_value(widget));
1719         widget = GHB_WIDGET(ud->builder, "audio_bitrate");
1720         ghb_settings_set(asettings,     "audio_bitrate", ghb_widget_value(widget));
1721         widget = GHB_WIDGET(ud->builder, "audio_sample_rate");
1722         ghb_settings_set(asettings,     "audio_sample_rate", ghb_widget_value(widget));
1723         widget = GHB_WIDGET(ud->builder, "audio_mix");
1724         ghb_settings_set(asettings,     "audio_mix", ghb_widget_value(widget));
1725         widget = GHB_WIDGET(ud->builder, "audio_drc");
1726         ghb_settings_set(asettings,     "audio_drc", ghb_widget_value(widget));
1727
1728         ud->audio_settings = g_slist_append(ud->audio_settings, asettings);
1729         add_to_audio_list(ud, asettings);
1730         count = g_slist_length(ud->audio_settings);
1731         if (count >= 8)
1732         {
1733                 gtk_widget_set_sensitive(xwidget, FALSE);
1734         }
1735 }
1736
1737 void
1738 audio_remove_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
1739 {
1740         GtkTreeView *treeview;
1741         GtkTreePath *treepath;
1742         GtkTreeSelection *selection;
1743         GtkTreeModel *store;
1744         GtkTreeIter iter, nextIter;
1745         gint *indices;
1746         gint row;
1747         GSList *link;
1748
1749         g_debug("audio_remove_clicked_cb ()\n");
1750         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1751         selection = gtk_tree_view_get_selection (treeview);
1752         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1753         {
1754                 nextIter = iter;
1755                 if (!gtk_tree_model_iter_next(store, &nextIter))
1756                 {
1757                         nextIter = iter;
1758                         if (gtk_tree_model_get_iter_first(store, &nextIter))
1759                         {
1760                                 gtk_tree_selection_select_iter (selection, &nextIter);
1761                         }
1762                 }
1763                 else
1764                 {
1765                         gtk_tree_selection_select_iter (selection, &nextIter);
1766                 }
1767         // Get the row number
1768                 treepath = gtk_tree_model_get_path (store, &iter);
1769                 indices = gtk_tree_path_get_indices (treepath);
1770                 g_free(treepath);
1771                 row = indices[0];
1772                 // Remove the selected item
1773                 gtk_list_store_remove (GTK_LIST_STORE(store), &iter);
1774                 // remove from audio settings list
1775                 if (row < 0) return;
1776                 link = g_slist_nth(ud->audio_settings, row);
1777                 if (link == NULL) return;
1778                 ud->audio_settings = g_slist_remove_link(ud->audio_settings, link);
1779                 g_hash_table_destroy((GHashTable*)link->data);
1780                 g_slist_free_1(link);
1781                 widget = GHB_WIDGET (ud->builder, "audio_add");
1782                 gtk_widget_set_sensitive(widget, TRUE);
1783         }
1784 }
1785
1786 static void
1787 audio_list_refresh(signal_user_data_t *ud)
1788 {
1789         GtkTreeView *treeview;
1790         GtkTreeIter iter;
1791         GtkListStore *store;
1792         gboolean done;
1793         
1794         g_debug("audio_list_refresh ()\n");
1795         GSList *link = ud->audio_settings;
1796         if (link == NULL) return;
1797         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
1798         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1799         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1800         {
1801                 do
1802                 {
1803                         GHashTable *asettings;
1804
1805                         asettings = (GHashTable*)link->data;
1806                         gtk_list_store_set(GTK_LIST_STORE(store), &iter, 
1807                                 // These are displayed in list
1808                                 0, ghb_settings_get_option(asettings, "audio_track"),
1809                                 1, ghb_settings_get_option(asettings, "audio_codec"),
1810                                 2, ghb_settings_get_option(asettings, "audio_bitrate"),
1811                                 3, ghb_settings_get_option(asettings, "audio_sample_rate"),
1812                                 4, ghb_settings_get_option(asettings, "audio_mix"),
1813                                 // These are used to set combo box values when a list item is selected
1814                                 5, ghb_settings_get_string(asettings, "audio_drc"),
1815                                 6, ghb_settings_get_short_opt(asettings, "audio_track"),
1816                                 7, ghb_settings_get_short_opt(asettings, "audio_codec"),
1817                                 8, ghb_settings_get_short_opt(asettings, "audio_bitrate"),
1818                                 9, ghb_settings_get_short_opt(asettings, "audio_sample_rate"),
1819                                 10, ghb_settings_get_short_opt(asettings, "audio_mix"),
1820                                 -1);
1821                         done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1822                         link = link->next;
1823                 } while (!done && link);
1824         }
1825 }
1826
1827 void
1828 ghb_presets_list_update(signal_user_data_t *ud)
1829 {
1830         GtkTreeView *treeview;
1831         GtkTreeIter iter;
1832         GtkListStore *store;
1833         gboolean done;
1834         gint ii = 0;
1835         gint index;
1836         gchar **presets;
1837         gchar **descriptions;
1838         gint flags, custom, def;
1839         
1840         g_debug("ghb_presets_list_update ()\n");
1841         presets = ghb_presets_get_names();
1842         descriptions = ghb_presets_get_descriptions();
1843         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1844         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1845         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1846         {
1847                 do
1848                 {
1849                         if ((presets != NULL) && (presets[ii] != NULL))
1850                         {
1851                                 // Update row with settings data
1852                                 g_debug("Updating row\n");
1853                                 flags = ghb_preset_flags(presets[ii], &index);
1854                                 def = flags & PRESET_DEFAULT;
1855                                 custom = flags & PRESET_CUSTOM;
1856                                 gtk_list_store_set(store, &iter, 
1857                                                         0, presets[ii], 
1858                                                         1, def ? 800 : 400, 
1859                                                         2, def ? 2 : 0,
1860                                                         3, custom ? "black" : "blue", 
1861                                                         4, descriptions[ii],
1862                                                         -1);
1863                                 ii++;
1864                                 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1865                         }
1866                         else
1867                         {
1868                                 // No more settings data, remove row
1869                                 g_debug("Removing row\n");
1870                                 done = !gtk_list_store_remove(store, &iter);
1871                         }
1872                 } while (!done);
1873         }
1874         while ((presets != NULL) && (presets[ii] != NULL))
1875         {
1876                 // Additional settings, add row
1877                 g_debug("Adding row %s\n", presets[ii]);
1878                 gtk_list_store_append(store, &iter);
1879                 flags = ghb_preset_flags(presets[ii], &index);
1880                 def = flags & PRESET_DEFAULT;
1881                 custom = flags & PRESET_CUSTOM;
1882                 gtk_list_store_set(store, &iter, 0, presets[ii], 
1883                                                         1, def ? 800 : 400, 
1884                                                         2, def ? 2 : 0,
1885                                                         3, custom ? "black" : "blue", 
1886                                                         4, descriptions[ii],
1887                                                         -1);
1888                 ii++;
1889         }
1890         g_strfreev (presets);
1891 }
1892
1893 void
1894 ghb_select_preset(GtkBuilder *builder, const gchar *preset)
1895 {
1896         GtkTreeView *treeview;
1897         GtkTreeSelection *selection;
1898         GtkTreeModel *store;
1899         GtkTreeIter iter;
1900         gchar *tpreset;
1901         gboolean done;
1902         
1903         g_debug("select_preset()\n");
1904         if (preset == NULL) return;
1905         treeview = GTK_TREE_VIEW(GHB_WIDGET(builder, "presets_list"));
1906         selection = gtk_tree_view_get_selection (treeview);
1907         store = gtk_tree_view_get_model (treeview);
1908         if (gtk_tree_model_get_iter_first(store, &iter))
1909         {
1910                 do
1911                 {
1912                         gtk_tree_model_get(store, &iter, 0, &tpreset, -1);
1913                         if (strcmp(preset, tpreset) == 0)
1914                         {
1915                                 gtk_tree_selection_select_iter (selection, &iter);
1916                                 break;
1917                         }
1918                         done = !gtk_tree_model_iter_next(store, &iter);
1919                 } while (!done);
1920         }
1921 }
1922
1923 void
1924 presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1925 {
1926         GtkWidget *dialog;
1927         GtkEntry *entry;
1928         GtkTextView *desc;
1929         GtkResponseType response;
1930         const gchar *preset = "";
1931
1932         g_debug("presets_save_clicked_cb ()\n");
1933         preset = ghb_settings_get_string (ud->settings, "preset");
1934         // Clear the description
1935         desc = GTK_TEXT_VIEW(GHB_WIDGET(ud->builder, "preset_description"));
1936         //gtk_entry_set_text(desc, "");
1937         dialog = GHB_WIDGET(ud->builder, "preset_save_dialog");
1938         entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "preset_name"));
1939         gtk_entry_set_text(entry, preset);
1940         response = gtk_dialog_run(GTK_DIALOG(dialog));
1941         gtk_widget_hide(dialog);
1942         if (response == GTK_RESPONSE_OK)
1943         {
1944                 // save the preset
1945                 const gchar *name = gtk_entry_get_text(entry);
1946                 g_debug("description to settings\n");
1947                 ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
1948                 ghb_settings_save(ud, name);
1949                 ghb_presets_list_update(ud);
1950                 // Make the new preset the selected item
1951                 ghb_select_preset(ud->builder, name);
1952         }
1953 }
1954
1955 void
1956 prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1957 {
1958         GtkWidget *dialog;
1959         GtkResponseType response;
1960
1961         g_debug("prefs_dialog_cb ()\n");
1962         dialog = GHB_WIDGET(ud->builder, "prefs_dialog");
1963         response = gtk_dialog_run(GTK_DIALOG(dialog));
1964         gtk_widget_hide(dialog);
1965 }
1966
1967 void
1968 presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1969 {
1970         GtkTreeView *treeview;
1971         GtkTreeSelection *selection;
1972         GtkTreeModel *store;
1973         GtkTreeIter iter;
1974         gchar *preset;
1975         GtkResponseType response;
1976
1977         g_debug("presets_remove_clicked_cb ()\n");
1978         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1979         selection = gtk_tree_view_get_selection (treeview);
1980         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1981         {
1982                 GtkWidget *dialog;
1983
1984                 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1985                 if (!ghb_presets_is_standard(preset))
1986                 {
1987                         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1988                                                                         GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1989                                                                         "Confirm deletion of preset %s.", preset);
1990                         response = gtk_dialog_run(GTK_DIALOG(dialog));
1991                         gtk_widget_destroy (dialog);
1992                         if (response == GTK_RESPONSE_YES)
1993                         {
1994                                 GtkTreeIter nextIter = iter;
1995                                 gchar *nextPreset = NULL;
1996                                 if (!gtk_tree_model_iter_next(store, &nextIter))
1997                                 {
1998                                         if (gtk_tree_model_get_iter_first(store, &nextIter))
1999                                         {
2000                                                 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
2001                                         }
2002                                 }
2003                                 else
2004                                 {
2005                                         gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
2006                                 }
2007                                 // Remove the selected item
2008                                 // First unselect it so that selecting the new item works properly
2009                                 gtk_tree_selection_unselect_iter (selection, &iter);
2010                                 ghb_presets_remove(ud->settings, preset);
2011                                 ghb_presets_list_update(ud);
2012                                 ghb_select_preset(ud->builder, nextPreset);
2013                         }
2014                 }
2015                 else
2016                 {
2017                         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2018                                                                         GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
2019                                                                         "Can not delete standard preset %s.", preset);
2020                         response = gtk_dialog_run(GTK_DIALOG(dialog));
2021                         gtk_widget_destroy (dialog);
2022                 }
2023         }
2024 }
2025
2026 static void
2027 preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
2028 {
2029         GtkWidget *widget;
2030
2031         ghb_ui_update_int (ud, "scale_width", tinfo->width - tinfo->crop[2] - tinfo->crop[3]);
2032         // If anamorphic or keep_aspect, the hight will be automatically calculated
2033         gboolean keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
2034         gboolean anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
2035         if (!(keep_aspect || anamorphic))
2036                 ghb_ui_update_int (ud, "scale_height", tinfo->height - tinfo->crop[0] - tinfo->crop[1]);
2037
2038         // Set the limits of cropping.  hb_set_anamorphic_size crashes if
2039         // you pass it a cropped width or height == 0.
2040         gint bound;
2041         bound = tinfo->height / 2 - 2;
2042         widget = GHB_WIDGET (ud->builder, "crop_top");
2043         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
2044         widget = GHB_WIDGET (ud->builder, "crop_bottom");
2045         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
2046         bound = tinfo->width / 2 - 2;
2047         widget = GHB_WIDGET (ud->builder, "crop_left");
2048         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
2049         widget = GHB_WIDGET (ud->builder, "crop_right");
2050         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
2051         if (ghb_settings_get_bool (ud->settings, "autocrop"))
2052         {
2053                 ghb_ui_update_int (ud, "crop_top", tinfo->crop[0]);
2054                 ghb_ui_update_int (ud, "crop_bottom", tinfo->crop[1]);
2055                 ghb_ui_update_int (ud, "crop_left", tinfo->crop[2]);
2056                 ghb_ui_update_int (ud, "crop_right", tinfo->crop[3]);
2057         }
2058 }
2059
2060 void
2061 presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
2062 {
2063         GtkTreeModel *store;
2064         GtkTreeIter iter;
2065         gchar *preset;
2066         GtkWidget *widget;
2067         gboolean sensitive = FALSE;
2068         ghb_title_info_t tinfo;
2069         
2070         g_debug("presets_list_selection_changed_cb ()\n");
2071         if (gtk_tree_selection_get_selected(selection, &store, &iter))
2072         {
2073                 gtk_tree_model_get(store, &iter, 0, &preset, -1);
2074                 if (!ghb_presets_is_standard(preset))
2075                 {
2076                         sensitive = TRUE;
2077                 }
2078                 ud->dont_clear_presets = TRUE;
2079                 // Temporarily set the video_quality range to (0,100)
2080                 // This is needed so the video_quality value does not get
2081                 // truncated when set.  The range will be readjusted below
2082                 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
2083                 gtk_range_set_range (GTK_RANGE(qp), 0, 100);
2084                 // Clear the audio list prior to changing the preset.  Existing audio
2085                 // can cause the container extension to be automatically changed when
2086                 // it shouldn't be
2087                 clear_audio_list(ud);
2088                 ghb_set_preset(ud, preset);
2089                 gint titleindex = ghb_settings_get_int(ud->settings, "title");
2090                 set_pref_audio(titleindex, ud);
2091                 ud->dont_clear_presets = FALSE;
2092                 if (ghb_get_title_info (&tinfo, titleindex))
2093                 {
2094                         preset_update_title_deps(ud, &tinfo);
2095                 }
2096                 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
2097
2098                 gint vqmin, vqmax;
2099                 ghb_vquality_range(ud, &vqmin, &vqmax);
2100                 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
2101         }
2102         else
2103         {
2104                 g_debug("No selection???  Perhaps unselected.\n");
2105         }
2106         widget = GHB_WIDGET (ud->builder, "presets_remove");
2107         gtk_widget_set_sensitive(widget, sensitive);
2108 }
2109
2110 void
2111 queue_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
2112 {
2113         GtkTreeModel *store;
2114         GtkTreeIter iter, piter;
2115         
2116         g_debug("queue_list_selection_changed_cb ()\n");
2117         // A queue entry is made up of a parent and multiple
2118         // children that are visible when expanded.  When and entry
2119         // is selected, I want the parent to be selected.
2120         // This is purely cosmetic.
2121         if (gtk_tree_selection_get_selected(selection, &store, &iter))
2122         {
2123                 if (gtk_tree_model_iter_parent (store, &piter, &iter))
2124                 {
2125                         GtkTreePath *path;
2126                         GtkTreeView *treeview;
2127                         
2128                         gtk_tree_selection_select_iter (selection, &piter);
2129                         path = gtk_tree_model_get_path (store, &piter);
2130                         treeview = gtk_tree_selection_get_tree_view (selection);
2131                         // Make the parent visible in scroll window if it is not.
2132                         gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
2133                         g_free(path);
2134                 }
2135         }
2136 }
2137
2138 static void
2139 add_to_queue_list(signal_user_data_t *ud, job_settings_t *item)
2140 {
2141         GtkTreeView *treeview;
2142         GtkTreeIter iter;
2143         GtkTreeStore *store;
2144         gchar *info;
2145         gint num_pass = 1;
2146         gint ii;
2147         GtkTreeIter citer;
2148         
2149         g_debug("update_queue_list ()\n");
2150         if (item == NULL) return;
2151         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2152         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2153                 
2154         gint title = ghb_settings_get_int(item->settings, "title");
2155         gint start_chapter = ghb_settings_get_int(item->settings, "start_chapter");
2156         gint end_chapter = ghb_settings_get_int(item->settings, "end_chapter");
2157         gboolean pass2 = ghb_settings_get_bool(item->settings, "two_pass");
2158         const gchar *vol_name = ghb_settings_get_string(item->settings, "volume_label");
2159         if (vol_name == NULL)
2160                 vol_name = "No Title";
2161         info = g_strdup_printf 
2162                 (
2163                  "<big><b>%s</b></big> (Title %d, Chapters %d through %d, %d Video %s)",
2164                  vol_name, title+1, start_chapter, end_chapter, 
2165                  pass2 ? 2:1, pass2 ? "Passes":"Pass");
2166
2167         gtk_tree_store_append(store, &iter, NULL);
2168         gtk_tree_store_set(store, &iter, 0, "hb-queue-job", 1, info, 2, "hb-queue-delete", -1);
2169         g_free(info);
2170         
2171         const gchar *vcodec = ghb_settings_get_option(item->settings, "video_codec");
2172         const gchar *container = ghb_settings_get_option(item->settings, "container");
2173         const gchar *acodec = ghb_settings_get_option(item->settings, "audio_codec");
2174         const gchar *dest = ghb_settings_get_string(item->settings, "destination");
2175         const gchar *preset = ghb_settings_get_string(item->settings, "preset");
2176         info = g_strdup_printf 
2177                 (
2178                  "<b>Preset:</b> %s\n"
2179                  "<b>Format:</b> %s Container, %s Video + %s Audio\n"
2180                  "<b>Destination:</b> %s",
2181                  preset, container, vcodec, acodec, dest);
2182
2183         gtk_tree_store_append(store, &citer, &iter);
2184         gtk_tree_store_set(store, &citer, 1, info, -1);
2185         g_free(info);
2186
2187         gint width = ghb_settings_get_int(item->settings, "scale_width");
2188         gint height = ghb_settings_get_int(item->settings, "scale_height");
2189         gboolean anamorphic = ghb_settings_get_bool(item->settings, "anamorphic");
2190         gboolean round_dim = ghb_settings_get_bool(item->settings, "round_dimensions");
2191         gboolean keep_aspect = ghb_settings_get_bool(item->settings, "keep_aspect");
2192         gchar *aspect_desc;
2193         if (anamorphic)
2194         {
2195                 if (round_dim)
2196                 {
2197                         aspect_desc = "(Anamorphic)";
2198                 }
2199                 else
2200                 {
2201                         aspect_desc = "(Strict Anamorphic)";
2202                 }
2203         }
2204         else
2205         {
2206                 if (keep_aspect)
2207                 {
2208                         aspect_desc = "(Aspect Preserved)";
2209                 }
2210                 else
2211                 {
2212                         aspect_desc = "(Aspect Lost)";
2213                 }
2214         }
2215         gboolean vqtype = ghb_settings_get_bool(item->settings, "vquality_type_constant");
2216         gint vqvalue = 0;
2217         gchar *vq_desc = "Error";
2218         if (!vqtype)
2219         {
2220                 vqtype = ghb_settings_get_bool(item->settings, "vquality_type_target");
2221                 if (!vqtype)
2222                 {
2223                         // Has to be bitrate
2224                         vqvalue = ghb_settings_get_int(item->settings, "video_bitrate");
2225                         vq_desc = "kbps";
2226                 }
2227                 else
2228                 {
2229                         // Target file size
2230                         vqvalue = ghb_settings_get_int(item->settings, "video_target");
2231                         vq_desc = "MB";
2232                 }
2233         }
2234         else
2235         {
2236                 // Constant quality
2237                 vqvalue = ghb_settings_get_int(item->settings, "video_quality");
2238                 vq_desc = "% Constant Quality";
2239         }
2240         const gchar *fps = ghb_settings_get_string(item->settings, "framerate");
2241         const gchar *vcodec_abbr = ghb_settings_get_short_opt(item->settings, "video_codec");
2242         gchar *extra_opts;
2243         if (strcmp(vcodec_abbr, "x264") == 0)
2244         {
2245                 gchar *x264opts = ghb_build_x264opts_string(item->settings);
2246                 g_debug("xopts (%s)\n", x264opts);
2247                 extra_opts = g_strdup_printf ("\n<b>x264 Options:</b> %s", x264opts);
2248                 g_free(x264opts);
2249         }
2250         else
2251         {
2252                 extra_opts = g_strdup("");
2253         }
2254         gboolean turbo = ghb_settings_get_bool (item->settings, "turbo");
2255         gchar *turbo_desc = "\n<b>Turbo:</b> Off";;
2256         if (turbo)
2257         {
2258                 turbo_desc = "\n<b>Turbo:</b> On";
2259         }
2260         num_pass = pass2 ? 2 : 1;
2261         for (ii = 0; ii < num_pass; ii++)
2262         {
2263                 gboolean final = (ii == (num_pass - 1));
2264                 GString *pass = g_string_new("");
2265                 g_string_append_printf( pass,
2266                         "<b>%s Pass</b>\n"
2267                         "<b>Picture:</b> %d x %d %s\n"
2268                         "<b>Video:</b> %s, %d %s, %s fps"
2269                         "%s",
2270                          ii ? "2nd":"1st", width, height, aspect_desc,
2271                          vcodec, vqvalue, vq_desc, fps, 
2272                          final ? extra_opts : turbo_desc);
2273
2274                 if (final)
2275                 {
2276                         // Add the audios
2277                         GSList *link = item->audio_settings;
2278                         while (link)
2279                         {
2280                                 GHashTable *asettings = (GHashTable*)link->data;
2281                                 const gchar *acodec = ghb_settings_get_option(asettings, "audio_codec");
2282                                 const gchar *bitrate = ghb_settings_get_string(asettings, "audio_bitrate");
2283                                 const gchar *samplerate = ghb_settings_get_string(asettings, "audio_sample_rate");
2284                                 gint track = ghb_settings_get_int(asettings, "audio_track");
2285                                 const gchar *mix = ghb_settings_get_option(asettings, "audio_mix");
2286                                 g_string_append_printf(pass,
2287                                         "\n<b>Audio:</b> %s, %s kbps, %s kHz, Track %d: %s",
2288                                          acodec, bitrate, samplerate, track+1, mix);
2289                                 link = link->next;
2290                         }
2291                 }
2292                 info = g_string_free(pass, FALSE);
2293                 gtk_tree_store_append(store, &citer, &iter);
2294                 gtk_tree_store_set(store, &citer, 0, ii ? "hb-queue-pass2" : "hb-queue-pass1", 1, info, -1);
2295                 g_free(info);
2296         }
2297         g_free(extra_opts);
2298 }
2299
2300 gboolean
2301 ghb_message_dialog(GtkMessageType type, const gchar *message, const gchar *no, const gchar *yes)
2302 {
2303         GtkWidget *dialog;
2304         GtkResponseType response;
2305                         
2306         // Toss up a warning dialog
2307         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2308                                                         type, GTK_BUTTONS_NONE,
2309                                                         message);
2310         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
2311                                                    no, GTK_RESPONSE_NO,
2312                                                    yes, GTK_RESPONSE_YES, NULL);
2313         response = gtk_dialog_run(GTK_DIALOG(dialog));
2314         gtk_widget_destroy (dialog);
2315         if (response == GTK_RESPONSE_NO)
2316         {
2317                 return FALSE;
2318         }
2319         return TRUE;
2320 }
2321
2322 static gint64
2323 estimate_file_size(signal_user_data_t *ud)
2324 {
2325         ghb_title_info_t tinfo;
2326         gint duration;
2327         gint bitrate;
2328         gint64 size;
2329         gint titleindex = ghb_settings_get_int(ud->settings, "title");
2330         if (titleindex < 0) return 0;
2331                         
2332         if (!ghb_get_title_info(&tinfo, titleindex)) return 0;
2333         duration = ((tinfo.hours*60)+tinfo.minutes)*60+tinfo.seconds;
2334         bitrate = ghb_guess_bitrate(ud->settings);
2335         size = (gint64)duration * (gint64)bitrate/8;
2336         return size;
2337 }
2338
2339 #define DISK_FREE_THRESH        (1024L*1024L*1024L*3)
2340
2341 static gboolean
2342 validate_settings(signal_user_data_t *ud)
2343 {
2344         // Check to see if the dest file exists or is
2345         // already in the queue
2346         gchar *message;
2347         gint titleindex = ghb_settings_get_int(ud->settings, "title");
2348         if (titleindex < 0) return FALSE;
2349         const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
2350         GSList *link = ud->queue;
2351         while (link != NULL)
2352         {
2353                 job_settings_t *item;
2354                 const gchar *filename;
2355                 item = (job_settings_t*)link->data;
2356                 filename = ghb_settings_get_string(item->settings, "destination");
2357                 if (strcmp(dest, filename) == 0)
2358                 {
2359                         message = g_strdup_printf(
2360                                                 "Destination: %s\n\n"
2361                                                 "Another queued job has specified the same destination.\n"
2362                                                 "Do you want to overwrite?",
2363                                                 dest);
2364                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
2365                         {
2366                                 g_free(message);
2367                                 return FALSE;
2368                         }
2369                         g_free(message);
2370                         break;
2371                 }
2372                 link = link->next;
2373         }
2374         gchar *destdir = g_path_get_dirname(dest);
2375         if (!g_file_test(destdir, G_FILE_TEST_IS_DIR))
2376         {
2377                 message = g_strdup_printf(
2378                                         "Destination: %s\n\n"
2379                                         "This is not a valid directory.",
2380                                         destdir);
2381                 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2382                 g_free(message);
2383                 g_free(destdir);
2384                 return FALSE;
2385         }
2386         if (g_access(destdir, R_OK|W_OK) != 0)
2387         {
2388                 message = g_strdup_printf(
2389                                         "Destination: %s\n\n"
2390                                         "Can not read or write the directory.",
2391                                         destdir);
2392                 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2393                 g_free(message);
2394                 g_free(destdir);
2395                 return FALSE;
2396         }
2397         GFile *gfile;
2398         GFileInfo *info;
2399         guint64 size;
2400         gchar *resolved = ghb_resolve_symlink(destdir);
2401
2402         gfile = g_file_new_for_path(resolved);
2403         info = g_file_query_filesystem_info(gfile, 
2404                                                 G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, NULL);
2405         if (info != NULL)
2406         {
2407                 if (g_file_info_has_attribute(info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE))
2408                 {
2409                         size = g_file_info_get_attribute_uint64(info, 
2410                                                                         G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
2411                         
2412                         gint64 fsize = estimate_file_size(ud);
2413                         if (size < fsize)
2414                         {
2415                                 message = g_strdup_printf(
2416                                                         "Destination filesystem is almost full: %uM free\n\n"
2417                                                         "Encode may be incomplete if you proceed.\n",
2418                                                         (guint)(size / (1024L*1024L)));
2419                                 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Proceed"))
2420                                 {
2421                                         g_free(message);
2422                                         return FALSE;
2423                                 }
2424                                 g_free(message);
2425                         }
2426                 }
2427                 g_object_unref(info);
2428         }
2429         g_object_unref(gfile);
2430         g_free(resolved);
2431         g_free(destdir);
2432         if (g_file_test(dest, G_FILE_TEST_EXISTS))
2433         {
2434                 message = g_strdup_printf(
2435                                         "Destination: %s\n\n"
2436                                         "File already exhists.\n"
2437                                         "Do you want to overwrite?",
2438                                         dest);
2439                 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
2440                 {
2441                         g_free(message);
2442                         return FALSE;
2443                 }
2444                 g_free(message);
2445                 g_unlink(dest);
2446         }
2447         // Validate video quality is in a reasonable range
2448         if (!ghb_validate_vquality(ud->settings))
2449         {
2450                 return FALSE;
2451         }
2452         // Validate audio settings
2453         if (!ghb_validate_audio(ud))
2454         {
2455                 return FALSE;
2456         }
2457         // Validate video settings
2458         if (!ghb_validate_video(ud))
2459         {
2460                 return FALSE;
2461         }
2462         // Validate container settings
2463         if (!ghb_validate_container(ud))
2464         {
2465                 return FALSE;
2466         }
2467         audio_list_refresh(ud);
2468         return TRUE;
2469 }
2470
2471 static gboolean
2472 queue_add(signal_user_data_t *ud)
2473 {
2474         // Add settings to the queue
2475         job_settings_t *queue_item;
2476         GSList *link;
2477         static gint unique_id = 0;
2478         
2479         g_debug("queue_add ()\n");
2480         if (!validate_settings(ud))
2481         {
2482                 return FALSE;
2483         }
2484         // Make a copy of current settings to be used for the new job
2485         queue_item = g_malloc(sizeof(job_settings_t));
2486         queue_item->settings = ghb_settings_dup(ud->settings);
2487         queue_item->audio_settings = NULL;
2488         link = ud->audio_settings;
2489         while (link != NULL)
2490         {
2491                 GHashTable *asettings;
2492                 asettings = ghb_settings_dup((GHashTable*)link->data);
2493                 queue_item->audio_settings =
2494                         g_slist_append(queue_item->audio_settings, asettings);
2495                 link = g_slist_next(link);
2496         }
2497         queue_item->chapter_list = g_strdupv(ud->chapter_list);
2498         ud->queue = g_slist_append(ud->queue, queue_item);
2499         add_to_queue_list(ud, queue_item);
2500         ghb_add_job (queue_item, unique_id);
2501         queue_item->unique_id = unique_id;
2502         queue_item->status = GHB_QUEUE_PENDING;
2503         unique_id++;
2504         return TRUE;
2505 }
2506
2507 void
2508 queue_add_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
2509 {
2510         g_debug("queue_add_clicked_cb ()\n");
2511         queue_add(ud);
2512 }
2513
2514 static gboolean
2515 cancel_encode(const gchar *extra_msg)
2516 {
2517         GtkWidget *dialog;
2518         GtkResponseType response;
2519         
2520         if (extra_msg == NULL) extra_msg = "";
2521         // Toss up a warning dialog
2522         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2523                                 GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
2524                                 "%sYour movie will be lost if you don't continue encoding.",
2525                                 extra_msg);
2526         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
2527                                                    "Continue Encoding", GTK_RESPONSE_NO,
2528                                                    "Stop Encoding", GTK_RESPONSE_YES, NULL);
2529         response = gtk_dialog_run(GTK_DIALOG(dialog));
2530         gtk_widget_destroy (dialog);
2531         if (response == GTK_RESPONSE_NO) return FALSE;
2532         ghb_stop_queue();
2533         return TRUE;
2534 }
2535
2536 void
2537 queue_remove_clicked_cb(GtkWidget *widget, gchar *path, signal_user_data_t *ud)
2538 {
2539         GtkTreeView *treeview;
2540         GtkTreePath *treepath;
2541         GtkTreeModel *store;
2542         GtkTreeIter iter;
2543         gint row;
2544         GSList *link;
2545         gint *indices;
2546         job_settings_t *queue_item;
2547         gint unique_id;
2548
2549         g_debug("queue_remove_clicked_cb ()\n");
2550         g_debug("ud %p\n", ud);
2551         g_debug("ud->builder %p\n", ud->builder);
2552
2553         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2554         store = gtk_tree_view_get_model(treeview);
2555         treepath = gtk_tree_path_new_from_string (path);
2556         if (gtk_tree_model_get_iter(store, &iter, treepath))
2557         {
2558                 // Find the entry in the queue
2559                 indices = gtk_tree_path_get_indices (treepath);
2560                 row = indices[0];
2561                 // Can only free the treepath After getting what I need from
2562                 // indices since this points into treepath somewhere.
2563                 gtk_tree_path_free (treepath);
2564                 if (row < 0) return;
2565                 link = g_slist_nth(ud->queue, row);
2566                 if (link == NULL) return;
2567                 queue_item = (job_settings_t*)link->data;
2568                 if (queue_item->status == GHB_QUEUE_RUNNING)
2569                 {
2570                         // Ask if wants to stop encode.
2571                         if (!cancel_encode(NULL))
2572                         {
2573                                 return;
2574                         }
2575                 }
2576                 // Remove the selected item
2577                 g_debug(" should be removing from treestore\n");
2578                 gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
2579                 // Remove the corresponding item from the queue list
2580                 ud->queue = g_slist_remove_link(ud->queue, link);
2581                 g_slist_free_1(link);
2582                 g_hash_table_destroy(queue_item->settings);
2583                 link = queue_item->audio_settings;
2584                 while (link != NULL)
2585                 {
2586                         GSList *nextlink;
2587                         g_hash_table_destroy((GHashTable*)link->data);
2588                         nextlink = g_slist_next(link);
2589                         g_slist_free_1(link);
2590                         link = nextlink;
2591                 }
2592                 g_strfreev (queue_item->chapter_list);
2593                 unique_id = queue_item->unique_id;
2594                 g_free(queue_item);
2595                 ghb_remove_job(unique_id);
2596         }
2597         else
2598         {       
2599                 gtk_tree_path_free (treepath);
2600         }
2601 }
2602
2603 static gint
2604 find_queue_item(GSList *queue, gint unique_id, job_settings_t **job)
2605 {
2606         job_settings_t *js;
2607         gint index = -1;
2608         
2609         while (queue != NULL)
2610         {
2611                 index++;
2612                 js = (job_settings_t*)queue->data;
2613                 if (js->unique_id == unique_id)
2614                 {
2615                         *job = js;
2616                         return index;
2617                 }
2618                 queue = queue->next;
2619         }
2620         *job = NULL;
2621         return index;
2622 }
2623
2624 static void
2625 queue_buttons_grey(signal_user_data_t *ud, gboolean working)
2626 {
2627         GtkWidget *widget;
2628         GtkAction *action;
2629         gint titleindex = ghb_settings_get_int(ud->settings, "title");
2630         gboolean title_ok = (titleindex >= 0);
2631         widget = GHB_WIDGET (ud->builder, "queue_start1");
2632         gtk_widget_set_sensitive (widget, !working && title_ok);
2633         widget = GHB_WIDGET (ud->builder, "queue_start2");
2634         gtk_widget_set_sensitive (widget, !working && title_ok);
2635         action = GHB_ACTION (ud->builder, "queue_start_menu");
2636         gtk_action_set_sensitive (action, !working && title_ok);
2637         widget = GHB_WIDGET (ud->builder, "queue_pause1");
2638         gtk_widget_set_sensitive (widget, working);
2639         widget = GHB_WIDGET (ud->builder, "queue_pause2");
2640         gtk_widget_set_sensitive (widget, working);
2641         action = GHB_ACTION (ud->builder, "queue_pause_menu");
2642         gtk_action_set_sensitive (action, working);
2643         widget = GHB_WIDGET (ud->builder, "queue_stop");
2644         gtk_widget_set_sensitive (widget, working);
2645         action = GHB_ACTION (ud->builder, "queue_stop_menu");
2646         gtk_action_set_sensitive (action, working);
2647 }
2648
2649 void queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud);
2650
2651 static void
2652 ghb_backend_events(signal_user_data_t *ud)
2653 {
2654         ghb_status_t status;
2655         gchar *status_str;
2656         GtkProgressBar *progress;
2657         gint titleindex;
2658         job_settings_t *js;
2659         static gint current_id = -1;
2660         gint index;
2661         GtkTreeView *treeview;
2662         GtkTreeStore *store;
2663         GtkTreeIter iter;
2664         static gint working = 0;
2665         static gboolean work_started = FALSE;
2666         
2667         ghb_track_status();
2668         ghb_get_status(&status);
2669         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2670         if (status.state & GHB_STATE_SCANNING)
2671         {
2672                 status_str = g_strdup_printf ("Scanning title %d of %d...", 
2673                                                                   status.title_cur, status.title_count );
2674                 gtk_progress_bar_set_text (progress, status_str);
2675                 g_free(status_str);
2676                 if (status.title_count > 0)
2677                 {
2678                         gtk_progress_bar_set_fraction (progress, 
2679                                 (gdouble)status.title_cur / status.title_count);
2680                 }
2681         }
2682         else if (status.state & GHB_STATE_SCANDONE)
2683         {
2684                 status_str = g_strdup_printf ("Scan done"); 
2685                 gtk_progress_bar_set_text (progress, status_str);
2686                 g_free(status_str);
2687                 gtk_progress_bar_set_fraction (progress, 1.0);
2688
2689                 ghb_title_info_t tinfo;
2690                         
2691                 ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE);
2692                 titleindex = ghb_longest_title();
2693                 ghb_ui_update_int(ud, "title", titleindex);
2694
2695                 // Are there really any titles.
2696                 if (!ghb_get_title_info(&tinfo, titleindex))
2697                 {
2698                         GtkProgressBar *progress;
2699                         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2700                         gtk_progress_bar_set_fraction (progress, 0);
2701                         gtk_progress_bar_set_text (progress, "No Source");
2702                 }
2703                 ghb_clear_state(GHB_STATE_SCANDONE);
2704                 queue_buttons_grey(ud, (0 != (status.state & GHB_STATE_WORKING)));
2705         }
2706         else if (status.state & GHB_STATE_WORKING)
2707         {
2708                 if(status.seconds > -1)
2709                 {
2710                         status_str= g_strdup_printf(
2711                                 "Encoding: task %d of %d, %.2f %%"
2712                                 " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)",
2713                                 status.job_cur, status.job_count, 
2714                                 100.0 * status.progress,
2715                                 status.rate_cur, status.rate_avg, status.hours, 
2716                                 status.minutes, status.seconds );
2717                 }
2718                 else
2719                 {
2720                         status_str= g_strdup_printf(
2721                                 "Encoding: task %d of %d, %.2f %%",
2722                                 status.job_cur, status.job_count, 
2723                                 100.0 * status.progress );
2724                 }
2725                 gtk_progress_bar_set_text (progress, status_str);
2726                 gtk_progress_bar_set_fraction (progress, status.progress);
2727                 g_free(status_str);
2728         }
2729         else if (status.state & GHB_STATE_WORKDONE)
2730         {
2731                 work_started = FALSE;
2732                 queue_buttons_grey(ud, FALSE);
2733                 index = find_queue_item(ud->queue, current_id, &js);
2734                 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2735                 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2736                 switch( status.error )
2737                 {
2738                         case GHB_ERROR_NONE:
2739                                 gtk_progress_bar_set_text( progress, "Rip done!" );
2740                                 if (js != NULL)
2741                                 {
2742                                         js->status = GHB_QUEUE_DONE;
2743                                         gchar *path = g_strdup_printf ("%d", index);
2744                                         if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2745                                         {
2746                                                 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
2747                                         }
2748                                         g_free(path);
2749                                 }
2750                                 break;
2751                         case GHB_ERROR_CANCELED:
2752                                 gtk_progress_bar_set_text( progress, "Rip canceled." );
2753                                 if (js != NULL)
2754                                 {
2755                                         js->status = GHB_QUEUE_CANCELED;
2756                                         gchar *path = g_strdup_printf ("%d", index);
2757                                         if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2758                                         {
2759                                                 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
2760                                         }
2761                                         g_free(path);
2762                                 }
2763                                 break;
2764                         default:
2765                                 gtk_progress_bar_set_text( progress, "Rip failed.");
2766                                 if (js != NULL)
2767                                 {
2768                                         js->status = GHB_QUEUE_CANCELED;
2769                                         gchar *path = g_strdup_printf ("%d", index);
2770                                         if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2771                                         {
2772                                                 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
2773                                         }
2774                                         g_free(path);
2775                                 }
2776                 }
2777                 current_id = -1;
2778                 gtk_progress_bar_set_fraction (progress, 1.0);
2779                 ghb_clear_state(GHB_STATE_WORKDONE);
2780         }
2781         else if (status.state & GHB_STATE_PAUSED)
2782         {
2783                 status_str = g_strdup_printf ("Paused"); 
2784                 gtk_progress_bar_set_text (progress, status_str);
2785                 g_free(status_str);
2786         }
2787         else if (status.state & GHB_STATE_MUXING)
2788         {
2789                 gtk_progress_bar_set_text(progress, "Muxing: this may take awhile...");
2790         }
2791         if (status.state & GHB_STATE_WORKING)
2792         {
2793                 if (!work_started)
2794                 {
2795                         work_started = TRUE;
2796                         queue_buttons_grey(ud, TRUE);
2797                 }
2798                 if (status.unique_id != current_id)
2799                 {
2800                         index = find_queue_item(ud->queue, current_id, &js);
2801                         if (js != NULL)
2802                         {
2803                                 js->status = GHB_QUEUE_DONE;
2804                                 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2805                                 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2806                                 gchar *path = g_strdup_printf ("%d", index);
2807                                 if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2808                                 {
2809                                         gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
2810                                 }
2811                                 g_free(path);
2812                         }
2813
2814                         index = find_queue_item(ud->queue, status.unique_id, &js);
2815                         if (js != NULL)
2816                         {
2817                                 js->status = GHB_QUEUE_RUNNING;
2818                                 current_id = status.unique_id;
2819                         }
2820                 }
2821                 index = find_queue_item(ud->queue, status.unique_id, &js);
2822                 if (index >= 0)
2823                 {
2824                         gchar working_icon[] = "hb-working0";
2825                         working_icon[10] = '0' + working;
2826                         working = (working+1) % 6;
2827                         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2828                         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2829                         gchar *path = g_strdup_printf ("%d", index);
2830                         if (gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(store), &iter, path))
2831                         {
2832                                 gtk_tree_store_set(store, &iter, 0, working_icon, -1);
2833                         }
2834                         g_free(path);
2835                 }
2836         }
2837 }
2838
2839 gboolean
2840 ghb_timer_cb(gpointer data)
2841 {
2842         signal_user_data_t *ud = (signal_user_data_t*)data;
2843
2844         ghb_backend_events(ud);
2845         if (update_default_destination)
2846         {
2847                 const gchar *dest = ghb_settings_get_string(ud->settings, "destination");
2848                 gchar *dest_dir = g_path_get_dirname (dest);
2849                 const gchar *def_dest = ghb_settings_get_string(ud->settings, "destination_dir");
2850                 if (strcmp(dest_dir, def_dest) != 0)
2851                 {
2852                         ghb_settings_set_string (ud->settings, "destination_dir", dest_dir);
2853                         ghb_pref_save (ud->settings, "destination_dir");
2854                 }
2855                 update_default_destination = FALSE;
2856         }
2857         if (update_preview)
2858         {
2859                 set_preview_image (ud);
2860                 update_preview = FALSE;
2861         }
2862         return TRUE;
2863 }
2864
2865 gboolean
2866 ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
2867 {
2868         gchar *text = NULL;
2869         gsize length;
2870         GtkTextView *textview;
2871         GtkTextBuffer *buffer;
2872         GtkTextIter iter;
2873         GtkTextMark *mark;
2874         GError *gerror = NULL;
2875         GIOStatus status;
2876         
2877         signal_user_data_t *ud = (signal_user_data_t*)data;
2878
2879         status = g_io_channel_read_line (source, &text, &length, NULL, &gerror);
2880         if (text != NULL)
2881         {
2882                 GdkWindow *window;
2883                 gint width, height;
2884                 gint x, y;
2885                 gboolean bottom = FALSE;
2886
2887                 textview = GTK_TEXT_VIEW(GHB_WIDGET (ud->builder, "activity_view"));
2888                 buffer = gtk_text_view_get_buffer (textview);
2889                 // I would like to auto-scroll the window when the scrollbar
2890                 // is at the bottom, 
2891                 // must determining whether the insert point is at
2892                 // the bottom of the window 
2893                 window = gtk_text_view_get_window(textview, GTK_TEXT_WINDOW_TEXT);
2894                 if (window != NULL)
2895                 {
2896                         gdk_drawable_get_size(GDK_DRAWABLE(window), &width, &height);
2897                         gtk_text_view_window_to_buffer_coords(textview, 
2898                                 GTK_TEXT_WINDOW_TEXT, width, height, &x, &y);
2899                         gtk_text_view_get_iter_at_location(textview, &iter, x, y);
2900                         if (gtk_text_iter_is_end(&iter))
2901                         {
2902                                 bottom = TRUE;
2903                         }
2904                 }
2905                 else
2906                 {
2907                         // If the window isn't available, assume bottom
2908                         bottom = TRUE;
2909                 }
2910                 gtk_text_buffer_get_end_iter(buffer, &iter);
2911                 gtk_text_buffer_insert(buffer, &iter, text, -1);
2912                 if (bottom)
2913                 {
2914                         //gtk_text_view_scroll_to_iter(textview, &iter, 0, FALSE, 0, 0);
2915                         mark = gtk_text_buffer_get_insert (buffer);
2916                         gtk_text_view_scroll_mark_onscreen(textview, mark);
2917                 }
2918                 g_io_channel_write_chars (ud->activity_log, text, length, &length, NULL);
2919                 g_free(text);
2920         }
2921         if (status != G_IO_STATUS_NORMAL)
2922         {
2923                 // This should never happen, but if it does I would get into an
2924                 // infinite loop.  Returning false removes this callback.
2925                 g_warning("Error while reading activity from pipe\n");
2926                 if (gerror != NULL)
2927                 {
2928                         g_warning("%s\n", gerror->message);
2929                         g_error_free (gerror);
2930                 }
2931                 return FALSE;
2932         }
2933         if (gerror != NULL)
2934                 g_error_free (gerror);
2935         return TRUE;
2936 }
2937
2938 void
2939 about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2940 {
2941         GtkWidget *widget = GHB_WIDGET (ud->builder, "hb_about");
2942         gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(widget), ghb_version());
2943         gtk_widget_show (widget);
2944 }
2945
2946 void
2947 guide_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2948 {
2949         gboolean result;
2950         char *argv[] = 
2951                 {"xdg-open","http://trac.handbrake.fr/wiki/HandBrakeGuide",NULL,NULL};
2952         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2953                                 NULL, NULL, NULL);
2954         if (result) return;
2955
2956         argv[0] = "gnome-open";
2957         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2958                                 NULL, NULL, NULL);
2959         if (result) return;
2960
2961         argv[0] = "kfmclient";
2962         argv[1] = "exec";
2963         argv[2] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2964         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2965                                 NULL, NULL, NULL);
2966         if (result) return;
2967
2968         argv[0] = "firefox";
2969         argv[1] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2970         argv[2] = NULL;
2971         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2972                                 NULL, NULL, NULL);
2973         if (result) return;
2974 }
2975
2976 void
2977 hb_about_response_cb(GtkWidget *widget, gint response, signal_user_data_t *ud)
2978 {
2979         gtk_widget_hide (widget);
2980 }
2981
2982 void
2983 show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2984 {
2985         GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
2986         gtk_widget_show (widget);
2987 }
2988
2989 void
2990 show_queue_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2991 {
2992         GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
2993         gtk_widget_show (widget);
2994 }
2995
2996 void
2997 show_presets_toggled_cb(GtkToggleButton *button, signal_user_data_t *ud)
2998 {
2999         GtkWidget *widget;
3000         GtkWindow *hb_window;
3001         
3002         g_debug("show_presets_clicked_cb ()\n");
3003         widget = GHB_WIDGET (ud->builder, "presets_frame");
3004         if (gtk_toggle_button_get_active(button))
3005         {
3006                 gtk_widget_show_now(widget);
3007         }
3008         else
3009         {
3010                 gtk_widget_hide(widget);
3011                 hb_window = GTK_WINDOW(GHB_WIDGET (ud->builder, "hb_window"));
3012                 gtk_window_resize(hb_window, 16, 16);
3013         }
3014         ghb_widget_to_setting(ud->settings, GTK_WIDGET(button));
3015         ghb_pref_save(ud->settings, "show_presets");
3016 }
3017
3018 void
3019 presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
3020 {
3021         GtkTreeView *treeview;
3022         GtkTreeSelection *selection;
3023         GtkTreeModel *store;
3024         GtkTreeIter iter;
3025         
3026         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
3027         selection = gtk_tree_view_get_selection(treeview);
3028         if (gtk_tree_selection_get_selected(selection, &store, &iter))
3029         {
3030                 GtkTreePath *path;
3031                 path = gtk_tree_model_get_path (store, &iter);
3032                 // Make the parent visible in scroll window if it is not.
3033                 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
3034                 g_free(path);
3035         }
3036 }
3037
3038 static void
3039 update_chapter_list(signal_user_data_t *ud)
3040 {
3041         GtkTreeView *treeview;
3042         GtkTreeIter iter;
3043         GtkListStore *store;
3044         gboolean done;
3045         gchar **chapters;
3046         gint titleindex, ii;
3047         
3048         g_debug("update_chapter_list ()\n");
3049         titleindex = ghb_settings_get_index(ud->settings, "title");
3050         chapters = ghb_get_chapters(titleindex);
3051         if (ud->chapter_list != NULL)
3052                 g_strfreev (ud->chapter_list);
3053         ud->chapter_list = chapters;
3054         
3055         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
3056         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
3057         ii = 0;
3058         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
3059         {
3060                 do
3061                 {
3062                         if (chapters != NULL && chapters[ii])
3063                         {
3064                                 // Update row with settings data
3065                                 g_debug("Updating row\n");
3066                                 gtk_list_store_set(store, &iter, 
3067                                         0, ii+1,
3068                                         1, chapters[ii],
3069                                         2, TRUE,
3070                                         -1);
3071                                 ii++;
3072                                 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
3073                         }
3074                         else
3075                         {
3076                                 // No more settings data, remove row
3077                                 g_debug("Removing row\n");
3078                                 done = !gtk_list_store_remove(store, &iter);
3079                         }
3080                 } while (!done);
3081         }
3082         while (chapters != NULL && chapters[ii])
3083         {
3084                 // Additional settings, add row
3085                 g_debug("Adding row\n");
3086                 g_debug("%d -- %s\n", ii, chapters[ii]);
3087                 gtk_list_store_append(store, &iter);
3088                 gtk_list_store_set(store, &iter, 
3089                         0, ii+1,
3090                         1, chapters[ii],
3091                         2, TRUE,
3092                         -1);
3093                 ii++;
3094         }
3095 }
3096
3097 void
3098 chapter_edited_cb(GtkCellRendererText *cell, gchar *path, gchar *text, signal_user_data_t *ud)
3099 {
3100         GtkTreePath *treepath;
3101         GtkListStore *store;
3102         GtkTreeView *treeview;
3103         GtkTreeViewColumn *column;
3104         GtkTreeIter iter;
3105         gint index;
3106         
3107         g_debug("chapter_edited_cb ()\n");
3108         g_debug("path (%s)\n", path);
3109         g_debug("text (%s)\n", text);
3110         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
3111         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
3112         treepath = gtk_tree_path_new_from_string (path);
3113         gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
3114         gtk_tree_path_free (treepath);
3115         gtk_list_store_set(store, &iter, 
3116                 1, text,
3117                 2, TRUE,
3118                 -1);
3119         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &index, -1);
3120         g_free(ud->chapter_list[index-1]);
3121         ud->chapter_list[index-1] = g_strdup(text);
3122         if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
3123         {
3124                 column = gtk_tree_view_get_column(treeview, 1);
3125                 treepath = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
3126                 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
3127                 gtk_tree_path_free (treepath);
3128         }
3129 }
3130
3131 void
3132 chapter_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
3133 {
3134         GtkTreeModel *store;
3135         GtkTreeIter iter;
3136         
3137         g_debug("chapter_list_selection_changed_cb ()\n");
3138         if (gtk_tree_selection_get_selected(selection, &store, &iter))
3139         {
3140                 // What to do??
3141         }
3142 }
3143
3144 void
3145 queue_list_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, GtkCellRenderer *cell)
3146 {
3147         GtkTreeViewColumn *column;
3148         gint width;
3149         
3150         column = gtk_tree_view_get_column (GTK_TREE_VIEW(widget), 0);
3151         width = gtk_tree_view_column_get_width(column);
3152         g_debug("col width %d alloc width %d\n", width, allocation->width);
3153         // Set new wrap-width.  Shave a little off to accomidate the icons
3154         // that share this column.
3155         if (width >= 564) // Don't allow below a certain size
3156                 g_object_set(cell, "wrap-width", width-70, NULL);
3157 }
3158
3159 void
3160 preview_button_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3161 {
3162         gint titleindex = ghb_settings_get_int(ud->settings, "title");
3163         if (titleindex < 0) return;
3164         g_debug("titleindex %d\n", titleindex);
3165
3166         GtkWidget *widget = GHB_WIDGET (ud->builder, "preview_window");
3167         gtk_widget_show (widget);
3168 }
3169
3170 void
3171 preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3172 {
3173         set_preview_image(ud);
3174 }
3175
3176 void
3177 preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
3178 {
3179         g_debug("-------------------------------allocate %d x %d\n", allocation->width, allocation->height);
3180         if (preview_button_width == allocation->width &&
3181                 preview_button_height == allocation->height)
3182         {
3183                 // Nothing to do. Bug out.
3184                 g_debug("nothing to do\n");
3185                 return;
3186         }
3187         g_debug("-------------------------------prev allocate %d x %d\n", preview_button_width, preview_button_height);
3188         preview_button_width = allocation->width;
3189         preview_button_height = allocation->height;
3190         set_preview_image(ud);
3191 }
3192
3193 void
3194 queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3195 {
3196         GSList *link = ud->queue;
3197         job_settings_t *job;
3198         gboolean running = FALSE;
3199         while (link != NULL)
3200         {
3201                 job = (job_settings_t*)link->data;
3202                 if ((job->status == GHB_QUEUE_RUNNING) || 
3203                         (job->status == GHB_QUEUE_PENDING))
3204                 {
3205                         running = TRUE;
3206                         break;
3207                 }
3208                 link = link->next;
3209         }
3210         if (!running)
3211         {
3212                 // The queue has no running or pending jobs.
3213                 // Add current settings to the queue, then run.
3214                 if (!queue_add(ud))
3215                         return;
3216         }
3217         ghb_start_queue();
3218 }
3219
3220 void
3221 queue_stop_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3222 {
3223         cancel_encode(NULL);
3224 }
3225
3226 void
3227 queue_pause_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3228 {
3229         ghb_pause_queue();
3230 }
3231
3232 void
3233 presets_default_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3234 {
3235         ghb_set_preset_default(ud->settings);
3236         ghb_presets_list_update(ud);
3237 }
3238
3239 void
3240 debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data)
3241 {
3242         signal_user_data_t *ud = (signal_user_data_t*)data;
3243         
3244         if (ud->debug)
3245         {
3246                 printf("%s: %s\n", domain, msg);
3247         }
3248 }
3249
3250 static void
3251 set_visible(GtkWidget *widget, gboolean visible)
3252 {
3253         if (visible)
3254         {
3255                 gtk_widget_show_now(widget);
3256         }
3257         else
3258         {
3259                 gtk_widget_hide(widget);
3260         }
3261 }
3262
3263 void
3264 ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
3265 {
3266         GtkWidget *widget;
3267         g_debug("ghb_hbfd\n");
3268         widget = GHB_WIDGET(ud->builder, "queue_pause1");
3269         set_visible(widget, !hbfd);
3270         widget = GHB_WIDGET(ud->builder, "queue_add");
3271         set_visible(widget, !hbfd);
3272         widget = GHB_WIDGET(ud->builder, "show_queue");
3273         set_visible(widget, !hbfd);
3274         widget = GHB_WIDGET(ud->builder, "show_activity");
3275         set_visible(widget, !hbfd);
3276
3277         widget = GHB_WIDGET(ud->builder, "chapter_box");
3278         set_visible(widget, !hbfd);
3279         widget = GHB_WIDGET(ud->builder, "container_box");
3280         set_visible(widget, !hbfd);
3281         widget = GHB_WIDGET(ud->builder, "settings_box");
3282         set_visible(widget, !hbfd);
3283         widget = GHB_WIDGET(ud->builder, "presets_save");
3284         set_visible(widget, !hbfd);
3285         widget = GHB_WIDGET(ud->builder, "presets_remove");
3286         set_visible(widget, !hbfd);
3287         widget = GHB_WIDGET(ud->builder, "presets_default");
3288         set_visible(widget, !hbfd);
3289         widget = GHB_WIDGET (ud->builder, "hb_window");
3290         gtk_window_resize(GTK_WINDOW(widget), 16, 16);
3291
3292 }
3293
3294 void
3295 hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
3296 {
3297         g_debug("hbfd_toggled_cb\n");
3298         ghb_widget_to_setting (ud->settings, widget);
3299         gboolean hbfd = ghb_settings_get_bool(ud->settings, "hbfd");
3300         ghb_hbfd(ud, hbfd);
3301         ghb_pref_save(ud->settings, "hbfd");
3302 }
3303
3304 void
3305 pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3306 {
3307         g_debug("pref_changed_cb\n");
3308         ghb_widget_to_setting (ud->settings, widget);
3309         const gchar *name = gtk_widget_get_name(widget);
3310         ghb_pref_save(ud->settings, name);
3311 }
3312
3313 void
3314 ghb_file_menu_add_dvd(signal_user_data_t *ud)
3315 {
3316         GList *link, *drives;
3317
3318         GtkActionGroup *agroup = GTK_ACTION_GROUP(
3319                 gtk_builder_get_object(ud->builder, "actiongroup1"));
3320         GtkUIManager *ui = GTK_UI_MANAGER(
3321                 gtk_builder_get_object(ud->builder, "uimanager1"));
3322         guint merge_id = gtk_ui_manager_new_merge_id(ui);
3323
3324         link = drives = dvd_device_list();
3325         while (link != NULL)
3326         {
3327                 gchar *name = (gchar*)link->data;
3328                 // Create action for this drive
3329                 GtkAction *action = gtk_action_new(name, name,
3330                         "Scan this DVD source", "gtk-cdrom");
3331                 // Add action to action group
3332                 gtk_action_group_add_action_with_accel(agroup, action, "");
3333                 // Add to ui manager
3334                 gtk_ui_manager_add_ui(ui, merge_id, 
3335                         "ui/menubar1/menuitem1/quit1", name, name,
3336                         GTK_UI_MANAGER_AUTO, TRUE);
3337                 // Connect signal to action (menu item)
3338                 g_signal_connect(action, "activate", 
3339                         (GCallback)dvd_source_activate_cb, ud);
3340                 g_free(name);
3341                 link = link->next;
3342         }
3343         g_list_free(drives);
3344
3345         // Add separator
3346         gtk_ui_manager_add_ui(ui, merge_id, 
3347                 "ui/menubar1/menuitem1/quit1", "", NULL,
3348                 GTK_UI_MANAGER_AUTO, TRUE);
3349 }
3350
3351 gboolean ghb_is_cd(GDrive *gd);
3352
3353 static GList*
3354 dvd_device_list()
3355 {
3356         GVolumeMonitor *gvm;
3357         GList *drives, *link;
3358         GList *dvd_devices = NULL;
3359         
3360         gvm = g_volume_monitor_get ();
3361         drives = g_volume_monitor_get_connected_drives (gvm);
3362         link = drives;
3363         while (link != NULL)
3364         {
3365                 GDrive *gd;
3366                 
3367                 gd = (GDrive*)link->data;
3368                 if (ghb_is_cd(gd))
3369                 {
3370                         gchar *device;
3371                         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3372                         dvd_devices = g_list_append(dvd_devices, (gpointer)device);
3373                 }
3374                 g_object_unref (gd);
3375                 link = link->next;
3376         }
3377         g_list_free(drives);
3378         return dvd_devices;
3379 }
3380
3381
3382 static DBusConnection *dbus_connection = NULL;
3383 static LibHalContext *hal_ctx;
3384
3385 gboolean
3386 ghb_is_cd(GDrive *gd)
3387 {
3388         gchar *device;
3389         LibHalDrive *halDrive;
3390         LibHalDriveType dtype;
3391
3392         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3393         halDrive = libhal_drive_from_device_file (hal_ctx, device);
3394         dtype = libhal_drive_get_type(halDrive);
3395         g_free(device);
3396         return (dtype == LIBHAL_DRIVE_TYPE_CDROM);
3397 }
3398
3399 void
3400 drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
3401 {
3402         gchar *device;
3403         gint state = ghb_get_state();
3404         static gboolean first_time = TRUE;
3405
3406         if (ud->current_dvd_device == NULL) return;
3407         // A drive change event happens when the program initially starts
3408         // and I don't want to automatically scan at that time.
3409         if (first_time)
3410         {
3411                 first_time = FALSE;
3412                 return;
3413         }
3414         if (state != GHB_STATE_IDLE) return;
3415         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3416         
3417         // DVD insertion detected.  Scan it.
3418         if (strcmp(device, ud->current_dvd_device) == 0)
3419         {
3420                 if (g_drive_has_media (gd))
3421                 {
3422                         GtkProgressBar *progress;
3423                         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
3424                         gtk_progress_bar_set_text (progress, "Scanning ...");
3425                         gtk_progress_bar_set_fraction (progress, 0);
3426                         update_source_label(ud, device);
3427                         ghb_hb_cleanup(TRUE);
3428                         ghb_backend_scan(device, 0);
3429                 }
3430                 else
3431                 {
3432                         ghb_hb_cleanup(TRUE);
3433                         ghb_backend_scan("/dev/null", 0);
3434                 }
3435         }
3436         g_free(device);
3437 }
3438
3439
3440 static gboolean
3441 dbus_init (void)
3442 {
3443     DBusError error;
3444
3445     if (dbus_connection != NULL)
3446         return TRUE;
3447
3448     dbus_error_init (&error);
3449     if (!(dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) {
3450         g_debug ("could not get system bus: %s\n", error.message);
3451         dbus_error_free (&error);
3452         return FALSE;
3453     }
3454
3455     //dbus_connection_setup_with_g_main (dbus_connection, NULL);
3456     //dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
3457     //dbus_connection_add_filter (dbus_connection, gvm_dbus_filter_function, NULL, NULL);
3458
3459     return TRUE;
3460 }
3461
3462 void
3463 ghb_hal_init()
3464 {
3465     DBusError error;
3466     char **devices;
3467     int nr;
3468
3469     if (!dbus_init ())
3470         return;
3471
3472     if (!(hal_ctx = libhal_ctx_new ())) {
3473         g_warning ("failed to create a HAL context!");
3474         return;
3475     }
3476
3477     libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
3478     dbus_error_init (&error);
3479     if (!libhal_ctx_init (hal_ctx, &error)) {
3480         g_warning ("libhal_ctx_init failed: %s", error.message ? error.message : "unknown");
3481         dbus_error_free (&error);
3482         libhal_ctx_free (hal_ctx);
3483         return;
3484     }
3485
3486     /*
3487      * Do something to ping the HAL daemon - the above functions will
3488      * succeed even if hald is not running, so long as DBUS is.  But we
3489      * want to exit silently if hald is not running, to behave on
3490      * pre-2.6 systems.
3491      */
3492     if (!(devices = libhal_get_all_devices (hal_ctx, &nr, &error))) {
3493         g_warning ("seems that HAL is not running: %s", error.message ? error.message : "unknown");
3494         dbus_error_free (&error);
3495
3496         libhal_ctx_shutdown (hal_ctx, NULL);
3497         libhal_ctx_free (hal_ctx);
3498         return;
3499     }
3500
3501     libhal_free_string_array (devices);
3502
3503     //gvm_hal_claim_branch ("/org/freedesktop/Hal/devices/local");
3504 }
3505