OSDN Git Service

LinGui: continue callbacks.c reduction. move audio tab handling to separate
[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 "hb.h"
29 #include "callbacks.h"
30 #include "queuehandler.h"
31 #include "audiohandler.h"
32 #include "resources.h"
33 #include "settings.h"
34 #include "presets.h"
35 #include "values.h"
36 #include "plist.h"
37 #include "hb-backend.h"
38 #include "ghb-dvd.h"
39 #include "ghbcellrenderertext.h"
40
41 static void update_chapter_list(signal_user_data_t *ud);
42 static GList* dvd_device_list();
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 void
55 ghb_init_dep_map()
56 {
57         dep_map = ghb_resource_get("widget-deps");
58         rev_map = ghb_resource_get("widget-reverse-deps");
59 }
60
61 static gboolean
62 dep_check(signal_user_data_t *ud, const gchar *name)
63 {
64         GtkWidget *widget;
65         GObject *dep_object;
66         gint ii;
67         gint count;
68         gboolean result = TRUE;
69         GValue *array, *data;
70         gchar *widget_name;
71         
72         g_debug("dep_check () %s", name);
73
74         array = ghb_dict_lookup(rev_map, name);
75         count = ghb_array_len(array);
76         for (ii = 0; ii < count; ii++)
77         {
78                 data = ghb_array_get_nth(array, ii);
79                 widget_name = ghb_value_string(ghb_array_get_nth(data, 0));
80                 widget = GHB_WIDGET(ud->builder, widget_name);
81                 dep_object = gtk_builder_get_object(ud->builder, name);
82                 g_free(widget_name);
83                 if (dep_object == NULL)
84                 {
85                         g_message("Failed to find widget");
86                 }
87                 else
88                 {
89                         gchar *value;
90                         gint jj = 0;
91                         gchar **values;
92                         gboolean sensitive = FALSE;
93                         gboolean die;
94
95                         die = ghb_value_boolean(ghb_array_get_nth(data, 2));
96                         value = ghb_value_string(ghb_array_get_nth(data, 1));
97                         values = g_strsplit(value, "|", 10);
98                         g_free(value);
99
100                         if (widget)
101                                 value = ghb_widget_string(widget);
102                         else
103                                 value = ghb_settings_get_string(ud->settings, name);
104                         while (values && values[jj])
105                         {
106                                 if (values[jj][0] == '>')
107                                 {
108                                         gdouble dbl = g_strtod (&values[jj][1], NULL);
109                                         gdouble dvalue = ghb_widget_double(widget);
110                                         if (dvalue > dbl)
111                                         {
112                                                 sensitive = TRUE;
113                                                 break;
114                                         }
115                                 }
116                                 else if (values[jj][0] == '<')
117                                 {
118                                         gdouble dbl = g_strtod (&values[jj][1], NULL);
119                                         gdouble dvalue = ghb_widget_double(widget);
120                                         if (dvalue < dbl)
121                                         {
122                                                 sensitive = TRUE;
123                                                 break;
124                                         }
125                                 }
126                                 if (strcmp(values[jj], value) == 0)
127                                 {
128                                         sensitive = TRUE;
129                                         break;
130                                 }
131                                 jj++;
132                         }
133                         sensitive = die ^ sensitive;
134                         if (!sensitive) result = FALSE;
135                         g_strfreev (values);
136                         g_free(value);
137                 }
138         }
139         return result;
140 }
141
142 void
143 ghb_check_dependency(signal_user_data_t *ud, GtkWidget *widget)
144 {
145         GObject *dep_object;
146         const gchar *name;
147         GValue *array, *data;
148         gint count, ii;
149         gchar *dep_name;
150         GType type;
151
152         type = GTK_WIDGET_TYPE(widget);
153         if (type == GTK_TYPE_COMBO_BOX || type == GTK_TYPE_COMBO_BOX_ENTRY)
154                 if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) < 0) return;
155
156         name = gtk_widget_get_name(widget);
157         g_debug("ghb_check_dependency () %s", name);
158
159         array = ghb_dict_lookup(dep_map, name);
160         count = ghb_array_len(array);
161         for (ii = 0; ii < count; ii++)
162         {
163                 gboolean sensitive;
164
165                 data = ghb_array_get_nth(array, ii);
166                 dep_name = ghb_value_string(data);
167                 dep_object = gtk_builder_get_object(ud->builder, dep_name);
168                 if (dep_object == NULL)
169                 {
170                         g_message("Failed to find dependent widget %s", dep_name);
171                         g_free(dep_name);
172                         continue;
173                 }
174                 sensitive = dep_check(ud, dep_name);
175                 g_free(dep_name);
176                 if (GTK_IS_ACTION(dep_object))
177                         gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
178                 else
179                         gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
180         }
181 }
182
183 void
184 ghb_check_all_depencencies(signal_user_data_t *ud)
185 {
186         GHashTableIter iter;
187         gchar *dep_name;
188         GValue *value;
189         GObject *dep_object;
190
191         g_debug("ghb_check_all_depencencies ()");
192         ghb_dict_iter_init(&iter, rev_map);
193         // middle (void*) cast prevents gcc warning "defreferencing type-punned
194         // pointer will break strict-aliasing rules"
195         while (g_hash_table_iter_next(
196                         &iter, (gpointer*)(void*)&dep_name, (gpointer*)(void*)&value))
197         {
198                 gboolean sensitive;
199                 dep_object = gtk_builder_get_object (ud->builder, dep_name);
200                 if (dep_object == NULL)
201                 {
202                         g_message("Failed to find dependent widget %s", dep_name);
203                         continue;
204                 }
205                 sensitive = dep_check(ud, dep_name);
206                 if (GTK_IS_ACTION(dep_object))
207                         gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
208                 else
209                         gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
210         }
211 }
212
213 static void
214 clear_presets_selection(signal_user_data_t *ud)
215 {
216         GtkTreeView *treeview;
217         GtkTreeSelection *selection;
218         
219         if (ud->dont_clear_presets) return;
220         g_debug("clear_presets_selection()");
221         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
222         selection = gtk_tree_view_get_selection (treeview);
223         gtk_tree_selection_unselect_all (selection);
224         ghb_settings_set_boolean(ud->settings, "preset_modified", TRUE);
225 }
226
227 static gchar*
228 expand_tilde(const gchar *path)
229 {
230         const gchar *user_home;
231         gchar *home;
232         const gchar *suffix;
233         gchar *expanded_path = NULL;
234         
235         g_debug("expand_tilde ()");
236         if (path[0] == '~')
237         {
238                 user_home = g_get_home_dir();
239                 home = NULL; // squash warning about home uninitialized
240                 if (path[1] == 0)
241                 {
242                         home = g_strdup(user_home);
243                         suffix = "";
244                 }
245                 else if (path[1] == '/')
246                 {
247                         home = g_strdup(user_home);
248                         suffix = &path[2];
249                 }
250                 else
251                 {
252                         home = g_path_get_dirname(user_home);
253                         suffix = &path[1];
254                 }
255                 expanded_path = g_strdup_printf("%s/%s", home, suffix);
256                 g_free(home);
257         }
258         return expanded_path;
259 }
260
261 void
262 on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud)
263 {
264         gint state = ghb_get_queue_state();
265         g_debug("on_quit1_activate ()");
266         if (state & GHB_STATE_WORKING)
267         {
268                 if (ghb_cancel_encode("Closing HandBrake will terminate encoding.\n"))
269                 {
270                         ghb_hb_cleanup(FALSE);
271                         gtk_main_quit();
272                         return;
273                 }
274                 return;
275         }
276         ghb_hb_cleanup(FALSE);
277         gtk_main_quit();
278 }
279
280 static void
281 set_destination(signal_user_data_t *ud)
282 {
283         g_debug("set_destination");
284         if (ghb_settings_get_boolean(ud->settings, "use_source_name"))
285         {
286                 gchar *vol_name, *filename, *extension;
287                 gchar *dir, *new_name;
288                 
289                 filename = ghb_settings_get_string(ud->settings, "destination");
290                 extension = ghb_settings_get_string(ud->settings, "container");
291                 dir = g_path_get_dirname (filename);
292                 vol_name = ghb_settings_get_string(ud->settings, "volume_label");
293                 if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
294                 {
295                         gint start, end;
296
297                         start = ghb_settings_get_int(ud->settings, "start_chapter");
298                         end = ghb_settings_get_int(ud->settings, "end_chapter");
299                         if (start == end)
300                         {
301                                 new_name = g_strdup_printf("%s/%s-%d.%s", 
302                                         dir, vol_name, start, extension);
303                         }
304                         else
305                         {
306                                 new_name = g_strdup_printf("%s/%s-%d-%d.%s", 
307                                         dir, vol_name, start, end, extension);
308                         }
309                 }
310                 else
311                 {
312                         new_name = g_strdup_printf("%s/%s.%s", dir, vol_name, extension);
313                 }
314                 ghb_ui_update(ud, "destination", ghb_string_value(new_name));
315                 g_free(filename);
316                 g_free(extension);
317                 g_free(vol_name);
318                 g_free(dir);
319                 g_free(new_name);
320         }
321 }
322
323 gboolean
324 uppers_and_unders(const gchar *str)
325 {
326         if (str == NULL) return FALSE;
327         while (*str)
328         {
329                 if (*str == ' ')
330                 {
331                         return FALSE;
332                 }
333                 if (*str >= 'a' && *str <= 'z')
334                 {
335                         return FALSE;
336                 }
337                 str++;
338         }
339         return TRUE;
340 }
341
342 enum
343 {
344         CAMEL_FIRST_UPPER,
345         CAMEL_OTHER
346 };
347
348 void
349 camel_convert(gchar *str)
350 {
351         gint state = CAMEL_OTHER;
352         
353         if (str == NULL) return;
354         while (*str)
355         {
356                 if (*str == '_') *str = ' ';
357                 switch (state)
358                 {
359                         case CAMEL_OTHER:
360                         {
361                                 if (*str >= 'A' && *str <= 'Z')
362                                         state = CAMEL_FIRST_UPPER;
363                                 else
364                                         state = CAMEL_OTHER;
365                                 
366                         } break;
367                         case CAMEL_FIRST_UPPER:
368                         {
369                                 if (*str >= 'A' && *str <= 'Z')
370                                         *str = *str - 'A' + 'a';
371                                 else
372                                         state = CAMEL_OTHER;
373                         } break;
374                 }
375                 str++;
376         }
377 }
378
379 static gboolean
380 update_source_label(signal_user_data_t *ud, const gchar *source)
381 {
382         gchar *label = NULL;
383         gint len;
384         gchar **path;
385         gchar *filename = g_strdup(source);
386         
387         len = strlen(filename);
388         if (filename[len-1] == '/') filename[len-1] = 0;
389         if (g_file_test(filename, G_FILE_TEST_IS_DIR))
390         {
391                 path = g_strsplit(filename, "/", -1);
392                 len = g_strv_length (path);
393                 if ((len > 1) && (strcmp("VIDEO_TS", path[len-1]) == 0))
394                 {
395                         label = g_strdup(path[len-2]);
396                 }
397                 else
398                 {
399                         label = g_strdup(path[len-1]);
400                 }
401                 g_strfreev (path);
402         }
403         else
404         {
405                 // Is regular file or block dev.
406                 // Check to see if it is a dvd image
407                 label = ghb_dvd_volname (filename);
408                 if (label == NULL)
409                 {
410                         path = g_strsplit(filename, "/", -1);
411                         len = g_strv_length (path);
412                         // Just use the last combonent of the path
413                         label = g_strdup(path[len-1]);
414                         g_strfreev (path);
415                 }
416                 else
417                 {
418                         if (uppers_and_unders(label))
419                         {
420                                 camel_convert(label);
421                         }
422                 }
423         }
424         g_free(filename);
425         GtkWidget *widget = GHB_WIDGET (ud->builder, "source_title");
426         if (label != NULL)
427         {
428                 gtk_label_set_text (GTK_LABEL(widget), label);
429                 ghb_settings_set_string(ud->settings, "volume_label", label);
430                 g_free(label);
431                 set_destination(ud);
432         }
433         else
434         {
435                 label = "No Title Found";
436                 gtk_label_set_text (GTK_LABEL(widget), label);
437                 ghb_settings_set_string(ud->settings, "volume_label", label);
438                 return FALSE;
439         }
440         return TRUE;
441 }
442
443 static GtkWidget *dvd_device_combo = NULL;
444
445 void
446 chooser_file_selected_cb(GtkFileChooser *dialog, GtkComboBox *combo)
447 {
448         const gchar *name = gtk_file_chooser_get_filename (dialog);
449         GtkTreeModel *store;
450         GtkTreeIter iter;
451         const gchar *device;
452         gboolean foundit = FALSE;
453         
454         if (name == NULL) return;
455         store = gtk_combo_box_get_model(combo);
456         if (gtk_tree_model_get_iter_first(store, &iter))
457         {
458                 do
459                 {
460                         gtk_tree_model_get(store, &iter, 0, &device, -1);
461                         if (strcmp(name, device) == 0)
462                         {
463                                 foundit = TRUE;
464                                 break;
465                         }
466                 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
467         }
468         if (foundit)
469                 gtk_combo_box_set_active_iter (combo, &iter);
470         else
471                 gtk_combo_box_set_active (combo, 0);
472 }
473
474 void
475 dvd_device_changed_cb(GtkComboBox *combo, GtkWidget *dialog)
476 {
477         gint ii = gtk_combo_box_get_active (combo);
478         if (ii != 0)
479         {
480                 const gchar *device = gtk_combo_box_get_active_text (combo);
481                 const gchar *name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog));
482                 if (name == NULL || strcmp(name, device) != 0)
483                         gtk_file_chooser_select_filename (GTK_FILE_CHOOSER(dialog), device);
484         }
485 }
486
487 void
488 source_type_changed_cb(GtkToggleButton *toggle, GtkFileChooser *chooser)
489 {
490         gchar *folder;
491         
492         g_debug("source_type_changed_cb ()");
493         folder = gtk_file_chooser_get_current_folder (chooser);
494         if (gtk_toggle_button_get_active (toggle))
495         {
496                 gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
497                 gtk_widget_set_sensitive (dvd_device_combo, FALSE);
498                 gtk_combo_box_set_active (GTK_COMBO_BOX(dvd_device_combo), 0);
499         }
500         else
501         {
502                 gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_OPEN);
503                 gtk_widget_set_sensitive (dvd_device_combo, TRUE);
504         }
505         if (folder != NULL)
506         {
507                 gtk_file_chooser_set_current_folder(chooser, folder);
508                 g_free(folder);
509         }
510 }
511
512 static GtkWidget*
513 source_dialog_extra_widgets(GtkWidget *dialog, gboolean checkbutton_active)
514 {
515         GtkBox *vbox;
516         GtkWidget *checkbutton;
517         
518         vbox = GTK_BOX(gtk_vbox_new (FALSE, 2));
519         checkbutton = gtk_check_button_new_with_label ("Open VIDEO_TS folder");
520         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), checkbutton_active);
521         gtk_box_pack_start (vbox, checkbutton, FALSE, FALSE, 1);
522         gtk_widget_show(checkbutton);
523
524         GtkWidget *combo;
525         GtkBox *hbox;
526         GList *drives, *link;
527         GtkWidget *label, *blank;
528
529         hbox = GTK_BOX(gtk_hbox_new (FALSE, 2));
530         combo = gtk_combo_box_new_text();
531         label = gtk_label_new("Detected DVD devices:");
532         blank = gtk_label_new("");
533         link = drives = dvd_device_list();
534         gtk_combo_box_append_text (GTK_COMBO_BOX(combo), "Not Selected");
535         while (link != NULL)
536         {
537                 gchar *name = (gchar*)link->data;
538                 gtk_combo_box_append_text (GTK_COMBO_BOX(combo), name);
539                 g_free(name);
540                 link = link->next;
541         }
542         g_list_free(drives);
543         gtk_combo_box_set_active (GTK_COMBO_BOX(combo), 0);
544         gtk_box_pack_start (vbox, GTK_WIDGET(hbox), FALSE, FALSE, 1);
545         gtk_widget_show(GTK_WIDGET(hbox));
546         gtk_box_pack_start (hbox, label, FALSE, FALSE, 1);
547         gtk_widget_show(label);
548         gtk_box_pack_start (hbox, combo, FALSE, FALSE, 2);
549         gtk_widget_show(combo);
550         gtk_box_pack_start (hbox, blank, TRUE, TRUE, 1);
551         gtk_widget_show(blank);
552  
553         // Ugly hackish global alert
554         dvd_device_combo = combo;
555         g_signal_connect(combo, "changed", (GCallback)dvd_device_changed_cb, dialog);
556         g_signal_connect(dialog, "selection-changed", (GCallback)chooser_file_selected_cb, combo);
557
558         g_signal_connect(checkbutton, "toggled", (GCallback)source_type_changed_cb, dialog);
559         return GTK_WIDGET(vbox);
560 }
561
562 static void
563 do_scan(signal_user_data_t *ud, const gchar *filename)
564 {
565         if (filename != NULL)
566         {
567                 ghb_settings_set_string(ud->settings, "source", filename);
568                 if (update_source_label(ud, filename))
569                 {
570                         GtkProgressBar *progress;
571                         progress = GTK_PROGRESS_BAR(GHB_WIDGET(ud->builder, "progressbar"));
572                         gchar *path;
573                         path = ghb_settings_get_string( ud->settings, "source");
574                         gtk_progress_bar_set_fraction (progress, 0);
575                         gtk_progress_bar_set_text (progress, "Scanning ...");
576                         ghb_hb_cleanup(TRUE);
577                         ghb_backend_scan (path, 0);
578                         g_free(path);
579                 }
580                 else
581                 {
582                         // TODO: error dialog
583                 }
584         }
585 }
586
587 void
588 source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
589 {
590         GtkWidget *dialog;
591         GtkWidget *widget;
592         gchar *sourcename;
593         gint    response;
594         GtkFileChooserAction action;
595         gboolean checkbutton_active;
596
597         g_debug("source_browse_clicked_cb ()");
598         sourcename = ghb_settings_get_string(ud->settings, "source");
599         checkbutton_active = FALSE;
600         if (g_file_test(sourcename, G_FILE_TEST_IS_DIR))
601         {
602                 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
603                 checkbutton_active = TRUE;
604         }
605         else
606         {
607                 action = GTK_FILE_CHOOSER_ACTION_OPEN;
608         }
609         dialog = gtk_file_chooser_dialog_new ("Select Source",
610                                                                 NULL,
611                                                                 action,
612                                                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
613                                                                 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
614                                                                 NULL);
615         widget = source_dialog_extra_widgets(dialog, checkbutton_active);
616         gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), widget);
617         gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), sourcename);
618         response = gtk_dialog_run(GTK_DIALOG (dialog));
619         gtk_widget_hide(dialog);
620         if (response == GTK_RESPONSE_ACCEPT)
621         {
622                 char *filename;
623
624                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
625                 if (filename != NULL)
626                 {
627                         do_scan(ud, filename);
628                         if (strcmp(sourcename, filename) != 0)
629                         {
630                                 ghb_settings_set_string (ud->settings, "default_source", filename);
631                                 ghb_pref_save (ud->settings, "default_source");
632                                 ghb_dvd_set_current (filename, ud);
633                         }
634                         g_free(filename);
635                 }
636         }
637         g_free(sourcename);
638         gtk_widget_destroy(dialog);
639 }
640
641 void
642 dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
643 {
644         const gchar *filename;
645         gchar *sourcename;
646
647         sourcename = ghb_settings_get_string(ud->settings, "source");
648         filename = gtk_action_get_name(action);
649         do_scan(ud, filename);
650         if (strcmp(sourcename, filename) != 0)
651         {
652                 ghb_settings_set_string (ud->settings, "default_source", filename);
653                 ghb_pref_save (ud->settings, "default_source");
654                 ghb_dvd_set_current (filename, ud);
655         }
656         g_free(sourcename);
657 }
658
659 static void
660 update_destination_extension(signal_user_data_t *ud)
661 {
662         static gchar *containers[] = {".mkv", ".mp4", ".m4v", ".avi", ".ogm", NULL};
663         gchar *filename;
664         gchar *extension;
665         gint ii;
666         GtkEntry *entry;
667
668         g_debug("update_destination_extension ()");
669         extension = ghb_settings_get_string(ud->settings, "container");
670         entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "destination"));
671         filename = g_strdup(gtk_entry_get_text(entry));
672         for (ii = 0; containers[ii] != NULL; ii++)
673         {
674                 if (g_str_has_suffix(filename, containers[ii]))
675                 {
676                         gchar *pos;
677                         gchar *new_name;
678                         
679                         pos = g_strrstr( filename, "." );
680                         if (pos == NULL)
681                         {
682                                 // No period? shouldn't happen
683                                 break;
684                         }
685                         *pos = 0;
686                         if (strcmp(extension, &pos[1]) == 0)
687                         {
688                                 // Extension is already correct
689                                 break;
690                         }
691                         new_name = g_strjoin(".", filename, extension, NULL); 
692                         ghb_ui_update(ud, "destination", ghb_string_value(new_name));
693                         g_free(new_name);
694                         break;
695                 }
696         }
697         g_free(extension);
698         g_free(filename);
699 }
700
701 static void
702 destination_select_title(GtkEntry *entry)
703 {
704         const gchar *dest;
705         gint start, end;
706
707         dest = gtk_entry_get_text(entry);
708         for (end = strlen(dest)-1; end > 0; end--)
709         {
710                 if (dest[end] == '.')
711                 {
712                         break;
713                 }
714         }
715         for (start = end; start >= 0; start--)
716         {
717                 if (dest[start] == '/')
718                 {
719                         start++;
720                         break;
721                 }
722         }
723         if (start < end)
724         {
725                 gtk_editable_select_region(GTK_EDITABLE(entry), start, end);
726         }
727 }
728
729 gboolean
730 destination_grab_cb(
731         GtkEntry *entry, 
732         signal_user_data_t *ud)
733 {
734         destination_select_title(entry);
735         return FALSE;
736 }
737
738 static gboolean update_default_destination = FALSE;
739
740 void
741 destination_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
742 {
743         gchar *dest;
744         
745         g_debug("destination_entry_changed_cb ()");
746         if ((dest = expand_tilde(gtk_entry_get_text(entry))) != NULL)
747         {
748                 gtk_entry_set_text(entry, dest);
749                 g_free(dest);
750         }
751         update_destination_extension(ud);
752         ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
753         // This signal goes off with ever keystroke, so I'm putting this
754         // update on the timer.
755         update_default_destination = TRUE;
756 }
757
758 void
759 destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
760 {
761         GtkWidget *dialog;
762         GtkEntry *entry;
763         gchar *destname;
764         gchar *basename;
765
766         g_debug("destination_browse_clicked_cb ()");
767         destname = ghb_settings_get_string(ud->settings, "destination");
768         dialog = gtk_file_chooser_dialog_new ("Choose Destination",
769                                           NULL,
770                                           GTK_FILE_CHOOSER_ACTION_SAVE,
771                                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
772                                           GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
773                                           NULL);
774         gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), destname);
775         basename = g_path_get_basename(destname);
776         g_free(destname);
777         gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
778         g_free(basename);
779         if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
780         {
781                 char *filename;
782                 
783                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
784                 entry = (GtkEntry*)GHB_WIDGET(ud->builder, "destination");
785                 if (entry == NULL)
786                 {
787                         g_debug("Failed to find widget: %s", "destination");
788                 }
789                 else
790                 {
791                         gtk_entry_set_text(entry, filename);
792                 }
793                 g_free (filename);
794         }
795         gtk_widget_destroy(dialog);
796 }
797
798 gboolean
799 window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
800 {
801         g_debug("window_destroy_event_cb ()");
802         ghb_hb_cleanup(FALSE);
803         gtk_main_quit();
804         return FALSE;
805 }
806
807 gboolean
808 window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
809 {
810         gint state = ghb_get_queue_state();
811         g_debug("window_delete_event_cb ()");
812         if (state & GHB_STATE_WORKING)
813         {
814                 if (ghb_cancel_encode("Closing HandBrake will terminate encoding.\n"))
815                 {
816                         ghb_hb_cleanup(FALSE);
817                         gtk_main_quit();
818                         return FALSE;
819                 }
820                 return TRUE;
821         }
822         ghb_hb_cleanup(FALSE);
823         gtk_main_quit();
824         return FALSE;
825 }
826
827 static void
828 update_acodec_combo(signal_user_data_t *ud)
829 {
830         ghb_grey_combo_options (ud->builder);
831 }
832
833 void
834 container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
835 {
836         const GValue *audio_list;
837         g_debug("container_changed_cb ()");
838         ghb_widget_to_setting(ud->settings, widget);
839         update_destination_extension(ud);
840         ghb_check_dependency(ud, widget);
841         update_acodec_combo(ud);
842         clear_presets_selection(ud);
843
844         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
845         if (ghb_ac3_in_audio_list (audio_list))
846         {
847                 gchar *container;
848
849                 container = ghb_settings_get_string(ud->settings, "container");
850                 if (strcmp(container, "mp4") == 0)
851                 {
852                         ghb_ui_update(ud, "container", ghb_string_value("m4v"));
853                 }
854                 g_free(container);
855         }
856 }
857
858 static gchar*
859 get_aspect_string(gint aspect_n, gint aspect_d)
860 {
861         gchar *aspect;
862
863         if (aspect_d < 10)
864         {
865                 aspect = g_strdup_printf("%d:%d", aspect_n, aspect_d);
866         }
867         else
868         {
869                 gdouble aspect_nf = (gdouble)aspect_n / aspect_d;
870                 aspect = g_strdup_printf("%.2f:1", aspect_nf);
871         }
872         return aspect;
873 }
874
875 static gchar*
876 get_rate_string(gint rate_base, gint rate)
877 {
878         gdouble rate_f = (gdouble)rate / rate_base;
879         gchar *rate_s;
880
881         rate_s = g_strdup_printf("%.6g", rate_f);
882         return rate_s;
883 }
884 static void
885 show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
886 {
887         GtkWidget *widget;
888         gchar *text;
889
890         widget = GHB_WIDGET (ud->builder, "title_duration");
891         if (tinfo->duration != 0)
892         {
893                 text = g_strdup_printf ("%02d:%02d:%02d", tinfo->hours, 
894                                 tinfo->minutes, tinfo->seconds);
895         }
896         else
897         {
898                 text = g_strdup_printf ("Unknown");
899         }
900         gtk_label_set_text (GTK_LABEL(widget), text);
901         g_free(text);
902         widget = GHB_WIDGET (ud->builder, "source_dimensions");
903         text = g_strdup_printf ("%d x %d", tinfo->width, tinfo->height);
904         gtk_label_set_text (GTK_LABEL(widget), text);
905         ghb_settings_set_int(ud->settings, "source_width", tinfo->width);
906         ghb_settings_set_int(ud->settings, "source_height", tinfo->height);
907         g_free(text);
908         widget = GHB_WIDGET (ud->builder, "source_aspect");
909         text = get_aspect_string(tinfo->aspect_n, tinfo->aspect_d);
910         gtk_label_set_text (GTK_LABEL(widget), text);
911         g_free(text);
912
913         widget = GHB_WIDGET (ud->builder, "source_frame_rate");
914         text = (gchar*)get_rate_string(tinfo->rate_base, tinfo->rate);
915         gtk_label_set_text (GTK_LABEL(widget), text);
916         g_free(text);
917
918         ghb_ui_update(ud, "scale_width", 
919                 ghb_int64_value(tinfo->width - tinfo->crop[2] - tinfo->crop[3]));
920         // If anamorphic or keep_aspect, the hight will be automatically calculated
921         gboolean keep_aspect, anamorphic;
922         keep_aspect = ghb_settings_get_boolean(ud->settings, "keep_aspect");
923         anamorphic = ghb_settings_get_boolean(ud->settings, "anamorphic");
924         if (!(keep_aspect || anamorphic))
925         {
926                 ghb_ui_update(ud, "scale_height", 
927                         ghb_int64_value(tinfo->height - tinfo->crop[0] - tinfo->crop[1]));
928         }
929
930         // Set the limits of cropping.  hb_set_anamorphic_size crashes if
931         // you pass it a cropped width or height == 0.
932         gint bound;
933         bound = tinfo->height / 2 - 2;
934         widget = GHB_WIDGET (ud->builder, "crop_top");
935         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
936         widget = GHB_WIDGET (ud->builder, "crop_bottom");
937         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
938         bound = tinfo->width / 2 - 2;
939         widget = GHB_WIDGET (ud->builder, "crop_left");
940         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
941         widget = GHB_WIDGET (ud->builder, "crop_right");
942         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
943         if (ghb_settings_get_boolean(ud->settings, "autocrop"))
944         {
945                 ghb_ui_update(ud, "crop_top", ghb_int64_value(tinfo->crop[0]));
946                 ghb_ui_update(ud, "crop_bottom", ghb_int64_value(tinfo->crop[1]));
947                 ghb_ui_update(ud, "crop_left", ghb_int64_value(tinfo->crop[2]));
948                 ghb_ui_update(ud, "crop_right", ghb_int64_value(tinfo->crop[3]));
949         }
950         g_debug("setting max end chapter %d", tinfo->num_chapters);
951         widget = GHB_WIDGET (ud->builder, "end_chapter");
952         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters);
953         gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), tinfo->num_chapters);
954         widget = GHB_WIDGET (ud->builder, "start_chapter");
955         gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1);
956 }
957
958 static gint preview_button_width;
959 static gint preview_button_height;
960 static gboolean update_preview = FALSE;
961
962 static void
963 set_preview_image(signal_user_data_t *ud)
964 {
965         GtkWidget *widget;
966         gint preview_width, preview_height, target_height, width, height;
967
968         g_debug("set_preview_button_image ()");
969         gint titleindex;
970
971         titleindex = ghb_settings_combo_int(ud->settings, "title");
972         if (titleindex < 0) return;
973         widget = GHB_WIDGET (ud->builder, "preview_frame");
974         gint frame = ghb_widget_int(widget) - 1;
975         GdkPixbuf *preview = ghb_get_preview_image (titleindex, frame, ud->settings, TRUE);
976         if (preview == NULL) return;
977         widget = GHB_WIDGET (ud->builder, "preview_image");
978         gtk_image_set_from_pixbuf(GTK_IMAGE(widget), preview);
979
980         preview_width = gdk_pixbuf_get_width(preview);
981         preview_height = gdk_pixbuf_get_height(preview);
982         gchar *text = g_strdup_printf("%d x %d", preview_width, preview_height);
983         widget = GHB_WIDGET (ud->builder, "preview_dims");
984         gtk_label_set_text(GTK_LABEL(widget), text);
985         g_free(text);
986         
987         g_debug("preview %d x %d", preview_width, preview_height);
988         target_height = MIN(preview_button_height - 12, 128);
989         height = target_height;
990         width = preview_width * height / preview_height;
991
992         if ((height >= 16) && (width >= 16))
993         {
994                 GdkPixbuf *scaled_preview;
995                 scaled_preview = gdk_pixbuf_scale_simple (preview, width, height, GDK_INTERP_NEAREST);
996                 if (scaled_preview != NULL)
997                 {
998                         g_object_unref (preview);
999                         
1000                         widget = GHB_WIDGET (ud->builder, "preview_button_image");
1001                         gtk_image_set_from_pixbuf(GTK_IMAGE(widget), scaled_preview);
1002                         g_object_unref (scaled_preview);
1003                 }
1004         }
1005 }
1006
1007 void
1008 title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1009 {
1010         ghb_title_info_t tinfo;
1011         gint titleindex;
1012         gchar *preset;
1013         
1014         g_debug("title_changed_cb ()");
1015         ghb_widget_to_setting(ud->settings, widget);
1016         ghb_check_dependency(ud, widget);
1017
1018         titleindex = ghb_settings_combo_int(ud->settings, "title");
1019         ghb_update_ui_combo_box (ud->builder, "audio_track", titleindex, FALSE);
1020         ghb_update_ui_combo_box (ud->builder, "subtitle_lang", titleindex, FALSE);
1021
1022         preset = ghb_settings_get_string (ud->settings, "preset");
1023         ghb_update_from_preset(ud, preset, "subtitle_lang");
1024         g_free(preset);
1025         if (ghb_get_title_info (&tinfo, titleindex))
1026         {
1027                 show_title_info(ud, &tinfo);
1028         }
1029         update_chapter_list (ud);
1030         ghb_adjust_audio_rate_combos(ud);
1031         ghb_set_pref_audio(titleindex, ud);
1032         if (ghb_settings_get_boolean(ud->settings, "vquality_type_target"))
1033         {
1034                 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1035                 ghb_ui_update(ud, "video_bitrate", ghb_int64_value(bitrate));
1036         }
1037
1038         // Unfortunately, there is no way to query how many frames were
1039         // actually generated during the scan.  It attempts to make 10.
1040         // If I knew how many were generated, I would adjust the spin
1041         // control range here.
1042         ghb_ui_update(ud, "preview_frame", ghb_int64_value(1));
1043
1044         set_preview_image (ud);
1045 }
1046
1047 void
1048 generic_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1049 {
1050         g_debug("generic_widget_changed_cb ()");
1051         ghb_check_dependency(ud, widget);
1052 }
1053
1054 void
1055 setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1056 {
1057         ghb_widget_to_setting(ud->settings, widget);
1058         ghb_check_dependency(ud, widget);
1059         clear_presets_selection(ud);
1060 }
1061
1062 static void
1063 validate_filter_widget(signal_user_data_t *ud, const gchar *name)
1064 {
1065         GtkTreeModel *store;
1066         GtkTreeIter iter;
1067         const gchar *str;
1068         gboolean foundit = FALSE;
1069         GtkComboBox *combo = GTK_COMBO_BOX(GHB_WIDGET(ud->builder, name));
1070         if (gtk_combo_box_get_active(combo) < 0)
1071         { // Validate user input
1072                 gchar *val = ghb_settings_get_string(ud->settings, name);
1073                 store = gtk_combo_box_get_model(combo);
1074                 // Check to see if user manually entered one of the combo options
1075                 if (gtk_tree_model_get_iter_first(store, &iter))
1076                 {
1077                         do
1078                         {
1079                                 gtk_tree_model_get(store, &iter, 0, &str, -1);
1080                                 if (strcasecmp(val, str) == 0)
1081                                 {
1082                                         gtk_combo_box_set_active_iter(combo, &iter);
1083                                         foundit = TRUE;
1084                                         break;
1085                                 }
1086                         } while (gtk_tree_model_iter_next(store, &iter));
1087                 }
1088                 if (!foundit)
1089                 { // validate format of filter string
1090                         if (!ghb_validate_filter_string(val, -1))
1091                                 gtk_combo_box_set_active(combo, 0);
1092                 }
1093                 g_free(val);
1094         }
1095 }
1096
1097 gboolean
1098 deint_tweak_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
1099         signal_user_data_t *ud)
1100 {
1101         g_debug("deint_tweak_focus_out_cb ()");
1102         validate_filter_widget(ud, "tweak_deinterlace");
1103         return FALSE;
1104 }
1105
1106 gboolean
1107 denoise_tweak_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
1108         signal_user_data_t *ud)
1109 {
1110         g_debug("denoise_tweak_focus_out_cb ()");
1111         validate_filter_widget(ud, "tweak_noise");
1112         return FALSE;
1113 }
1114
1115 void
1116 http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1117 {
1118         ghb_widget_to_setting(ud->settings, widget);
1119         ghb_check_dependency(ud, widget);
1120         clear_presets_selection(ud);
1121         ghb_grey_combo_options (ud->builder);
1122 }
1123
1124 void
1125 vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1126 {
1127         gint vqmin, vqmax;
1128
1129         ghb_widget_to_setting(ud->settings, widget);
1130         ghb_check_dependency(ud, widget);
1131         clear_presets_selection(ud);
1132         ghb_vquality_range(ud, &vqmin, &vqmax);
1133         GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1134         gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1135 }
1136
1137 void
1138 target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1139 {
1140         const gchar *name = gtk_widget_get_name(widget);
1141         g_debug("setting_widget_changed_cb () %s", name);
1142         ghb_widget_to_setting(ud->settings, widget);
1143         ghb_check_dependency(ud, widget);
1144         clear_presets_selection(ud);
1145         if (ghb_settings_get_boolean(ud->settings, "vquality_type_target"))
1146         {
1147                 gint titleindex;
1148                 titleindex = ghb_settings_combo_int(ud->settings, "title");
1149                 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1150                 ghb_ui_update(ud, "video_bitrate", ghb_int64_value(bitrate));
1151         }
1152 }
1153
1154 void
1155 start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1156 {
1157         gint start, end;
1158         const gchar *name = gtk_widget_get_name(widget);
1159
1160         g_debug("start_chapter_changed_cb () %s", name);
1161         ghb_widget_to_setting(ud->settings, widget);
1162         start = ghb_settings_get_int(ud->settings, "start_chapter");
1163         end = ghb_settings_get_int(ud->settings, "end_chapter");
1164         if (start > end)
1165                 ghb_ui_update(ud, "end_chapter", ghb_int_value(start));
1166         ghb_check_dependency(ud, widget);
1167         if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
1168         {
1169                 set_destination(ud);
1170         }
1171 }
1172
1173 void
1174 end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1175 {
1176         gint start, end;
1177         const gchar *name = gtk_widget_get_name(widget);
1178
1179         g_debug("end_chapter_changed_cb () %s", name);
1180         ghb_widget_to_setting(ud->settings, widget);
1181         start = ghb_settings_get_int(ud->settings, "start_chapter");
1182         end = ghb_settings_get_int(ud->settings, "end_chapter");
1183         if (start > end)
1184                 ghb_ui_update(ud, "start_chapter", ghb_int_value(end));
1185         ghb_check_dependency(ud, widget);
1186         if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
1187         {
1188                 set_destination(ud);
1189         }
1190 }
1191
1192 void
1193 scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1194 {
1195         g_debug("scale_width_changed_cb ()");
1196         ghb_widget_to_setting(ud->settings, widget);
1197         ghb_check_dependency(ud, widget);
1198         ghb_set_scale (ud, GHB_SCALE_KEEP_WIDTH);
1199         update_preview = TRUE;
1200         gchar *text;
1201         gint width = ghb_settings_get_int(ud->settings, "scale_width");
1202         gint height = ghb_settings_get_int(ud->settings, "scale_height");
1203         widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1204         text = g_strdup_printf ("%d x %d", width, height);
1205         gtk_label_set_text (GTK_LABEL(widget), text);
1206         g_free(text);
1207 }
1208
1209 void
1210 scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1211 {
1212         g_debug("scale_height_changed_cb ()");
1213         ghb_widget_to_setting(ud->settings, widget);
1214         ghb_check_dependency(ud, widget);
1215         ghb_set_scale (ud, GHB_SCALE_KEEP_HEIGHT);
1216         update_preview = TRUE;
1217         gchar *text;
1218         gint width = ghb_settings_get_int(ud->settings, "scale_width");
1219         gint height = ghb_settings_get_int(ud->settings, "scale_height");
1220         widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1221         text = g_strdup_printf ("%d x %d", width, height);
1222         gtk_label_set_text (GTK_LABEL(widget), text);
1223         g_free(text);
1224 }
1225
1226 void
1227 crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1228 {
1229         gint titleindex, crop[4];
1230         ghb_title_info_t tinfo;
1231         
1232         g_debug("crop_changed_cb ()");
1233         ghb_widget_to_setting(ud->settings, widget);
1234         ghb_check_dependency(ud, widget);
1235         ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1236
1237         crop[0] = ghb_settings_get_int(ud->settings, "crop_top");
1238         crop[1] = ghb_settings_get_int(ud->settings, "crop_bottom");
1239         crop[2] = ghb_settings_get_int(ud->settings, "crop_left");
1240         crop[3] = ghb_settings_get_int(ud->settings, "crop_right");
1241         titleindex = ghb_settings_combo_int(ud->settings, "title");
1242         if (ghb_get_title_info (&tinfo, titleindex))
1243         {
1244                 gint width, height;
1245                 gchar *text;
1246                 
1247                 width = tinfo.width - crop[2] - crop[3];
1248                 height = tinfo.height - crop[0] - crop[1];
1249                 widget = GHB_WIDGET (ud->builder, "crop_dimensions");
1250                 text = g_strdup_printf ("%d x %d", width, height);
1251                 gtk_label_set_text (GTK_LABEL(widget), text);
1252                 g_free(text);
1253         }
1254         gchar *text;
1255         widget = GHB_WIDGET (ud->builder, "crop_values");
1256         text = g_strdup_printf ("%d:%d:%d:%d", crop[0], crop[1], crop[2], crop[3]);
1257         gtk_label_set_text (GTK_LABEL(widget), text);
1258         g_free(text);
1259         update_preview = TRUE;
1260 }
1261
1262 void
1263 scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1264 {
1265         g_debug("scale_changed_cb ()");
1266         ghb_widget_to_setting(ud->settings, widget);
1267         ghb_check_dependency(ud, widget);
1268         clear_presets_selection(ud);
1269         ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1270         update_preview = TRUE;
1271         
1272         gchar *text;
1273         
1274         text = ghb_settings_get_boolean(ud->settings, "autocrop") ? "On" : "Off";
1275         widget = GHB_WIDGET (ud->builder, "crop_auto");
1276         gtk_label_set_text (GTK_LABEL(widget), text);
1277         text = ghb_settings_get_boolean(ud->settings, "autoscale") ? "On" : "Off";
1278         widget = GHB_WIDGET (ud->builder, "scale_auto");
1279         gtk_label_set_text (GTK_LABEL(widget), text);
1280         text = ghb_settings_get_boolean(ud->settings, "anamorphic") ? "On" : "Off";
1281         widget = GHB_WIDGET (ud->builder, "scale_anamorphic");
1282         gtk_label_set_text (GTK_LABEL(widget), text);
1283 }
1284
1285 void
1286 generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
1287 {
1288         // Normally (due to user input) I only want to process the entry
1289         // when editing is done and the focus-out signal is sent.
1290         // But... there's always a but.
1291         // If the entry is changed by software, the focus-out signal is not sent.
1292         // The changed signal is sent ... so here we are.
1293         // I don't want to process upon every keystroke, so I prevent processing
1294         // while the widget has focus.
1295         g_debug("generic_entry_changed_cb ()");
1296         if (!GTK_WIDGET_HAS_FOCUS((GtkWidget*)entry))
1297         {
1298                 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
1299         }
1300 }
1301
1302 gboolean
1303 generic_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
1304         signal_user_data_t *ud)
1305 {
1306         g_debug("generic_focus_out_cb ()");
1307         ghb_widget_to_setting(ud->settings, widget);
1308         return FALSE;
1309 }
1310
1311 // Flag needed to prevent x264 options processing from chasing its tail
1312 static gboolean ignore_options_update = FALSE;
1313
1314 void
1315 x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1316 {
1317         ghb_widget_to_setting(ud->settings, widget);
1318         if (!ignore_options_update)
1319         {
1320                 ignore_options_update = TRUE;
1321                 ghb_x264_opt_update(ud, widget);
1322                 ignore_options_update = FALSE;
1323         }
1324         ghb_check_dependency(ud, widget);
1325         clear_presets_selection(ud);
1326 }
1327
1328 void
1329 x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1330 {
1331         g_debug("x264_entry_changed_cb ()");
1332         if (!ignore_options_update)
1333         {
1334                 GtkWidget *textview;
1335                 gchar *options;
1336
1337                 textview = GTK_WIDGET(GHB_WIDGET(ud->builder, "x264_options"));
1338                 ghb_widget_to_setting(ud->settings, textview);
1339                 options = ghb_settings_get_string(ud->settings, "x264_options");
1340                 ignore_options_update = TRUE;
1341                 ghb_x264_parse_options(ud, options);
1342                 if (!GTK_WIDGET_HAS_FOCUS(textview))
1343                 {
1344                         gchar *sopts;
1345
1346                         sopts = ghb_sanitize_x264opts(ud, options);
1347                         ghb_ui_update(ud, "x264_options", ghb_string_value(sopts));
1348                         ghb_x264_parse_options(ud, sopts);
1349                         g_free(sopts);
1350                 }
1351                 g_free(options);
1352                 ignore_options_update = FALSE;
1353         }
1354 }
1355
1356 gboolean
1357 x264_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
1358         signal_user_data_t *ud)
1359 {
1360         gchar *options, *sopts;
1361
1362         ghb_widget_to_setting(ud->settings, widget);
1363         options = ghb_settings_get_string(ud->settings, "x264_options");
1364         sopts = ghb_sanitize_x264opts(ud, options);
1365         ignore_options_update = TRUE;
1366         if (sopts != NULL)
1367         {
1368                 ghb_ui_update(ud, "x264_options", ghb_string_value(sopts));
1369                 ghb_x264_parse_options(ud, sopts);
1370         }
1371         g_free(options);
1372         g_free(sopts);
1373         ignore_options_update = FALSE;
1374         return FALSE;
1375 }
1376
1377 void
1378 ghb_presets_list_update(signal_user_data_t *ud)
1379 {
1380         GtkTreeView *treeview;
1381         GtkTreeIter iter;
1382         GtkListStore *store;
1383         gboolean done;
1384         GList *presets, *plink;
1385         gchar *preset, *def_preset;
1386         gchar *description;
1387         gint flags, custom, def;
1388         
1389         g_debug("ghb_presets_list_update ()");
1390         def_preset = ghb_settings_get_string(ud->settings, "default_preset");
1391         plink = presets = ghb_presets_get_names();
1392         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1393         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1394         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1395         {
1396                 do
1397                 {
1398                         if (plink)
1399                         {
1400                                 // Update row with settings data
1401                                 g_debug("Updating row");
1402                                 preset = (gchar*)plink->data;
1403                                 def = 0;
1404                                 if (strcmp(preset, def_preset) == 0)
1405                                         def = PRESET_DEFAULT;
1406                                 
1407                                 description = ghb_presets_get_description(preset);
1408                                 flags = ghb_preset_flags(preset);
1409                                 custom = flags & PRESET_CUSTOM;
1410                                 gtk_list_store_set(store, &iter, 
1411                                                         0, preset, 
1412                                                         1, def ? 800 : 400, 
1413                                                         2, def ? 2 : 0,
1414                                                         3, custom ? "black" : "blue", 
1415                                                         4, description,
1416                                                         -1);
1417                                 plink = plink->next;
1418                                 g_free(description);
1419                                 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1420                         }
1421                         else
1422                         {
1423                                 // No more settings data, remove row
1424                                 g_debug("Removing row");
1425                                 done = !gtk_list_store_remove(store, &iter);
1426                         }
1427                 } while (!done);
1428         }
1429         while (plink)
1430         {
1431                 // Additional settings, add row
1432                 g_debug("Adding rows");
1433                 preset = (gchar*)plink->data;
1434                 def = 0;
1435                 if (strcmp(preset, def_preset) == 0)
1436                         def = PRESET_DEFAULT;
1437
1438                 description = ghb_presets_get_description(preset);
1439                 gtk_list_store_append(store, &iter);
1440                 flags = ghb_preset_flags(preset);
1441                 custom = flags & PRESET_CUSTOM;
1442                 gtk_list_store_set(store, &iter, 0, preset, 
1443                                                         1, def ? 800 : 400, 
1444                                                         2, def ? 2 : 0,
1445                                                         3, custom ? "black" : "blue", 
1446                                                         4, description,
1447                                                         -1);
1448                 plink = plink->next;
1449                 g_free(description);
1450         }
1451         g_free(def_preset);
1452         g_list_free (presets);
1453 }
1454
1455 void
1456 ghb_select_preset(GtkBuilder *builder, const gchar *preset)
1457 {
1458         GtkTreeView *treeview;
1459         GtkTreeSelection *selection;
1460         GtkTreeModel *store;
1461         GtkTreeIter iter;
1462         gchar *tpreset;
1463         gboolean done;
1464         gboolean foundit = FALSE;
1465         
1466         g_debug("select_preset()");
1467         if (preset == NULL) return;
1468         treeview = GTK_TREE_VIEW(GHB_WIDGET(builder, "presets_list"));
1469         selection = gtk_tree_view_get_selection (treeview);
1470         store = gtk_tree_view_get_model (treeview);
1471         if (gtk_tree_model_get_iter_first(store, &iter))
1472         {
1473                 do
1474                 {
1475                         gtk_tree_model_get(store, &iter, 0, &tpreset, -1);
1476                         if (strcmp(preset, tpreset) == 0)
1477                         {
1478                                 gtk_tree_selection_select_iter (selection, &iter);
1479                                 foundit = TRUE;
1480                                 g_free(tpreset);
1481                                 break;
1482                         }
1483                         g_free(tpreset);
1484                         done = !gtk_tree_model_iter_next(store, &iter);
1485                 } while (!done);
1486         }
1487         if (!foundit)
1488         {
1489                 gtk_tree_model_get_iter_first(store, &iter);
1490                 gtk_tree_selection_select_iter (selection, &iter);
1491         }
1492 }
1493
1494 static void
1495 update_audio_presets(signal_user_data_t *ud)
1496 {
1497         g_debug("update_audio_presets");
1498         const GValue *audio_list;
1499
1500         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
1501         ghb_settings_set_value(ud->settings, "pref_audio_list", audio_list);
1502 }
1503
1504 void
1505 presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1506 {
1507         GtkWidget *dialog;
1508         GtkEntry *entry;
1509         GtkTextView *desc;
1510         GtkResponseType response;
1511         gchar *preset;
1512
1513         g_debug("presets_save_clicked_cb ()");
1514         preset = ghb_settings_get_string (ud->settings, "preset");
1515         // Clear the description
1516         desc = GTK_TEXT_VIEW(GHB_WIDGET(ud->builder, "preset_description"));
1517         dialog = GHB_WIDGET(ud->builder, "preset_save_dialog");
1518         entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "preset_name"));
1519         gtk_entry_set_text(entry, preset);
1520         g_free(preset);
1521         response = gtk_dialog_run(GTK_DIALOG(dialog));
1522         gtk_widget_hide(dialog);
1523         if (response == GTK_RESPONSE_OK)
1524         {
1525                 // save the preset
1526                 const gchar *name = gtk_entry_get_text(entry);
1527                 g_debug("description to settings");
1528                 ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
1529                 // Construct the audio settings presets from the current audio list
1530                 update_audio_presets(ud);
1531                 ghb_settings_save(ud, name);
1532                 ghb_presets_list_update(ud);
1533                 // Make the new preset the selected item
1534                 ghb_select_preset(ud->builder, name);
1535         }
1536 }
1537
1538 void
1539 presets_restore_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1540 {
1541         g_debug("presets_restore_clicked_cb ()");
1542         // Reload only the standard presets
1543         ghb_presets_reload(ud);
1544         ghb_presets_list_update(ud);
1545         // Updating the presets list shuffles things around
1546         // need to make sure the proper preset is selected
1547         gchar *preset = ghb_settings_get_string (ud->settings, "preset");
1548         ghb_select_preset(ud->builder, preset);
1549         g_free(preset);
1550 }
1551
1552 void
1553 prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1554 {
1555         GtkWidget *dialog;
1556         GtkResponseType response;
1557
1558         g_debug("prefs_dialog_cb ()");
1559         dialog = GHB_WIDGET(ud->builder, "prefs_dialog");
1560         response = gtk_dialog_run(GTK_DIALOG(dialog));
1561         gtk_widget_hide(dialog);
1562 }
1563
1564 void
1565 presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1566 {
1567         GtkTreeView *treeview;
1568         GtkTreeSelection *selection;
1569         GtkTreeModel *store;
1570         GtkTreeIter iter;
1571         gchar *preset;
1572         GtkResponseType response;
1573
1574         g_debug("presets_remove_clicked_cb ()");
1575         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1576         selection = gtk_tree_view_get_selection (treeview);
1577         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1578         {
1579                 GtkWidget *dialog;
1580
1581                 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1582                 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1583                                                                 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1584                                                                 "Confirm deletion of preset %s.", preset);
1585                 response = gtk_dialog_run(GTK_DIALOG(dialog));
1586                 gtk_widget_destroy (dialog);
1587                 if (response == GTK_RESPONSE_YES)
1588                 {
1589                         GtkTreeIter nextIter = iter;
1590                         gchar *nextPreset = NULL;
1591                         if (!gtk_tree_model_iter_next(store, &nextIter))
1592                         {
1593                                 if (gtk_tree_model_get_iter_first(store, &nextIter))
1594                                 {
1595                                         gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1596                                 }
1597                         }
1598                         else
1599                         {
1600                                 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1601                         }
1602                         // Remove the selected item
1603                         // First unselect it so that selecting the new item works properly
1604                         gtk_tree_selection_unselect_iter (selection, &iter);
1605                         ghb_presets_remove(preset);
1606                         ghb_presets_list_update(ud);
1607                         ghb_select_preset(ud->builder, nextPreset);
1608                 }
1609         }
1610 }
1611
1612 static void
1613 preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
1614 {
1615         GtkWidget *widget;
1616
1617         ghb_ui_update(ud, "scale_width", 
1618                         ghb_int64_value(tinfo->width - tinfo->crop[2] - tinfo->crop[3]));
1619         // If anamorphic or keep_aspect, the hight will be automatically calculated
1620         gboolean keep_aspect, anamorphic;
1621         keep_aspect = ghb_settings_get_boolean(ud->settings, "keep_aspect");
1622         anamorphic = ghb_settings_get_boolean(ud->settings, "anamorphic");
1623         if (!(keep_aspect || anamorphic))
1624         {
1625                 ghb_ui_update(ud, "scale_height", 
1626                         ghb_int64_value(tinfo->height - tinfo->crop[0] - tinfo->crop[1]));
1627         }
1628
1629         // Set the limits of cropping.  hb_set_anamorphic_size crashes if
1630         // you pass it a cropped width or height == 0.
1631         gint bound;
1632         bound = tinfo->height / 2 - 2;
1633         widget = GHB_WIDGET (ud->builder, "crop_top");
1634         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1635         widget = GHB_WIDGET (ud->builder, "crop_bottom");
1636         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1637         bound = tinfo->width / 2 - 2;
1638         widget = GHB_WIDGET (ud->builder, "crop_left");
1639         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1640         widget = GHB_WIDGET (ud->builder, "crop_right");
1641         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1642         if (ghb_settings_get_boolean(ud->settings, "autocrop"))
1643         {
1644                 ghb_ui_update(ud, "crop_top", ghb_int64_value(tinfo->crop[0]));
1645                 ghb_ui_update(ud, "crop_bottom", ghb_int64_value(tinfo->crop[1]));
1646                 ghb_ui_update(ud, "crop_left", ghb_int64_value(tinfo->crop[2]));
1647                 ghb_ui_update(ud, "crop_right", ghb_int64_value(tinfo->crop[3]));
1648         }
1649 }
1650
1651 void
1652 presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
1653 {
1654         GtkTreeModel *store;
1655         GtkTreeIter iter;
1656         gchar *preset;
1657         ghb_title_info_t tinfo;
1658         GtkWidget *widget;
1659         
1660         g_debug("presets_list_selection_changed_cb ()");
1661         widget = GHB_WIDGET (ud->builder, "presets_remove");
1662         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1663         {
1664                 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1665                 ud->dont_clear_presets = TRUE;
1666                 // Temporarily set the video_quality range to (0,100)
1667                 // This is needed so the video_quality value does not get
1668                 // truncated when set.  The range will be readjusted below
1669                 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1670                 gtk_range_set_range (GTK_RANGE(qp), 0, 100);
1671                 // Clear the audio list prior to changing the preset.  Existing audio
1672                 // can cause the container extension to be automatically changed when
1673                 // it shouldn't be
1674                 ghb_clear_audio_list(ud);
1675                 ghb_set_preset(ud, preset);
1676                 gint titleindex;
1677                 titleindex = ghb_settings_combo_int(ud->settings, "title");
1678                 ghb_set_pref_audio(titleindex, ud);
1679                 ghb_settings_set_boolean(ud->settings, "preset_modified", FALSE);
1680                 ud->dont_clear_presets = FALSE;
1681                 if (ghb_get_title_info (&tinfo, titleindex))
1682                 {
1683                         preset_update_title_deps(ud, &tinfo);
1684                 }
1685                 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1686
1687                 gint vqmin, vqmax;
1688                 ghb_vquality_range(ud, &vqmin, &vqmax);
1689                 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1690                 gtk_widget_set_sensitive(widget, TRUE);
1691         }
1692         else
1693         {
1694                 g_debug("No selection???  Perhaps unselected.");
1695                 gtk_widget_set_sensitive(widget, FALSE);
1696         }
1697 }
1698
1699 gboolean
1700 ghb_message_dialog(GtkMessageType type, const gchar *message, const gchar *no, const gchar *yes)
1701 {
1702         GtkWidget *dialog;
1703         GtkResponseType response;
1704                         
1705         // Toss up a warning dialog
1706         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1707                                                         type, GTK_BUTTONS_NONE,
1708                                                         message);
1709         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
1710                                                    no, GTK_RESPONSE_NO,
1711                                                    yes, GTK_RESPONSE_YES, NULL);
1712         response = gtk_dialog_run(GTK_DIALOG(dialog));
1713         gtk_widget_destroy (dialog);
1714         if (response == GTK_RESPONSE_NO)
1715         {
1716                 return FALSE;
1717         }
1718         return TRUE;
1719 }
1720
1721 gboolean
1722 ghb_cancel_encode(const gchar *extra_msg)
1723 {
1724         GtkWidget *dialog;
1725         GtkResponseType response;
1726         
1727         if (extra_msg == NULL) extra_msg = "";
1728         // Toss up a warning dialog
1729         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1730                                 GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
1731                                 "%sYour movie will be lost if you don't continue encoding.",
1732                                 extra_msg);
1733         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
1734                                                    "Continue Encoding", GTK_RESPONSE_NO,
1735                                                    "Stop Encoding", GTK_RESPONSE_YES, NULL);
1736         response = gtk_dialog_run(GTK_DIALOG(dialog));
1737         gtk_widget_destroy (dialog);
1738         if (response == GTK_RESPONSE_NO) return FALSE;
1739         ghb_stop_queue();
1740         return TRUE;
1741 }
1742
1743 static void
1744 submit_job(GValue *settings)
1745 {
1746         static gint unique_id = 1;
1747
1748         g_debug("submit_job");
1749         if (settings == NULL) return;
1750         ghb_settings_set_int(settings, "job_unique_id", unique_id);
1751         ghb_settings_set_int(settings, "job_status", GHB_QUEUE_RUNNING);
1752         ghb_add_job (settings, unique_id);
1753         ghb_start_queue();
1754         unique_id++;
1755 }
1756
1757 static void
1758 queue_scan(GValue *js)
1759 {
1760         gchar *path;
1761         gint titlenum;
1762
1763         path = ghb_settings_get_string( js, "source");
1764         titlenum = ghb_settings_get_int(js, "titlenum");
1765         ghb_backend_queue_scan(path, titlenum);
1766         g_free(path);
1767 }
1768
1769 GValue* 
1770 ghb_start_next_job(signal_user_data_t *ud, gboolean find_first)
1771 {
1772         static gint current = 0;
1773         gint count, ii, jj;
1774         GValue *js;
1775         gint status;
1776
1777         g_debug("start_next_job");
1778         count = ghb_array_len(ud->queue);
1779         if (find_first)
1780         {       // Start the first pending item in the queue
1781                 current = 0;
1782                 for (ii = 0; ii < count; ii++)
1783                 {
1784
1785                         js = ghb_array_get_nth(ud->queue, ii);
1786                         status = ghb_settings_get_int(js, "job_status");
1787                         if (status == GHB_QUEUE_PENDING)
1788                         {
1789                                 current = ii;
1790                                 queue_scan(js);
1791                                 return js;
1792                         }
1793                 }
1794                 // Nothing pending
1795                 return NULL;
1796         }
1797         // Find the next pending item after the current running item
1798         for (ii = 0; ii < count-1; ii++)
1799         {
1800                 js = ghb_array_get_nth(ud->queue, ii);
1801                 status = ghb_settings_get_int(js, "job_status");
1802                 if (status == GHB_QUEUE_RUNNING)
1803                 {
1804                         for (jj = ii+1; jj < count; jj++)
1805                         {
1806                                 js = ghb_array_get_nth(ud->queue, jj);
1807                                 status = ghb_settings_get_int(js, "job_status");
1808                                 if (status == GHB_QUEUE_PENDING)
1809                                 {
1810                                         current = jj;
1811                                         queue_scan(js);
1812                                         return js;
1813                                 }
1814                         }
1815                 }
1816         }
1817         // No running item found? Maybe it was deleted
1818         // Look for a pending item starting from the last index we started
1819         for (ii = current; ii < count; ii++)
1820         {
1821                 js = ghb_array_get_nth(ud->queue, ii);
1822                 status = ghb_settings_get_int(js, "job_status");
1823                 if (status == GHB_QUEUE_PENDING)
1824                 {
1825                         current = ii;
1826                         queue_scan(js);
1827                         return js;
1828                 }
1829         }
1830         // Nothing found
1831         return NULL;
1832 }
1833
1834 static gint
1835 find_queue_job(GValue *queue, gint unique_id, GValue **job)
1836 {
1837         GValue *js;
1838         gint ii, count;
1839         gint job_unique_id;
1840         
1841         *job = NULL;
1842         g_debug("find_queue_job");
1843         count = ghb_array_len(queue);
1844         for (ii = 0; ii < count; ii++)
1845         {
1846                 js = ghb_array_get_nth(queue, ii);
1847                 job_unique_id = ghb_settings_get_int(js, "job_unique_id");
1848                 if (job_unique_id == unique_id)
1849                 {
1850                         *job = js;
1851                         return ii;
1852                 }
1853         }
1854         return -1;
1855 }
1856
1857 gchar*
1858 working_status_string(signal_user_data_t *ud, ghb_status_t *status)
1859 {
1860         gchar *task_str, *job_str, *status_str;
1861         gint qcount;
1862         gint index;
1863         GValue *js;
1864
1865         if (status->job_count > 1)
1866         {
1867                 task_str = g_strdup_printf("pass %d of %d, ", 
1868                         status->job_cur, status->job_count);
1869         }
1870         else
1871         {
1872                 task_str = g_strdup("");
1873         }
1874         qcount = ghb_array_len(ud->queue);
1875         if (qcount > 1)
1876         {
1877                 index = find_queue_job(ud->queue, status->unique_id, &js);
1878                 job_str = g_strdup_printf("job %d of %d, ", index+1, qcount);
1879         }
1880         else
1881         {
1882                 job_str = g_strdup("");
1883         }
1884         if(status->seconds > -1)
1885         {
1886                 status_str= g_strdup_printf(
1887                         "Encoding: %s%s%.2f %%"
1888                         " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)",
1889                         job_str, task_str,
1890                         100.0 * status->progress,
1891                         status->rate_cur, status->rate_avg, status->hours, 
1892                         status->minutes, status->seconds );
1893         }
1894         else
1895         {
1896                 status_str= g_strdup_printf(
1897                         "Encoding: %s%s%.2f %%",
1898                         job_str, task_str,
1899                         100.0 * status->progress );
1900         }
1901         g_free(task_str);
1902         g_free(job_str);
1903         return status_str;
1904 }
1905
1906 static void
1907 ghb_backend_events(signal_user_data_t *ud)
1908 {
1909         ghb_status_t status;
1910         gchar *status_str;
1911         GtkProgressBar *progress;
1912         gint titleindex;
1913         GValue *js;
1914         gint index;
1915         GtkTreeView *treeview;
1916         GtkTreeStore *store;
1917         GtkTreeIter iter;
1918         static gint working = 0;
1919         static gboolean work_started = FALSE;
1920         
1921         ghb_track_status();
1922         ghb_get_status(&status);
1923         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
1924         // First handle the status of title scans
1925         // Then handle the status of the queue
1926         if (status.state & GHB_STATE_SCANNING)
1927         {
1928                 status_str = g_strdup_printf ("Scanning title %d of %d...", 
1929                                                                   status.title_cur, status.title_count );
1930                 gtk_progress_bar_set_text (progress, status_str);
1931                 g_free(status_str);
1932                 if (status.title_count > 0)
1933                 {
1934                         gtk_progress_bar_set_fraction (progress, 
1935                                 (gdouble)status.title_cur / status.title_count);
1936                 }
1937         }
1938         else if (status.state & GHB_STATE_SCANDONE)
1939         {
1940                 status_str = g_strdup_printf ("Scan done"); 
1941                 gtk_progress_bar_set_text (progress, status_str);
1942                 g_free(status_str);
1943                 gtk_progress_bar_set_fraction (progress, 1.0);
1944
1945                 ghb_title_info_t tinfo;
1946                         
1947                 ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE);
1948                 titleindex = ghb_longest_title();
1949                 ghb_ui_update(ud, "title", ghb_int64_value(titleindex));
1950
1951                 // Are there really any titles.
1952                 if (!ghb_get_title_info(&tinfo, titleindex))
1953                 {
1954                         GtkProgressBar *progress;
1955                         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
1956                         gtk_progress_bar_set_fraction (progress, 0);
1957                         gtk_progress_bar_set_text (progress, "No Source");
1958                 }
1959                 ghb_clear_state(GHB_STATE_SCANDONE);
1960                 ghb_queue_buttons_grey(ud, work_started);
1961         }
1962         else if (status.queue_state & GHB_STATE_SCANNING)
1963         {
1964                 status_str = g_strdup_printf ("Scanning ...");
1965                 gtk_progress_bar_set_text (progress, status_str);
1966                 g_free(status_str);
1967                 gtk_progress_bar_set_fraction (progress, 0);
1968         }
1969         else if (status.queue_state & GHB_STATE_SCANDONE)
1970         {
1971                 ghb_clear_queue_state(GHB_STATE_SCANDONE);
1972                 submit_job(ud->current_job);
1973         }
1974         else if (status.queue_state & GHB_STATE_PAUSED)
1975         {
1976                 status_str = g_strdup_printf ("Paused"); 
1977                 gtk_progress_bar_set_text (progress, status_str);
1978                 g_free(status_str);
1979         }
1980         else if (status.queue_state & GHB_STATE_WORKING)
1981         {
1982                 status_str = working_status_string(ud, &status);
1983                 gtk_progress_bar_set_text (progress, status_str);
1984                 gtk_progress_bar_set_fraction (progress, status.progress);
1985                 g_free(status_str);
1986         }
1987         else if (status.queue_state & GHB_STATE_WORKDONE)
1988         {
1989                 gint qstatus;
1990
1991                 work_started = FALSE;
1992                 ghb_queue_buttons_grey(ud, FALSE);
1993                 index = find_queue_job(ud->queue, status.unique_id, &js);
1994                 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
1995                 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
1996                 if (ud->cancel_encode)
1997                         status.error = GHB_ERROR_CANCELED;
1998                 switch( status.error )
1999                 {
2000                         case GHB_ERROR_NONE:
2001                                 gtk_progress_bar_set_text( progress, "Rip done!" );
2002                                 qstatus = GHB_QUEUE_DONE;
2003                                 if (js != NULL)
2004                                 {
2005                                         gchar *path = g_strdup_printf ("%d", index);
2006                                         if (gtk_tree_model_get_iter_from_string(
2007                                                         GTK_TREE_MODEL(store), &iter, path))
2008                                         {
2009                                                 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
2010                                         }
2011                                         g_free(path);
2012                                 }
2013                                 break;
2014                         case GHB_ERROR_CANCELED:
2015                                 gtk_progress_bar_set_text( progress, "Rip canceled." );
2016                                 qstatus = GHB_QUEUE_CANCELED;
2017                                 if (js != NULL)
2018                                 {
2019                                         gchar *path = g_strdup_printf ("%d", index);
2020                                         if (gtk_tree_model_get_iter_from_string(
2021                                                         GTK_TREE_MODEL(store), &iter, path))
2022                                         {
2023                                                 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
2024                                         }
2025                                         g_free(path);
2026                                 }
2027                                 break;
2028                         default:
2029                                 gtk_progress_bar_set_text( progress, "Rip failed.");
2030                                 qstatus = GHB_QUEUE_CANCELED;
2031                                 if (js != NULL)
2032                                 {
2033                                         gchar *path = g_strdup_printf ("%d", index);
2034                                         if (gtk_tree_model_get_iter_from_string(
2035                                                         GTK_TREE_MODEL(store), &iter, path))
2036                                         {
2037                                                 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
2038                                         }
2039                                         g_free(path);
2040                                 }
2041                 }
2042                 gtk_progress_bar_set_fraction (progress, 1.0);
2043                 ghb_clear_queue_state(GHB_STATE_WORKDONE);
2044                 if (!ud->cancel_encode)
2045                         ud->current_job = ghb_start_next_job(ud, FALSE);
2046                 else
2047                         ud->current_job = NULL;
2048                 if (js)
2049                         ghb_settings_set_int(js, "job_status", qstatus);
2050                 ghb_save_queue(ud->queue);
2051                 ud->cancel_encode = FALSE;
2052         }
2053         else if (status.queue_state & GHB_STATE_MUXING)
2054         {
2055                 gtk_progress_bar_set_text(progress, "Muxing: this may take awhile...");
2056         }
2057         if (status.queue_state & GHB_STATE_SCANNING)
2058         {
2059                 // This needs to be in scanning and working since scanning
2060                 // happens fast enough that it can be missed
2061                 if (!work_started)
2062                 {
2063                         work_started = TRUE;
2064                         ghb_queue_buttons_grey(ud, TRUE);
2065                 }
2066         }
2067         if (status.queue_state & GHB_STATE_WORKING)
2068         {
2069                 // This needs to be in scanning and working since scanning
2070                 // happens fast enough that it can be missed
2071                 if (!work_started)
2072                 {
2073                         work_started = TRUE;
2074                         ghb_queue_buttons_grey(ud, TRUE);
2075                 }
2076                 index = find_queue_job(ud->queue, status.unique_id, &js);
2077                 if (status.unique_id != 0 && index >= 0)
2078                 {
2079                         gchar working_icon[] = "hb-working0";
2080                         working_icon[10] = '0' + working;
2081                         working = (working+1) % 6;
2082                         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2083                         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2084                         gchar *path = g_strdup_printf ("%d", index);
2085                         if (gtk_tree_model_get_iter_from_string(
2086                                         GTK_TREE_MODEL(store), &iter, path))
2087                         {
2088                                 gtk_tree_store_set(store, &iter, 0, working_icon, -1);
2089                         }
2090                         g_free(path);
2091                 }
2092                 GtkLabel *label;
2093                 gchar *status_str;
2094
2095                 status_str = working_status_string(ud, &status);
2096                 label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_status"));
2097                 gtk_label_set_text (label, status_str);
2098                 g_free(status_str);
2099         }
2100 }
2101
2102 gboolean
2103 ghb_timer_cb(gpointer data)
2104 {
2105         signal_user_data_t *ud = (signal_user_data_t*)data;
2106
2107         ghb_backend_events(ud);
2108         if (update_default_destination)
2109         {
2110                 gchar *dest, *dest_dir, *def_dest;
2111                 dest = ghb_settings_get_string(ud->settings, "destination");
2112                 dest_dir = g_path_get_dirname (dest);
2113                 def_dest = ghb_settings_get_string(ud->settings, "destination_dir");
2114                 if (strcmp(dest_dir, def_dest) != 0)
2115                 {
2116                         ghb_settings_set_string (ud->settings, "destination_dir", dest_dir);
2117                         ghb_pref_save (ud->settings, "destination_dir");
2118                 }
2119                 g_free(dest);
2120                 g_free(dest_dir);
2121                 g_free(def_dest);
2122                 update_default_destination = FALSE;
2123         }
2124         if (update_preview)
2125         {
2126                 set_preview_image (ud);
2127                 update_preview = FALSE;
2128         }
2129         return TRUE;
2130 }
2131
2132 gboolean
2133 ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
2134 {
2135         gchar *text = NULL;
2136         gsize length;
2137         GtkTextView *textview;
2138         GtkTextBuffer *buffer;
2139         GtkTextIter iter;
2140         GtkTextMark *mark;
2141         GError *gerror = NULL;
2142         GIOStatus status;
2143         
2144         signal_user_data_t *ud = (signal_user_data_t*)data;
2145
2146         status = g_io_channel_read_line (source, &text, &length, NULL, &gerror);
2147         if (text != NULL)
2148         {
2149                 GdkWindow *window;
2150                 gint width, height;
2151                 gint x, y;
2152                 gboolean bottom = FALSE;
2153
2154                 textview = GTK_TEXT_VIEW(GHB_WIDGET (ud->builder, "activity_view"));
2155                 buffer = gtk_text_view_get_buffer (textview);
2156                 // I would like to auto-scroll the window when the scrollbar
2157                 // is at the bottom, 
2158                 // must determining whether the insert point is at
2159                 // the bottom of the window 
2160                 window = gtk_text_view_get_window(textview, GTK_TEXT_WINDOW_TEXT);
2161                 if (window != NULL)
2162                 {
2163                         gdk_drawable_get_size(GDK_DRAWABLE(window), &width, &height);
2164                         gtk_text_view_window_to_buffer_coords(textview, 
2165                                 GTK_TEXT_WINDOW_TEXT, width, height, &x, &y);
2166                         gtk_text_view_get_iter_at_location(textview, &iter, x, y);
2167                         if (gtk_text_iter_is_end(&iter))
2168                         {
2169                                 bottom = TRUE;
2170                         }
2171                 }
2172                 else
2173                 {
2174                         // If the window isn't available, assume bottom
2175                         bottom = TRUE;
2176                 }
2177                 gtk_text_buffer_get_end_iter(buffer, &iter);
2178                 gtk_text_buffer_insert(buffer, &iter, text, -1);
2179                 if (bottom)
2180                 {
2181                         //gtk_text_view_scroll_to_iter(textview, &iter, 0, FALSE, 0, 0);
2182                         mark = gtk_text_buffer_get_insert (buffer);
2183                         gtk_text_view_scroll_mark_onscreen(textview, mark);
2184                 }
2185                 g_io_channel_write_chars (ud->activity_log, text, length, &length, NULL);
2186                 g_free(text);
2187         }
2188         if (status != G_IO_STATUS_NORMAL)
2189         {
2190                 // This should never happen, but if it does I would get into an
2191                 // infinite loop.  Returning false removes this callback.
2192                 g_warning("Error while reading activity from pipe");
2193                 if (gerror != NULL)
2194                 {
2195                         g_warning("%s", gerror->message);
2196                         g_error_free (gerror);
2197                 }
2198                 return FALSE;
2199         }
2200         if (gerror != NULL)
2201                 g_error_free (gerror);
2202         return TRUE;
2203 }
2204
2205 void
2206 about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2207 {
2208         GtkWidget *widget = GHB_WIDGET (ud->builder, "hb_about");
2209         gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(widget), ghb_version());
2210         gtk_widget_show (widget);
2211 }
2212
2213 void
2214 guide_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2215 {
2216         gboolean result;
2217         char *argv[] = 
2218                 {"xdg-open","http://trac.handbrake.fr/wiki/HandBrakeGuide",NULL,NULL};
2219         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2220                                 NULL, NULL, NULL);
2221         if (result) return;
2222
2223         argv[0] = "gnome-open";
2224         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2225                                 NULL, NULL, NULL);
2226         if (result) return;
2227
2228         argv[0] = "kfmclient";
2229         argv[1] = "exec";
2230         argv[2] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2231         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2232                                 NULL, NULL, NULL);
2233         if (result) return;
2234
2235         argv[0] = "firefox";
2236         argv[1] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2237         argv[2] = NULL;
2238         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2239                                 NULL, NULL, NULL);
2240         if (result) return;
2241 }
2242
2243 void
2244 hb_about_response_cb(GtkWidget *widget, gint response, signal_user_data_t *ud)
2245 {
2246         gtk_widget_hide (widget);
2247 }
2248
2249 void
2250 show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2251 {
2252         GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
2253         gtk_widget_show (widget);
2254 }
2255
2256 void
2257 show_queue_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2258 {
2259         GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
2260         gtk_widget_show (widget);
2261 }
2262
2263 void
2264 show_presets_toggled_cb(GtkToggleButton *button, signal_user_data_t *ud)
2265 {
2266         GtkWidget *widget;
2267         GtkWindow *hb_window;
2268         
2269         g_debug("show_presets_clicked_cb ()");
2270         widget = GHB_WIDGET (ud->builder, "presets_frame");
2271         if (gtk_toggle_button_get_active(button))
2272         {
2273                 gtk_widget_show_now(widget);
2274         }
2275         else
2276         {
2277                 gtk_widget_hide(widget);
2278                 hb_window = GTK_WINDOW(GHB_WIDGET (ud->builder, "hb_window"));
2279                 gtk_window_resize(hb_window, 16, 16);
2280         }
2281         ghb_widget_to_setting(ud->settings, GTK_WIDGET(button));
2282         ghb_pref_save(ud->settings, "show_presets");
2283 }
2284
2285 void
2286 presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
2287 {
2288         GtkTreeView *treeview;
2289         GtkTreeSelection *selection;
2290         GtkTreeModel *store;
2291         GtkTreeIter iter;
2292         
2293         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
2294         selection = gtk_tree_view_get_selection(treeview);
2295         if (gtk_tree_selection_get_selected(selection, &store, &iter))
2296         {
2297                 GtkTreePath *path;
2298                 path = gtk_tree_model_get_path (store, &iter);
2299                 // Make the parent visible in scroll window if it is not.
2300                 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
2301                 gtk_tree_path_free(path);
2302         }
2303 }
2304
2305 static void
2306 update_chapter_list(signal_user_data_t *ud)
2307 {
2308         GtkTreeView *treeview;
2309         GtkTreeIter iter;
2310         GtkListStore *store;
2311         gboolean done;
2312         GValue *chapters;
2313         gint titleindex, ii;
2314         gint count;
2315         
2316         g_debug("update_chapter_list ()");
2317         titleindex = ghb_settings_combo_int(ud->settings, "title");
2318         chapters = ghb_get_chapters(titleindex);
2319         count = ghb_array_len(chapters);
2320         if (chapters)
2321                 ghb_settings_set_value(ud->settings, "chapter_list", chapters);
2322         
2323         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
2324         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
2325         ii = 0;
2326         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
2327         {
2328                 do
2329                 {
2330
2331                         if (ii < count)
2332                         {
2333                                 gchar *chapter;
2334
2335                                 // Update row with settings data
2336                                 g_debug("Updating row");
2337                                 chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
2338                                 gtk_list_store_set(store, &iter, 
2339                                         0, ii+1,
2340                                         1, chapter,
2341                                         2, TRUE,
2342                                         -1);
2343                                 g_free(chapter);
2344                                 ii++;
2345                                 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
2346                         }
2347                         else
2348                         {
2349                                 // No more settings data, remove row
2350                                 g_debug("Removing row");
2351                                 done = !gtk_list_store_remove(store, &iter);
2352                         }
2353                 } while (!done);
2354         }
2355         while (ii < count)
2356         {
2357                 gchar *chapter;
2358
2359                 // Additional settings, add row
2360                 g_debug("Adding row");
2361                 chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
2362                 gtk_list_store_append(store, &iter);
2363                 gtk_list_store_set(store, &iter, 
2364                         0, ii+1,
2365                         1, chapter,
2366                         2, TRUE,
2367                         -1);
2368                 g_free(chapter);
2369                 ii++;
2370         }
2371 }
2372
2373 static gint chapter_edit_key = 0;
2374
2375 gboolean
2376 chapter_keypress_cb(
2377         GhbCellRendererText *cell,
2378         GdkEventKey *event,
2379         signal_user_data_t *ud)
2380 {
2381         chapter_edit_key = event->keyval;
2382         return FALSE;
2383 }
2384
2385 void
2386 chapter_edited_cb(
2387         GhbCellRendererText *cell, 
2388         gchar *path, 
2389         gchar *text, 
2390         signal_user_data_t *ud)
2391 {
2392         GtkTreePath *treepath;
2393         GtkListStore *store;
2394         GtkTreeView *treeview;
2395         GtkTreeIter iter;
2396         gint index;
2397         gint *pi;
2398         gint row;
2399         
2400         g_debug("chapter_edited_cb ()");
2401         g_debug("path (%s)", path);
2402         g_debug("text (%s)", text);
2403         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
2404         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
2405         treepath = gtk_tree_path_new_from_string (path);
2406         pi = gtk_tree_path_get_indices(treepath);
2407         row = pi[0];
2408         gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
2409         gtk_list_store_set(store, &iter, 
2410                 1, text,
2411                 2, TRUE,
2412                 -1);
2413         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &index, -1);
2414
2415         GValue *chapters;
2416         GValue *chapter;
2417
2418         chapters = ghb_settings_get_value(ud->settings, "chapter_list");
2419         chapter = ghb_array_get_nth(chapters, index-1);
2420         g_value_set_string(chapter, text);
2421         if ((chapter_edit_key == GDK_Return || chapter_edit_key == GDK_Down) &&
2422                 gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
2423         {
2424                 GtkTreeViewColumn *column;
2425
2426                 gtk_tree_path_next(treepath);
2427                 // When a cell has been edited, I want to advance to the
2428                 // next cell and start editing it automaitcally.
2429                 // Unfortunately, we may not be in a state here where
2430                 // editing is allowed.  This happens when the user selects
2431                 // a new cell with the mouse instead of just hitting enter.
2432                 // Some kind of Gtk quirk.  widget_editable==NULL assertion.
2433                 // Editing is enabled again once the selection event has been
2434                 // processed.  So I'm queueing up a callback to be called
2435                 // when things go idle.  There, I will advance to the next
2436                 // cell and initiate editing.
2437                 //
2438                 // Now, you might be asking why I don't catch the keypress
2439                 // event and determine what action to take based on that.
2440                 // The Gtk developers in their infinite wisdom have made the 
2441                 // actual GtkEdit widget being used a private member of
2442                 // GtkCellRendererText, so it can not be accessed to hang a
2443                 // signal handler off of.  And they also do not propagate the
2444                 // keypress signals in any other way.  So that information is lost.
2445                 //g_idle_add((GSourceFunc)next_cell, ud);
2446                 //
2447                 // Keeping the above comment for posterity.
2448                 // I got industrious and made my own CellTextRendererText that
2449                 // passes on the key-press-event. So now I have much better
2450                 // control of this.
2451                 column = gtk_tree_view_get_column(treeview, 1);
2452                 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
2453         }
2454         else if (chapter_edit_key == GDK_Up && row > 0)
2455         {
2456                 GtkTreeViewColumn *column;
2457                 gtk_tree_path_prev(treepath);
2458                 column = gtk_tree_view_get_column(treeview, 1);
2459                 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
2460         }
2461         gtk_tree_path_free (treepath);
2462 }
2463
2464 void
2465 chapter_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
2466 {
2467         g_debug("chapter_list_selection_changed_cb ()");
2468         //chapter_selection_changed = TRUE;
2469 }
2470
2471 void
2472 preview_button_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2473 {
2474         gint titleindex;
2475
2476         titleindex = ghb_settings_combo_int(ud->settings, "title");
2477         if (titleindex < 0) return;
2478         g_debug("titleindex %d", titleindex);
2479
2480         GtkWidget *widget = GHB_WIDGET (ud->builder, "preview_window");
2481         gtk_widget_show (widget);
2482 }
2483
2484 void
2485 preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2486 {
2487         set_preview_image(ud);
2488 }
2489
2490 void
2491 preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
2492 {
2493         g_debug("-------------------------------allocate %d x %d", allocation->width, allocation->height);
2494         if (preview_button_width == allocation->width &&
2495                 preview_button_height == allocation->height)
2496         {
2497                 // Nothing to do. Bug out.
2498                 g_debug("nothing to do");
2499                 return;
2500         }
2501         g_debug("-------------------------------prev allocate %d x %d", preview_button_width, preview_button_height);
2502         preview_button_width = allocation->width;
2503         preview_button_height = allocation->height;
2504         set_preview_image(ud);
2505 }
2506
2507 void
2508 presets_default_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2509 {
2510         ghb_set_preset_default(ud->settings);
2511         ghb_presets_list_update(ud);
2512 }
2513
2514 void
2515 debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data)
2516 {
2517         signal_user_data_t *ud = (signal_user_data_t*)data;
2518         
2519         if (ud->debug)
2520         {
2521                 printf("%s: %s\n", domain, msg);
2522         }
2523 }
2524
2525 static void
2526 set_visible(GtkWidget *widget, gboolean visible)
2527 {
2528         if (visible)
2529         {
2530                 gtk_widget_show_now(widget);
2531         }
2532         else
2533         {
2534                 gtk_widget_hide(widget);
2535         }
2536 }
2537
2538 void
2539 ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
2540 {
2541         GtkWidget *widget;
2542         g_debug("ghb_hbfd");
2543         widget = GHB_WIDGET(ud->builder, "queue_pause1");
2544         set_visible(widget, !hbfd);
2545         widget = GHB_WIDGET(ud->builder, "queue_add");
2546         set_visible(widget, !hbfd);
2547         widget = GHB_WIDGET(ud->builder, "show_queue");
2548         set_visible(widget, !hbfd);
2549         widget = GHB_WIDGET(ud->builder, "show_activity");
2550         set_visible(widget, !hbfd);
2551
2552         widget = GHB_WIDGET(ud->builder, "chapter_box");
2553         set_visible(widget, !hbfd);
2554         widget = GHB_WIDGET(ud->builder, "container_box");
2555         set_visible(widget, !hbfd);
2556         widget = GHB_WIDGET(ud->builder, "settings_box");
2557         set_visible(widget, !hbfd);
2558         widget = GHB_WIDGET(ud->builder, "presets_save");
2559         set_visible(widget, !hbfd);
2560         widget = GHB_WIDGET(ud->builder, "presets_remove");
2561         set_visible(widget, !hbfd);
2562         widget = GHB_WIDGET(ud->builder, "presets_default");
2563         set_visible(widget, !hbfd);
2564         widget = GHB_WIDGET (ud->builder, "hb_window");
2565         gtk_window_resize(GTK_WINDOW(widget), 16, 16);
2566
2567 }
2568
2569 void
2570 hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
2571 {
2572         g_debug("hbfd_toggled_cb");
2573         ghb_widget_to_setting (ud->settings, widget);
2574         gboolean hbfd = ghb_settings_get_boolean(ud->settings, "hbfd");
2575         ghb_hbfd(ud, hbfd);
2576         ghb_pref_save(ud->settings, "hbfd");
2577 }
2578
2579 void
2580 pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2581 {
2582         g_debug("pref_changed_cb");
2583         ghb_widget_to_setting (ud->settings, widget);
2584         ghb_check_dependency(ud, widget);
2585         const gchar *name = gtk_widget_get_name(widget);
2586         ghb_pref_save(ud->settings, name);
2587 }
2588
2589 void
2590 tweaks_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2591 {
2592         g_debug("tweaks_changed_cb");
2593         ghb_widget_to_setting (ud->settings, widget);
2594         const gchar *name = gtk_widget_get_name(widget);
2595         ghb_pref_save(ud->settings, name);
2596
2597         gboolean tweaks = ghb_settings_get_boolean(ud->settings, "allow_tweaks");
2598         widget = GHB_WIDGET(ud->builder, "deinterlace");
2599         tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2600         widget = GHB_WIDGET(ud->builder, "tweak_deinterlace");
2601         !tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2602
2603         widget = GHB_WIDGET(ud->builder, "denoise");
2604         tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2605         widget = GHB_WIDGET(ud->builder, "tweak_denoise");
2606         !tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2607         if (tweaks)
2608         {
2609                 const GValue *value;
2610                 value = ghb_settings_get_value(ud->settings, "deinterlace");
2611                 ghb_ui_update(ud, "tweak_deinterlace", value);
2612                 value = ghb_settings_get_value(ud->settings, "denoise");
2613                 ghb_ui_update(ud, "tweak_denoise", value);
2614         }
2615         else
2616         {
2617                 const GValue *value;
2618                 value = ghb_settings_get_value(ud->settings, "tweak_deinterlace");
2619                 ghb_ui_update(ud, "deinterlace", value);
2620                 value = ghb_settings_get_value(ud->settings, "tweak_denoise");
2621                 ghb_ui_update(ud, "denoise", value);
2622         }
2623 }
2624
2625 void
2626 hbfd_feature_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2627 {
2628         g_debug("hbfd_feature_changed_cb");
2629         ghb_widget_to_setting (ud->settings, widget);
2630         const gchar *name = gtk_widget_get_name(widget);
2631         ghb_pref_save(ud->settings, name);
2632
2633         gboolean hbfd = ghb_settings_get_boolean(ud->settings, "hbfd_feature");
2634         GtkAction *action;
2635         if (hbfd)
2636         {
2637                 const GValue *val;
2638                 val = ghb_settings_get_value(ud->settings, "hbfd");
2639                 ghb_ui_update(ud, "hbfd", val);
2640         }
2641         action = GHB_ACTION (ud->builder, "hbfd");
2642         gtk_action_set_visible(action, hbfd);
2643 }
2644
2645 void
2646 ghb_file_menu_add_dvd(signal_user_data_t *ud)
2647 {
2648         GList *link, *drives;
2649
2650         GtkActionGroup *agroup = GTK_ACTION_GROUP(
2651                 gtk_builder_get_object(ud->builder, "actiongroup1"));
2652         GtkUIManager *ui = GTK_UI_MANAGER(
2653                 gtk_builder_get_object(ud->builder, "uimanager1"));
2654         guint merge_id = gtk_ui_manager_new_merge_id(ui);
2655
2656         link = drives = dvd_device_list();
2657         while (link != NULL)
2658         {
2659                 gchar *name = (gchar*)link->data;
2660                 // Create action for this drive
2661                 GtkAction *action = gtk_action_new(name, name,
2662                         "Scan this DVD source", "gtk-cdrom");
2663                 // Add action to action group
2664                 gtk_action_group_add_action_with_accel(agroup, action, "");
2665                 // Add to ui manager
2666                 gtk_ui_manager_add_ui(ui, merge_id, 
2667                         "ui/menubar1/menuitem1/quit1", name, name,
2668                         GTK_UI_MANAGER_AUTO, TRUE);
2669                 // Connect signal to action (menu item)
2670                 g_signal_connect(action, "activate", 
2671                         (GCallback)dvd_source_activate_cb, ud);
2672                 g_free(name);
2673                 link = link->next;
2674         }
2675         g_list_free(drives);
2676
2677         // Add separator
2678         gtk_ui_manager_add_ui(ui, merge_id, 
2679                 "ui/menubar1/menuitem1/quit1", "", NULL,
2680                 GTK_UI_MANAGER_AUTO, TRUE);
2681 }
2682
2683 gboolean ghb_is_cd(GDrive *gd);
2684
2685 static GList*
2686 dvd_device_list()
2687 {
2688         GVolumeMonitor *gvm;
2689         GList *drives, *link;
2690         GList *dvd_devices = NULL;
2691         
2692         gvm = g_volume_monitor_get ();
2693         drives = g_volume_monitor_get_connected_drives (gvm);
2694         link = drives;
2695         while (link != NULL)
2696         {
2697                 GDrive *gd;
2698                 
2699                 gd = (GDrive*)link->data;
2700                 if (ghb_is_cd(gd))
2701                 {
2702                         gchar *device;
2703                         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2704                         dvd_devices = g_list_append(dvd_devices, (gpointer)device);
2705                 }
2706                 g_object_unref (gd);
2707                 link = link->next;
2708         }
2709         g_list_free(drives);
2710         return dvd_devices;
2711 }
2712
2713
2714 static DBusConnection *dbus_connection = NULL;
2715 static LibHalContext *hal_ctx;
2716
2717 gboolean
2718 ghb_is_cd(GDrive *gd)
2719 {
2720         gchar *device;
2721         LibHalDrive *halDrive;
2722         LibHalDriveType dtype;
2723
2724         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2725         halDrive = libhal_drive_from_device_file (hal_ctx, device);
2726         dtype = libhal_drive_get_type(halDrive);
2727         libhal_drive_free(halDrive);
2728         g_free(device);
2729         return (dtype == LIBHAL_DRIVE_TYPE_CDROM);
2730 }
2731
2732 void
2733 drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
2734 {
2735         gchar *device;
2736         gint state = ghb_get_state();
2737         static gboolean first_time = TRUE;
2738
2739         if (ud->current_dvd_device == NULL) return;
2740         // A drive change event happens when the program initially starts
2741         // and I don't want to automatically scan at that time.
2742         if (first_time)
2743         {
2744                 first_time = FALSE;
2745                 return;
2746         }
2747         if (state != GHB_STATE_IDLE) return;
2748         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2749         
2750         // DVD insertion detected.  Scan it.
2751         if (strcmp(device, ud->current_dvd_device) == 0)
2752         {
2753                 if (g_drive_has_media (gd))
2754                 {
2755                         GtkProgressBar *progress;
2756                         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2757                         gtk_progress_bar_set_text (progress, "Scanning ...");
2758                         gtk_progress_bar_set_fraction (progress, 0);
2759                         update_source_label(ud, device);
2760                         ghb_hb_cleanup(TRUE);
2761                         ghb_backend_scan(device, 0);
2762                 }
2763                 else
2764                 {
2765                         ghb_hb_cleanup(TRUE);
2766                         ghb_backend_scan("/dev/null", 0);
2767                 }
2768         }
2769         g_free(device);
2770 }
2771
2772
2773 static gboolean
2774 dbus_init (void)
2775 {
2776         DBusError error;
2777
2778         if (dbus_connection != NULL)
2779                 return TRUE;
2780
2781         dbus_error_init (&error);
2782         if (!(dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) {
2783                 g_debug ("could not get system bus: %s", error.message);
2784                 dbus_error_free (&error);
2785                 return FALSE;
2786         }
2787
2788         //dbus_connection_setup_with_g_main (dbus_connection, NULL);
2789         //dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
2790         //dbus_connection_add_filter (dbus_connection, gvm_dbus_filter_function, NULL, NULL);
2791
2792         return TRUE;
2793 }
2794
2795 void
2796 ghb_hal_init()
2797 {
2798         DBusError error;
2799         char **devices;
2800         int nr;
2801
2802         if (!dbus_init ())
2803                 return;
2804
2805         if (!(hal_ctx = libhal_ctx_new ())) {
2806                 g_warning ("failed to create a HAL context!");
2807                 return;
2808         }
2809
2810         libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
2811         dbus_error_init (&error);
2812         if (!libhal_ctx_init (hal_ctx, &error)) {
2813                 g_warning ("libhal_ctx_init failed: %s", error.message ? error.message : "unknown");
2814                 dbus_error_free (&error);
2815                 libhal_ctx_free (hal_ctx);
2816                 return;
2817         }
2818
2819         /*
2820          * Do something to ping the HAL daemon - the above functions will
2821          * succeed even if hald is not running, so long as DBUS is.  But we
2822          * want to exit silently if hald is not running, to behave on
2823          * pre-2.6 systems.
2824          */
2825         if (!(devices = libhal_get_all_devices (hal_ctx, &nr, &error))) {
2826                 g_warning ("seems that HAL is not running: %s", error.message ? error.message : "unknown");
2827                 dbus_error_free (&error);
2828
2829                 libhal_ctx_shutdown (hal_ctx, NULL);
2830                 libhal_ctx_free (hal_ctx);
2831                 return;
2832         }
2833
2834         libhal_free_string_array (devices);
2835
2836         //gvm_hal_claim_branch ("/org/freedesktop/Hal/devices/local");
2837 }
2838
2839 gboolean 
2840 tweak_setting_cb(
2841         GtkWidget *widget, 
2842         GdkEventButton *event, 
2843         signal_user_data_t *ud)
2844 {
2845         const gchar *name;
2846         gchar *tweak_name;
2847         gboolean ret = FALSE;
2848         gboolean allow_tweaks;
2849
2850         g_debug("press %d %d", event->type, event->button);
2851         allow_tweaks = ghb_settings_get_boolean(ud->settings, "allow_tweaks");
2852         if (allow_tweaks && event->type == GDK_BUTTON_PRESS && event->button == 3)
2853         { // Its a right mouse click
2854                 GtkWidget *dialog;
2855                 GtkEntry *entry;
2856                 GtkResponseType response;
2857                 gchar *tweak = NULL;
2858
2859                 name = gtk_widget_get_name(widget);
2860                 if (g_str_has_prefix(name, "tweak_"))
2861                 {
2862                         tweak_name = g_strdup(name);
2863                 }
2864                 else
2865                 {
2866                         tweak_name = g_strdup_printf("tweak_%s", name);
2867                 }
2868
2869                 tweak = ghb_settings_get_string (ud->settings, tweak_name);
2870                 dialog = GHB_WIDGET(ud->builder, "tweak_dialog");
2871                 gtk_window_set_title(GTK_WINDOW(dialog), tweak_name);
2872                 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "tweak_setting"));
2873                 if (tweak)
2874                 {
2875                         gtk_entry_set_text(entry, tweak);
2876                         g_free(tweak);
2877                 }
2878                 response = gtk_dialog_run(GTK_DIALOG(dialog));
2879                 gtk_widget_hide(dialog);
2880                 if (response == GTK_RESPONSE_OK)
2881                 {
2882                         tweak = (gchar*)gtk_entry_get_text(entry);
2883                         if (ghb_validate_filter_string(tweak, -1))
2884                                 ghb_settings_set_string(ud->settings, tweak_name, tweak);
2885                         else
2886                         {
2887                                 gchar *message;
2888                                 message = g_strdup_printf(
2889                                                         "Invalid Settings:\n%s",
2890                                                         tweak);
2891                                 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2892                                 g_free(message);
2893                         }
2894                 }
2895                 g_free(tweak_name);
2896                 ret = TRUE;
2897         }
2898         return ret;
2899 }
2900
2901 gboolean 
2902 easter_egg_cb(
2903         GtkWidget *widget, 
2904         GdkEventButton *event, 
2905         signal_user_data_t *ud)
2906 {
2907         g_debug("press %d %d", event->type, event->button);
2908         if (event->type == GDK_3BUTTON_PRESS && event->button == 1)
2909         { // Its a tripple left mouse button click
2910                 GtkWidget *widget;
2911                 widget = GHB_WIDGET(ud->builder, "allow_tweaks");
2912                 gtk_widget_show(widget);
2913                 widget = GHB_WIDGET(ud->builder, "hbfd_feature");
2914                 gtk_widget_show(widget);
2915         }
2916         else if (event->type == GDK_BUTTON_PRESS && event->button == 1)
2917         {
2918                 GtkWidget *widget;
2919                 widget = GHB_WIDGET(ud->builder, "allow_tweaks");
2920                 gtk_widget_hide(widget);
2921                 widget = GHB_WIDGET(ud->builder, "hbfd_feature");
2922                 gtk_widget_hide(widget);
2923         }
2924         return FALSE;
2925 }
2926
2927 gchar*
2928 format_deblock_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
2929 {
2930         if (val < 5.0)
2931         {
2932                 return g_strdup_printf("Off");
2933         }
2934         else
2935         {
2936                 return g_strdup_printf("%d", (gint)val);
2937         }
2938 }