OSDN Git Service

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