OSDN Git Service

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