OSDN Git Service

LinGui: trim both callbacks.c and settings.c. Move code to x264handler
[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 void
214 ghb_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("ghb_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         ghb_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 setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1049 {
1050         ghb_widget_to_setting(ud->settings, widget);
1051         ghb_check_dependency(ud, widget);
1052         ghb_clear_presets_selection(ud);
1053 }
1054
1055 static void
1056 validate_filter_widget(signal_user_data_t *ud, const gchar *name)
1057 {
1058         GtkTreeModel *store;
1059         GtkTreeIter iter;
1060         const gchar *str;
1061         gboolean foundit = FALSE;
1062         GtkComboBox *combo = GTK_COMBO_BOX(GHB_WIDGET(ud->builder, name));
1063         if (gtk_combo_box_get_active(combo) < 0)
1064         { // Validate user input
1065                 gchar *val = ghb_settings_get_string(ud->settings, name);
1066                 store = gtk_combo_box_get_model(combo);
1067                 // Check to see if user manually entered one of the combo options
1068                 if (gtk_tree_model_get_iter_first(store, &iter))
1069                 {
1070                         do
1071                         {
1072                                 gtk_tree_model_get(store, &iter, 0, &str, -1);
1073                                 if (strcasecmp(val, str) == 0)
1074                                 {
1075                                         gtk_combo_box_set_active_iter(combo, &iter);
1076                                         foundit = TRUE;
1077                                         break;
1078                                 }
1079                         } while (gtk_tree_model_iter_next(store, &iter));
1080                 }
1081                 if (!foundit)
1082                 { // validate format of filter string
1083                         if (!ghb_validate_filter_string(val, -1))
1084                                 gtk_combo_box_set_active(combo, 0);
1085                 }
1086                 g_free(val);
1087         }
1088 }
1089
1090 gboolean
1091 deint_tweak_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
1092         signal_user_data_t *ud)
1093 {
1094         g_debug("deint_tweak_focus_out_cb ()");
1095         validate_filter_widget(ud, "tweak_deinterlace");
1096         return FALSE;
1097 }
1098
1099 gboolean
1100 denoise_tweak_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
1101         signal_user_data_t *ud)
1102 {
1103         g_debug("denoise_tweak_focus_out_cb ()");
1104         validate_filter_widget(ud, "tweak_noise");
1105         return FALSE;
1106 }
1107
1108 void
1109 http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1110 {
1111         ghb_widget_to_setting(ud->settings, widget);
1112         ghb_check_dependency(ud, widget);
1113         ghb_clear_presets_selection(ud);
1114         // AC3 is not allowed when Web optimized
1115         ghb_grey_combo_options (ud->builder);
1116 }
1117
1118 void
1119 vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1120 {
1121         gint vqmin, vqmax;
1122
1123         ghb_widget_to_setting(ud->settings, widget);
1124         ghb_check_dependency(ud, widget);
1125         ghb_clear_presets_selection(ud);
1126         ghb_vquality_range(ud, &vqmin, &vqmax);
1127         GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1128         gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1129 }
1130
1131 void
1132 target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1133 {
1134         const gchar *name = gtk_widget_get_name(widget);
1135         g_debug("setting_widget_changed_cb () %s", name);
1136         ghb_widget_to_setting(ud->settings, widget);
1137         ghb_check_dependency(ud, widget);
1138         ghb_clear_presets_selection(ud);
1139         if (ghb_settings_get_boolean(ud->settings, "vquality_type_target"))
1140         {
1141                 gint titleindex;
1142                 titleindex = ghb_settings_combo_int(ud->settings, "title");
1143                 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1144                 ghb_ui_update(ud, "video_bitrate", ghb_int64_value(bitrate));
1145         }
1146 }
1147
1148 void
1149 start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1150 {
1151         gint start, end;
1152         const gchar *name = gtk_widget_get_name(widget);
1153
1154         g_debug("start_chapter_changed_cb () %s", name);
1155         ghb_widget_to_setting(ud->settings, widget);
1156         start = ghb_settings_get_int(ud->settings, "start_chapter");
1157         end = ghb_settings_get_int(ud->settings, "end_chapter");
1158         if (start > end)
1159                 ghb_ui_update(ud, "end_chapter", ghb_int_value(start));
1160         ghb_check_dependency(ud, widget);
1161         if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
1162         {
1163                 set_destination(ud);
1164         }
1165 }
1166
1167 void
1168 end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1169 {
1170         gint start, end;
1171         const gchar *name = gtk_widget_get_name(widget);
1172
1173         g_debug("end_chapter_changed_cb () %s", name);
1174         ghb_widget_to_setting(ud->settings, widget);
1175         start = ghb_settings_get_int(ud->settings, "start_chapter");
1176         end = ghb_settings_get_int(ud->settings, "end_chapter");
1177         if (start > end)
1178                 ghb_ui_update(ud, "start_chapter", ghb_int_value(end));
1179         ghb_check_dependency(ud, widget);
1180         if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
1181         {
1182                 set_destination(ud);
1183         }
1184 }
1185
1186 void
1187 scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1188 {
1189         g_debug("scale_width_changed_cb ()");
1190         ghb_widget_to_setting(ud->settings, widget);
1191         ghb_check_dependency(ud, widget);
1192         ghb_set_scale (ud, GHB_SCALE_KEEP_WIDTH);
1193         update_preview = TRUE;
1194         gchar *text;
1195         gint width = ghb_settings_get_int(ud->settings, "scale_width");
1196         gint height = ghb_settings_get_int(ud->settings, "scale_height");
1197         widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1198         text = g_strdup_printf ("%d x %d", width, height);
1199         gtk_label_set_text (GTK_LABEL(widget), text);
1200         g_free(text);
1201 }
1202
1203 void
1204 scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1205 {
1206         g_debug("scale_height_changed_cb ()");
1207         ghb_widget_to_setting(ud->settings, widget);
1208         ghb_check_dependency(ud, widget);
1209         ghb_set_scale (ud, GHB_SCALE_KEEP_HEIGHT);
1210         update_preview = TRUE;
1211         gchar *text;
1212         gint width = ghb_settings_get_int(ud->settings, "scale_width");
1213         gint height = ghb_settings_get_int(ud->settings, "scale_height");
1214         widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1215         text = g_strdup_printf ("%d x %d", width, height);
1216         gtk_label_set_text (GTK_LABEL(widget), text);
1217         g_free(text);
1218 }
1219
1220 void
1221 crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1222 {
1223         gint titleindex, crop[4];
1224         ghb_title_info_t tinfo;
1225         
1226         g_debug("crop_changed_cb ()");
1227         ghb_widget_to_setting(ud->settings, widget);
1228         ghb_check_dependency(ud, widget);
1229         ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1230
1231         crop[0] = ghb_settings_get_int(ud->settings, "crop_top");
1232         crop[1] = ghb_settings_get_int(ud->settings, "crop_bottom");
1233         crop[2] = ghb_settings_get_int(ud->settings, "crop_left");
1234         crop[3] = ghb_settings_get_int(ud->settings, "crop_right");
1235         titleindex = ghb_settings_combo_int(ud->settings, "title");
1236         if (ghb_get_title_info (&tinfo, titleindex))
1237         {
1238                 gint width, height;
1239                 gchar *text;
1240                 
1241                 width = tinfo.width - crop[2] - crop[3];
1242                 height = tinfo.height - crop[0] - crop[1];
1243                 widget = GHB_WIDGET (ud->builder, "crop_dimensions");
1244                 text = g_strdup_printf ("%d x %d", width, height);
1245                 gtk_label_set_text (GTK_LABEL(widget), text);
1246                 g_free(text);
1247         }
1248         gchar *text;
1249         widget = GHB_WIDGET (ud->builder, "crop_values");
1250         text = g_strdup_printf ("%d:%d:%d:%d", crop[0], crop[1], crop[2], crop[3]);
1251         gtk_label_set_text (GTK_LABEL(widget), text);
1252         g_free(text);
1253         update_preview = TRUE;
1254 }
1255
1256 void
1257 scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1258 {
1259         g_debug("scale_changed_cb ()");
1260         ghb_widget_to_setting(ud->settings, widget);
1261         ghb_check_dependency(ud, widget);
1262         ghb_clear_presets_selection(ud);
1263         ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1264         update_preview = TRUE;
1265         
1266         gchar *text;
1267         
1268         text = ghb_settings_get_boolean(ud->settings, "autocrop") ? "On" : "Off";
1269         widget = GHB_WIDGET (ud->builder, "crop_auto");
1270         gtk_label_set_text (GTK_LABEL(widget), text);
1271         text = ghb_settings_get_boolean(ud->settings, "autoscale") ? "On" : "Off";
1272         widget = GHB_WIDGET (ud->builder, "scale_auto");
1273         gtk_label_set_text (GTK_LABEL(widget), text);
1274         text = ghb_settings_get_boolean(ud->settings, "anamorphic") ? "On" : "Off";
1275         widget = GHB_WIDGET (ud->builder, "scale_anamorphic");
1276         gtk_label_set_text (GTK_LABEL(widget), text);
1277 }
1278
1279 void
1280 generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
1281 {
1282         // Normally (due to user input) I only want to process the entry
1283         // when editing is done and the focus-out signal is sent.
1284         // But... there's always a but.
1285         // If the entry is changed by software, the focus-out signal is not sent.
1286         // The changed signal is sent ... so here we are.
1287         // I don't want to process upon every keystroke, so I prevent processing
1288         // while the widget has focus.
1289         g_debug("generic_entry_changed_cb ()");
1290         if (!GTK_WIDGET_HAS_FOCUS((GtkWidget*)entry))
1291         {
1292                 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
1293         }
1294 }
1295
1296 void
1297 ghb_presets_list_update(signal_user_data_t *ud)
1298 {
1299         GtkTreeView *treeview;
1300         GtkTreeIter iter;
1301         GtkListStore *store;
1302         gboolean done;
1303         GList *presets, *plink;
1304         gchar *preset, *def_preset;
1305         gchar *description;
1306         gint flags, custom, def;
1307         
1308         g_debug("ghb_presets_list_update ()");
1309         def_preset = ghb_settings_get_string(ud->settings, "default_preset");
1310         plink = presets = ghb_presets_get_names();
1311         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1312         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1313         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1314         {
1315                 do
1316                 {
1317                         if (plink)
1318                         {
1319                                 // Update row with settings data
1320                                 g_debug("Updating row");
1321                                 preset = (gchar*)plink->data;
1322                                 def = 0;
1323                                 if (strcmp(preset, def_preset) == 0)
1324                                         def = PRESET_DEFAULT;
1325                                 
1326                                 description = ghb_presets_get_description(preset);
1327                                 flags = ghb_preset_flags(preset);
1328                                 custom = flags & PRESET_CUSTOM;
1329                                 gtk_list_store_set(store, &iter, 
1330                                                         0, preset, 
1331                                                         1, def ? 800 : 400, 
1332                                                         2, def ? 2 : 0,
1333                                                         3, custom ? "black" : "blue", 
1334                                                         4, description,
1335                                                         -1);
1336                                 plink = plink->next;
1337                                 g_free(description);
1338                                 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1339                         }
1340                         else
1341                         {
1342                                 // No more settings data, remove row
1343                                 g_debug("Removing row");
1344                                 done = !gtk_list_store_remove(store, &iter);
1345                         }
1346                 } while (!done);
1347         }
1348         while (plink)
1349         {
1350                 // Additional settings, add row
1351                 g_debug("Adding rows");
1352                 preset = (gchar*)plink->data;
1353                 def = 0;
1354                 if (strcmp(preset, def_preset) == 0)
1355                         def = PRESET_DEFAULT;
1356
1357                 description = ghb_presets_get_description(preset);
1358                 gtk_list_store_append(store, &iter);
1359                 flags = ghb_preset_flags(preset);
1360                 custom = flags & PRESET_CUSTOM;
1361                 gtk_list_store_set(store, &iter, 0, preset, 
1362                                                         1, def ? 800 : 400, 
1363                                                         2, def ? 2 : 0,
1364                                                         3, custom ? "black" : "blue", 
1365                                                         4, description,
1366                                                         -1);
1367                 plink = plink->next;
1368                 g_free(description);
1369         }
1370         g_free(def_preset);
1371         g_list_free (presets);
1372 }
1373
1374 void
1375 ghb_select_preset(GtkBuilder *builder, const gchar *preset)
1376 {
1377         GtkTreeView *treeview;
1378         GtkTreeSelection *selection;
1379         GtkTreeModel *store;
1380         GtkTreeIter iter;
1381         gchar *tpreset;
1382         gboolean done;
1383         gboolean foundit = FALSE;
1384         
1385         g_debug("select_preset()");
1386         if (preset == NULL) return;
1387         treeview = GTK_TREE_VIEW(GHB_WIDGET(builder, "presets_list"));
1388         selection = gtk_tree_view_get_selection (treeview);
1389         store = gtk_tree_view_get_model (treeview);
1390         if (gtk_tree_model_get_iter_first(store, &iter))
1391         {
1392                 do
1393                 {
1394                         gtk_tree_model_get(store, &iter, 0, &tpreset, -1);
1395                         if (strcmp(preset, tpreset) == 0)
1396                         {
1397                                 gtk_tree_selection_select_iter (selection, &iter);
1398                                 foundit = TRUE;
1399                                 g_free(tpreset);
1400                                 break;
1401                         }
1402                         g_free(tpreset);
1403                         done = !gtk_tree_model_iter_next(store, &iter);
1404                 } while (!done);
1405         }
1406         if (!foundit)
1407         {
1408                 gtk_tree_model_get_iter_first(store, &iter);
1409                 gtk_tree_selection_select_iter (selection, &iter);
1410         }
1411 }
1412
1413 static void
1414 update_audio_presets(signal_user_data_t *ud)
1415 {
1416         g_debug("update_audio_presets");
1417         const GValue *audio_list;
1418
1419         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
1420         ghb_settings_set_value(ud->settings, "pref_audio_list", audio_list);
1421 }
1422
1423 void
1424 presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1425 {
1426         GtkWidget *dialog;
1427         GtkEntry *entry;
1428         GtkTextView *desc;
1429         GtkResponseType response;
1430         gchar *preset;
1431
1432         g_debug("presets_save_clicked_cb ()");
1433         preset = ghb_settings_get_string (ud->settings, "preset");
1434         // Clear the description
1435         desc = GTK_TEXT_VIEW(GHB_WIDGET(ud->builder, "preset_description"));
1436         dialog = GHB_WIDGET(ud->builder, "preset_save_dialog");
1437         entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "preset_name"));
1438         gtk_entry_set_text(entry, preset);
1439         g_free(preset);
1440         response = gtk_dialog_run(GTK_DIALOG(dialog));
1441         gtk_widget_hide(dialog);
1442         if (response == GTK_RESPONSE_OK)
1443         {
1444                 // save the preset
1445                 const gchar *name = gtk_entry_get_text(entry);
1446                 g_debug("description to settings");
1447                 ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
1448                 // Construct the audio settings presets from the current audio list
1449                 update_audio_presets(ud);
1450                 ghb_settings_save(ud, name);
1451                 ghb_presets_list_update(ud);
1452                 // Make the new preset the selected item
1453                 ghb_select_preset(ud->builder, name);
1454         }
1455 }
1456
1457 void
1458 presets_restore_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1459 {
1460         g_debug("presets_restore_clicked_cb ()");
1461         // Reload only the standard presets
1462         ghb_presets_reload(ud);
1463         ghb_presets_list_update(ud);
1464         // Updating the presets list shuffles things around
1465         // need to make sure the proper preset is selected
1466         gchar *preset = ghb_settings_get_string (ud->settings, "preset");
1467         ghb_select_preset(ud->builder, preset);
1468         g_free(preset);
1469 }
1470
1471 void
1472 presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1473 {
1474         GtkTreeView *treeview;
1475         GtkTreeSelection *selection;
1476         GtkTreeModel *store;
1477         GtkTreeIter iter;
1478         gchar *preset;
1479         GtkResponseType response;
1480
1481         g_debug("presets_remove_clicked_cb ()");
1482         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1483         selection = gtk_tree_view_get_selection (treeview);
1484         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1485         {
1486                 GtkWidget *dialog;
1487
1488                 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1489                 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1490                                                                 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1491                                                                 "Confirm deletion of preset %s.", preset);
1492                 response = gtk_dialog_run(GTK_DIALOG(dialog));
1493                 gtk_widget_destroy (dialog);
1494                 if (response == GTK_RESPONSE_YES)
1495                 {
1496                         GtkTreeIter nextIter = iter;
1497                         gchar *nextPreset = NULL;
1498                         if (!gtk_tree_model_iter_next(store, &nextIter))
1499                         {
1500                                 if (gtk_tree_model_get_iter_first(store, &nextIter))
1501                                 {
1502                                         gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1503                                 }
1504                         }
1505                         else
1506                         {
1507                                 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1508                         }
1509                         // Remove the selected item
1510                         // First unselect it so that selecting the new item works properly
1511                         gtk_tree_selection_unselect_iter (selection, &iter);
1512                         ghb_presets_remove(preset);
1513                         ghb_presets_list_update(ud);
1514                         ghb_select_preset(ud->builder, nextPreset);
1515                 }
1516         }
1517 }
1518
1519 static void
1520 preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
1521 {
1522         GtkWidget *widget;
1523
1524         ghb_ui_update(ud, "scale_width", 
1525                         ghb_int64_value(tinfo->width - tinfo->crop[2] - tinfo->crop[3]));
1526         // If anamorphic or keep_aspect, the hight will be automatically calculated
1527         gboolean keep_aspect, anamorphic;
1528         keep_aspect = ghb_settings_get_boolean(ud->settings, "keep_aspect");
1529         anamorphic = ghb_settings_get_boolean(ud->settings, "anamorphic");
1530         if (!(keep_aspect || anamorphic))
1531         {
1532                 ghb_ui_update(ud, "scale_height", 
1533                         ghb_int64_value(tinfo->height - tinfo->crop[0] - tinfo->crop[1]));
1534         }
1535
1536         // Set the limits of cropping.  hb_set_anamorphic_size crashes if
1537         // you pass it a cropped width or height == 0.
1538         gint bound;
1539         bound = tinfo->height / 2 - 2;
1540         widget = GHB_WIDGET (ud->builder, "crop_top");
1541         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1542         widget = GHB_WIDGET (ud->builder, "crop_bottom");
1543         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1544         bound = tinfo->width / 2 - 2;
1545         widget = GHB_WIDGET (ud->builder, "crop_left");
1546         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1547         widget = GHB_WIDGET (ud->builder, "crop_right");
1548         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1549         if (ghb_settings_get_boolean(ud->settings, "autocrop"))
1550         {
1551                 ghb_ui_update(ud, "crop_top", ghb_int64_value(tinfo->crop[0]));
1552                 ghb_ui_update(ud, "crop_bottom", ghb_int64_value(tinfo->crop[1]));
1553                 ghb_ui_update(ud, "crop_left", ghb_int64_value(tinfo->crop[2]));
1554                 ghb_ui_update(ud, "crop_right", ghb_int64_value(tinfo->crop[3]));
1555         }
1556 }
1557
1558 void
1559 presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
1560 {
1561         GtkTreeModel *store;
1562         GtkTreeIter iter;
1563         gchar *preset;
1564         ghb_title_info_t tinfo;
1565         GtkWidget *widget;
1566         
1567         g_debug("presets_list_selection_changed_cb ()");
1568         widget = GHB_WIDGET (ud->builder, "presets_remove");
1569         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1570         {
1571                 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1572                 ud->dont_clear_presets = TRUE;
1573                 // Temporarily set the video_quality range to (0,100)
1574                 // This is needed so the video_quality value does not get
1575                 // truncated when set.  The range will be readjusted below
1576                 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1577                 gtk_range_set_range (GTK_RANGE(qp), 0, 100);
1578                 // Clear the audio list prior to changing the preset.  Existing audio
1579                 // can cause the container extension to be automatically changed when
1580                 // it shouldn't be
1581                 ghb_clear_audio_list(ud);
1582                 ghb_set_preset(ud, preset);
1583                 gint titleindex;
1584                 titleindex = ghb_settings_combo_int(ud->settings, "title");
1585                 ghb_set_pref_audio(titleindex, ud);
1586                 ghb_settings_set_boolean(ud->settings, "preset_modified", FALSE);
1587                 ud->dont_clear_presets = FALSE;
1588                 if (ghb_get_title_info (&tinfo, titleindex))
1589                 {
1590                         preset_update_title_deps(ud, &tinfo);
1591                 }
1592                 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1593
1594                 gint vqmin, vqmax;
1595                 ghb_vquality_range(ud, &vqmin, &vqmax);
1596                 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1597                 gtk_widget_set_sensitive(widget, TRUE);
1598         }
1599         else
1600         {
1601                 g_debug("No selection???  Perhaps unselected.");
1602                 gtk_widget_set_sensitive(widget, FALSE);
1603         }
1604 }
1605
1606 void
1607 prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1608 {
1609         GtkWidget *dialog;
1610         GtkResponseType response;
1611
1612         g_debug("prefs_dialog_cb ()");
1613         dialog = GHB_WIDGET(ud->builder, "prefs_dialog");
1614         response = gtk_dialog_run(GTK_DIALOG(dialog));
1615         gtk_widget_hide(dialog);
1616 }
1617
1618 gboolean
1619 ghb_message_dialog(GtkMessageType type, const gchar *message, const gchar *no, const gchar *yes)
1620 {
1621         GtkWidget *dialog;
1622         GtkResponseType response;
1623                         
1624         // Toss up a warning dialog
1625         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1626                                                         type, GTK_BUTTONS_NONE,
1627                                                         message);
1628         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
1629                                                    no, GTK_RESPONSE_NO,
1630                                                    yes, GTK_RESPONSE_YES, NULL);
1631         response = gtk_dialog_run(GTK_DIALOG(dialog));
1632         gtk_widget_destroy (dialog);
1633         if (response == GTK_RESPONSE_NO)
1634         {
1635                 return FALSE;
1636         }
1637         return TRUE;
1638 }
1639
1640 gboolean
1641 ghb_cancel_encode(const gchar *extra_msg)
1642 {
1643         GtkWidget *dialog;
1644         GtkResponseType response;
1645         
1646         if (extra_msg == NULL) extra_msg = "";
1647         // Toss up a warning dialog
1648         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1649                                 GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
1650                                 "%sYour movie will be lost if you don't continue encoding.",
1651                                 extra_msg);
1652         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
1653                                                    "Continue Encoding", GTK_RESPONSE_NO,
1654                                                    "Stop Encoding", GTK_RESPONSE_YES, NULL);
1655         response = gtk_dialog_run(GTK_DIALOG(dialog));
1656         gtk_widget_destroy (dialog);
1657         if (response == GTK_RESPONSE_NO) return FALSE;
1658         ghb_stop_queue();
1659         return TRUE;
1660 }
1661
1662 static void
1663 submit_job(GValue *settings)
1664 {
1665         static gint unique_id = 1;
1666
1667         g_debug("submit_job");
1668         if (settings == NULL) return;
1669         ghb_settings_set_int(settings, "job_unique_id", unique_id);
1670         ghb_settings_set_int(settings, "job_status", GHB_QUEUE_RUNNING);
1671         ghb_add_job (settings, unique_id);
1672         ghb_start_queue();
1673         unique_id++;
1674 }
1675
1676 static void
1677 queue_scan(GValue *js)
1678 {
1679         gchar *path;
1680         gint titlenum;
1681
1682         path = ghb_settings_get_string( js, "source");
1683         titlenum = ghb_settings_get_int(js, "titlenum");
1684         ghb_backend_queue_scan(path, titlenum);
1685         g_free(path);
1686 }
1687
1688 GValue* 
1689 ghb_start_next_job(signal_user_data_t *ud, gboolean find_first)
1690 {
1691         static gint current = 0;
1692         gint count, ii, jj;
1693         GValue *js;
1694         gint status;
1695
1696         g_debug("start_next_job");
1697         count = ghb_array_len(ud->queue);
1698         if (find_first)
1699         {       // Start the first pending item in the queue
1700                 current = 0;
1701                 for (ii = 0; ii < count; ii++)
1702                 {
1703
1704                         js = ghb_array_get_nth(ud->queue, ii);
1705                         status = ghb_settings_get_int(js, "job_status");
1706                         if (status == GHB_QUEUE_PENDING)
1707                         {
1708                                 current = ii;
1709                                 queue_scan(js);
1710                                 return js;
1711                         }
1712                 }
1713                 // Nothing pending
1714                 return NULL;
1715         }
1716         // Find the next pending item after the current running item
1717         for (ii = 0; ii < count-1; ii++)
1718         {
1719                 js = ghb_array_get_nth(ud->queue, ii);
1720                 status = ghb_settings_get_int(js, "job_status");
1721                 if (status == GHB_QUEUE_RUNNING)
1722                 {
1723                         for (jj = ii+1; jj < count; jj++)
1724                         {
1725                                 js = ghb_array_get_nth(ud->queue, jj);
1726                                 status = ghb_settings_get_int(js, "job_status");
1727                                 if (status == GHB_QUEUE_PENDING)
1728                                 {
1729                                         current = jj;
1730                                         queue_scan(js);
1731                                         return js;
1732                                 }
1733                         }
1734                 }
1735         }
1736         // No running item found? Maybe it was deleted
1737         // Look for a pending item starting from the last index we started
1738         for (ii = current; ii < count; ii++)
1739         {
1740                 js = ghb_array_get_nth(ud->queue, ii);
1741                 status = ghb_settings_get_int(js, "job_status");
1742                 if (status == GHB_QUEUE_PENDING)
1743                 {
1744                         current = ii;
1745                         queue_scan(js);
1746                         return js;
1747                 }
1748         }
1749         // Nothing found
1750         return NULL;
1751 }
1752
1753 static gint
1754 find_queue_job(GValue *queue, gint unique_id, GValue **job)
1755 {
1756         GValue *js;
1757         gint ii, count;
1758         gint job_unique_id;
1759         
1760         *job = NULL;
1761         g_debug("find_queue_job");
1762         count = ghb_array_len(queue);
1763         for (ii = 0; ii < count; ii++)
1764         {
1765                 js = ghb_array_get_nth(queue, ii);
1766                 job_unique_id = ghb_settings_get_int(js, "job_unique_id");
1767                 if (job_unique_id == unique_id)
1768                 {
1769                         *job = js;
1770                         return ii;
1771                 }
1772         }
1773         return -1;
1774 }
1775
1776 gchar*
1777 working_status_string(signal_user_data_t *ud, ghb_status_t *status)
1778 {
1779         gchar *task_str, *job_str, *status_str;
1780         gint qcount;
1781         gint index;
1782         GValue *js;
1783
1784         if (status->job_count > 1)
1785         {
1786                 task_str = g_strdup_printf("pass %d of %d, ", 
1787                         status->job_cur, status->job_count);
1788         }
1789         else
1790         {
1791                 task_str = g_strdup("");
1792         }
1793         qcount = ghb_array_len(ud->queue);
1794         if (qcount > 1)
1795         {
1796                 index = find_queue_job(ud->queue, status->unique_id, &js);
1797                 job_str = g_strdup_printf("job %d of %d, ", index+1, qcount);
1798         }
1799         else
1800         {
1801                 job_str = g_strdup("");
1802         }
1803         if(status->seconds > -1)
1804         {
1805                 status_str= g_strdup_printf(
1806                         "Encoding: %s%s%.2f %%"
1807                         " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)",
1808                         job_str, task_str,
1809                         100.0 * status->progress,
1810                         status->rate_cur, status->rate_avg, status->hours, 
1811                         status->minutes, status->seconds );
1812         }
1813         else
1814         {
1815                 status_str= g_strdup_printf(
1816                         "Encoding: %s%s%.2f %%",
1817                         job_str, task_str,
1818                         100.0 * status->progress );
1819         }
1820         g_free(task_str);
1821         g_free(job_str);
1822         return status_str;
1823 }
1824
1825 static void
1826 ghb_backend_events(signal_user_data_t *ud)
1827 {
1828         ghb_status_t status;
1829         gchar *status_str;
1830         GtkProgressBar *progress;
1831         gint titleindex;
1832         GValue *js;
1833         gint index;
1834         GtkTreeView *treeview;
1835         GtkTreeStore *store;
1836         GtkTreeIter iter;
1837         static gint working = 0;
1838         static gboolean work_started = FALSE;
1839         
1840         ghb_track_status();
1841         ghb_get_status(&status);
1842         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
1843         // First handle the status of title scans
1844         // Then handle the status of the queue
1845         if (status.state & GHB_STATE_SCANNING)
1846         {
1847                 status_str = g_strdup_printf ("Scanning title %d of %d...", 
1848                                                                   status.title_cur, status.title_count );
1849                 gtk_progress_bar_set_text (progress, status_str);
1850                 g_free(status_str);
1851                 if (status.title_count > 0)
1852                 {
1853                         gtk_progress_bar_set_fraction (progress, 
1854                                 (gdouble)status.title_cur / status.title_count);
1855                 }
1856         }
1857         else if (status.state & GHB_STATE_SCANDONE)
1858         {
1859                 status_str = g_strdup_printf ("Scan done"); 
1860                 gtk_progress_bar_set_text (progress, status_str);
1861                 g_free(status_str);
1862                 gtk_progress_bar_set_fraction (progress, 1.0);
1863
1864                 ghb_title_info_t tinfo;
1865                         
1866                 ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE);
1867                 titleindex = ghb_longest_title();
1868                 ghb_ui_update(ud, "title", ghb_int64_value(titleindex));
1869
1870                 // Are there really any titles.
1871                 if (!ghb_get_title_info(&tinfo, titleindex))
1872                 {
1873                         GtkProgressBar *progress;
1874                         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
1875                         gtk_progress_bar_set_fraction (progress, 0);
1876                         gtk_progress_bar_set_text (progress, "No Source");
1877                 }
1878                 ghb_clear_state(GHB_STATE_SCANDONE);
1879                 ghb_queue_buttons_grey(ud, work_started);
1880         }
1881         else if (status.queue_state & GHB_STATE_SCANNING)
1882         {
1883                 status_str = g_strdup_printf ("Scanning ...");
1884                 gtk_progress_bar_set_text (progress, status_str);
1885                 g_free(status_str);
1886                 gtk_progress_bar_set_fraction (progress, 0);
1887         }
1888         else if (status.queue_state & GHB_STATE_SCANDONE)
1889         {
1890                 ghb_clear_queue_state(GHB_STATE_SCANDONE);
1891                 submit_job(ud->current_job);
1892         }
1893         else if (status.queue_state & GHB_STATE_PAUSED)
1894         {
1895                 status_str = g_strdup_printf ("Paused"); 
1896                 gtk_progress_bar_set_text (progress, status_str);
1897                 g_free(status_str);
1898         }
1899         else if (status.queue_state & GHB_STATE_WORKING)
1900         {
1901                 status_str = working_status_string(ud, &status);
1902                 gtk_progress_bar_set_text (progress, status_str);
1903                 gtk_progress_bar_set_fraction (progress, status.progress);
1904                 g_free(status_str);
1905         }
1906         else if (status.queue_state & GHB_STATE_WORKDONE)
1907         {
1908                 gint qstatus;
1909
1910                 work_started = FALSE;
1911                 ghb_queue_buttons_grey(ud, FALSE);
1912                 index = find_queue_job(ud->queue, status.unique_id, &js);
1913                 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
1914                 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
1915                 if (ud->cancel_encode)
1916                         status.error = GHB_ERROR_CANCELED;
1917                 switch( status.error )
1918                 {
1919                         case GHB_ERROR_NONE:
1920                                 gtk_progress_bar_set_text( progress, "Rip done!" );
1921                                 qstatus = GHB_QUEUE_DONE;
1922                                 if (js != NULL)
1923                                 {
1924                                         gchar *path = g_strdup_printf ("%d", index);
1925                                         if (gtk_tree_model_get_iter_from_string(
1926                                                         GTK_TREE_MODEL(store), &iter, path))
1927                                         {
1928                                                 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
1929                                         }
1930                                         g_free(path);
1931                                 }
1932                                 break;
1933                         case GHB_ERROR_CANCELED:
1934                                 gtk_progress_bar_set_text( progress, "Rip canceled." );
1935                                 qstatus = GHB_QUEUE_CANCELED;
1936                                 if (js != NULL)
1937                                 {
1938                                         gchar *path = g_strdup_printf ("%d", index);
1939                                         if (gtk_tree_model_get_iter_from_string(
1940                                                         GTK_TREE_MODEL(store), &iter, path))
1941                                         {
1942                                                 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
1943                                         }
1944                                         g_free(path);
1945                                 }
1946                                 break;
1947                         default:
1948                                 gtk_progress_bar_set_text( progress, "Rip failed.");
1949                                 qstatus = GHB_QUEUE_CANCELED;
1950                                 if (js != NULL)
1951                                 {
1952                                         gchar *path = g_strdup_printf ("%d", index);
1953                                         if (gtk_tree_model_get_iter_from_string(
1954                                                         GTK_TREE_MODEL(store), &iter, path))
1955                                         {
1956                                                 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
1957                                         }
1958                                         g_free(path);
1959                                 }
1960                 }
1961                 gtk_progress_bar_set_fraction (progress, 1.0);
1962                 ghb_clear_queue_state(GHB_STATE_WORKDONE);
1963                 if (!ud->cancel_encode)
1964                         ud->current_job = ghb_start_next_job(ud, FALSE);
1965                 else
1966                         ud->current_job = NULL;
1967                 if (js)
1968                         ghb_settings_set_int(js, "job_status", qstatus);
1969                 ghb_save_queue(ud->queue);
1970                 ud->cancel_encode = FALSE;
1971         }
1972         else if (status.queue_state & GHB_STATE_MUXING)
1973         {
1974                 gtk_progress_bar_set_text(progress, "Muxing: this may take awhile...");
1975         }
1976         if (status.queue_state & GHB_STATE_SCANNING)
1977         {
1978                 // This needs to be in scanning and working since scanning
1979                 // happens fast enough that it can be missed
1980                 if (!work_started)
1981                 {
1982                         work_started = TRUE;
1983                         ghb_queue_buttons_grey(ud, TRUE);
1984                 }
1985         }
1986         if (status.queue_state & GHB_STATE_WORKING)
1987         {
1988                 // This needs to be in scanning and working since scanning
1989                 // happens fast enough that it can be missed
1990                 if (!work_started)
1991                 {
1992                         work_started = TRUE;
1993                         ghb_queue_buttons_grey(ud, TRUE);
1994                 }
1995                 index = find_queue_job(ud->queue, status.unique_id, &js);
1996                 if (status.unique_id != 0 && index >= 0)
1997                 {
1998                         gchar working_icon[] = "hb-working0";
1999                         working_icon[10] = '0' + working;
2000                         working = (working+1) % 6;
2001                         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2002                         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2003                         gchar *path = g_strdup_printf ("%d", index);
2004                         if (gtk_tree_model_get_iter_from_string(
2005                                         GTK_TREE_MODEL(store), &iter, path))
2006                         {
2007                                 gtk_tree_store_set(store, &iter, 0, working_icon, -1);
2008                         }
2009                         g_free(path);
2010                 }
2011                 GtkLabel *label;
2012                 gchar *status_str;
2013
2014                 status_str = working_status_string(ud, &status);
2015                 label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_status"));
2016                 gtk_label_set_text (label, status_str);
2017                 g_free(status_str);
2018         }
2019 }
2020
2021 gboolean
2022 ghb_timer_cb(gpointer data)
2023 {
2024         signal_user_data_t *ud = (signal_user_data_t*)data;
2025
2026         ghb_backend_events(ud);
2027         if (update_default_destination)
2028         {
2029                 gchar *dest, *dest_dir, *def_dest;
2030                 dest = ghb_settings_get_string(ud->settings, "destination");
2031                 dest_dir = g_path_get_dirname (dest);
2032                 def_dest = ghb_settings_get_string(ud->settings, "destination_dir");
2033                 if (strcmp(dest_dir, def_dest) != 0)
2034                 {
2035                         ghb_settings_set_string (ud->settings, "destination_dir", dest_dir);
2036                         ghb_pref_save (ud->settings, "destination_dir");
2037                 }
2038                 g_free(dest);
2039                 g_free(dest_dir);
2040                 g_free(def_dest);
2041                 update_default_destination = FALSE;
2042         }
2043         if (update_preview)
2044         {
2045                 set_preview_image (ud);
2046                 update_preview = FALSE;
2047         }
2048         return TRUE;
2049 }
2050
2051 gboolean
2052 ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
2053 {
2054         gchar *text = NULL;
2055         gsize length;
2056         GtkTextView *textview;
2057         GtkTextBuffer *buffer;
2058         GtkTextIter iter;
2059         GtkTextMark *mark;
2060         GError *gerror = NULL;
2061         GIOStatus status;
2062         
2063         signal_user_data_t *ud = (signal_user_data_t*)data;
2064
2065         status = g_io_channel_read_line (source, &text, &length, NULL, &gerror);
2066         if (text != NULL)
2067         {
2068                 GdkWindow *window;
2069                 gint width, height;
2070                 gint x, y;
2071                 gboolean bottom = FALSE;
2072
2073                 textview = GTK_TEXT_VIEW(GHB_WIDGET (ud->builder, "activity_view"));
2074                 buffer = gtk_text_view_get_buffer (textview);
2075                 // I would like to auto-scroll the window when the scrollbar
2076                 // is at the bottom, 
2077                 // must determining whether the insert point is at
2078                 // the bottom of the window 
2079                 window = gtk_text_view_get_window(textview, GTK_TEXT_WINDOW_TEXT);
2080                 if (window != NULL)
2081                 {
2082                         gdk_drawable_get_size(GDK_DRAWABLE(window), &width, &height);
2083                         gtk_text_view_window_to_buffer_coords(textview, 
2084                                 GTK_TEXT_WINDOW_TEXT, width, height, &x, &y);
2085                         gtk_text_view_get_iter_at_location(textview, &iter, x, y);
2086                         if (gtk_text_iter_is_end(&iter))
2087                         {
2088                                 bottom = TRUE;
2089                         }
2090                 }
2091                 else
2092                 {
2093                         // If the window isn't available, assume bottom
2094                         bottom = TRUE;
2095                 }
2096                 gtk_text_buffer_get_end_iter(buffer, &iter);
2097                 gtk_text_buffer_insert(buffer, &iter, text, -1);
2098                 if (bottom)
2099                 {
2100                         //gtk_text_view_scroll_to_iter(textview, &iter, 0, FALSE, 0, 0);
2101                         mark = gtk_text_buffer_get_insert (buffer);
2102                         gtk_text_view_scroll_mark_onscreen(textview, mark);
2103                 }
2104                 g_io_channel_write_chars (ud->activity_log, text, length, &length, NULL);
2105                 g_free(text);
2106         }
2107         if (status != G_IO_STATUS_NORMAL)
2108         {
2109                 // This should never happen, but if it does I would get into an
2110                 // infinite loop.  Returning false removes this callback.
2111                 g_warning("Error while reading activity from pipe");
2112                 if (gerror != NULL)
2113                 {
2114                         g_warning("%s", gerror->message);
2115                         g_error_free (gerror);
2116                 }
2117                 return FALSE;
2118         }
2119         if (gerror != NULL)
2120                 g_error_free (gerror);
2121         return TRUE;
2122 }
2123
2124 void
2125 about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2126 {
2127         GtkWidget *widget = GHB_WIDGET (ud->builder, "hb_about");
2128         gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(widget), ghb_version());
2129         gtk_widget_show (widget);
2130 }
2131
2132 void
2133 guide_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2134 {
2135         gboolean result;
2136         char *argv[] = 
2137                 {"xdg-open","http://trac.handbrake.fr/wiki/HandBrakeGuide",NULL,NULL};
2138         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2139                                 NULL, NULL, NULL);
2140         if (result) return;
2141
2142         argv[0] = "gnome-open";
2143         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2144                                 NULL, NULL, NULL);
2145         if (result) return;
2146
2147         argv[0] = "kfmclient";
2148         argv[1] = "exec";
2149         argv[2] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2150         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2151                                 NULL, NULL, NULL);
2152         if (result) return;
2153
2154         argv[0] = "firefox";
2155         argv[1] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2156         argv[2] = NULL;
2157         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2158                                 NULL, NULL, NULL);
2159         if (result) return;
2160 }
2161
2162 void
2163 hb_about_response_cb(GtkWidget *widget, gint response, signal_user_data_t *ud)
2164 {
2165         gtk_widget_hide (widget);
2166 }
2167
2168 void
2169 show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2170 {
2171         GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
2172         gtk_widget_show (widget);
2173 }
2174
2175 void
2176 show_queue_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2177 {
2178         GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
2179         gtk_widget_show (widget);
2180 }
2181
2182 void
2183 show_presets_toggled_cb(GtkToggleButton *button, signal_user_data_t *ud)
2184 {
2185         GtkWidget *widget;
2186         GtkWindow *hb_window;
2187         
2188         g_debug("show_presets_clicked_cb ()");
2189         widget = GHB_WIDGET (ud->builder, "presets_frame");
2190         if (gtk_toggle_button_get_active(button))
2191         {
2192                 gtk_widget_show_now(widget);
2193         }
2194         else
2195         {
2196                 gtk_widget_hide(widget);
2197                 hb_window = GTK_WINDOW(GHB_WIDGET (ud->builder, "hb_window"));
2198                 gtk_window_resize(hb_window, 16, 16);
2199         }
2200         ghb_widget_to_setting(ud->settings, GTK_WIDGET(button));
2201         ghb_pref_save(ud->settings, "show_presets");
2202 }
2203
2204 void
2205 presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
2206 {
2207         GtkTreeView *treeview;
2208         GtkTreeSelection *selection;
2209         GtkTreeModel *store;
2210         GtkTreeIter iter;
2211         
2212         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
2213         selection = gtk_tree_view_get_selection(treeview);
2214         if (gtk_tree_selection_get_selected(selection, &store, &iter))
2215         {
2216                 GtkTreePath *path;
2217                 path = gtk_tree_model_get_path (store, &iter);
2218                 // Make the parent visible in scroll window if it is not.
2219                 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
2220                 gtk_tree_path_free(path);
2221         }
2222 }
2223
2224 static void
2225 update_chapter_list(signal_user_data_t *ud)
2226 {
2227         GtkTreeView *treeview;
2228         GtkTreeIter iter;
2229         GtkListStore *store;
2230         gboolean done;
2231         GValue *chapters;
2232         gint titleindex, ii;
2233         gint count;
2234         
2235         g_debug("update_chapter_list ()");
2236         titleindex = ghb_settings_combo_int(ud->settings, "title");
2237         chapters = ghb_get_chapters(titleindex);
2238         count = ghb_array_len(chapters);
2239         if (chapters)
2240                 ghb_settings_set_value(ud->settings, "chapter_list", chapters);
2241         
2242         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
2243         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
2244         ii = 0;
2245         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
2246         {
2247                 do
2248                 {
2249
2250                         if (ii < count)
2251                         {
2252                                 gchar *chapter;
2253
2254                                 // Update row with settings data
2255                                 g_debug("Updating row");
2256                                 chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
2257                                 gtk_list_store_set(store, &iter, 
2258                                         0, ii+1,
2259                                         1, chapter,
2260                                         2, TRUE,
2261                                         -1);
2262                                 g_free(chapter);
2263                                 ii++;
2264                                 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
2265                         }
2266                         else
2267                         {
2268                                 // No more settings data, remove row
2269                                 g_debug("Removing row");
2270                                 done = !gtk_list_store_remove(store, &iter);
2271                         }
2272                 } while (!done);
2273         }
2274         while (ii < count)
2275         {
2276                 gchar *chapter;
2277
2278                 // Additional settings, add row
2279                 g_debug("Adding row");
2280                 chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
2281                 gtk_list_store_append(store, &iter);
2282                 gtk_list_store_set(store, &iter, 
2283                         0, ii+1,
2284                         1, chapter,
2285                         2, TRUE,
2286                         -1);
2287                 g_free(chapter);
2288                 ii++;
2289         }
2290 }
2291
2292 static gint chapter_edit_key = 0;
2293
2294 gboolean
2295 chapter_keypress_cb(
2296         GhbCellRendererText *cell,
2297         GdkEventKey *event,
2298         signal_user_data_t *ud)
2299 {
2300         chapter_edit_key = event->keyval;
2301         return FALSE;
2302 }
2303
2304 void
2305 chapter_edited_cb(
2306         GhbCellRendererText *cell, 
2307         gchar *path, 
2308         gchar *text, 
2309         signal_user_data_t *ud)
2310 {
2311         GtkTreePath *treepath;
2312         GtkListStore *store;
2313         GtkTreeView *treeview;
2314         GtkTreeIter iter;
2315         gint index;
2316         gint *pi;
2317         gint row;
2318         
2319         g_debug("chapter_edited_cb ()");
2320         g_debug("path (%s)", path);
2321         g_debug("text (%s)", text);
2322         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
2323         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
2324         treepath = gtk_tree_path_new_from_string (path);
2325         pi = gtk_tree_path_get_indices(treepath);
2326         row = pi[0];
2327         gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
2328         gtk_list_store_set(store, &iter, 
2329                 1, text,
2330                 2, TRUE,
2331                 -1);
2332         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &index, -1);
2333
2334         GValue *chapters;
2335         GValue *chapter;
2336
2337         chapters = ghb_settings_get_value(ud->settings, "chapter_list");
2338         chapter = ghb_array_get_nth(chapters, index-1);
2339         g_value_set_string(chapter, text);
2340         if ((chapter_edit_key == GDK_Return || chapter_edit_key == GDK_Down) &&
2341                 gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
2342         {
2343                 GtkTreeViewColumn *column;
2344
2345                 gtk_tree_path_next(treepath);
2346                 // When a cell has been edited, I want to advance to the
2347                 // next cell and start editing it automaitcally.
2348                 // Unfortunately, we may not be in a state here where
2349                 // editing is allowed.  This happens when the user selects
2350                 // a new cell with the mouse instead of just hitting enter.
2351                 // Some kind of Gtk quirk.  widget_editable==NULL assertion.
2352                 // Editing is enabled again once the selection event has been
2353                 // processed.  So I'm queueing up a callback to be called
2354                 // when things go idle.  There, I will advance to the next
2355                 // cell and initiate editing.
2356                 //
2357                 // Now, you might be asking why I don't catch the keypress
2358                 // event and determine what action to take based on that.
2359                 // The Gtk developers in their infinite wisdom have made the 
2360                 // actual GtkEdit widget being used a private member of
2361                 // GtkCellRendererText, so it can not be accessed to hang a
2362                 // signal handler off of.  And they also do not propagate the
2363                 // keypress signals in any other way.  So that information is lost.
2364                 //g_idle_add((GSourceFunc)next_cell, ud);
2365                 //
2366                 // Keeping the above comment for posterity.
2367                 // I got industrious and made my own CellTextRendererText that
2368                 // passes on the key-press-event. So now I have much better
2369                 // control of this.
2370                 column = gtk_tree_view_get_column(treeview, 1);
2371                 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
2372         }
2373         else if (chapter_edit_key == GDK_Up && row > 0)
2374         {
2375                 GtkTreeViewColumn *column;
2376                 gtk_tree_path_prev(treepath);
2377                 column = gtk_tree_view_get_column(treeview, 1);
2378                 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
2379         }
2380         gtk_tree_path_free (treepath);
2381 }
2382
2383 void
2384 chapter_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
2385 {
2386         g_debug("chapter_list_selection_changed_cb ()");
2387         //chapter_selection_changed = TRUE;
2388 }
2389
2390 void
2391 preview_button_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2392 {
2393         gint titleindex;
2394
2395         titleindex = ghb_settings_combo_int(ud->settings, "title");
2396         if (titleindex < 0) return;
2397         g_debug("titleindex %d", titleindex);
2398
2399         GtkWidget *widget = GHB_WIDGET (ud->builder, "preview_window");
2400         gtk_widget_show (widget);
2401 }
2402
2403 void
2404 preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2405 {
2406         set_preview_image(ud);
2407 }
2408
2409 void
2410 preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
2411 {
2412         g_debug("-------------------------------allocate %d x %d", allocation->width, allocation->height);
2413         if (preview_button_width == allocation->width &&
2414                 preview_button_height == allocation->height)
2415         {
2416                 // Nothing to do. Bug out.
2417                 g_debug("nothing to do");
2418                 return;
2419         }
2420         g_debug("-------------------------------prev allocate %d x %d", preview_button_width, preview_button_height);
2421         preview_button_width = allocation->width;
2422         preview_button_height = allocation->height;
2423         set_preview_image(ud);
2424 }
2425
2426 void
2427 presets_default_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2428 {
2429         ghb_set_preset_default(ud->settings);
2430         ghb_presets_list_update(ud);
2431 }
2432
2433 void
2434 debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data)
2435 {
2436         signal_user_data_t *ud = (signal_user_data_t*)data;
2437         
2438         if (ud->debug)
2439         {
2440                 printf("%s: %s\n", domain, msg);
2441         }
2442 }
2443
2444 static void
2445 set_visible(GtkWidget *widget, gboolean visible)
2446 {
2447         if (visible)
2448         {
2449                 gtk_widget_show_now(widget);
2450         }
2451         else
2452         {
2453                 gtk_widget_hide(widget);
2454         }
2455 }
2456
2457 void
2458 ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
2459 {
2460         GtkWidget *widget;
2461         g_debug("ghb_hbfd");
2462         widget = GHB_WIDGET(ud->builder, "queue_pause1");
2463         set_visible(widget, !hbfd);
2464         widget = GHB_WIDGET(ud->builder, "queue_add");
2465         set_visible(widget, !hbfd);
2466         widget = GHB_WIDGET(ud->builder, "show_queue");
2467         set_visible(widget, !hbfd);
2468         widget = GHB_WIDGET(ud->builder, "show_activity");
2469         set_visible(widget, !hbfd);
2470
2471         widget = GHB_WIDGET(ud->builder, "chapter_box");
2472         set_visible(widget, !hbfd);
2473         widget = GHB_WIDGET(ud->builder, "container_box");
2474         set_visible(widget, !hbfd);
2475         widget = GHB_WIDGET(ud->builder, "settings_box");
2476         set_visible(widget, !hbfd);
2477         widget = GHB_WIDGET(ud->builder, "presets_save");
2478         set_visible(widget, !hbfd);
2479         widget = GHB_WIDGET(ud->builder, "presets_remove");
2480         set_visible(widget, !hbfd);
2481         widget = GHB_WIDGET(ud->builder, "presets_default");
2482         set_visible(widget, !hbfd);
2483         widget = GHB_WIDGET (ud->builder, "hb_window");
2484         gtk_window_resize(GTK_WINDOW(widget), 16, 16);
2485
2486 }
2487
2488 void
2489 hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
2490 {
2491         g_debug("hbfd_toggled_cb");
2492         ghb_widget_to_setting (ud->settings, widget);
2493         gboolean hbfd = ghb_settings_get_boolean(ud->settings, "hbfd");
2494         ghb_hbfd(ud, hbfd);
2495         ghb_pref_save(ud->settings, "hbfd");
2496 }
2497
2498 void
2499 pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2500 {
2501         g_debug("pref_changed_cb");
2502         ghb_widget_to_setting (ud->settings, widget);
2503         ghb_check_dependency(ud, widget);
2504         const gchar *name = gtk_widget_get_name(widget);
2505         ghb_pref_save(ud->settings, name);
2506 }
2507
2508 void
2509 tweaks_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2510 {
2511         g_debug("tweaks_changed_cb");
2512         ghb_widget_to_setting (ud->settings, widget);
2513         const gchar *name = gtk_widget_get_name(widget);
2514         ghb_pref_save(ud->settings, name);
2515
2516         gboolean tweaks = ghb_settings_get_boolean(ud->settings, "allow_tweaks");
2517         widget = GHB_WIDGET(ud->builder, "deinterlace");
2518         tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2519         widget = GHB_WIDGET(ud->builder, "tweak_deinterlace");
2520         !tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2521
2522         widget = GHB_WIDGET(ud->builder, "denoise");
2523         tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2524         widget = GHB_WIDGET(ud->builder, "tweak_denoise");
2525         !tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2526         if (tweaks)
2527         {
2528                 const GValue *value;
2529                 value = ghb_settings_get_value(ud->settings, "deinterlace");
2530                 ghb_ui_update(ud, "tweak_deinterlace", value);
2531                 value = ghb_settings_get_value(ud->settings, "denoise");
2532                 ghb_ui_update(ud, "tweak_denoise", value);
2533         }
2534         else
2535         {
2536                 const GValue *value;
2537                 value = ghb_settings_get_value(ud->settings, "tweak_deinterlace");
2538                 ghb_ui_update(ud, "deinterlace", value);
2539                 value = ghb_settings_get_value(ud->settings, "tweak_denoise");
2540                 ghb_ui_update(ud, "denoise", value);
2541         }
2542 }
2543
2544 void
2545 hbfd_feature_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2546 {
2547         g_debug("hbfd_feature_changed_cb");
2548         ghb_widget_to_setting (ud->settings, widget);
2549         const gchar *name = gtk_widget_get_name(widget);
2550         ghb_pref_save(ud->settings, name);
2551
2552         gboolean hbfd = ghb_settings_get_boolean(ud->settings, "hbfd_feature");
2553         GtkAction *action;
2554         if (hbfd)
2555         {
2556                 const GValue *val;
2557                 val = ghb_settings_get_value(ud->settings, "hbfd");
2558                 ghb_ui_update(ud, "hbfd", val);
2559         }
2560         action = GHB_ACTION (ud->builder, "hbfd");
2561         gtk_action_set_visible(action, hbfd);
2562 }
2563
2564 void
2565 ghb_file_menu_add_dvd(signal_user_data_t *ud)
2566 {
2567         GList *link, *drives;
2568
2569         GtkActionGroup *agroup = GTK_ACTION_GROUP(
2570                 gtk_builder_get_object(ud->builder, "actiongroup1"));
2571         GtkUIManager *ui = GTK_UI_MANAGER(
2572                 gtk_builder_get_object(ud->builder, "uimanager1"));
2573         guint merge_id = gtk_ui_manager_new_merge_id(ui);
2574
2575         link = drives = dvd_device_list();
2576         while (link != NULL)
2577         {
2578                 gchar *name = (gchar*)link->data;
2579                 // Create action for this drive
2580                 GtkAction *action = gtk_action_new(name, name,
2581                         "Scan this DVD source", "gtk-cdrom");
2582                 // Add action to action group
2583                 gtk_action_group_add_action_with_accel(agroup, action, "");
2584                 // Add to ui manager
2585                 gtk_ui_manager_add_ui(ui, merge_id, 
2586                         "ui/menubar1/menuitem1/quit1", name, name,
2587                         GTK_UI_MANAGER_AUTO, TRUE);
2588                 // Connect signal to action (menu item)
2589                 g_signal_connect(action, "activate", 
2590                         (GCallback)dvd_source_activate_cb, ud);
2591                 g_free(name);
2592                 link = link->next;
2593         }
2594         g_list_free(drives);
2595
2596         // Add separator
2597         gtk_ui_manager_add_ui(ui, merge_id, 
2598                 "ui/menubar1/menuitem1/quit1", "", NULL,
2599                 GTK_UI_MANAGER_AUTO, TRUE);
2600 }
2601
2602 gboolean ghb_is_cd(GDrive *gd);
2603
2604 static GList*
2605 dvd_device_list()
2606 {
2607         GVolumeMonitor *gvm;
2608         GList *drives, *link;
2609         GList *dvd_devices = NULL;
2610         
2611         gvm = g_volume_monitor_get ();
2612         drives = g_volume_monitor_get_connected_drives (gvm);
2613         link = drives;
2614         while (link != NULL)
2615         {
2616                 GDrive *gd;
2617                 
2618                 gd = (GDrive*)link->data;
2619                 if (ghb_is_cd(gd))
2620                 {
2621                         gchar *device;
2622                         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2623                         dvd_devices = g_list_append(dvd_devices, (gpointer)device);
2624                 }
2625                 g_object_unref (gd);
2626                 link = link->next;
2627         }
2628         g_list_free(drives);
2629         return dvd_devices;
2630 }
2631
2632
2633 static DBusConnection *dbus_connection = NULL;
2634 static LibHalContext *hal_ctx;
2635
2636 gboolean
2637 ghb_is_cd(GDrive *gd)
2638 {
2639         gchar *device;
2640         LibHalDrive *halDrive;
2641         LibHalDriveType dtype;
2642
2643         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2644         halDrive = libhal_drive_from_device_file (hal_ctx, device);
2645         dtype = libhal_drive_get_type(halDrive);
2646         libhal_drive_free(halDrive);
2647         g_free(device);
2648         return (dtype == LIBHAL_DRIVE_TYPE_CDROM);
2649 }
2650
2651 void
2652 drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
2653 {
2654         gchar *device;
2655         gint state = ghb_get_state();
2656         static gboolean first_time = TRUE;
2657
2658         if (ud->current_dvd_device == NULL) return;
2659         // A drive change event happens when the program initially starts
2660         // and I don't want to automatically scan at that time.
2661         if (first_time)
2662         {
2663                 first_time = FALSE;
2664                 return;
2665         }
2666         if (state != GHB_STATE_IDLE) return;
2667         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2668         
2669         // DVD insertion detected.  Scan it.
2670         if (strcmp(device, ud->current_dvd_device) == 0)
2671         {
2672                 if (g_drive_has_media (gd))
2673                 {
2674                         GtkProgressBar *progress;
2675                         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2676                         gtk_progress_bar_set_text (progress, "Scanning ...");
2677                         gtk_progress_bar_set_fraction (progress, 0);
2678                         update_source_label(ud, device);
2679                         ghb_hb_cleanup(TRUE);
2680                         ghb_backend_scan(device, 0);
2681                 }
2682                 else
2683                 {
2684                         ghb_hb_cleanup(TRUE);
2685                         ghb_backend_scan("/dev/null", 0);
2686                 }
2687         }
2688         g_free(device);
2689 }
2690
2691
2692 static gboolean
2693 dbus_init (void)
2694 {
2695         DBusError error;
2696
2697         if (dbus_connection != NULL)
2698                 return TRUE;
2699
2700         dbus_error_init (&error);
2701         if (!(dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) {
2702                 g_debug ("could not get system bus: %s", error.message);
2703                 dbus_error_free (&error);
2704                 return FALSE;
2705         }
2706
2707         //dbus_connection_setup_with_g_main (dbus_connection, NULL);
2708         //dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
2709         //dbus_connection_add_filter (dbus_connection, gvm_dbus_filter_function, NULL, NULL);
2710
2711         return TRUE;
2712 }
2713
2714 void
2715 ghb_hal_init()
2716 {
2717         DBusError error;
2718         char **devices;
2719         int nr;
2720
2721         if (!dbus_init ())
2722                 return;
2723
2724         if (!(hal_ctx = libhal_ctx_new ())) {
2725                 g_warning ("failed to create a HAL context!");
2726                 return;
2727         }
2728
2729         libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
2730         dbus_error_init (&error);
2731         if (!libhal_ctx_init (hal_ctx, &error)) {
2732                 g_warning ("libhal_ctx_init failed: %s", error.message ? error.message : "unknown");
2733                 dbus_error_free (&error);
2734                 libhal_ctx_free (hal_ctx);
2735                 return;
2736         }
2737
2738         /*
2739          * Do something to ping the HAL daemon - the above functions will
2740          * succeed even if hald is not running, so long as DBUS is.  But we
2741          * want to exit silently if hald is not running, to behave on
2742          * pre-2.6 systems.
2743          */
2744         if (!(devices = libhal_get_all_devices (hal_ctx, &nr, &error))) {
2745                 g_warning ("seems that HAL is not running: %s", error.message ? error.message : "unknown");
2746                 dbus_error_free (&error);
2747
2748                 libhal_ctx_shutdown (hal_ctx, NULL);
2749                 libhal_ctx_free (hal_ctx);
2750                 return;
2751         }
2752
2753         libhal_free_string_array (devices);
2754
2755         //gvm_hal_claim_branch ("/org/freedesktop/Hal/devices/local");
2756 }
2757
2758 gboolean 
2759 tweak_setting_cb(
2760         GtkWidget *widget, 
2761         GdkEventButton *event, 
2762         signal_user_data_t *ud)
2763 {
2764         const gchar *name;
2765         gchar *tweak_name;
2766         gboolean ret = FALSE;
2767         gboolean allow_tweaks;
2768
2769         g_debug("press %d %d", event->type, event->button);
2770         allow_tweaks = ghb_settings_get_boolean(ud->settings, "allow_tweaks");
2771         if (allow_tweaks && event->type == GDK_BUTTON_PRESS && event->button == 3)
2772         { // Its a right mouse click
2773                 GtkWidget *dialog;
2774                 GtkEntry *entry;
2775                 GtkResponseType response;
2776                 gchar *tweak = NULL;
2777
2778                 name = gtk_widget_get_name(widget);
2779                 if (g_str_has_prefix(name, "tweak_"))
2780                 {
2781                         tweak_name = g_strdup(name);
2782                 }
2783                 else
2784                 {
2785                         tweak_name = g_strdup_printf("tweak_%s", name);
2786                 }
2787
2788                 tweak = ghb_settings_get_string (ud->settings, tweak_name);
2789                 dialog = GHB_WIDGET(ud->builder, "tweak_dialog");
2790                 gtk_window_set_title(GTK_WINDOW(dialog), tweak_name);
2791                 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "tweak_setting"));
2792                 if (tweak)
2793                 {
2794                         gtk_entry_set_text(entry, tweak);
2795                         g_free(tweak);
2796                 }
2797                 response = gtk_dialog_run(GTK_DIALOG(dialog));
2798                 gtk_widget_hide(dialog);
2799                 if (response == GTK_RESPONSE_OK)
2800                 {
2801                         tweak = (gchar*)gtk_entry_get_text(entry);
2802                         if (ghb_validate_filter_string(tweak, -1))
2803                                 ghb_settings_set_string(ud->settings, tweak_name, tweak);
2804                         else
2805                         {
2806                                 gchar *message;
2807                                 message = g_strdup_printf(
2808                                                         "Invalid Settings:\n%s",
2809                                                         tweak);
2810                                 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2811                                 g_free(message);
2812                         }
2813                 }
2814                 g_free(tweak_name);
2815                 ret = TRUE;
2816         }
2817         return ret;
2818 }
2819
2820 gboolean 
2821 easter_egg_cb(
2822         GtkWidget *widget, 
2823         GdkEventButton *event, 
2824         signal_user_data_t *ud)
2825 {
2826         g_debug("press %d %d", event->type, event->button);
2827         if (event->type == GDK_3BUTTON_PRESS && event->button == 1)
2828         { // Its a tripple left mouse button click
2829                 GtkWidget *widget;
2830                 widget = GHB_WIDGET(ud->builder, "allow_tweaks");
2831                 gtk_widget_show(widget);
2832                 widget = GHB_WIDGET(ud->builder, "hbfd_feature");
2833                 gtk_widget_show(widget);
2834         }
2835         else if (event->type == GDK_BUTTON_PRESS && event->button == 1)
2836         {
2837                 GtkWidget *widget;
2838                 widget = GHB_WIDGET(ud->builder, "allow_tweaks");
2839                 gtk_widget_hide(widget);
2840                 widget = GHB_WIDGET(ud->builder, "hbfd_feature");
2841                 gtk_widget_hide(widget);
2842         }
2843         return FALSE;
2844 }
2845
2846 gchar*
2847 format_deblock_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
2848 {
2849         if (val < 5.0)
2850         {
2851                 return g_strdup_printf("Off");
2852         }
2853         else
2854         {
2855                 return g_strdup_printf("%d", (gint)val);
2856         }
2857 }