OSDN Git Service

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