OSDN Git Service

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