OSDN Git Service

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