OSDN Git Service

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