OSDN Git Service

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