OSDN Git Service

LinGui: Make preset key/values mostly align with macui presets.
[handbrake-jp/handbrake-jp-git.git] / gtk / src / callbacks.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * callbacks.c
4  * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
5  * 
6  * callbacks.c is free software.
7  * 
8  * You may redistribute it and/or modify it under the terms of the
9  * GNU General Public License, as published by the Free Software
10  * Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  */
13
14 #ifdef HAVE_CONFIG_H
15 #  include <config.h>
16 #endif
17
18 #include <string.h>
19 #include <poll.h>
20 #include <fcntl.h>
21 #include <sys/stat.h>
22 #include <libhal-storage.h>
23 #include <gtk/gtk.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <glib/gstdio.h>
26 #include <gio/gio.h>
27
28 #include "hb.h"
29 #include "callbacks.h"
30 #include "queuehandler.h"
31 #include "audiohandler.h"
32 #include "resources.h"
33 #include "settings.h"
34 #include "presets.h"
35 #include "values.h"
36 #include "plist.h"
37 #include "hb-backend.h"
38 #include "ghb-dvd.h"
39 #include "ghbcellrenderertext.h"
40
41 static void update_chapter_list(signal_user_data_t *ud);
42 static GList* dvd_device_list();
43
44 // This is a dependency map used for greying widgets
45 // that are dependent on the state of another widget.
46 // The enable_value comes from the values that are
47 // obtained from ghb_widget_value().  For combo boxes
48 // you will have to look further to combo box options
49 // maps in hb-backend.c
50
51 GValue *dep_map;
52 GValue *rev_map;
53
54 void
55 ghb_init_dep_map()
56 {
57         dep_map = ghb_resource_get("widget-deps");
58         rev_map = ghb_resource_get("widget-reverse-deps");
59 }
60
61 static gboolean
62 dep_check(signal_user_data_t *ud, const gchar *name)
63 {
64         GtkWidget *widget;
65         GObject *dep_object;
66         gint ii;
67         gint count;
68         gboolean result = TRUE;
69         GValue *array, *data;
70         gchar *widget_name;
71         
72         g_debug("dep_check () %s", name);
73
74         array = ghb_dict_lookup(rev_map, name);
75         count = ghb_array_len(array);
76         for (ii = 0; ii < count; ii++)
77         {
78                 data = ghb_array_get_nth(array, ii);
79                 widget_name = ghb_value_string(ghb_array_get_nth(data, 0));
80                 widget = GHB_WIDGET(ud->builder, widget_name);
81                 dep_object = gtk_builder_get_object(ud->builder, name);
82                 g_free(widget_name);
83                 if (dep_object == NULL)
84                 {
85                         g_message("Failed to find widget");
86                 }
87                 else
88                 {
89                         gchar *value;
90                         gint jj = 0;
91                         gchar **values;
92                         gboolean sensitive = FALSE;
93                         gboolean die;
94
95                         die = ghb_value_boolean(ghb_array_get_nth(data, 2));
96                         value = ghb_value_string(ghb_array_get_nth(data, 1));
97                         values = g_strsplit(value, "|", 10);
98                         g_free(value);
99
100                         if (widget)
101                                 value = ghb_widget_string(widget);
102                         else
103                                 value = ghb_settings_get_string(ud->settings, name);
104                         while (values && values[jj])
105                         {
106                                 if (values[jj][0] == '>')
107                                 {
108                                         gdouble dbl = g_strtod (&values[jj][1], NULL);
109                                         gdouble dvalue = ghb_widget_double(widget);
110                                         if (dvalue > dbl)
111                                         {
112                                                 sensitive = TRUE;
113                                                 break;
114                                         }
115                                 }
116                                 else if (values[jj][0] == '<')
117                                 {
118                                         gdouble dbl = g_strtod (&values[jj][1], NULL);
119                                         gdouble dvalue = ghb_widget_double(widget);
120                                         if (dvalue < dbl)
121                                         {
122                                                 sensitive = TRUE;
123                                                 break;
124                                         }
125                                 }
126                                 if (strcmp(values[jj], value) == 0)
127                                 {
128                                         sensitive = TRUE;
129                                         break;
130                                 }
131                                 jj++;
132                         }
133                         sensitive = die ^ sensitive;
134                         if (!sensitive) result = FALSE;
135                         g_strfreev (values);
136                         g_free(value);
137                 }
138         }
139         return result;
140 }
141
142 void
143 ghb_check_dependency(signal_user_data_t *ud, GtkWidget *widget)
144 {
145         GObject *dep_object;
146         const gchar *name;
147         GValue *array, *data;
148         gint count, ii;
149         gchar *dep_name;
150         GType type;
151
152         type = GTK_WIDGET_TYPE(widget);
153         if (type == GTK_TYPE_COMBO_BOX || type == GTK_TYPE_COMBO_BOX_ENTRY)
154                 if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) < 0) return;
155
156         name = gtk_widget_get_name(widget);
157         g_debug("ghb_check_dependency () %s", name);
158
159         array = ghb_dict_lookup(dep_map, name);
160         count = ghb_array_len(array);
161         for (ii = 0; ii < count; ii++)
162         {
163                 gboolean sensitive;
164
165                 data = ghb_array_get_nth(array, ii);
166                 dep_name = ghb_value_string(data);
167                 dep_object = gtk_builder_get_object(ud->builder, dep_name);
168                 if (dep_object == NULL)
169                 {
170                         g_message("Failed to find dependent widget %s", dep_name);
171                         g_free(dep_name);
172                         continue;
173                 }
174                 sensitive = dep_check(ud, dep_name);
175                 g_free(dep_name);
176                 if (GTK_IS_ACTION(dep_object))
177                         gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
178                 else
179                         gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
180         }
181 }
182
183 void
184 ghb_check_all_depencencies(signal_user_data_t *ud)
185 {
186         GHashTableIter iter;
187         gchar *dep_name;
188         GValue *value;
189         GObject *dep_object;
190
191         g_debug("ghb_check_all_depencencies ()");
192         ghb_dict_iter_init(&iter, rev_map);
193         // middle (void*) cast prevents gcc warning "defreferencing type-punned
194         // pointer will break strict-aliasing rules"
195         while (g_hash_table_iter_next(
196                         &iter, (gpointer*)(void*)&dep_name, (gpointer*)(void*)&value))
197         {
198                 gboolean sensitive;
199                 dep_object = gtk_builder_get_object (ud->builder, dep_name);
200                 if (dep_object == NULL)
201                 {
202                         g_message("Failed to find dependent widget %s", dep_name);
203                         continue;
204                 }
205                 sensitive = dep_check(ud, dep_name);
206                 if (GTK_IS_ACTION(dep_object))
207                         gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
208                 else
209                         gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
210         }
211 }
212
213 static gchar*
214 expand_tilde(const gchar *path)
215 {
216         const gchar *user_home;
217         gchar *home;
218         const gchar *suffix;
219         gchar *expanded_path = NULL;
220         
221         g_debug("expand_tilde ()");
222         if (path[0] == '~')
223         {
224                 user_home = g_get_home_dir();
225                 home = NULL; // squash warning about home uninitialized
226                 if (path[1] == 0)
227                 {
228                         home = g_strdup(user_home);
229                         suffix = "";
230                 }
231                 else if (path[1] == '/')
232                 {
233                         home = g_strdup(user_home);
234                         suffix = &path[2];
235                 }
236                 else
237                 {
238                         home = g_path_get_dirname(user_home);
239                         suffix = &path[1];
240                 }
241                 expanded_path = g_strdup_printf("%s/%s", home, suffix);
242                 g_free(home);
243         }
244         return expanded_path;
245 }
246
247 void
248 on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud)
249 {
250         gint state = ghb_get_queue_state();
251         g_debug("on_quit1_activate ()");
252         if (state & GHB_STATE_WORKING)
253         {
254                 if (ghb_cancel_encode("Closing HandBrake will terminate encoding.\n"))
255                 {
256                         ghb_hb_cleanup(FALSE);
257                         gtk_main_quit();
258                         return;
259                 }
260                 return;
261         }
262         ghb_hb_cleanup(FALSE);
263         gtk_main_quit();
264 }
265
266 static void
267 set_destination(signal_user_data_t *ud)
268 {
269         g_debug("set_destination");
270         if (ghb_settings_get_boolean(ud->settings, "use_source_name"))
271         {
272                 gchar *vol_name, *filename, *extension;
273                 gchar *dir, *new_name;
274                 
275                 filename = ghb_settings_get_string(ud->settings, "destination");
276                 extension = ghb_settings_get_string(ud->settings, "FileFormat");
277                 dir = g_path_get_dirname (filename);
278                 vol_name = ghb_settings_get_string(ud->settings, "volume_label");
279                 if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
280                 {
281                         gint start, end;
282
283                         start = ghb_settings_get_int(ud->settings, "start_chapter");
284                         end = ghb_settings_get_int(ud->settings, "end_chapter");
285                         if (start == end)
286                         {
287                                 new_name = g_strdup_printf("%s/%s-%d.%s", 
288                                         dir, vol_name, start, extension);
289                         }
290                         else
291                         {
292                                 new_name = g_strdup_printf("%s/%s-%d-%d.%s", 
293                                         dir, vol_name, start, end, extension);
294                         }
295                 }
296                 else
297                 {
298                         new_name = g_strdup_printf("%s/%s.%s", dir, vol_name, extension);
299                 }
300                 ghb_ui_update(ud, "destination", ghb_string_value(new_name));
301                 g_free(filename);
302                 g_free(extension);
303                 g_free(vol_name);
304                 g_free(dir);
305                 g_free(new_name);
306         }
307 }
308
309 gboolean
310 uppers_and_unders(const gchar *str)
311 {
312         if (str == NULL) return FALSE;
313         while (*str)
314         {
315                 if (*str == ' ')
316                 {
317                         return FALSE;
318                 }
319                 if (*str >= 'a' && *str <= 'z')
320                 {
321                         return FALSE;
322                 }
323                 str++;
324         }
325         return TRUE;
326 }
327
328 enum
329 {
330         CAMEL_FIRST_UPPER,
331         CAMEL_OTHER
332 };
333
334 void
335 camel_convert(gchar *str)
336 {
337         gint state = CAMEL_OTHER;
338         
339         if (str == NULL) return;
340         while (*str)
341         {
342                 if (*str == '_') *str = ' ';
343                 switch (state)
344                 {
345                         case CAMEL_OTHER:
346                         {
347                                 if (*str >= 'A' && *str <= 'Z')
348                                         state = CAMEL_FIRST_UPPER;
349                                 else
350                                         state = CAMEL_OTHER;
351                                 
352                         } break;
353                         case CAMEL_FIRST_UPPER:
354                         {
355                                 if (*str >= 'A' && *str <= 'Z')
356                                         *str = *str - 'A' + 'a';
357                                 else
358                                         state = CAMEL_OTHER;
359                         } break;
360                 }
361                 str++;
362         }
363 }
364
365 static gchar*
366 get_file_label(const gchar *filename)
367 {
368         static gchar *containers[] = 
369                 {".vob", ".mpg", ".m2ts", ".mkv", ".mp4", ".m4v", ".avi", ".ogm", NULL};
370         gchar *base;
371         gint ii;
372
373         base = g_path_get_basename(filename);
374         for (ii = 0; containers[ii] != NULL; ii++)
375         {
376                 if (g_str_has_suffix(base, containers[ii]))
377                 {
378                         gchar *pos;
379                         pos = strrchr(base, '.');
380                         *pos = 0;
381                         break;
382                 }
383         }
384         return base;
385 }
386
387 static gboolean
388 update_source_label(signal_user_data_t *ud, const gchar *source)
389 {
390         gchar *label = NULL;
391         gint len;
392         gchar **path;
393         gchar *filename = g_strdup(source);
394         
395         len = strlen(filename);
396         if (filename[len-1] == '/') filename[len-1] = 0;
397         if (g_file_test(filename, G_FILE_TEST_IS_DIR))
398         {
399                 path = g_strsplit(filename, "/", -1);
400                 len = g_strv_length (path);
401                 if ((len > 1) && (strcmp("VIDEO_TS", path[len-1]) == 0))
402                 {
403                         label = g_strdup(path[len-2]);
404                 }
405                 else
406                 {
407                         label = g_strdup(path[len-1]);
408                 }
409                 g_strfreev (path);
410         }
411         else
412         {
413                 // Is regular file or block dev.
414                 // Check to see if it is a dvd image
415                 label = ghb_dvd_volname (filename);
416                 if (label == NULL)
417                 {
418                         label = get_file_label(filename);
419                 }
420                 else
421                 {
422                         if (uppers_and_unders(label))
423                         {
424                                 camel_convert(label);
425                         }
426                 }
427         }
428         g_free(filename);
429         GtkWidget *widget = GHB_WIDGET (ud->builder, "source_title");
430         if (label != NULL)
431         {
432                 gtk_label_set_text (GTK_LABEL(widget), label);
433                 ghb_settings_set_string(ud->settings, "volume_label", label);
434                 g_free(label);
435                 set_destination(ud);
436         }
437         else
438         {
439                 label = "No Title Found";
440                 gtk_label_set_text (GTK_LABEL(widget), label);
441                 ghb_settings_set_string(ud->settings, "volume_label", label);
442                 return FALSE;
443         }
444         return TRUE;
445 }
446
447 static GtkWidget *dvd_device_combo = NULL;
448
449 void
450 chooser_file_selected_cb(GtkFileChooser *dialog, GtkComboBox *combo)
451 {
452         const gchar *name = gtk_file_chooser_get_filename (dialog);
453         GtkTreeModel *store;
454         GtkTreeIter iter;
455         const gchar *device;
456         gboolean foundit = FALSE;
457         
458         if (name == NULL) return;
459         store = gtk_combo_box_get_model(combo);
460         if (gtk_tree_model_get_iter_first(store, &iter))
461         {
462                 do
463                 {
464                         gtk_tree_model_get(store, &iter, 0, &device, -1);
465                         if (strcmp(name, device) == 0)
466                         {
467                                 foundit = TRUE;
468                                 break;
469                         }
470                 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
471         }
472         if (foundit)
473                 gtk_combo_box_set_active_iter (combo, &iter);
474         else
475                 gtk_combo_box_set_active (combo, 0);
476 }
477
478 void
479 dvd_device_changed_cb(GtkComboBox *combo, GtkWidget *dialog)
480 {
481         gint ii = gtk_combo_box_get_active (combo);
482         if (ii != 0)
483         {
484                 const gchar *device = gtk_combo_box_get_active_text (combo);
485                 const gchar *name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog));
486                 if (name == NULL || strcmp(name, device) != 0)
487                         gtk_file_chooser_select_filename (GTK_FILE_CHOOSER(dialog), device);
488         }
489 }
490
491 void
492 source_type_changed_cb(GtkToggleButton *toggle, GtkFileChooser *chooser)
493 {
494         gchar *folder;
495         
496         g_debug("source_type_changed_cb ()");
497         folder = gtk_file_chooser_get_current_folder (chooser);
498         if (gtk_toggle_button_get_active (toggle))
499         {
500                 gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
501                 gtk_widget_set_sensitive (dvd_device_combo, FALSE);
502                 gtk_combo_box_set_active (GTK_COMBO_BOX(dvd_device_combo), 0);
503         }
504         else
505         {
506                 gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_OPEN);
507                 gtk_widget_set_sensitive (dvd_device_combo, TRUE);
508         }
509         if (folder != NULL)
510         {
511                 gtk_file_chooser_set_current_folder(chooser, folder);
512                 g_free(folder);
513         }
514 }
515
516 static GtkWidget*
517 source_dialog_extra_widgets(GtkWidget *dialog, gboolean checkbutton_active)
518 {
519         GtkBox *vbox;
520         GtkWidget *checkbutton;
521         
522         vbox = GTK_BOX(gtk_vbox_new (FALSE, 2));
523         checkbutton = gtk_check_button_new_with_label ("Open VIDEO_TS folder");
524         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbutton), checkbutton_active);
525         gtk_box_pack_start (vbox, checkbutton, FALSE, FALSE, 1);
526         gtk_widget_show(checkbutton);
527
528         GtkWidget *combo;
529         GtkBox *hbox;
530         GList *drives, *link;
531         GtkWidget *label, *blank;
532
533         hbox = GTK_BOX(gtk_hbox_new (FALSE, 2));
534         combo = gtk_combo_box_new_text();
535         label = gtk_label_new("Detected DVD devices:");
536         blank = gtk_label_new("");
537         link = drives = dvd_device_list();
538         gtk_combo_box_append_text (GTK_COMBO_BOX(combo), "Not Selected");
539         while (link != NULL)
540         {
541                 gchar *name = (gchar*)link->data;
542                 gtk_combo_box_append_text (GTK_COMBO_BOX(combo), name);
543                 g_free(name);
544                 link = link->next;
545         }
546         g_list_free(drives);
547         gtk_combo_box_set_active (GTK_COMBO_BOX(combo), 0);
548         gtk_box_pack_start (vbox, GTK_WIDGET(hbox), FALSE, FALSE, 1);
549         gtk_widget_show(GTK_WIDGET(hbox));
550         gtk_box_pack_start (hbox, label, FALSE, FALSE, 1);
551         gtk_widget_show(label);
552         gtk_box_pack_start (hbox, combo, FALSE, FALSE, 2);
553         gtk_widget_show(combo);
554         gtk_box_pack_start (hbox, blank, TRUE, TRUE, 1);
555         gtk_widget_show(blank);
556  
557         // Ugly hackish global alert
558         dvd_device_combo = combo;
559         g_signal_connect(combo, "changed", (GCallback)dvd_device_changed_cb, dialog);
560         g_signal_connect(dialog, "selection-changed", (GCallback)chooser_file_selected_cb, combo);
561
562         g_signal_connect(checkbutton, "toggled", (GCallback)source_type_changed_cb, dialog);
563         return GTK_WIDGET(vbox);
564 }
565
566 extern GValue *ghb_queue_edit_settings;
567 static gchar *last_scan_file = NULL;
568
569 void
570 ghb_do_scan(signal_user_data_t *ud, const gchar *filename, gboolean force)
571 {
572         if (!force && last_scan_file != NULL &&
573                 strcmp(last_scan_file, filename) == 0)
574         {
575                 if (ghb_queue_edit_settings)
576                 {
577                         gint jstatus;
578
579                         jstatus = ghb_settings_get_int(ghb_queue_edit_settings, "job_status");
580                         ghb_settings_to_ui(ud, ghb_queue_edit_settings);
581                         ghb_set_audio(ud, ghb_queue_edit_settings);
582                         if (jstatus == GHB_QUEUE_PENDING)
583                         {
584                                 ghb_value_free(ghb_queue_edit_settings);
585                         }
586                         ghb_queue_edit_settings = NULL;
587                 }
588                 return;
589         }
590         if (last_scan_file != NULL)
591                 g_free(last_scan_file);
592         last_scan_file = NULL;
593         if (filename != NULL)
594         {
595                 last_scan_file = g_strdup(filename);
596                 ghb_settings_set_string(ud->settings, "source", filename);
597                 if (update_source_label(ud, filename))
598                 {
599                         GtkProgressBar *progress;
600                         progress = GTK_PROGRESS_BAR(GHB_WIDGET(ud->builder, "progressbar"));
601                         gchar *path;
602                         path = ghb_settings_get_string( ud->settings, "source");
603                         gtk_progress_bar_set_fraction (progress, 0);
604                         gtk_progress_bar_set_text (progress, "Scanning ...");
605                         ghb_hb_cleanup(TRUE);
606                         ghb_backend_scan (path, 0);
607                         g_free(path);
608                 }
609                 else
610                 {
611                         // TODO: error dialog
612                 }
613         }
614 }
615
616 void
617 source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
618 {
619         GtkWidget *dialog;
620         GtkWidget *widget;
621         gchar *sourcename;
622         gint    response;
623         GtkFileChooserAction action;
624         gboolean checkbutton_active;
625
626         g_debug("source_browse_clicked_cb ()");
627         sourcename = ghb_settings_get_string(ud->settings, "source");
628         checkbutton_active = FALSE;
629         if (g_file_test(sourcename, G_FILE_TEST_IS_DIR))
630         {
631                 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
632                 checkbutton_active = TRUE;
633         }
634         else
635         {
636                 action = GTK_FILE_CHOOSER_ACTION_OPEN;
637         }
638         dialog = gtk_file_chooser_dialog_new ("Select Source",
639                                                                 NULL,
640                                                                 action,
641                                                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
642                                                                 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
643                                                                 NULL);
644         widget = source_dialog_extra_widgets(dialog, checkbutton_active);
645         gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), widget);
646         gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), sourcename);
647         response = gtk_dialog_run(GTK_DIALOG (dialog));
648         gtk_widget_hide(dialog);
649         if (response == GTK_RESPONSE_ACCEPT)
650         {
651                 char *filename;
652
653                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
654                 if (filename != NULL)
655                 {
656                         ghb_do_scan(ud, filename, TRUE);
657                         if (strcmp(sourcename, filename) != 0)
658                         {
659                                 ghb_settings_set_string (ud->settings, "default_source", filename);
660                                 ghb_pref_save (ud->settings, "default_source");
661                                 ghb_dvd_set_current (filename, ud);
662                         }
663                         g_free(filename);
664                 }
665         }
666         g_free(sourcename);
667         gtk_widget_destroy(dialog);
668 }
669
670 void
671 dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
672 {
673         const gchar *filename;
674         gchar *sourcename;
675
676         sourcename = ghb_settings_get_string(ud->settings, "source");
677         filename = gtk_action_get_name(action);
678         ghb_do_scan(ud, filename, TRUE);
679         if (strcmp(sourcename, filename) != 0)
680         {
681                 ghb_settings_set_string (ud->settings, "default_source", filename);
682                 ghb_pref_save (ud->settings, "default_source");
683                 ghb_dvd_set_current (filename, ud);
684         }
685         g_free(sourcename);
686 }
687
688 static void
689 update_destination_extension(signal_user_data_t *ud)
690 {
691         static gchar *containers[] = {".mkv", ".mp4", ".m4v", ".avi", ".ogm", NULL};
692         gchar *filename;
693         gchar *extension;
694         gint ii;
695         GtkEntry *entry;
696
697         g_debug("update_destination_extension ()");
698         extension = ghb_settings_get_string(ud->settings, "FileFormat");
699         entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "destination"));
700         filename = g_strdup(gtk_entry_get_text(entry));
701         for (ii = 0; containers[ii] != NULL; ii++)
702         {
703                 if (g_str_has_suffix(filename, containers[ii]))
704                 {
705                         gchar *pos;
706                         gchar *new_name;
707                         
708                         pos = g_strrstr( filename, "." );
709                         if (pos == NULL)
710                         {
711                                 // No period? shouldn't happen
712                                 break;
713                         }
714                         *pos = 0;
715                         if (strcmp(extension, &pos[1]) == 0)
716                         {
717                                 // Extension is already correct
718                                 break;
719                         }
720                         new_name = g_strjoin(".", filename, extension, NULL); 
721                         ghb_ui_update(ud, "destination", ghb_string_value(new_name));
722                         g_free(new_name);
723                         break;
724                 }
725         }
726         g_free(extension);
727         g_free(filename);
728 }
729
730 static void
731 destination_select_title(GtkEntry *entry)
732 {
733         const gchar *dest;
734         gint start, end;
735
736         dest = gtk_entry_get_text(entry);
737         for (end = strlen(dest)-1; end > 0; end--)
738         {
739                 if (dest[end] == '.')
740                 {
741                         break;
742                 }
743         }
744         for (start = end; start >= 0; start--)
745         {
746                 if (dest[start] == '/')
747                 {
748                         start++;
749                         break;
750                 }
751         }
752         if (start < end)
753         {
754                 gtk_editable_select_region(GTK_EDITABLE(entry), start, end);
755         }
756 }
757
758 gboolean
759 destination_grab_cb(
760         GtkEntry *entry, 
761         signal_user_data_t *ud)
762 {
763         destination_select_title(entry);
764         return FALSE;
765 }
766
767 static gboolean update_default_destination = FALSE;
768
769 void
770 destination_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
771 {
772         gchar *dest;
773         
774         g_debug("destination_entry_changed_cb ()");
775         if ((dest = expand_tilde(gtk_entry_get_text(entry))) != NULL)
776         {
777                 gtk_entry_set_text(entry, dest);
778                 g_free(dest);
779         }
780         update_destination_extension(ud);
781         ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
782         // This signal goes off with ever keystroke, so I'm putting this
783         // update on the timer.
784         update_default_destination = TRUE;
785 }
786
787 void
788 destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
789 {
790         GtkWidget *dialog;
791         GtkEntry *entry;
792         gchar *destname;
793         gchar *basename;
794
795         g_debug("destination_browse_clicked_cb ()");
796         destname = ghb_settings_get_string(ud->settings, "destination");
797         dialog = gtk_file_chooser_dialog_new ("Choose Destination",
798                                           NULL,
799                                           GTK_FILE_CHOOSER_ACTION_SAVE,
800                                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
801                                           GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
802                                           NULL);
803         gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), destname);
804         basename = g_path_get_basename(destname);
805         g_free(destname);
806         gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
807         g_free(basename);
808         if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
809         {
810                 char *filename;
811                 
812                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
813                 entry = (GtkEntry*)GHB_WIDGET(ud->builder, "destination");
814                 if (entry == NULL)
815                 {
816                         g_debug("Failed to find widget: %s", "destination");
817                 }
818                 else
819                 {
820                         gtk_entry_set_text(entry, filename);
821                 }
822                 g_free (filename);
823         }
824         gtk_widget_destroy(dialog);
825 }
826
827 gboolean
828 window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
829 {
830         g_debug("window_destroy_event_cb ()");
831         ghb_hb_cleanup(FALSE);
832         gtk_main_quit();
833         return FALSE;
834 }
835
836 gboolean
837 window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
838 {
839         gint state = ghb_get_queue_state();
840         g_debug("window_delete_event_cb ()");
841         if (state & GHB_STATE_WORKING)
842         {
843                 if (ghb_cancel_encode("Closing HandBrake will terminate encoding.\n"))
844                 {
845                         ghb_hb_cleanup(FALSE);
846                         gtk_main_quit();
847                         return FALSE;
848                 }
849                 return TRUE;
850         }
851         ghb_hb_cleanup(FALSE);
852         gtk_main_quit();
853         return FALSE;
854 }
855
856 static void
857 update_acodec_combo(signal_user_data_t *ud)
858 {
859         ghb_grey_combo_options (ud->builder);
860 }
861
862 void
863 container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
864 {
865         const GValue *audio_list;
866         g_debug("container_changed_cb ()");
867         ghb_widget_to_setting(ud->settings, widget);
868         update_destination_extension(ud);
869         ghb_check_dependency(ud, widget);
870         update_acodec_combo(ud);
871         ghb_clear_presets_selection(ud);
872
873         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
874         if (ghb_ac3_in_audio_list (audio_list))
875         {
876                 gchar *container;
877
878                 container = ghb_settings_get_string(ud->settings, "FileFormat");
879                 if (strcmp(container, "mp4") == 0)
880                 {
881                         ghb_ui_update(ud, "FileFormat", ghb_string_value("m4v"));
882                 }
883                 g_free(container);
884         }
885 }
886
887 static gchar*
888 get_aspect_string(gint aspect_n, gint aspect_d)
889 {
890         gchar *aspect;
891
892         if (aspect_d < 10)
893         {
894                 aspect = g_strdup_printf("%d:%d", aspect_n, aspect_d);
895         }
896         else
897         {
898                 gdouble aspect_nf = (gdouble)aspect_n / aspect_d;
899                 aspect = g_strdup_printf("%.2f:1", aspect_nf);
900         }
901         return aspect;
902 }
903
904 static gchar*
905 get_rate_string(gint rate_base, gint rate)
906 {
907         gdouble rate_f = (gdouble)rate / rate_base;
908         gchar *rate_s;
909
910         rate_s = g_strdup_printf("%.6g", rate_f);
911         return rate_s;
912 }
913 static void
914 show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
915 {
916         GtkWidget *widget;
917         gchar *text;
918
919         widget = GHB_WIDGET (ud->builder, "title_duration");
920         if (tinfo->duration != 0)
921         {
922                 text = g_strdup_printf ("%02d:%02d:%02d", tinfo->hours, 
923                                 tinfo->minutes, tinfo->seconds);
924         }
925         else
926         {
927                 text = g_strdup_printf ("Unknown");
928         }
929         gtk_label_set_text (GTK_LABEL(widget), text);
930         g_free(text);
931         widget = GHB_WIDGET (ud->builder, "source_dimensions");
932         text = g_strdup_printf ("%d x %d", tinfo->width, tinfo->height);
933         gtk_label_set_text (GTK_LABEL(widget), text);
934         ghb_settings_set_int(ud->settings, "source_width", tinfo->width);
935         ghb_settings_set_int(ud->settings, "source_height", tinfo->height);
936         g_free(text);
937         widget = GHB_WIDGET (ud->builder, "source_aspect");
938         text = get_aspect_string(tinfo->aspect_n, tinfo->aspect_d);
939         gtk_label_set_text (GTK_LABEL(widget), text);
940         g_free(text);
941
942         widget = GHB_WIDGET (ud->builder, "source_frame_rate");
943         text = (gchar*)get_rate_string(tinfo->rate_base, tinfo->rate);
944         gtk_label_set_text (GTK_LABEL(widget), text);
945         g_free(text);
946
947         ghb_ui_update(ud, "scale_width", 
948                 ghb_int64_value(tinfo->width - tinfo->crop[2] - tinfo->crop[3]));
949         // If anamorphic or keep_aspect, the hight will be automatically calculated
950         gboolean keep_aspect, anamorphic;
951         keep_aspect = ghb_settings_get_boolean(ud->settings, "PictureKeepRatio");
952         anamorphic = ghb_settings_get_boolean(ud->settings, "anamorphic");
953         if (!(keep_aspect || anamorphic))
954         {
955                 ghb_ui_update(ud, "scale_height", 
956                         ghb_int64_value(tinfo->height - tinfo->crop[0] - tinfo->crop[1]));
957         }
958
959         // Set the limits of cropping.  hb_set_anamorphic_size crashes if
960         // you pass it a cropped width or height == 0.
961         gint bound;
962         bound = tinfo->height / 2 - 2;
963         widget = GHB_WIDGET (ud->builder, "PictureTopCrop");
964         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
965         widget = GHB_WIDGET (ud->builder, "PictureBottomCrop");
966         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
967         bound = tinfo->width / 2 - 2;
968         widget = GHB_WIDGET (ud->builder, "PictureLeftCrop");
969         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
970         widget = GHB_WIDGET (ud->builder, "PictureRightCrop");
971         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
972         if (ghb_settings_get_boolean(ud->settings, "PictureAutoCrop"))
973         {
974                 ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(tinfo->crop[0]));
975                 ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(tinfo->crop[1]));
976                 ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(tinfo->crop[2]));
977                 ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(tinfo->crop[3]));
978         }
979         gint width, height, crop[4];
980         crop[0] = ghb_settings_get_int(ud->settings, "PictureTopCrop");
981         crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
982         crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
983         crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
984         width = tinfo->width - crop[2] - crop[3];
985         height = tinfo->height - crop[0] - crop[1];
986         widget = GHB_WIDGET (ud->builder, "crop_dimensions");
987         text = g_strdup_printf ("%d x %d", width, height);
988         gtk_label_set_text (GTK_LABEL(widget), text);
989         g_free(text);
990
991         g_debug("setting max end chapter %d", tinfo->num_chapters);
992         widget = GHB_WIDGET (ud->builder, "end_chapter");
993         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters);
994         gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), tinfo->num_chapters);
995         widget = GHB_WIDGET (ud->builder, "start_chapter");
996         gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1);
997 }
998
999 static gint preview_button_width;
1000 static gint preview_button_height;
1001 static gboolean update_preview = FALSE;
1002
1003 static void
1004 set_preview_image(signal_user_data_t *ud)
1005 {
1006         GtkWidget *widget;
1007         gint preview_width, preview_height, target_height, width, height;
1008
1009         g_debug("set_preview_button_image ()");
1010         gint titleindex;
1011
1012         titleindex = ghb_settings_combo_int(ud->settings, "title");
1013         if (titleindex < 0) return;
1014         widget = GHB_WIDGET (ud->builder, "preview_frame");
1015         gint frame = ghb_widget_int(widget) - 1;
1016         GdkPixbuf *preview = ghb_get_preview_image (titleindex, frame, ud->settings, TRUE);
1017         if (preview == NULL) return;
1018         widget = GHB_WIDGET (ud->builder, "preview_image");
1019         gtk_image_set_from_pixbuf(GTK_IMAGE(widget), preview);
1020
1021         preview_width = gdk_pixbuf_get_width(preview);
1022         preview_height = gdk_pixbuf_get_height(preview);
1023         gchar *text = g_strdup_printf("%d x %d", preview_width, preview_height);
1024         widget = GHB_WIDGET (ud->builder, "preview_dims");
1025         gtk_label_set_text(GTK_LABEL(widget), text);
1026         g_free(text);
1027         
1028         g_debug("preview %d x %d", preview_width, preview_height);
1029         target_height = MIN(preview_button_height - 12, 128);
1030         height = target_height;
1031         width = preview_width * height / preview_height;
1032
1033         if ((height >= 16) && (width >= 16))
1034         {
1035                 GdkPixbuf *scaled_preview;
1036                 scaled_preview = gdk_pixbuf_scale_simple (preview, width, height, GDK_INTERP_NEAREST);
1037                 if (scaled_preview != NULL)
1038                 {
1039                         g_object_unref (preview);
1040                         
1041                         widget = GHB_WIDGET (ud->builder, "preview_button_image");
1042                         gtk_image_set_from_pixbuf(GTK_IMAGE(widget), scaled_preview);
1043                         g_object_unref (scaled_preview);
1044                 }
1045         }
1046 }
1047
1048 void
1049 title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1050 {
1051         ghb_title_info_t tinfo;
1052         gint titleindex;
1053         
1054         g_debug("title_changed_cb ()");
1055         ghb_widget_to_setting(ud->settings, widget);
1056         ghb_check_dependency(ud, widget);
1057
1058         titleindex = ghb_settings_combo_int(ud->settings, "title");
1059         ghb_update_ui_combo_box (ud->builder, "AudioTrack", titleindex, FALSE);
1060         ghb_update_ui_combo_box (ud->builder, "Subtitles", titleindex, FALSE);
1061
1062         ghb_update_from_preset(ud, "Subtitles");
1063         if (ghb_get_title_info (&tinfo, titleindex))
1064         {
1065                 show_title_info(ud, &tinfo);
1066         }
1067         update_chapter_list (ud);
1068         ghb_adjust_audio_rate_combos(ud);
1069         ghb_set_pref_audio(titleindex, ud);
1070         if (ghb_settings_get_boolean(ud->settings, "vquality_type_target"))
1071         {
1072                 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1073                 ghb_ui_update(ud, "VideoAvgBitrate", ghb_int64_value(bitrate));
1074         }
1075
1076         // Unfortunately, there is no way to query how many frames were
1077         // actually generated during the scan.  It attempts to make 10.
1078         // If I knew how many were generated, I would adjust the spin
1079         // control range here.
1080         ghb_ui_update(ud, "preview_frame", ghb_int64_value(1));
1081
1082         set_preview_image (ud);
1083 }
1084
1085 void
1086 setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1087 {
1088         ghb_widget_to_setting(ud->settings, widget);
1089         ghb_check_dependency(ud, widget);
1090         ghb_clear_presets_selection(ud);
1091 }
1092
1093 static void
1094 validate_filter_widget(signal_user_data_t *ud, const gchar *name)
1095 {
1096         GtkTreeModel *store;
1097         GtkTreeIter iter;
1098         const gchar *str;
1099         gboolean foundit = FALSE;
1100         GtkComboBox *combo = GTK_COMBO_BOX(GHB_WIDGET(ud->builder, name));
1101         if (gtk_combo_box_get_active(combo) < 0)
1102         { // Validate user input
1103                 gchar *val = ghb_settings_get_string(ud->settings, name);
1104                 store = gtk_combo_box_get_model(combo);
1105                 // Check to see if user manually entered one of the combo options
1106                 if (gtk_tree_model_get_iter_first(store, &iter))
1107                 {
1108                         do
1109                         {
1110                                 gtk_tree_model_get(store, &iter, 0, &str, -1);
1111                                 if (strcasecmp(val, str) == 0)
1112                                 {
1113                                         gtk_combo_box_set_active_iter(combo, &iter);
1114                                         foundit = TRUE;
1115                                         break;
1116                                 }
1117                         } while (gtk_tree_model_iter_next(store, &iter));
1118                 }
1119                 if (!foundit)
1120                 { // validate format of filter string
1121                         if (!ghb_validate_filter_string(val, -1))
1122                                 gtk_combo_box_set_active(combo, 0);
1123                 }
1124                 g_free(val);
1125         }
1126 }
1127
1128 gboolean
1129 deint_tweak_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
1130         signal_user_data_t *ud)
1131 {
1132         g_debug("deint_tweak_focus_out_cb ()");
1133         validate_filter_widget(ud, "tweak_PictureDeinterlace");
1134         return FALSE;
1135 }
1136
1137 gboolean
1138 denoise_tweak_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
1139         signal_user_data_t *ud)
1140 {
1141         g_debug("denoise_tweak_focus_out_cb ()");
1142         validate_filter_widget(ud, "tweak_PictureDenoise");
1143         return FALSE;
1144 }
1145
1146 void
1147 http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1148 {
1149         ghb_widget_to_setting(ud->settings, widget);
1150         ghb_check_dependency(ud, widget);
1151         ghb_clear_presets_selection(ud);
1152         // AC3 is not allowed when Web optimized
1153         ghb_grey_combo_options (ud->builder);
1154 }
1155
1156 void
1157 vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1158 {
1159         gdouble vqmin, vqmax, step, page;
1160         gint digits;
1161         gint vcodec;
1162
1163         ghb_widget_to_setting(ud->settings, widget);
1164         ghb_check_dependency(ud, widget);
1165         ghb_clear_presets_selection(ud);
1166         ghb_vquality_range(ud, &vqmin, &vqmax, &step, &page, &digits);
1167         GtkWidget *qp = GHB_WIDGET(ud->builder, "VideoQualitySlider");
1168         gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1169         gtk_range_set_increments (GTK_RANGE(qp), step, page);
1170         gtk_scale_set_digits(GTK_SCALE(qp), digits);
1171         vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
1172         if (vcodec != HB_VCODEC_X264 && vcodec != HB_VCODEC_FFMPEG)
1173         {
1174                 ghb_ui_update(ud, "directqp", ghb_boolean_value(FALSE));
1175         }
1176 }
1177
1178 void
1179 target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1180 {
1181         const gchar *name = gtk_widget_get_name(widget);
1182         g_debug("setting_widget_changed_cb () %s", name);
1183         ghb_widget_to_setting(ud->settings, widget);
1184         ghb_check_dependency(ud, widget);
1185         ghb_clear_presets_selection(ud);
1186         if (ghb_settings_get_boolean(ud->settings, "vquality_type_target"))
1187         {
1188                 gint titleindex;
1189                 titleindex = ghb_settings_combo_int(ud->settings, "title");
1190                 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1191                 ghb_ui_update(ud, "VideoAvgBitrate", ghb_int64_value(bitrate));
1192         }
1193 }
1194
1195 void
1196 start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1197 {
1198         gint start, end;
1199         const gchar *name = gtk_widget_get_name(widget);
1200
1201         g_debug("start_chapter_changed_cb () %s", name);
1202         ghb_widget_to_setting(ud->settings, widget);
1203         start = ghb_settings_get_int(ud->settings, "start_chapter");
1204         end = ghb_settings_get_int(ud->settings, "end_chapter");
1205         if (start > end)
1206                 ghb_ui_update(ud, "end_chapter", ghb_int_value(start));
1207         ghb_check_dependency(ud, widget);
1208         if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
1209         {
1210                 set_destination(ud);
1211         }
1212 }
1213
1214 void
1215 end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1216 {
1217         gint start, end;
1218         const gchar *name = gtk_widget_get_name(widget);
1219
1220         g_debug("end_chapter_changed_cb () %s", name);
1221         ghb_widget_to_setting(ud->settings, widget);
1222         start = ghb_settings_get_int(ud->settings, "start_chapter");
1223         end = ghb_settings_get_int(ud->settings, "end_chapter");
1224         if (start > end)
1225                 ghb_ui_update(ud, "start_chapter", ghb_int_value(end));
1226         ghb_check_dependency(ud, widget);
1227         if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
1228         {
1229                 set_destination(ud);
1230         }
1231 }
1232
1233 void
1234 scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1235 {
1236         g_debug("scale_width_changed_cb ()");
1237         ghb_widget_to_setting(ud->settings, widget);
1238         ghb_check_dependency(ud, widget);
1239         ghb_set_scale (ud, GHB_SCALE_KEEP_WIDTH);
1240         update_preview = TRUE;
1241         gchar *text;
1242         gint width = ghb_settings_get_int(ud->settings, "scale_width");
1243         gint height = ghb_settings_get_int(ud->settings, "scale_height");
1244         widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1245         text = g_strdup_printf ("%d x %d", width, height);
1246         gtk_label_set_text (GTK_LABEL(widget), text);
1247         g_free(text);
1248 }
1249
1250 void
1251 scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1252 {
1253         g_debug("scale_height_changed_cb ()");
1254         ghb_widget_to_setting(ud->settings, widget);
1255         ghb_check_dependency(ud, widget);
1256         ghb_set_scale (ud, GHB_SCALE_KEEP_HEIGHT);
1257         update_preview = TRUE;
1258         gchar *text;
1259         gint width = ghb_settings_get_int(ud->settings, "scale_width");
1260         gint height = ghb_settings_get_int(ud->settings, "scale_height");
1261         widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1262         text = g_strdup_printf ("%d x %d", width, height);
1263         gtk_label_set_text (GTK_LABEL(widget), text);
1264         g_free(text);
1265 }
1266
1267 void
1268 crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1269 {
1270         gint titleindex, crop[4];
1271         ghb_title_info_t tinfo;
1272         
1273         g_debug("crop_changed_cb ()");
1274         ghb_widget_to_setting(ud->settings, widget);
1275         ghb_check_dependency(ud, widget);
1276         ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1277
1278         crop[0] = ghb_settings_get_int(ud->settings, "PictureTopCrop");
1279         crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
1280         crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
1281         crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
1282         titleindex = ghb_settings_combo_int(ud->settings, "title");
1283         if (ghb_get_title_info (&tinfo, titleindex))
1284         {
1285                 gint width, height;
1286                 gchar *text;
1287                 
1288                 width = tinfo.width - crop[2] - crop[3];
1289                 height = tinfo.height - crop[0] - crop[1];
1290                 widget = GHB_WIDGET (ud->builder, "crop_dimensions");
1291                 text = g_strdup_printf ("%d x %d", width, height);
1292                 gtk_label_set_text (GTK_LABEL(widget), text);
1293                 g_free(text);
1294         }
1295         gchar *text;
1296         widget = GHB_WIDGET (ud->builder, "crop_values");
1297         text = g_strdup_printf ("%d:%d:%d:%d", crop[0], crop[1], crop[2], crop[3]);
1298         gtk_label_set_text (GTK_LABEL(widget), text);
1299         g_free(text);
1300         update_preview = TRUE;
1301 }
1302
1303 void
1304 scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1305 {
1306         g_debug("scale_changed_cb ()");
1307         ghb_widget_to_setting(ud->settings, widget);
1308         ghb_check_dependency(ud, widget);
1309         ghb_clear_presets_selection(ud);
1310         ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1311         update_preview = TRUE;
1312         
1313         gchar *text;
1314         
1315         text = ghb_settings_get_boolean(ud->settings, "PictureAutoCrop") ? "On" : "Off";
1316         widget = GHB_WIDGET (ud->builder, "crop_auto");
1317         gtk_label_set_text (GTK_LABEL(widget), text);
1318         text = ghb_settings_get_boolean(ud->settings, "autoscale") ? "On" : "Off";
1319         widget = GHB_WIDGET (ud->builder, "scale_auto");
1320         gtk_label_set_text (GTK_LABEL(widget), text);
1321         text = ghb_settings_get_boolean(ud->settings, "anamorphic") ? "On" : "Off";
1322         widget = GHB_WIDGET (ud->builder, "scale_anamorphic");
1323         gtk_label_set_text (GTK_LABEL(widget), text);
1324 }
1325
1326 void
1327 generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
1328 {
1329         // Normally (due to user input) I only want to process the entry
1330         // when editing is done and the focus-out signal is sent.
1331         // But... there's always a but.
1332         // If the entry is changed by software, the focus-out signal is not sent.
1333         // The changed signal is sent ... so here we are.
1334         // I don't want to process upon every keystroke, so I prevent processing
1335         // while the widget has focus.
1336         g_debug("generic_entry_changed_cb ()");
1337         if (!GTK_WIDGET_HAS_FOCUS((GtkWidget*)entry))
1338         {
1339                 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
1340         }
1341 }
1342
1343 void
1344 prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1345 {
1346         GtkWidget *dialog;
1347         GtkResponseType response;
1348
1349         g_debug("prefs_dialog_cb ()");
1350         dialog = GHB_WIDGET(ud->builder, "prefs_dialog");
1351         response = gtk_dialog_run(GTK_DIALOG(dialog));
1352         gtk_widget_hide(dialog);
1353 }
1354
1355 gboolean
1356 ghb_message_dialog(GtkMessageType type, const gchar *message, const gchar *no, const gchar *yes)
1357 {
1358         GtkWidget *dialog;
1359         GtkResponseType response;
1360                         
1361         // Toss up a warning dialog
1362         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1363                                                         type, GTK_BUTTONS_NONE,
1364                                                         message);
1365         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
1366                                                    no, GTK_RESPONSE_NO,
1367                                                    yes, GTK_RESPONSE_YES, NULL);
1368         response = gtk_dialog_run(GTK_DIALOG(dialog));
1369         gtk_widget_destroy (dialog);
1370         if (response == GTK_RESPONSE_NO)
1371         {
1372                 return FALSE;
1373         }
1374         return TRUE;
1375 }
1376
1377 gboolean
1378 ghb_cancel_encode(const gchar *extra_msg)
1379 {
1380         GtkWidget *dialog;
1381         GtkResponseType response;
1382         
1383         if (extra_msg == NULL) extra_msg = "";
1384         // Toss up a warning dialog
1385         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1386                                 GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
1387                                 "%sYour movie will be lost if you don't continue encoding.",
1388                                 extra_msg);
1389         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
1390                                                    "Continue Encoding", GTK_RESPONSE_NO,
1391                                                    "Stop Encoding", GTK_RESPONSE_YES, NULL);
1392         response = gtk_dialog_run(GTK_DIALOG(dialog));
1393         gtk_widget_destroy (dialog);
1394         if (response == GTK_RESPONSE_NO) return FALSE;
1395         ghb_stop_queue();
1396         return TRUE;
1397 }
1398
1399 static void
1400 submit_job(GValue *settings)
1401 {
1402         static gint unique_id = 1;
1403
1404         g_debug("submit_job");
1405         if (settings == NULL) return;
1406         ghb_settings_set_int(settings, "job_unique_id", unique_id);
1407         ghb_settings_set_int(settings, "job_status", GHB_QUEUE_RUNNING);
1408         ghb_add_job (settings, unique_id);
1409         ghb_start_queue();
1410         unique_id++;
1411 }
1412
1413 static void
1414 queue_scan(GValue *js)
1415 {
1416         gchar *path;
1417         gint titlenum;
1418
1419         path = ghb_settings_get_string( js, "source");
1420         titlenum = ghb_settings_get_int(js, "titlenum");
1421         ghb_backend_queue_scan(path, titlenum);
1422         g_free(path);
1423 }
1424
1425 GValue* 
1426 ghb_start_next_job(signal_user_data_t *ud, gboolean find_first)
1427 {
1428         static gint current = 0;
1429         gint count, ii, jj;
1430         GValue *js;
1431         gint status;
1432
1433         g_debug("start_next_job");
1434         count = ghb_array_len(ud->queue);
1435         if (find_first)
1436         {       // Start the first pending item in the queue
1437                 current = 0;
1438                 for (ii = 0; ii < count; ii++)
1439                 {
1440
1441                         js = ghb_array_get_nth(ud->queue, ii);
1442                         status = ghb_settings_get_int(js, "job_status");
1443                         if (status == GHB_QUEUE_PENDING)
1444                         {
1445                                 current = ii;
1446                                 queue_scan(js);
1447                                 return js;
1448                         }
1449                 }
1450                 // Nothing pending
1451                 return NULL;
1452         }
1453         // Find the next pending item after the current running item
1454         for (ii = 0; ii < count-1; ii++)
1455         {
1456                 js = ghb_array_get_nth(ud->queue, ii);
1457                 status = ghb_settings_get_int(js, "job_status");
1458                 if (status == GHB_QUEUE_RUNNING)
1459                 {
1460                         for (jj = ii+1; jj < count; jj++)
1461                         {
1462                                 js = ghb_array_get_nth(ud->queue, jj);
1463                                 status = ghb_settings_get_int(js, "job_status");
1464                                 if (status == GHB_QUEUE_PENDING)
1465                                 {
1466                                         current = jj;
1467                                         queue_scan(js);
1468                                         return js;
1469                                 }
1470                         }
1471                 }
1472         }
1473         // No running item found? Maybe it was deleted
1474         // Look for a pending item starting from the last index we started
1475         for (ii = current; ii < count; ii++)
1476         {
1477                 js = ghb_array_get_nth(ud->queue, ii);
1478                 status = ghb_settings_get_int(js, "job_status");
1479                 if (status == GHB_QUEUE_PENDING)
1480                 {
1481                         current = ii;
1482                         queue_scan(js);
1483                         return js;
1484                 }
1485         }
1486         // Nothing found
1487         return NULL;
1488 }
1489
1490 static gint
1491 find_queue_job(GValue *queue, gint unique_id, GValue **job)
1492 {
1493         GValue *js;
1494         gint ii, count;
1495         gint job_unique_id;
1496         
1497         *job = NULL;
1498         g_debug("find_queue_job");
1499         count = ghb_array_len(queue);
1500         for (ii = 0; ii < count; ii++)
1501         {
1502                 js = ghb_array_get_nth(queue, ii);
1503                 job_unique_id = ghb_settings_get_int(js, "job_unique_id");
1504                 if (job_unique_id == unique_id)
1505                 {
1506                         *job = js;
1507                         return ii;
1508                 }
1509         }
1510         return -1;
1511 }
1512
1513 gchar*
1514 working_status_string(signal_user_data_t *ud, ghb_status_t *status)
1515 {
1516         gchar *task_str, *job_str, *status_str;
1517         gint qcount;
1518         gint index;
1519         GValue *js;
1520
1521         if (status->job_count > 1)
1522         {
1523                 task_str = g_strdup_printf("pass %d of %d, ", 
1524                         status->job_cur, status->job_count);
1525         }
1526         else
1527         {
1528                 task_str = g_strdup("");
1529         }
1530         qcount = ghb_array_len(ud->queue);
1531         if (qcount > 1)
1532         {
1533                 index = find_queue_job(ud->queue, status->unique_id, &js);
1534                 job_str = g_strdup_printf("job %d of %d, ", index+1, qcount);
1535         }
1536         else
1537         {
1538                 job_str = g_strdup("");
1539         }
1540         if(status->seconds > -1)
1541         {
1542                 status_str= g_strdup_printf(
1543                         "Encoding: %s%s%.2f %%"
1544                         " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)",
1545                         job_str, task_str,
1546                         100.0 * status->progress,
1547                         status->rate_cur, status->rate_avg, status->hours, 
1548                         status->minutes, status->seconds );
1549         }
1550         else
1551         {
1552                 status_str= g_strdup_printf(
1553                         "Encoding: %s%s%.2f %%",
1554                         job_str, task_str,
1555                         100.0 * status->progress );
1556         }
1557         g_free(task_str);
1558         g_free(job_str);
1559         return status_str;
1560 }
1561
1562 static void
1563 ghb_backend_events(signal_user_data_t *ud)
1564 {
1565         ghb_status_t status;
1566         gchar *status_str;
1567         GtkProgressBar *progress;
1568         gint titleindex;
1569         GValue *js;
1570         gint index;
1571         GtkTreeView *treeview;
1572         GtkTreeStore *store;
1573         GtkTreeIter iter;
1574         static gint working = 0;
1575         static gboolean work_started = FALSE;
1576         
1577         ghb_track_status();
1578         ghb_get_status(&status);
1579         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
1580         // First handle the status of title scans
1581         // Then handle the status of the queue
1582         if (status.state & GHB_STATE_SCANNING)
1583         {
1584                 if (status.title_cur == 0)
1585                 {
1586                         status_str = g_strdup ("Scanning...");
1587                 }
1588                 else
1589                 {
1590                         status_str = g_strdup_printf ("Scanning title %d of %d...", 
1591                                                                   status.title_cur, status.title_count );
1592                 }
1593                 gtk_progress_bar_set_text (progress, status_str);
1594                 g_free(status_str);
1595                 if (status.title_count > 0)
1596                 {
1597                         gtk_progress_bar_set_fraction (progress, 
1598                                 (gdouble)status.title_cur / status.title_count);
1599                 }
1600         }
1601         else if (status.state & GHB_STATE_SCANDONE)
1602         {
1603                 status_str = g_strdup_printf ("Scan done"); 
1604                 gtk_progress_bar_set_text (progress, status_str);
1605                 g_free(status_str);
1606                 gtk_progress_bar_set_fraction (progress, 1.0);
1607
1608                 ghb_title_info_t tinfo;
1609                         
1610                 ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE);
1611                 titleindex = ghb_longest_title();
1612                 ghb_ui_update(ud, "title", ghb_int64_value(titleindex));
1613
1614                 // Are there really any titles.
1615                 if (!ghb_get_title_info(&tinfo, titleindex))
1616                 {
1617                         GtkProgressBar *progress;
1618                         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
1619                         gtk_progress_bar_set_fraction (progress, 0);
1620                         gtk_progress_bar_set_text (progress, "No Source");
1621                 }
1622                 ghb_clear_state(GHB_STATE_SCANDONE);
1623                 ghb_queue_buttons_grey(ud, work_started);
1624                 if (ghb_queue_edit_settings)
1625                 {
1626                         gint jstatus;
1627
1628                         jstatus = ghb_settings_get_int(ghb_queue_edit_settings, "job_status");
1629                         ghb_settings_to_ui(ud, ghb_queue_edit_settings);
1630                         ghb_set_audio(ud, ghb_queue_edit_settings);
1631                         if (jstatus == GHB_QUEUE_PENDING)
1632                         {
1633                                 ghb_value_free(ghb_queue_edit_settings);
1634                         }
1635                         ghb_queue_edit_settings = NULL;
1636                 }
1637         }
1638         else if (status.queue_state & GHB_STATE_SCANNING)
1639         {
1640                 status_str = g_strdup_printf ("Scanning ...");
1641                 gtk_progress_bar_set_text (progress, status_str);
1642                 g_free(status_str);
1643                 gtk_progress_bar_set_fraction (progress, 0);
1644         }
1645         else if (status.queue_state & GHB_STATE_SCANDONE)
1646         {
1647                 ghb_clear_queue_state(GHB_STATE_SCANDONE);
1648                 submit_job(ud->current_job);
1649         }
1650         else if (status.queue_state & GHB_STATE_PAUSED)
1651         {
1652                 status_str = g_strdup_printf ("Paused"); 
1653                 gtk_progress_bar_set_text (progress, status_str);
1654                 g_free(status_str);
1655         }
1656         else if (status.queue_state & GHB_STATE_WORKING)
1657         {
1658                 status_str = working_status_string(ud, &status);
1659                 gtk_progress_bar_set_text (progress, status_str);
1660                 gtk_progress_bar_set_fraction (progress, status.progress);
1661                 g_free(status_str);
1662         }
1663         else if (status.queue_state & GHB_STATE_WORKDONE)
1664         {
1665                 gint qstatus;
1666
1667                 work_started = FALSE;
1668                 ghb_queue_buttons_grey(ud, FALSE);
1669                 index = find_queue_job(ud->queue, status.unique_id, &js);
1670                 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
1671                 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
1672                 if (ud->cancel_encode)
1673                         status.error = GHB_ERROR_CANCELED;
1674                 switch( status.error )
1675                 {
1676                         case GHB_ERROR_NONE:
1677                                 gtk_progress_bar_set_text( progress, "Rip done!" );
1678                                 qstatus = GHB_QUEUE_DONE;
1679                                 if (js != NULL)
1680                                 {
1681                                         gchar *path = g_strdup_printf ("%d", index);
1682                                         if (gtk_tree_model_get_iter_from_string(
1683                                                         GTK_TREE_MODEL(store), &iter, path))
1684                                         {
1685                                                 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
1686                                         }
1687                                         g_free(path);
1688                                 }
1689                                 break;
1690                         case GHB_ERROR_CANCELED:
1691                                 gtk_progress_bar_set_text( progress, "Rip canceled." );
1692                                 qstatus = GHB_QUEUE_CANCELED;
1693                                 if (js != NULL)
1694                                 {
1695                                         gchar *path = g_strdup_printf ("%d", index);
1696                                         if (gtk_tree_model_get_iter_from_string(
1697                                                         GTK_TREE_MODEL(store), &iter, path))
1698                                         {
1699                                                 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
1700                                         }
1701                                         g_free(path);
1702                                 }
1703                                 break;
1704                         default:
1705                                 gtk_progress_bar_set_text( progress, "Rip failed.");
1706                                 qstatus = GHB_QUEUE_CANCELED;
1707                                 if (js != NULL)
1708                                 {
1709                                         gchar *path = g_strdup_printf ("%d", index);
1710                                         if (gtk_tree_model_get_iter_from_string(
1711                                                         GTK_TREE_MODEL(store), &iter, path))
1712                                         {
1713                                                 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
1714                                         }
1715                                         g_free(path);
1716                                 }
1717                 }
1718                 gtk_progress_bar_set_fraction (progress, 1.0);
1719                 ghb_clear_queue_state(GHB_STATE_WORKDONE);
1720                 if (!ud->cancel_encode)
1721                         ud->current_job = ghb_start_next_job(ud, FALSE);
1722                 else
1723                         ud->current_job = NULL;
1724                 if (js)
1725                         ghb_settings_set_int(js, "job_status", qstatus);
1726                 ghb_save_queue(ud->queue);
1727                 ud->cancel_encode = FALSE;
1728         }
1729         else if (status.queue_state & GHB_STATE_MUXING)
1730         {
1731                 gtk_progress_bar_set_text(progress, "Muxing: this may take awhile...");
1732         }
1733         if (status.queue_state & GHB_STATE_SCANNING)
1734         {
1735                 // This needs to be in scanning and working since scanning
1736                 // happens fast enough that it can be missed
1737                 if (!work_started)
1738                 {
1739                         work_started = TRUE;
1740                         ghb_queue_buttons_grey(ud, TRUE);
1741                 }
1742         }
1743         if (status.queue_state & GHB_STATE_WORKING)
1744         {
1745                 // This needs to be in scanning and working since scanning
1746                 // happens fast enough that it can be missed
1747                 if (!work_started)
1748                 {
1749                         work_started = TRUE;
1750                         ghb_queue_buttons_grey(ud, TRUE);
1751                 }
1752                 index = find_queue_job(ud->queue, status.unique_id, &js);
1753                 if (status.unique_id != 0 && index >= 0)
1754                 {
1755                         gchar working_icon[] = "hb-working0";
1756                         working_icon[10] = '0' + working;
1757                         working = (working+1) % 6;
1758                         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
1759                         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
1760                         gchar *path = g_strdup_printf ("%d", index);
1761                         if (gtk_tree_model_get_iter_from_string(
1762                                         GTK_TREE_MODEL(store), &iter, path))
1763                         {
1764                                 gtk_tree_store_set(store, &iter, 0, working_icon, -1);
1765                         }
1766                         g_free(path);
1767                 }
1768                 GtkLabel *label;
1769                 gchar *status_str;
1770
1771                 status_str = working_status_string(ud, &status);
1772                 label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_status"));
1773                 gtk_label_set_text (label, status_str);
1774                 g_free(status_str);
1775         }
1776 }
1777
1778 gboolean
1779 ghb_timer_cb(gpointer data)
1780 {
1781         signal_user_data_t *ud = (signal_user_data_t*)data;
1782
1783         ghb_backend_events(ud);
1784         if (update_default_destination)
1785         {
1786                 gchar *dest, *dest_dir, *def_dest;
1787                 dest = ghb_settings_get_string(ud->settings, "destination");
1788                 dest_dir = g_path_get_dirname (dest);
1789                 def_dest = ghb_settings_get_string(ud->settings, "destination_dir");
1790                 if (strcmp(dest_dir, def_dest) != 0)
1791                 {
1792                         ghb_settings_set_string (ud->settings, "destination_dir", dest_dir);
1793                         ghb_pref_save (ud->settings, "destination_dir");
1794                 }
1795                 g_free(dest);
1796                 g_free(dest_dir);
1797                 g_free(def_dest);
1798                 update_default_destination = FALSE;
1799         }
1800         if (update_preview)
1801         {
1802                 set_preview_image (ud);
1803                 update_preview = FALSE;
1804         }
1805         return TRUE;
1806 }
1807
1808 gboolean
1809 ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
1810 {
1811         gchar *text = NULL;
1812         gsize length;
1813         GtkTextView *textview;
1814         GtkTextBuffer *buffer;
1815         GtkTextIter iter;
1816         GtkTextMark *mark;
1817         GError *gerror = NULL;
1818         GIOStatus status;
1819         
1820         signal_user_data_t *ud = (signal_user_data_t*)data;
1821
1822         status = g_io_channel_read_line (source, &text, &length, NULL, &gerror);
1823         if (text != NULL)
1824         {
1825                 GdkWindow *window;
1826                 gint width, height;
1827                 gint x, y;
1828                 gboolean bottom = FALSE;
1829
1830                 textview = GTK_TEXT_VIEW(GHB_WIDGET (ud->builder, "activity_view"));
1831                 buffer = gtk_text_view_get_buffer (textview);
1832                 // I would like to auto-scroll the window when the scrollbar
1833                 // is at the bottom, 
1834                 // must determining whether the insert point is at
1835                 // the bottom of the window 
1836                 window = gtk_text_view_get_window(textview, GTK_TEXT_WINDOW_TEXT);
1837                 if (window != NULL)
1838                 {
1839                         gdk_drawable_get_size(GDK_DRAWABLE(window), &width, &height);
1840                         gtk_text_view_window_to_buffer_coords(textview, 
1841                                 GTK_TEXT_WINDOW_TEXT, width, height, &x, &y);
1842                         gtk_text_view_get_iter_at_location(textview, &iter, x, y);
1843                         if (gtk_text_iter_is_end(&iter))
1844                         {
1845                                 bottom = TRUE;
1846                         }
1847                 }
1848                 else
1849                 {
1850                         // If the window isn't available, assume bottom
1851                         bottom = TRUE;
1852                 }
1853                 gtk_text_buffer_get_end_iter(buffer, &iter);
1854                 gtk_text_buffer_insert(buffer, &iter, text, -1);
1855                 if (bottom)
1856                 {
1857                         //gtk_text_view_scroll_to_iter(textview, &iter, 0, FALSE, 0, 0);
1858                         mark = gtk_text_buffer_get_insert (buffer);
1859                         gtk_text_view_scroll_mark_onscreen(textview, mark);
1860                 }
1861                 g_io_channel_write_chars (ud->activity_log, text, length, &length, NULL);
1862                 g_free(text);
1863         }
1864         if (status != G_IO_STATUS_NORMAL)
1865         {
1866                 // This should never happen, but if it does I would get into an
1867                 // infinite loop.  Returning false removes this callback.
1868                 g_warning("Error while reading activity from pipe");
1869                 if (gerror != NULL)
1870                 {
1871                         g_warning("%s", gerror->message);
1872                         g_error_free (gerror);
1873                 }
1874                 return FALSE;
1875         }
1876         if (gerror != NULL)
1877                 g_error_free (gerror);
1878         return TRUE;
1879 }
1880
1881 void
1882 about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1883 {
1884         GtkWidget *widget = GHB_WIDGET (ud->builder, "hb_about");
1885         gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(widget), ghb_version());
1886         gtk_widget_show (widget);
1887 }
1888
1889 void
1890 guide_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1891 {
1892         gboolean result;
1893         char *argv[] = 
1894                 {"xdg-open","http://trac.handbrake.fr/wiki/HandBrakeGuide",NULL,NULL};
1895         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
1896                                 NULL, NULL, NULL);
1897         if (result) return;
1898
1899         argv[0] = "gnome-open";
1900         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
1901                                 NULL, NULL, NULL);
1902         if (result) return;
1903
1904         argv[0] = "kfmclient";
1905         argv[1] = "exec";
1906         argv[2] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
1907         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
1908                                 NULL, NULL, NULL);
1909         if (result) return;
1910
1911         argv[0] = "firefox";
1912         argv[1] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
1913         argv[2] = NULL;
1914         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
1915                                 NULL, NULL, NULL);
1916         if (result) return;
1917 }
1918
1919 void
1920 hb_about_response_cb(GtkWidget *widget, gint response, signal_user_data_t *ud)
1921 {
1922         gtk_widget_hide (widget);
1923 }
1924
1925 void
1926 show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1927 {
1928         GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
1929         gtk_widget_show (widget);
1930 }
1931
1932 void
1933 show_queue_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1934 {
1935         GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
1936         gtk_widget_show (widget);
1937 }
1938
1939 void
1940 show_presets_toggled_cb(GtkToggleButton *button, signal_user_data_t *ud)
1941 {
1942         GtkWidget *widget;
1943         GtkWindow *hb_window;
1944         
1945         g_debug("show_presets_clicked_cb ()");
1946         widget = GHB_WIDGET (ud->builder, "presets_frame");
1947         if (gtk_toggle_button_get_active(button))
1948         {
1949                 gtk_widget_show_now(widget);
1950         }
1951         else
1952         {
1953                 gtk_widget_hide(widget);
1954                 hb_window = GTK_WINDOW(GHB_WIDGET (ud->builder, "hb_window"));
1955                 gtk_window_resize(hb_window, 16, 16);
1956         }
1957         ghb_widget_to_setting(ud->settings, GTK_WIDGET(button));
1958         ghb_pref_save(ud->settings, "show_presets");
1959 }
1960
1961 static void
1962 update_chapter_list(signal_user_data_t *ud)
1963 {
1964         GtkTreeView *treeview;
1965         GtkTreeIter iter;
1966         GtkListStore *store;
1967         gboolean done;
1968         GValue *chapters;
1969         gint titleindex, ii;
1970         gint count;
1971         
1972         g_debug("update_chapter_list ()");
1973         titleindex = ghb_settings_combo_int(ud->settings, "title");
1974         chapters = ghb_get_chapters(titleindex);
1975         count = ghb_array_len(chapters);
1976         if (chapters)
1977                 ghb_settings_set_value(ud->settings, "chapter_list", chapters);
1978         
1979         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
1980         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1981         ii = 0;
1982         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1983         {
1984                 do
1985                 {
1986
1987                         if (ii < count)
1988                         {
1989                                 gchar *chapter;
1990
1991                                 // Update row with settings data
1992                                 g_debug("Updating row");
1993                                 chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
1994                                 gtk_list_store_set(store, &iter, 
1995                                         0, ii+1,
1996                                         1, chapter,
1997                                         2, TRUE,
1998                                         -1);
1999                                 g_free(chapter);
2000                                 ii++;
2001                                 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
2002                         }
2003                         else
2004                         {
2005                                 // No more settings data, remove row
2006                                 g_debug("Removing row");
2007                                 done = !gtk_list_store_remove(store, &iter);
2008                         }
2009                 } while (!done);
2010         }
2011         while (ii < count)
2012         {
2013                 gchar *chapter;
2014
2015                 // Additional settings, add row
2016                 g_debug("Adding row");
2017                 chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
2018                 gtk_list_store_append(store, &iter);
2019                 gtk_list_store_set(store, &iter, 
2020                         0, ii+1,
2021                         1, chapter,
2022                         2, TRUE,
2023                         -1);
2024                 g_free(chapter);
2025                 ii++;
2026         }
2027 }
2028
2029 static gint chapter_edit_key = 0;
2030
2031 gboolean
2032 chapter_keypress_cb(
2033         GhbCellRendererText *cell,
2034         GdkEventKey *event,
2035         signal_user_data_t *ud)
2036 {
2037         chapter_edit_key = event->keyval;
2038         return FALSE;
2039 }
2040
2041 void
2042 chapter_edited_cb(
2043         GhbCellRendererText *cell, 
2044         gchar *path, 
2045         gchar *text, 
2046         signal_user_data_t *ud)
2047 {
2048         GtkTreePath *treepath;
2049         GtkListStore *store;
2050         GtkTreeView *treeview;
2051         GtkTreeIter iter;
2052         gint index;
2053         gint *pi;
2054         gint row;
2055         
2056         g_debug("chapter_edited_cb ()");
2057         g_debug("path (%s)", path);
2058         g_debug("text (%s)", text);
2059         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
2060         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
2061         treepath = gtk_tree_path_new_from_string (path);
2062         pi = gtk_tree_path_get_indices(treepath);
2063         row = pi[0];
2064         gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
2065         gtk_list_store_set(store, &iter, 
2066                 1, text,
2067                 2, TRUE,
2068                 -1);
2069         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &index, -1);
2070
2071         GValue *chapters;
2072         GValue *chapter;
2073
2074         chapters = ghb_settings_get_value(ud->settings, "chapter_list");
2075         chapter = ghb_array_get_nth(chapters, index-1);
2076         g_value_set_string(chapter, text);
2077         if ((chapter_edit_key == GDK_Return || chapter_edit_key == GDK_Down) &&
2078                 gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
2079         {
2080                 GtkTreeViewColumn *column;
2081
2082                 gtk_tree_path_next(treepath);
2083                 // When a cell has been edited, I want to advance to the
2084                 // next cell and start editing it automaitcally.
2085                 // Unfortunately, we may not be in a state here where
2086                 // editing is allowed.  This happens when the user selects
2087                 // a new cell with the mouse instead of just hitting enter.
2088                 // Some kind of Gtk quirk.  widget_editable==NULL assertion.
2089                 // Editing is enabled again once the selection event has been
2090                 // processed.  So I'm queueing up a callback to be called
2091                 // when things go idle.  There, I will advance to the next
2092                 // cell and initiate editing.
2093                 //
2094                 // Now, you might be asking why I don't catch the keypress
2095                 // event and determine what action to take based on that.
2096                 // The Gtk developers in their infinite wisdom have made the 
2097                 // actual GtkEdit widget being used a private member of
2098                 // GtkCellRendererText, so it can not be accessed to hang a
2099                 // signal handler off of.  And they also do not propagate the
2100                 // keypress signals in any other way.  So that information is lost.
2101                 //g_idle_add((GSourceFunc)next_cell, ud);
2102                 //
2103                 // Keeping the above comment for posterity.
2104                 // I got industrious and made my own CellTextRendererText that
2105                 // passes on the key-press-event. So now I have much better
2106                 // control of this.
2107                 column = gtk_tree_view_get_column(treeview, 1);
2108                 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
2109         }
2110         else if (chapter_edit_key == GDK_Up && row > 0)
2111         {
2112                 GtkTreeViewColumn *column;
2113                 gtk_tree_path_prev(treepath);
2114                 column = gtk_tree_view_get_column(treeview, 1);
2115                 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
2116         }
2117         gtk_tree_path_free (treepath);
2118 }
2119
2120 void
2121 chapter_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
2122 {
2123         g_debug("chapter_list_selection_changed_cb ()");
2124         //chapter_selection_changed = TRUE;
2125 }
2126
2127 void
2128 preview_button_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2129 {
2130         gint titleindex;
2131
2132         titleindex = ghb_settings_combo_int(ud->settings, "title");
2133         if (titleindex < 0) return;
2134         g_debug("titleindex %d", titleindex);
2135
2136         GtkWidget *widget = GHB_WIDGET (ud->builder, "preview_window");
2137         gtk_widget_show (widget);
2138 }
2139
2140 void
2141 preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2142 {
2143         set_preview_image(ud);
2144 }
2145
2146 void
2147 preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
2148 {
2149         g_debug("-------------------------------allocate %d x %d", allocation->width, allocation->height);
2150         if (preview_button_width == allocation->width &&
2151                 preview_button_height == allocation->height)
2152         {
2153                 // Nothing to do. Bug out.
2154                 g_debug("nothing to do");
2155                 return;
2156         }
2157         g_debug("-------------------------------prev allocate %d x %d", preview_button_width, preview_button_height);
2158         preview_button_width = allocation->width;
2159         preview_button_height = allocation->height;
2160         set_preview_image(ud);
2161 }
2162
2163 void
2164 debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data)
2165 {
2166         signal_user_data_t *ud = (signal_user_data_t*)data;
2167         
2168         if (ud->debug)
2169         {
2170                 printf("%s: %s\n", domain, msg);
2171         }
2172 }
2173
2174 static void
2175 set_visible(GtkWidget *widget, gboolean visible)
2176 {
2177         if (visible)
2178         {
2179                 gtk_widget_show_now(widget);
2180         }
2181         else
2182         {
2183                 gtk_widget_hide(widget);
2184         }
2185 }
2186
2187 void
2188 ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
2189 {
2190         GtkWidget *widget;
2191         g_debug("ghb_hbfd");
2192         widget = GHB_WIDGET(ud->builder, "queue_pause1");
2193         set_visible(widget, !hbfd);
2194         widget = GHB_WIDGET(ud->builder, "queue_add");
2195         set_visible(widget, !hbfd);
2196         widget = GHB_WIDGET(ud->builder, "show_queue");
2197         set_visible(widget, !hbfd);
2198         widget = GHB_WIDGET(ud->builder, "show_activity");
2199         set_visible(widget, !hbfd);
2200
2201         widget = GHB_WIDGET(ud->builder, "chapter_box");
2202         set_visible(widget, !hbfd);
2203         widget = GHB_WIDGET(ud->builder, "container_box");
2204         set_visible(widget, !hbfd);
2205         widget = GHB_WIDGET(ud->builder, "settings_box");
2206         set_visible(widget, !hbfd);
2207         widget = GHB_WIDGET(ud->builder, "presets_save");
2208         set_visible(widget, !hbfd);
2209         widget = GHB_WIDGET(ud->builder, "presets_remove");
2210         set_visible(widget, !hbfd);
2211         widget = GHB_WIDGET(ud->builder, "presets_default");
2212         set_visible(widget, !hbfd);
2213         widget = GHB_WIDGET (ud->builder, "hb_window");
2214         gtk_window_resize(GTK_WINDOW(widget), 16, 16);
2215
2216 }
2217
2218 void
2219 hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
2220 {
2221         g_debug("hbfd_toggled_cb");
2222         ghb_widget_to_setting (ud->settings, widget);
2223         gboolean hbfd = ghb_settings_get_boolean(ud->settings, "hbfd");
2224         ghb_hbfd(ud, hbfd);
2225         ghb_pref_save(ud->settings, "hbfd");
2226 }
2227
2228 void
2229 pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2230 {
2231         g_debug("pref_changed_cb");
2232         ghb_widget_to_setting (ud->settings, widget);
2233         ghb_check_dependency(ud, widget);
2234         const gchar *name = gtk_widget_get_name(widget);
2235         ghb_pref_save(ud->settings, name);
2236 }
2237
2238 void
2239 tweaks_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2240 {
2241         g_debug("tweaks_changed_cb");
2242         ghb_widget_to_setting (ud->settings, widget);
2243         const gchar *name = gtk_widget_get_name(widget);
2244         ghb_pref_save(ud->settings, name);
2245
2246         gboolean tweaks = ghb_settings_get_boolean(ud->settings, "allow_tweaks");
2247         widget = GHB_WIDGET(ud->builder, "PictureDeinterlace");
2248         tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2249         widget = GHB_WIDGET(ud->builder, "tweak_PictureDeinterlace");
2250         !tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2251
2252         widget = GHB_WIDGET(ud->builder, "PictureDenoise");
2253         tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2254         widget = GHB_WIDGET(ud->builder, "tweak_PictureDenoise");
2255         !tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2256         if (tweaks)
2257         {
2258                 const GValue *value;
2259                 value = ghb_settings_get_value(ud->settings, "PictureDeinterlace");
2260                 ghb_ui_update(ud, "tweak_PictureDeinterlace", value);
2261                 value = ghb_settings_get_value(ud->settings, "PictureDenoise");
2262                 ghb_ui_update(ud, "tweak_PictureDenoise", value);
2263         }
2264         else
2265         {
2266                 const GValue *value;
2267                 value = ghb_settings_get_value(ud->settings, "tweak_PictureDeinterlace");
2268                 ghb_ui_update(ud, "PictureDeinterlace", value);
2269                 value = ghb_settings_get_value(ud->settings, "tweak_PictureDenoise");
2270                 ghb_ui_update(ud, "PictureDenoise", value);
2271         }
2272 }
2273
2274 void
2275 hbfd_feature_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2276 {
2277         g_debug("hbfd_feature_changed_cb");
2278         ghb_widget_to_setting (ud->settings, widget);
2279         const gchar *name = gtk_widget_get_name(widget);
2280         ghb_pref_save(ud->settings, name);
2281
2282         gboolean hbfd = ghb_settings_get_boolean(ud->settings, "hbfd_feature");
2283         GtkAction *action;
2284         if (hbfd)
2285         {
2286                 const GValue *val;
2287                 val = ghb_settings_get_value(ud->settings, "hbfd");
2288                 ghb_ui_update(ud, "hbfd", val);
2289         }
2290         action = GHB_ACTION (ud->builder, "hbfd");
2291         gtk_action_set_visible(action, hbfd);
2292 }
2293
2294 void
2295 ghb_file_menu_add_dvd(signal_user_data_t *ud)
2296 {
2297         GList *link, *drives;
2298
2299         GtkActionGroup *agroup = GTK_ACTION_GROUP(
2300                 gtk_builder_get_object(ud->builder, "actiongroup1"));
2301         GtkUIManager *ui = GTK_UI_MANAGER(
2302                 gtk_builder_get_object(ud->builder, "uimanager1"));
2303         guint merge_id = gtk_ui_manager_new_merge_id(ui);
2304
2305         link = drives = dvd_device_list();
2306         while (link != NULL)
2307         {
2308                 gchar *name = (gchar*)link->data;
2309                 // Create action for this drive
2310                 GtkAction *action = gtk_action_new(name, name,
2311                         "Scan this DVD source", "gtk-cdrom");
2312                 // Add action to action group
2313                 gtk_action_group_add_action_with_accel(agroup, action, "");
2314                 // Add to ui manager
2315                 gtk_ui_manager_add_ui(ui, merge_id, 
2316                         "ui/menubar1/menuitem1/quit1", name, name,
2317                         GTK_UI_MANAGER_AUTO, TRUE);
2318                 // Connect signal to action (menu item)
2319                 g_signal_connect(action, "activate", 
2320                         (GCallback)dvd_source_activate_cb, ud);
2321                 g_free(name);
2322                 link = link->next;
2323         }
2324         g_list_free(drives);
2325
2326         // Add separator
2327         gtk_ui_manager_add_ui(ui, merge_id, 
2328                 "ui/menubar1/menuitem1/quit1", "", NULL,
2329                 GTK_UI_MANAGER_AUTO, TRUE);
2330 }
2331
2332 gboolean ghb_is_cd(GDrive *gd);
2333
2334 static GList*
2335 dvd_device_list()
2336 {
2337         GVolumeMonitor *gvm;
2338         GList *drives, *link;
2339         GList *dvd_devices = NULL;
2340         
2341         gvm = g_volume_monitor_get ();
2342         drives = g_volume_monitor_get_connected_drives (gvm);
2343         link = drives;
2344         while (link != NULL)
2345         {
2346                 GDrive *gd;
2347                 
2348                 gd = (GDrive*)link->data;
2349                 if (ghb_is_cd(gd))
2350                 {
2351                         gchar *device;
2352                         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2353                         dvd_devices = g_list_append(dvd_devices, (gpointer)device);
2354                 }
2355                 g_object_unref (gd);
2356                 link = link->next;
2357         }
2358         g_list_free(drives);
2359         return dvd_devices;
2360 }
2361
2362
2363 static DBusConnection *dbus_connection = NULL;
2364 static LibHalContext *hal_ctx;
2365
2366 gboolean
2367 ghb_is_cd(GDrive *gd)
2368 {
2369         gchar *device;
2370         LibHalDrive *halDrive;
2371         LibHalDriveType dtype;
2372
2373         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2374         halDrive = libhal_drive_from_device_file (hal_ctx, device);
2375         dtype = libhal_drive_get_type(halDrive);
2376         libhal_drive_free(halDrive);
2377         g_free(device);
2378         return (dtype == LIBHAL_DRIVE_TYPE_CDROM);
2379 }
2380
2381 void
2382 drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
2383 {
2384         gchar *device;
2385         gint state = ghb_get_state();
2386         static gboolean first_time = TRUE;
2387
2388         if (ud->current_dvd_device == NULL) return;
2389         // A drive change event happens when the program initially starts
2390         // and I don't want to automatically scan at that time.
2391         if (first_time)
2392         {
2393                 first_time = FALSE;
2394                 return;
2395         }
2396         if (state != GHB_STATE_IDLE) return;
2397         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2398         
2399         // DVD insertion detected.  Scan it.
2400         if (strcmp(device, ud->current_dvd_device) == 0)
2401         {
2402                 if (g_drive_has_media (gd))
2403                 {
2404                         GtkProgressBar *progress;
2405                         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2406                         gtk_progress_bar_set_text (progress, "Scanning ...");
2407                         gtk_progress_bar_set_fraction (progress, 0);
2408                         update_source_label(ud, device);
2409                         ghb_hb_cleanup(TRUE);
2410                         ghb_backend_scan(device, 0);
2411                 }
2412                 else
2413                 {
2414                         ghb_hb_cleanup(TRUE);
2415                         ghb_backend_scan("/dev/null", 0);
2416                 }
2417         }
2418         g_free(device);
2419 }
2420
2421
2422 static gboolean
2423 dbus_init (void)
2424 {
2425         DBusError error;
2426
2427         if (dbus_connection != NULL)
2428                 return TRUE;
2429
2430         dbus_error_init (&error);
2431         if (!(dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) {
2432                 g_debug ("could not get system bus: %s", error.message);
2433                 dbus_error_free (&error);
2434                 return FALSE;
2435         }
2436
2437         //dbus_connection_setup_with_g_main (dbus_connection, NULL);
2438         //dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
2439         //dbus_connection_add_filter (dbus_connection, gvm_dbus_filter_function, NULL, NULL);
2440
2441         return TRUE;
2442 }
2443
2444 void
2445 ghb_hal_init()
2446 {
2447         DBusError error;
2448         char **devices;
2449         int nr;
2450
2451         if (!dbus_init ())
2452                 return;
2453
2454         if (!(hal_ctx = libhal_ctx_new ())) {
2455                 g_warning ("failed to create a HAL context!");
2456                 return;
2457         }
2458
2459         libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
2460         dbus_error_init (&error);
2461         if (!libhal_ctx_init (hal_ctx, &error)) {
2462                 g_warning ("libhal_ctx_init failed: %s", error.message ? error.message : "unknown");
2463                 dbus_error_free (&error);
2464                 libhal_ctx_free (hal_ctx);
2465                 return;
2466         }
2467
2468         /*
2469          * Do something to ping the HAL daemon - the above functions will
2470          * succeed even if hald is not running, so long as DBUS is.  But we
2471          * want to exit silently if hald is not running, to behave on
2472          * pre-2.6 systems.
2473          */
2474         if (!(devices = libhal_get_all_devices (hal_ctx, &nr, &error))) {
2475                 g_warning ("seems that HAL is not running: %s", error.message ? error.message : "unknown");
2476                 dbus_error_free (&error);
2477
2478                 libhal_ctx_shutdown (hal_ctx, NULL);
2479                 libhal_ctx_free (hal_ctx);
2480                 return;
2481         }
2482
2483         libhal_free_string_array (devices);
2484
2485         //gvm_hal_claim_branch ("/org/freedesktop/Hal/devices/local");
2486 }
2487
2488 gboolean 
2489 tweak_setting_cb(
2490         GtkWidget *widget, 
2491         GdkEventButton *event, 
2492         signal_user_data_t *ud)
2493 {
2494         const gchar *name;
2495         gchar *tweak_name;
2496         gboolean ret = FALSE;
2497         gboolean allow_tweaks;
2498
2499         g_debug("press %d %d", event->type, event->button);
2500         allow_tweaks = ghb_settings_get_boolean(ud->settings, "allow_tweaks");
2501         if (allow_tweaks && event->type == GDK_BUTTON_PRESS && event->button == 3)
2502         { // Its a right mouse click
2503                 GtkWidget *dialog;
2504                 GtkEntry *entry;
2505                 GtkResponseType response;
2506                 gchar *tweak = NULL;
2507
2508                 name = gtk_widget_get_name(widget);
2509                 if (g_str_has_prefix(name, "tweak_"))
2510                 {
2511                         tweak_name = g_strdup(name);
2512                 }
2513                 else
2514                 {
2515                         tweak_name = g_strdup_printf("tweak_%s", name);
2516                 }
2517
2518                 tweak = ghb_settings_get_string (ud->settings, tweak_name);
2519                 dialog = GHB_WIDGET(ud->builder, "tweak_dialog");
2520                 gtk_window_set_title(GTK_WINDOW(dialog), tweak_name);
2521                 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "tweak_setting"));
2522                 if (tweak)
2523                 {
2524                         gtk_entry_set_text(entry, tweak);
2525                         g_free(tweak);
2526                 }
2527                 response = gtk_dialog_run(GTK_DIALOG(dialog));
2528                 gtk_widget_hide(dialog);
2529                 if (response == GTK_RESPONSE_OK)
2530                 {
2531                         tweak = (gchar*)gtk_entry_get_text(entry);
2532                         if (ghb_validate_filter_string(tweak, -1))
2533                                 ghb_settings_set_string(ud->settings, tweak_name, tweak);
2534                         else
2535                         {
2536                                 gchar *message;
2537                                 message = g_strdup_printf(
2538                                                         "Invalid Settings:\n%s",
2539                                                         tweak);
2540                                 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2541                                 g_free(message);
2542                         }
2543                 }
2544                 g_free(tweak_name);
2545                 ret = TRUE;
2546         }
2547         return ret;
2548 }
2549
2550 gboolean 
2551 easter_egg_cb(
2552         GtkWidget *widget, 
2553         GdkEventButton *event, 
2554         signal_user_data_t *ud)
2555 {
2556         g_debug("press %d %d", event->type, event->button);
2557         if (event->type == GDK_3BUTTON_PRESS && event->button == 1)
2558         { // Its a tripple left mouse button click
2559                 GtkWidget *widget;
2560                 widget = GHB_WIDGET(ud->builder, "allow_tweaks");
2561                 gtk_widget_show(widget);
2562                 widget = GHB_WIDGET(ud->builder, "hbfd_feature");
2563                 gtk_widget_show(widget);
2564         }
2565         else if (event->type == GDK_BUTTON_PRESS && event->button == 1)
2566         {
2567                 GtkWidget *widget;
2568                 widget = GHB_WIDGET(ud->builder, "allow_tweaks");
2569                 gtk_widget_hide(widget);
2570                 widget = GHB_WIDGET(ud->builder, "hbfd_feature");
2571                 gtk_widget_hide(widget);
2572         }
2573         return FALSE;
2574 }
2575
2576 gchar*
2577 format_deblock_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
2578 {
2579         if (val < 5.0)
2580         {
2581                 return g_strdup_printf("Off");
2582         }
2583         else
2584         {
2585                 return g_strdup_printf("%d", (gint)val);
2586         }
2587 }
2588
2589 gchar*
2590 format_vquality_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
2591 {
2592         if (ghb_settings_get_boolean(ud->settings, "directqp"))
2593         {
2594                 gint vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
2595                 // Only x264 and ffmpeg currently support direct qp/crf entry
2596                 if (vcodec != HB_VCODEC_X264 && vcodec != HB_VCODEC_FFMPEG)
2597                 {
2598                         val *= 100;
2599                         return g_strdup_printf("%.1f", val);
2600                 }
2601                 return g_strdup_printf("%d", (gint)val);
2602         }
2603         else
2604         {
2605                 val *= 100;
2606                 return g_strdup_printf("%.1f", val);
2607         }
2608 }