OSDN Git Service

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