OSDN Git Service

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