OSDN Git Service

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