OSDN Git Service

LinGui: fix a stupid error in calculating picture scaling
[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         ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
980         gint width, height, crop[4];
981         crop[0] = ghb_settings_get_int(ud->settings, "PictureTopCrop");
982         crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
983         crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
984         crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
985         width = tinfo->width - crop[2] - crop[3];
986         height = tinfo->height - crop[0] - crop[1];
987         widget = GHB_WIDGET (ud->builder, "crop_dimensions");
988         text = g_strdup_printf ("%d x %d", width, height);
989         gtk_label_set_text (GTK_LABEL(widget), text);
990         g_free(text);
991
992         g_debug("setting max end chapter %d", tinfo->num_chapters);
993         widget = GHB_WIDGET (ud->builder, "end_chapter");
994         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters);
995         gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), tinfo->num_chapters);
996         widget = GHB_WIDGET (ud->builder, "start_chapter");
997         gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1);
998 }
999
1000 static gint preview_button_width;
1001 static gint preview_button_height;
1002 static gboolean update_preview = FALSE;
1003
1004 static void
1005 set_preview_image(signal_user_data_t *ud)
1006 {
1007         GtkWidget *widget;
1008         gint preview_width, preview_height, target_height, width, height;
1009
1010         g_debug("set_preview_button_image ()");
1011         gint titleindex;
1012
1013         titleindex = ghb_settings_combo_int(ud->settings, "title");
1014         if (titleindex < 0) return;
1015         widget = GHB_WIDGET (ud->builder, "preview_frame");
1016         gint frame = ghb_widget_int(widget) - 1;
1017         GdkPixbuf *preview = ghb_get_preview_image (titleindex, frame, ud->settings, TRUE);
1018         if (preview == NULL) return;
1019         widget = GHB_WIDGET (ud->builder, "preview_image");
1020         gtk_image_set_from_pixbuf(GTK_IMAGE(widget), preview);
1021
1022         preview_width = gdk_pixbuf_get_width(preview);
1023         preview_height = gdk_pixbuf_get_height(preview);
1024         gchar *text = g_strdup_printf("%d x %d", preview_width, preview_height);
1025         widget = GHB_WIDGET (ud->builder, "preview_dims");
1026         gtk_label_set_text(GTK_LABEL(widget), text);
1027         g_free(text);
1028         
1029         g_debug("preview %d x %d", preview_width, preview_height);
1030         target_height = MIN(preview_button_height - 12, 128);
1031         height = target_height;
1032         width = preview_width * height / preview_height;
1033
1034         if ((height >= 16) && (width >= 16))
1035         {
1036                 GdkPixbuf *scaled_preview;
1037                 scaled_preview = gdk_pixbuf_scale_simple (preview, width, height, GDK_INTERP_NEAREST);
1038                 if (scaled_preview != NULL)
1039                 {
1040                         g_object_unref (preview);
1041                         
1042                         widget = GHB_WIDGET (ud->builder, "preview_button_image");
1043                         gtk_image_set_from_pixbuf(GTK_IMAGE(widget), scaled_preview);
1044                         g_object_unref (scaled_preview);
1045                 }
1046         }
1047 }
1048
1049 void
1050 title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1051 {
1052         ghb_title_info_t tinfo;
1053         gint titleindex;
1054         
1055         g_debug("title_changed_cb ()");
1056         ghb_widget_to_setting(ud->settings, widget);
1057         ghb_check_dependency(ud, widget);
1058
1059         titleindex = ghb_settings_combo_int(ud->settings, "title");
1060         ghb_update_ui_combo_box (ud->builder, "AudioTrack", titleindex, FALSE);
1061         ghb_update_ui_combo_box (ud->builder, "Subtitles", titleindex, FALSE);
1062
1063         ghb_update_from_preset(ud, "Subtitles");
1064         if (ghb_get_title_info (&tinfo, titleindex))
1065         {
1066                 show_title_info(ud, &tinfo);
1067         }
1068         update_chapter_list (ud);
1069         ghb_adjust_audio_rate_combos(ud);
1070         ghb_set_pref_audio(titleindex, ud);
1071         if (ghb_settings_get_boolean(ud->settings, "vquality_type_target"))
1072         {
1073                 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1074                 ghb_ui_update(ud, "VideoAvgBitrate", ghb_int64_value(bitrate));
1075         }
1076
1077         // Unfortunately, there is no way to query how many frames were
1078         // actually generated during the scan.  It attempts to make 10.
1079         // If I knew how many were generated, I would adjust the spin
1080         // control range here.
1081         ghb_ui_update(ud, "preview_frame", ghb_int64_value(1));
1082
1083         set_preview_image (ud);
1084 }
1085
1086 void
1087 setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1088 {
1089         ghb_widget_to_setting(ud->settings, widget);
1090         ghb_check_dependency(ud, widget);
1091         ghb_clear_presets_selection(ud);
1092 }
1093
1094 static void
1095 validate_filter_widget(signal_user_data_t *ud, const gchar *name)
1096 {
1097         GtkTreeModel *store;
1098         GtkTreeIter iter;
1099         const gchar *str;
1100         gboolean foundit = FALSE;
1101         GtkComboBox *combo = GTK_COMBO_BOX(GHB_WIDGET(ud->builder, name));
1102         if (gtk_combo_box_get_active(combo) < 0)
1103         { // Validate user input
1104                 gchar *val = ghb_settings_get_string(ud->settings, name);
1105                 store = gtk_combo_box_get_model(combo);
1106                 // Check to see if user manually entered one of the combo options
1107                 if (gtk_tree_model_get_iter_first(store, &iter))
1108                 {
1109                         do
1110                         {
1111                                 gtk_tree_model_get(store, &iter, 0, &str, -1);
1112                                 if (strcasecmp(val, str) == 0)
1113                                 {
1114                                         gtk_combo_box_set_active_iter(combo, &iter);
1115                                         foundit = TRUE;
1116                                         break;
1117                                 }
1118                         } while (gtk_tree_model_iter_next(store, &iter));
1119                 }
1120                 if (!foundit)
1121                 { // validate format of filter string
1122                         if (!ghb_validate_filter_string(val, -1))
1123                                 gtk_combo_box_set_active(combo, 0);
1124                 }
1125                 g_free(val);
1126         }
1127 }
1128
1129 gboolean
1130 deint_tweak_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
1131         signal_user_data_t *ud)
1132 {
1133         g_debug("deint_tweak_focus_out_cb ()");
1134         validate_filter_widget(ud, "tweak_PictureDeinterlace");
1135         return FALSE;
1136 }
1137
1138 gboolean
1139 denoise_tweak_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
1140         signal_user_data_t *ud)
1141 {
1142         g_debug("denoise_tweak_focus_out_cb ()");
1143         validate_filter_widget(ud, "tweak_PictureDenoise");
1144         return FALSE;
1145 }
1146
1147 void
1148 http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1149 {
1150         ghb_widget_to_setting(ud->settings, widget);
1151         ghb_check_dependency(ud, widget);
1152         ghb_clear_presets_selection(ud);
1153         // AC3 is not allowed when Web optimized
1154         ghb_grey_combo_options (ud->builder);
1155 }
1156
1157 void
1158 vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1159 {
1160         gdouble vqmin, vqmax, step, page;
1161         gint digits;
1162         gint vcodec;
1163
1164         ghb_widget_to_setting(ud->settings, widget);
1165         ghb_check_dependency(ud, widget);
1166         ghb_clear_presets_selection(ud);
1167         ghb_vquality_range(ud, &vqmin, &vqmax, &step, &page, &digits);
1168         GtkWidget *qp = GHB_WIDGET(ud->builder, "VideoQualitySlider");
1169         gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1170         gtk_range_set_increments (GTK_RANGE(qp), step, page);
1171         gtk_scale_set_digits(GTK_SCALE(qp), digits);
1172         vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
1173         if (vcodec != HB_VCODEC_X264 && vcodec != HB_VCODEC_FFMPEG)
1174         {
1175                 ghb_ui_update(ud, "directqp", ghb_boolean_value(FALSE));
1176         }
1177 }
1178
1179 void
1180 target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1181 {
1182         const gchar *name = gtk_widget_get_name(widget);
1183         g_debug("setting_widget_changed_cb () %s", name);
1184         ghb_widget_to_setting(ud->settings, widget);
1185         ghb_check_dependency(ud, widget);
1186         ghb_clear_presets_selection(ud);
1187         if (ghb_settings_get_boolean(ud->settings, "vquality_type_target"))
1188         {
1189                 gint titleindex;
1190                 titleindex = ghb_settings_combo_int(ud->settings, "title");
1191                 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1192                 ghb_ui_update(ud, "VideoAvgBitrate", ghb_int64_value(bitrate));
1193         }
1194 }
1195
1196 void
1197 start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1198 {
1199         gint start, end;
1200         const gchar *name = gtk_widget_get_name(widget);
1201
1202         g_debug("start_chapter_changed_cb () %s", name);
1203         ghb_widget_to_setting(ud->settings, widget);
1204         start = ghb_settings_get_int(ud->settings, "start_chapter");
1205         end = ghb_settings_get_int(ud->settings, "end_chapter");
1206         if (start > end)
1207                 ghb_ui_update(ud, "end_chapter", ghb_int_value(start));
1208         ghb_check_dependency(ud, widget);
1209         if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
1210         {
1211                 set_destination(ud);
1212         }
1213 }
1214
1215 void
1216 end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1217 {
1218         gint start, end;
1219         const gchar *name = gtk_widget_get_name(widget);
1220
1221         g_debug("end_chapter_changed_cb () %s", name);
1222         ghb_widget_to_setting(ud->settings, widget);
1223         start = ghb_settings_get_int(ud->settings, "start_chapter");
1224         end = ghb_settings_get_int(ud->settings, "end_chapter");
1225         if (start > end)
1226                 ghb_ui_update(ud, "start_chapter", ghb_int_value(end));
1227         ghb_check_dependency(ud, widget);
1228         if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
1229         {
1230                 set_destination(ud);
1231         }
1232 }
1233
1234 void
1235 scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1236 {
1237         g_debug("scale_width_changed_cb ()");
1238         ghb_widget_to_setting(ud->settings, widget);
1239         ghb_check_dependency(ud, widget);
1240         ghb_set_scale (ud, GHB_SCALE_KEEP_WIDTH);
1241         update_preview = TRUE;
1242         gchar *text;
1243         gint width = ghb_settings_get_int(ud->settings, "scale_width");
1244         gint height = ghb_settings_get_int(ud->settings, "scale_height");
1245         widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1246         text = g_strdup_printf ("%d x %d", width, height);
1247         gtk_label_set_text (GTK_LABEL(widget), text);
1248         g_free(text);
1249 }
1250
1251 void
1252 scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1253 {
1254         g_debug("scale_height_changed_cb ()");
1255         ghb_widget_to_setting(ud->settings, widget);
1256         ghb_check_dependency(ud, widget);
1257         ghb_set_scale (ud, GHB_SCALE_KEEP_HEIGHT);
1258         update_preview = TRUE;
1259         gchar *text;
1260         gint width = ghb_settings_get_int(ud->settings, "scale_width");
1261         gint height = ghb_settings_get_int(ud->settings, "scale_height");
1262         widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1263         text = g_strdup_printf ("%d x %d", width, height);
1264         gtk_label_set_text (GTK_LABEL(widget), text);
1265         g_free(text);
1266 }
1267
1268 void
1269 crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1270 {
1271         gint titleindex, crop[4];
1272         ghb_title_info_t tinfo;
1273         
1274         g_debug("crop_changed_cb ()");
1275         ghb_widget_to_setting(ud->settings, widget);
1276         ghb_check_dependency(ud, widget);
1277         ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1278
1279         crop[0] = ghb_settings_get_int(ud->settings, "PictureTopCrop");
1280         crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
1281         crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
1282         crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
1283         titleindex = ghb_settings_combo_int(ud->settings, "title");
1284         if (ghb_get_title_info (&tinfo, titleindex))
1285         {
1286                 gint width, height;
1287                 gchar *text;
1288                 
1289                 width = tinfo.width - crop[2] - crop[3];
1290                 height = tinfo.height - crop[0] - crop[1];
1291                 widget = GHB_WIDGET (ud->builder, "crop_dimensions");
1292                 text = g_strdup_printf ("%d x %d", width, height);
1293                 gtk_label_set_text (GTK_LABEL(widget), text);
1294                 g_free(text);
1295         }
1296         gchar *text;
1297         widget = GHB_WIDGET (ud->builder, "crop_values");
1298         text = g_strdup_printf ("%d:%d:%d:%d", crop[0], crop[1], crop[2], crop[3]);
1299         gtk_label_set_text (GTK_LABEL(widget), text);
1300         g_free(text);
1301         update_preview = TRUE;
1302 }
1303
1304 void
1305 scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1306 {
1307         g_debug("scale_changed_cb ()");
1308         ghb_widget_to_setting(ud->settings, widget);
1309         ghb_check_dependency(ud, widget);
1310         ghb_clear_presets_selection(ud);
1311         ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1312         update_preview = TRUE;
1313         
1314         gchar *text;
1315         
1316         text = ghb_settings_get_boolean(ud->settings, "PictureAutoCrop") ? "On" : "Off";
1317         widget = GHB_WIDGET (ud->builder, "crop_auto");
1318         gtk_label_set_text (GTK_LABEL(widget), text);
1319         text = ghb_settings_get_boolean(ud->settings, "autoscale") ? "On" : "Off";
1320         widget = GHB_WIDGET (ud->builder, "scale_auto");
1321         gtk_label_set_text (GTK_LABEL(widget), text);
1322         text = ghb_settings_get_boolean(ud->settings, "anamorphic") ? "On" : "Off";
1323         widget = GHB_WIDGET (ud->builder, "scale_anamorphic");
1324         gtk_label_set_text (GTK_LABEL(widget), text);
1325 }
1326
1327 void
1328 generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
1329 {
1330         // Normally (due to user input) I only want to process the entry
1331         // when editing is done and the focus-out signal is sent.
1332         // But... there's always a but.
1333         // If the entry is changed by software, the focus-out signal is not sent.
1334         // The changed signal is sent ... so here we are.
1335         // I don't want to process upon every keystroke, so I prevent processing
1336         // while the widget has focus.
1337         g_debug("generic_entry_changed_cb ()");
1338         if (!GTK_WIDGET_HAS_FOCUS((GtkWidget*)entry))
1339         {
1340                 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
1341         }
1342 }
1343
1344 void
1345 prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1346 {
1347         GtkWidget *dialog;
1348         GtkResponseType response;
1349
1350         g_debug("prefs_dialog_cb ()");
1351         dialog = GHB_WIDGET(ud->builder, "prefs_dialog");
1352         response = gtk_dialog_run(GTK_DIALOG(dialog));
1353         gtk_widget_hide(dialog);
1354 }
1355
1356 gboolean
1357 ghb_message_dialog(GtkMessageType type, const gchar *message, const gchar *no, const gchar *yes)
1358 {
1359         GtkWidget *dialog;
1360         GtkResponseType response;
1361                         
1362         // Toss up a warning dialog
1363         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1364                                                         type, GTK_BUTTONS_NONE,
1365                                                         message);
1366         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
1367                                                    no, GTK_RESPONSE_NO,
1368                                                    yes, GTK_RESPONSE_YES, NULL);
1369         response = gtk_dialog_run(GTK_DIALOG(dialog));
1370         gtk_widget_destroy (dialog);
1371         if (response == GTK_RESPONSE_NO)
1372         {
1373                 return FALSE;
1374         }
1375         return TRUE;
1376 }
1377
1378 gboolean
1379 ghb_cancel_encode(const gchar *extra_msg)
1380 {
1381         GtkWidget *dialog;
1382         GtkResponseType response;
1383         
1384         if (extra_msg == NULL) extra_msg = "";
1385         // Toss up a warning dialog
1386         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1387                                 GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
1388                                 "%sYour movie will be lost if you don't continue encoding.",
1389                                 extra_msg);
1390         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
1391                                                    "Continue Encoding", GTK_RESPONSE_NO,
1392                                                    "Stop Encoding", GTK_RESPONSE_YES, NULL);
1393         response = gtk_dialog_run(GTK_DIALOG(dialog));
1394         gtk_widget_destroy (dialog);
1395         if (response == GTK_RESPONSE_NO) return FALSE;
1396         ghb_stop_queue();
1397         return TRUE;
1398 }
1399
1400 static void
1401 submit_job(GValue *settings)
1402 {
1403         static gint unique_id = 1;
1404
1405         g_debug("submit_job");
1406         if (settings == NULL) return;
1407         ghb_settings_set_int(settings, "job_unique_id", unique_id);
1408         ghb_settings_set_int(settings, "job_status", GHB_QUEUE_RUNNING);
1409         ghb_add_job (settings, unique_id);
1410         ghb_start_queue();
1411         unique_id++;
1412 }
1413
1414 static void
1415 queue_scan(GValue *js)
1416 {
1417         gchar *path;
1418         gint titlenum;
1419
1420         path = ghb_settings_get_string( js, "source");
1421         titlenum = ghb_settings_get_int(js, "titlenum");
1422         ghb_backend_queue_scan(path, titlenum);
1423         g_free(path);
1424 }
1425
1426 GValue* 
1427 ghb_start_next_job(signal_user_data_t *ud, gboolean find_first)
1428 {
1429         static gint current = 0;
1430         gint count, ii, jj;
1431         GValue *js;
1432         gint status;
1433
1434         g_debug("start_next_job");
1435         count = ghb_array_len(ud->queue);
1436         if (find_first)
1437         {       // Start the first pending item in the queue
1438                 current = 0;
1439                 for (ii = 0; ii < count; ii++)
1440                 {
1441
1442                         js = ghb_array_get_nth(ud->queue, ii);
1443                         status = ghb_settings_get_int(js, "job_status");
1444                         if (status == GHB_QUEUE_PENDING)
1445                         {
1446                                 current = ii;
1447                                 queue_scan(js);
1448                                 return js;
1449                         }
1450                 }
1451                 // Nothing pending
1452                 return NULL;
1453         }
1454         // Find the next pending item after the current running item
1455         for (ii = 0; ii < count-1; ii++)
1456         {
1457                 js = ghb_array_get_nth(ud->queue, ii);
1458                 status = ghb_settings_get_int(js, "job_status");
1459                 if (status == GHB_QUEUE_RUNNING)
1460                 {
1461                         for (jj = ii+1; jj < count; jj++)
1462                         {
1463                                 js = ghb_array_get_nth(ud->queue, jj);
1464                                 status = ghb_settings_get_int(js, "job_status");
1465                                 if (status == GHB_QUEUE_PENDING)
1466                                 {
1467                                         current = jj;
1468                                         queue_scan(js);
1469                                         return js;
1470                                 }
1471                         }
1472                 }
1473         }
1474         // No running item found? Maybe it was deleted
1475         // Look for a pending item starting from the last index we started
1476         for (ii = current; ii < count; ii++)
1477         {
1478                 js = ghb_array_get_nth(ud->queue, ii);
1479                 status = ghb_settings_get_int(js, "job_status");
1480                 if (status == GHB_QUEUE_PENDING)
1481                 {
1482                         current = ii;
1483                         queue_scan(js);
1484                         return js;
1485                 }
1486         }
1487         // Nothing found
1488         return NULL;
1489 }
1490
1491 static gint
1492 find_queue_job(GValue *queue, gint unique_id, GValue **job)
1493 {
1494         GValue *js;
1495         gint ii, count;
1496         gint job_unique_id;
1497         
1498         *job = NULL;
1499         g_debug("find_queue_job");
1500         count = ghb_array_len(queue);
1501         for (ii = 0; ii < count; ii++)
1502         {
1503                 js = ghb_array_get_nth(queue, ii);
1504                 job_unique_id = ghb_settings_get_int(js, "job_unique_id");
1505                 if (job_unique_id == unique_id)
1506                 {
1507                         *job = js;
1508                         return ii;
1509                 }
1510         }
1511         return -1;
1512 }
1513
1514 gchar*
1515 working_status_string(signal_user_data_t *ud, ghb_status_t *status)
1516 {
1517         gchar *task_str, *job_str, *status_str;
1518         gint qcount;
1519         gint index;
1520         GValue *js;
1521
1522         if (status->job_count > 1)
1523         {
1524                 task_str = g_strdup_printf("pass %d of %d, ", 
1525                         status->job_cur, status->job_count);
1526         }
1527         else
1528         {
1529                 task_str = g_strdup("");
1530         }
1531         qcount = ghb_array_len(ud->queue);
1532         if (qcount > 1)
1533         {
1534                 index = find_queue_job(ud->queue, status->unique_id, &js);
1535                 job_str = g_strdup_printf("job %d of %d, ", index+1, qcount);
1536         }
1537         else
1538         {
1539                 job_str = g_strdup("");
1540         }
1541         if(status->seconds > -1)
1542         {
1543                 status_str= g_strdup_printf(
1544                         "Encoding: %s%s%.2f %%"
1545                         " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)",
1546                         job_str, task_str,
1547                         100.0 * status->progress,
1548                         status->rate_cur, status->rate_avg, status->hours, 
1549                         status->minutes, status->seconds );
1550         }
1551         else
1552         {
1553                 status_str= g_strdup_printf(
1554                         "Encoding: %s%s%.2f %%",
1555                         job_str, task_str,
1556                         100.0 * status->progress );
1557         }
1558         g_free(task_str);
1559         g_free(job_str);
1560         return status_str;
1561 }
1562
1563 static void
1564 ghb_backend_events(signal_user_data_t *ud)
1565 {
1566         ghb_status_t status;
1567         gchar *status_str;
1568         GtkProgressBar *progress;
1569         gint titleindex;
1570         GValue *js;
1571         gint index;
1572         GtkTreeView *treeview;
1573         GtkTreeStore *store;
1574         GtkTreeIter iter;
1575         static gint working = 0;
1576         static gboolean work_started = FALSE;
1577         
1578         ghb_track_status();
1579         ghb_get_status(&status);
1580         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
1581         // First handle the status of title scans
1582         // Then handle the status of the queue
1583         if (status.state & GHB_STATE_SCANNING)
1584         {
1585                 if (status.title_cur == 0)
1586                 {
1587                         status_str = g_strdup ("Scanning...");
1588                 }
1589                 else
1590                 {
1591                         status_str = g_strdup_printf ("Scanning title %d of %d...", 
1592                                                                   status.title_cur, status.title_count );
1593                 }
1594                 gtk_progress_bar_set_text (progress, status_str);
1595                 g_free(status_str);
1596                 if (status.title_count > 0)
1597                 {
1598                         gtk_progress_bar_set_fraction (progress, 
1599                                 (gdouble)status.title_cur / status.title_count);
1600                 }
1601         }
1602         else if (status.state & GHB_STATE_SCANDONE)
1603         {
1604                 status_str = g_strdup_printf ("Scan done"); 
1605                 gtk_progress_bar_set_text (progress, status_str);
1606                 g_free(status_str);
1607                 gtk_progress_bar_set_fraction (progress, 1.0);
1608
1609                 ghb_title_info_t tinfo;
1610                         
1611                 ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE);
1612                 titleindex = ghb_longest_title();
1613                 ghb_ui_update(ud, "title", ghb_int64_value(titleindex));
1614
1615                 // Are there really any titles.
1616                 if (!ghb_get_title_info(&tinfo, titleindex))
1617                 {
1618                         GtkProgressBar *progress;
1619                         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
1620                         gtk_progress_bar_set_fraction (progress, 0);
1621                         gtk_progress_bar_set_text (progress, "No Source");
1622                 }
1623                 ghb_clear_state(GHB_STATE_SCANDONE);
1624                 ghb_queue_buttons_grey(ud, work_started);
1625                 if (ghb_queue_edit_settings)
1626                 {
1627                         gint jstatus;
1628
1629                         jstatus = ghb_settings_get_int(ghb_queue_edit_settings, "job_status");
1630                         ghb_settings_to_ui(ud, ghb_queue_edit_settings);
1631                         ghb_set_audio(ud, ghb_queue_edit_settings);
1632                         if (jstatus == GHB_QUEUE_PENDING)
1633                         {
1634                                 ghb_value_free(ghb_queue_edit_settings);
1635                         }
1636                         ghb_queue_edit_settings = NULL;
1637                 }
1638         }
1639         else if (status.queue_state & GHB_STATE_SCANNING)
1640         {
1641                 status_str = g_strdup_printf ("Scanning ...");
1642                 gtk_progress_bar_set_text (progress, status_str);
1643                 g_free(status_str);
1644                 gtk_progress_bar_set_fraction (progress, 0);
1645         }
1646         else if (status.queue_state & GHB_STATE_SCANDONE)
1647         {
1648                 ghb_clear_queue_state(GHB_STATE_SCANDONE);
1649                 submit_job(ud->current_job);
1650         }
1651         else if (status.queue_state & GHB_STATE_PAUSED)
1652         {
1653                 status_str = g_strdup_printf ("Paused"); 
1654                 gtk_progress_bar_set_text (progress, status_str);
1655                 g_free(status_str);
1656         }
1657         else if (status.queue_state & GHB_STATE_WORKING)
1658         {
1659                 status_str = working_status_string(ud, &status);
1660                 gtk_progress_bar_set_text (progress, status_str);
1661                 gtk_progress_bar_set_fraction (progress, status.progress);
1662                 g_free(status_str);
1663         }
1664         else if (status.queue_state & GHB_STATE_WORKDONE)
1665         {
1666                 gint qstatus;
1667
1668                 work_started = FALSE;
1669                 ghb_queue_buttons_grey(ud, FALSE);
1670                 index = find_queue_job(ud->queue, status.unique_id, &js);
1671                 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
1672                 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
1673                 if (ud->cancel_encode)
1674                         status.error = GHB_ERROR_CANCELED;
1675                 switch( status.error )
1676                 {
1677                         case GHB_ERROR_NONE:
1678                                 gtk_progress_bar_set_text( progress, "Rip done!" );
1679                                 qstatus = GHB_QUEUE_DONE;
1680                                 if (js != NULL)
1681                                 {
1682                                         gchar *path = g_strdup_printf ("%d", index);
1683                                         if (gtk_tree_model_get_iter_from_string(
1684                                                         GTK_TREE_MODEL(store), &iter, path))
1685                                         {
1686                                                 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
1687                                         }
1688                                         g_free(path);
1689                                 }
1690                                 break;
1691                         case GHB_ERROR_CANCELED:
1692                                 gtk_progress_bar_set_text( progress, "Rip canceled." );
1693                                 qstatus = GHB_QUEUE_CANCELED;
1694                                 if (js != NULL)
1695                                 {
1696                                         gchar *path = g_strdup_printf ("%d", index);
1697                                         if (gtk_tree_model_get_iter_from_string(
1698                                                         GTK_TREE_MODEL(store), &iter, path))
1699                                         {
1700                                                 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
1701                                         }
1702                                         g_free(path);
1703                                 }
1704                                 break;
1705                         default:
1706                                 gtk_progress_bar_set_text( progress, "Rip failed.");
1707                                 qstatus = GHB_QUEUE_CANCELED;
1708                                 if (js != NULL)
1709                                 {
1710                                         gchar *path = g_strdup_printf ("%d", index);
1711                                         if (gtk_tree_model_get_iter_from_string(
1712                                                         GTK_TREE_MODEL(store), &iter, path))
1713                                         {
1714                                                 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
1715                                         }
1716                                         g_free(path);
1717                                 }
1718                 }
1719                 gtk_progress_bar_set_fraction (progress, 1.0);
1720                 ghb_clear_queue_state(GHB_STATE_WORKDONE);
1721                 if (!ud->cancel_encode)
1722                         ud->current_job = ghb_start_next_job(ud, FALSE);
1723                 else
1724                         ud->current_job = NULL;
1725                 if (js)
1726                         ghb_settings_set_int(js, "job_status", qstatus);
1727                 ghb_save_queue(ud->queue);
1728                 ud->cancel_encode = FALSE;
1729         }
1730         else if (status.queue_state & GHB_STATE_MUXING)
1731         {
1732                 gtk_progress_bar_set_text(progress, "Muxing: this may take awhile...");
1733         }
1734         if (status.queue_state & GHB_STATE_SCANNING)
1735         {
1736                 // This needs to be in scanning and working since scanning
1737                 // happens fast enough that it can be missed
1738                 if (!work_started)
1739                 {
1740                         work_started = TRUE;
1741                         ghb_queue_buttons_grey(ud, TRUE);
1742                 }
1743         }
1744         if (status.queue_state & GHB_STATE_WORKING)
1745         {
1746                 // This needs to be in scanning and working since scanning
1747                 // happens fast enough that it can be missed
1748                 if (!work_started)
1749                 {
1750                         work_started = TRUE;
1751                         ghb_queue_buttons_grey(ud, TRUE);
1752                 }
1753                 index = find_queue_job(ud->queue, status.unique_id, &js);
1754                 if (status.unique_id != 0 && index >= 0)
1755                 {
1756                         gchar working_icon[] = "hb-working0";
1757                         working_icon[10] = '0' + working;
1758                         working = (working+1) % 6;
1759                         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
1760                         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
1761                         gchar *path = g_strdup_printf ("%d", index);
1762                         if (gtk_tree_model_get_iter_from_string(
1763                                         GTK_TREE_MODEL(store), &iter, path))
1764                         {
1765                                 gtk_tree_store_set(store, &iter, 0, working_icon, -1);
1766                         }
1767                         g_free(path);
1768                 }
1769                 GtkLabel *label;
1770                 gchar *status_str;
1771
1772                 status_str = working_status_string(ud, &status);
1773                 label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_status"));
1774                 gtk_label_set_text (label, status_str);
1775                 g_free(status_str);
1776         }
1777 }
1778
1779 gboolean
1780 ghb_timer_cb(gpointer data)
1781 {
1782         signal_user_data_t *ud = (signal_user_data_t*)data;
1783
1784         ghb_backend_events(ud);
1785         if (update_default_destination)
1786         {
1787                 gchar *dest, *dest_dir, *def_dest;
1788                 dest = ghb_settings_get_string(ud->settings, "destination");
1789                 dest_dir = g_path_get_dirname (dest);
1790                 def_dest = ghb_settings_get_string(ud->settings, "destination_dir");
1791                 if (strcmp(dest_dir, def_dest) != 0)
1792                 {
1793                         ghb_settings_set_string (ud->settings, "destination_dir", dest_dir);
1794                         ghb_pref_save (ud->settings, "destination_dir");
1795                 }
1796                 g_free(dest);
1797                 g_free(dest_dir);
1798                 g_free(def_dest);
1799                 update_default_destination = FALSE;
1800         }
1801         if (update_preview)
1802         {
1803                 set_preview_image (ud);
1804                 update_preview = FALSE;
1805         }
1806         return TRUE;
1807 }
1808
1809 gboolean
1810 ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
1811 {
1812         gchar *text = NULL;
1813         gsize length;
1814         GtkTextView *textview;
1815         GtkTextBuffer *buffer;
1816         GtkTextIter iter;
1817         GtkTextMark *mark;
1818         GError *gerror = NULL;
1819         GIOStatus status;
1820         
1821         signal_user_data_t *ud = (signal_user_data_t*)data;
1822
1823         status = g_io_channel_read_line (source, &text, &length, NULL, &gerror);
1824         if (text != NULL)
1825         {
1826                 GdkWindow *window;
1827                 gint width, height;
1828                 gint x, y;
1829                 gboolean bottom = FALSE;
1830
1831                 textview = GTK_TEXT_VIEW(GHB_WIDGET (ud->builder, "activity_view"));
1832                 buffer = gtk_text_view_get_buffer (textview);
1833                 // I would like to auto-scroll the window when the scrollbar
1834                 // is at the bottom, 
1835                 // must determining whether the insert point is at
1836                 // the bottom of the window 
1837                 window = gtk_text_view_get_window(textview, GTK_TEXT_WINDOW_TEXT);
1838                 if (window != NULL)
1839                 {
1840                         gdk_drawable_get_size(GDK_DRAWABLE(window), &width, &height);
1841                         gtk_text_view_window_to_buffer_coords(textview, 
1842                                 GTK_TEXT_WINDOW_TEXT, width, height, &x, &y);
1843                         gtk_text_view_get_iter_at_location(textview, &iter, x, y);
1844                         if (gtk_text_iter_is_end(&iter))
1845                         {
1846                                 bottom = TRUE;
1847                         }
1848                 }
1849                 else
1850                 {
1851                         // If the window isn't available, assume bottom
1852                         bottom = TRUE;
1853                 }
1854                 gtk_text_buffer_get_end_iter(buffer, &iter);
1855                 gtk_text_buffer_insert(buffer, &iter, text, -1);
1856                 if (bottom)
1857                 {
1858                         //gtk_text_view_scroll_to_iter(textview, &iter, 0, FALSE, 0, 0);
1859                         mark = gtk_text_buffer_get_insert (buffer);
1860                         gtk_text_view_scroll_mark_onscreen(textview, mark);
1861                 }
1862                 g_io_channel_write_chars (ud->activity_log, text, length, &length, NULL);
1863                 g_free(text);
1864         }
1865         if (status != G_IO_STATUS_NORMAL)
1866         {
1867                 // This should never happen, but if it does I would get into an
1868                 // infinite loop.  Returning false removes this callback.
1869                 g_warning("Error while reading activity from pipe");
1870                 if (gerror != NULL)
1871                 {
1872                         g_warning("%s", gerror->message);
1873                         g_error_free (gerror);
1874                 }
1875                 return FALSE;
1876         }
1877         if (gerror != NULL)
1878                 g_error_free (gerror);
1879         return TRUE;
1880 }
1881
1882 void
1883 about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1884 {
1885         GtkWidget *widget = GHB_WIDGET (ud->builder, "hb_about");
1886         gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(widget), ghb_version());
1887         gtk_widget_show (widget);
1888 }
1889
1890 void
1891 guide_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1892 {
1893         gboolean result;
1894         char *argv[] = 
1895                 {"xdg-open","http://trac.handbrake.fr/wiki/HandBrakeGuide",NULL,NULL};
1896         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
1897                                 NULL, NULL, NULL);
1898         if (result) return;
1899
1900         argv[0] = "gnome-open";
1901         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
1902                                 NULL, NULL, NULL);
1903         if (result) return;
1904
1905         argv[0] = "kfmclient";
1906         argv[1] = "exec";
1907         argv[2] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
1908         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
1909                                 NULL, NULL, NULL);
1910         if (result) return;
1911
1912         argv[0] = "firefox";
1913         argv[1] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
1914         argv[2] = NULL;
1915         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
1916                                 NULL, NULL, NULL);
1917         if (result) return;
1918 }
1919
1920 void
1921 hb_about_response_cb(GtkWidget *widget, gint response, signal_user_data_t *ud)
1922 {
1923         gtk_widget_hide (widget);
1924 }
1925
1926 void
1927 show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1928 {
1929         GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
1930         gtk_widget_show (widget);
1931 }
1932
1933 void
1934 show_queue_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1935 {
1936         GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
1937         gtk_widget_show (widget);
1938 }
1939
1940 void
1941 show_presets_toggled_cb(GtkToggleButton *button, signal_user_data_t *ud)
1942 {
1943         GtkWidget *widget;
1944         GtkWindow *hb_window;
1945         
1946         g_debug("show_presets_clicked_cb ()");
1947         widget = GHB_WIDGET (ud->builder, "presets_frame");
1948         if (gtk_toggle_button_get_active(button))
1949         {
1950                 gtk_widget_show_now(widget);
1951         }
1952         else
1953         {
1954                 gtk_widget_hide(widget);
1955                 hb_window = GTK_WINDOW(GHB_WIDGET (ud->builder, "hb_window"));
1956                 gtk_window_resize(hb_window, 16, 16);
1957         }
1958         ghb_widget_to_setting(ud->settings, GTK_WIDGET(button));
1959         ghb_pref_save(ud->settings, "show_presets");
1960 }
1961
1962 static void
1963 update_chapter_list(signal_user_data_t *ud)
1964 {
1965         GtkTreeView *treeview;
1966         GtkTreeIter iter;
1967         GtkListStore *store;
1968         gboolean done;
1969         GValue *chapters;
1970         gint titleindex, ii;
1971         gint count;
1972         
1973         g_debug("update_chapter_list ()");
1974         titleindex = ghb_settings_combo_int(ud->settings, "title");
1975         chapters = ghb_get_chapters(titleindex);
1976         count = ghb_array_len(chapters);
1977         if (chapters)
1978                 ghb_settings_set_value(ud->settings, "chapter_list", chapters);
1979         
1980         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
1981         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1982         ii = 0;
1983         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
1984         {
1985                 do
1986                 {
1987
1988                         if (ii < count)
1989                         {
1990                                 gchar *chapter;
1991
1992                                 // Update row with settings data
1993                                 g_debug("Updating row");
1994                                 chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
1995                                 gtk_list_store_set(store, &iter, 
1996                                         0, ii+1,
1997                                         1, chapter,
1998                                         2, TRUE,
1999                                         -1);
2000                                 g_free(chapter);
2001                                 ii++;
2002                                 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
2003                         }
2004                         else
2005                         {
2006                                 // No more settings data, remove row
2007                                 g_debug("Removing row");
2008                                 done = !gtk_list_store_remove(store, &iter);
2009                         }
2010                 } while (!done);
2011         }
2012         while (ii < count)
2013         {
2014                 gchar *chapter;
2015
2016                 // Additional settings, add row
2017                 g_debug("Adding row");
2018                 chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
2019                 gtk_list_store_append(store, &iter);
2020                 gtk_list_store_set(store, &iter, 
2021                         0, ii+1,
2022                         1, chapter,
2023                         2, TRUE,
2024                         -1);
2025                 g_free(chapter);
2026                 ii++;
2027         }
2028 }
2029
2030 static gint chapter_edit_key = 0;
2031
2032 gboolean
2033 chapter_keypress_cb(
2034         GhbCellRendererText *cell,
2035         GdkEventKey *event,
2036         signal_user_data_t *ud)
2037 {
2038         chapter_edit_key = event->keyval;
2039         return FALSE;
2040 }
2041
2042 void
2043 chapter_edited_cb(
2044         GhbCellRendererText *cell, 
2045         gchar *path, 
2046         gchar *text, 
2047         signal_user_data_t *ud)
2048 {
2049         GtkTreePath *treepath;
2050         GtkListStore *store;
2051         GtkTreeView *treeview;
2052         GtkTreeIter iter;
2053         gint index;
2054         gint *pi;
2055         gint row;
2056         
2057         g_debug("chapter_edited_cb ()");
2058         g_debug("path (%s)", path);
2059         g_debug("text (%s)", text);
2060         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
2061         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
2062         treepath = gtk_tree_path_new_from_string (path);
2063         pi = gtk_tree_path_get_indices(treepath);
2064         row = pi[0];
2065         gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
2066         gtk_list_store_set(store, &iter, 
2067                 1, text,
2068                 2, TRUE,
2069                 -1);
2070         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &index, -1);
2071
2072         GValue *chapters;
2073         GValue *chapter;
2074
2075         chapters = ghb_settings_get_value(ud->settings, "chapter_list");
2076         chapter = ghb_array_get_nth(chapters, index-1);
2077         g_value_set_string(chapter, text);
2078         if ((chapter_edit_key == GDK_Return || chapter_edit_key == GDK_Down) &&
2079                 gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
2080         {
2081                 GtkTreeViewColumn *column;
2082
2083                 gtk_tree_path_next(treepath);
2084                 // When a cell has been edited, I want to advance to the
2085                 // next cell and start editing it automaitcally.
2086                 // Unfortunately, we may not be in a state here where
2087                 // editing is allowed.  This happens when the user selects
2088                 // a new cell with the mouse instead of just hitting enter.
2089                 // Some kind of Gtk quirk.  widget_editable==NULL assertion.
2090                 // Editing is enabled again once the selection event has been
2091                 // processed.  So I'm queueing up a callback to be called
2092                 // when things go idle.  There, I will advance to the next
2093                 // cell and initiate editing.
2094                 //
2095                 // Now, you might be asking why I don't catch the keypress
2096                 // event and determine what action to take based on that.
2097                 // The Gtk developers in their infinite wisdom have made the 
2098                 // actual GtkEdit widget being used a private member of
2099                 // GtkCellRendererText, so it can not be accessed to hang a
2100                 // signal handler off of.  And they also do not propagate the
2101                 // keypress signals in any other way.  So that information is lost.
2102                 //g_idle_add((GSourceFunc)next_cell, ud);
2103                 //
2104                 // Keeping the above comment for posterity.
2105                 // I got industrious and made my own CellTextRendererText that
2106                 // passes on the key-press-event. So now I have much better
2107                 // control of this.
2108                 column = gtk_tree_view_get_column(treeview, 1);
2109                 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
2110         }
2111         else if (chapter_edit_key == GDK_Up && row > 0)
2112         {
2113                 GtkTreeViewColumn *column;
2114                 gtk_tree_path_prev(treepath);
2115                 column = gtk_tree_view_get_column(treeview, 1);
2116                 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
2117         }
2118         gtk_tree_path_free (treepath);
2119 }
2120
2121 void
2122 chapter_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
2123 {
2124         g_debug("chapter_list_selection_changed_cb ()");
2125         //chapter_selection_changed = TRUE;
2126 }
2127
2128 void
2129 preview_button_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2130 {
2131         gint titleindex;
2132
2133         titleindex = ghb_settings_combo_int(ud->settings, "title");
2134         if (titleindex < 0) return;
2135         g_debug("titleindex %d", titleindex);
2136
2137         GtkWidget *widget = GHB_WIDGET (ud->builder, "preview_window");
2138         gtk_widget_show (widget);
2139 }
2140
2141 void
2142 preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2143 {
2144         set_preview_image(ud);
2145 }
2146
2147 void
2148 preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
2149 {
2150         g_debug("-------------------------------allocate %d x %d", allocation->width, allocation->height);
2151         if (preview_button_width == allocation->width &&
2152                 preview_button_height == allocation->height)
2153         {
2154                 // Nothing to do. Bug out.
2155                 g_debug("nothing to do");
2156                 return;
2157         }
2158         g_debug("-------------------------------prev allocate %d x %d", preview_button_width, preview_button_height);
2159         preview_button_width = allocation->width;
2160         preview_button_height = allocation->height;
2161         set_preview_image(ud);
2162 }
2163
2164 void
2165 debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data)
2166 {
2167         signal_user_data_t *ud = (signal_user_data_t*)data;
2168         
2169         if (ud->debug)
2170         {
2171                 printf("%s: %s\n", domain, msg);
2172         }
2173 }
2174
2175 static void
2176 set_visible(GtkWidget *widget, gboolean visible)
2177 {
2178         if (visible)
2179         {
2180                 gtk_widget_show_now(widget);
2181         }
2182         else
2183         {
2184                 gtk_widget_hide(widget);
2185         }
2186 }
2187
2188 void
2189 ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
2190 {
2191         GtkWidget *widget;
2192         g_debug("ghb_hbfd");
2193         widget = GHB_WIDGET(ud->builder, "queue_pause1");
2194         set_visible(widget, !hbfd);
2195         widget = GHB_WIDGET(ud->builder, "queue_add");
2196         set_visible(widget, !hbfd);
2197         widget = GHB_WIDGET(ud->builder, "show_queue");
2198         set_visible(widget, !hbfd);
2199         widget = GHB_WIDGET(ud->builder, "show_activity");
2200         set_visible(widget, !hbfd);
2201
2202         widget = GHB_WIDGET(ud->builder, "chapter_box");
2203         set_visible(widget, !hbfd);
2204         widget = GHB_WIDGET(ud->builder, "container_box");
2205         set_visible(widget, !hbfd);
2206         widget = GHB_WIDGET(ud->builder, "settings_box");
2207         set_visible(widget, !hbfd);
2208         widget = GHB_WIDGET(ud->builder, "presets_save");
2209         set_visible(widget, !hbfd);
2210         widget = GHB_WIDGET(ud->builder, "presets_remove");
2211         set_visible(widget, !hbfd);
2212         widget = GHB_WIDGET(ud->builder, "presets_default");
2213         set_visible(widget, !hbfd);
2214         widget = GHB_WIDGET (ud->builder, "hb_window");
2215         gtk_window_resize(GTK_WINDOW(widget), 16, 16);
2216
2217 }
2218
2219 void
2220 hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
2221 {
2222         g_debug("hbfd_toggled_cb");
2223         ghb_widget_to_setting (ud->settings, widget);
2224         gboolean hbfd = ghb_settings_get_boolean(ud->settings, "hbfd");
2225         ghb_hbfd(ud, hbfd);
2226         ghb_pref_save(ud->settings, "hbfd");
2227 }
2228
2229 void
2230 pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2231 {
2232         g_debug("pref_changed_cb");
2233         ghb_widget_to_setting (ud->settings, widget);
2234         ghb_check_dependency(ud, widget);
2235         const gchar *name = gtk_widget_get_name(widget);
2236         ghb_pref_save(ud->settings, name);
2237 }
2238
2239 void
2240 tweaks_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2241 {
2242         g_debug("tweaks_changed_cb");
2243         ghb_widget_to_setting (ud->settings, widget);
2244         const gchar *name = gtk_widget_get_name(widget);
2245         ghb_pref_save(ud->settings, name);
2246
2247         gboolean tweaks = ghb_settings_get_boolean(ud->settings, "allow_tweaks");
2248         widget = GHB_WIDGET(ud->builder, "PictureDeinterlace");
2249         tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2250         widget = GHB_WIDGET(ud->builder, "tweak_PictureDeinterlace");
2251         !tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2252
2253         widget = GHB_WIDGET(ud->builder, "PictureDenoise");
2254         tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2255         widget = GHB_WIDGET(ud->builder, "tweak_PictureDenoise");
2256         !tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget);
2257         if (tweaks)
2258         {
2259                 const GValue *value;
2260                 value = ghb_settings_get_value(ud->settings, "PictureDeinterlace");
2261                 ghb_ui_update(ud, "tweak_PictureDeinterlace", value);
2262                 value = ghb_settings_get_value(ud->settings, "PictureDenoise");
2263                 ghb_ui_update(ud, "tweak_PictureDenoise", value);
2264         }
2265         else
2266         {
2267                 const GValue *value;
2268                 value = ghb_settings_get_value(ud->settings, "tweak_PictureDeinterlace");
2269                 ghb_ui_update(ud, "PictureDeinterlace", value);
2270                 value = ghb_settings_get_value(ud->settings, "tweak_PictureDenoise");
2271                 ghb_ui_update(ud, "PictureDenoise", value);
2272         }
2273 }
2274
2275 void
2276 hbfd_feature_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
2277 {
2278         g_debug("hbfd_feature_changed_cb");
2279         ghb_widget_to_setting (ud->settings, widget);
2280         const gchar *name = gtk_widget_get_name(widget);
2281         ghb_pref_save(ud->settings, name);
2282
2283         gboolean hbfd = ghb_settings_get_boolean(ud->settings, "hbfd_feature");
2284         GtkAction *action;
2285         if (hbfd)
2286         {
2287                 const GValue *val;
2288                 val = ghb_settings_get_value(ud->settings, "hbfd");
2289                 ghb_ui_update(ud, "hbfd", val);
2290         }
2291         action = GHB_ACTION (ud->builder, "hbfd");
2292         gtk_action_set_visible(action, hbfd);
2293 }
2294
2295 void
2296 ghb_file_menu_add_dvd(signal_user_data_t *ud)
2297 {
2298         GList *link, *drives;
2299
2300         GtkActionGroup *agroup = GTK_ACTION_GROUP(
2301                 gtk_builder_get_object(ud->builder, "actiongroup1"));
2302         GtkUIManager *ui = GTK_UI_MANAGER(
2303                 gtk_builder_get_object(ud->builder, "uimanager1"));
2304         guint merge_id = gtk_ui_manager_new_merge_id(ui);
2305
2306         link = drives = dvd_device_list();
2307         while (link != NULL)
2308         {
2309                 gchar *name = (gchar*)link->data;
2310                 // Create action for this drive
2311                 GtkAction *action = gtk_action_new(name, name,
2312                         "Scan this DVD source", "gtk-cdrom");
2313                 // Add action to action group
2314                 gtk_action_group_add_action_with_accel(agroup, action, "");
2315                 // Add to ui manager
2316                 gtk_ui_manager_add_ui(ui, merge_id, 
2317                         "ui/menubar1/menuitem1/quit1", name, name,
2318                         GTK_UI_MANAGER_AUTO, TRUE);
2319                 // Connect signal to action (menu item)
2320                 g_signal_connect(action, "activate", 
2321                         (GCallback)dvd_source_activate_cb, ud);
2322                 g_free(name);
2323                 link = link->next;
2324         }
2325         g_list_free(drives);
2326
2327         // Add separator
2328         gtk_ui_manager_add_ui(ui, merge_id, 
2329                 "ui/menubar1/menuitem1/quit1", "", NULL,
2330                 GTK_UI_MANAGER_AUTO, TRUE);
2331 }
2332
2333 gboolean ghb_is_cd(GDrive *gd);
2334
2335 static GList*
2336 dvd_device_list()
2337 {
2338         GVolumeMonitor *gvm;
2339         GList *drives, *link;
2340         GList *dvd_devices = NULL;
2341         
2342         gvm = g_volume_monitor_get ();
2343         drives = g_volume_monitor_get_connected_drives (gvm);
2344         link = drives;
2345         while (link != NULL)
2346         {
2347                 GDrive *gd;
2348                 
2349                 gd = (GDrive*)link->data;
2350                 if (ghb_is_cd(gd))
2351                 {
2352                         gchar *device;
2353                         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2354                         dvd_devices = g_list_append(dvd_devices, (gpointer)device);
2355                 }
2356                 g_object_unref (gd);
2357                 link = link->next;
2358         }
2359         g_list_free(drives);
2360         return dvd_devices;
2361 }
2362
2363
2364 static DBusConnection *dbus_connection = NULL;
2365 static LibHalContext *hal_ctx;
2366
2367 gboolean
2368 ghb_is_cd(GDrive *gd)
2369 {
2370         gchar *device;
2371         LibHalDrive *halDrive;
2372         LibHalDriveType dtype;
2373
2374         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2375         halDrive = libhal_drive_from_device_file (hal_ctx, device);
2376         dtype = libhal_drive_get_type(halDrive);
2377         libhal_drive_free(halDrive);
2378         g_free(device);
2379         return (dtype == LIBHAL_DRIVE_TYPE_CDROM);
2380 }
2381
2382 void
2383 drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
2384 {
2385         gchar *device;
2386         gint state = ghb_get_state();
2387         static gboolean first_time = TRUE;
2388
2389         if (ud->current_dvd_device == NULL) return;
2390         // A drive change event happens when the program initially starts
2391         // and I don't want to automatically scan at that time.
2392         if (first_time)
2393         {
2394                 first_time = FALSE;
2395                 return;
2396         }
2397         if (state != GHB_STATE_IDLE) return;
2398         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2399         
2400         // DVD insertion detected.  Scan it.
2401         if (strcmp(device, ud->current_dvd_device) == 0)
2402         {
2403                 if (g_drive_has_media (gd))
2404                 {
2405                         GtkProgressBar *progress;
2406                         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2407                         gtk_progress_bar_set_text (progress, "Scanning ...");
2408                         gtk_progress_bar_set_fraction (progress, 0);
2409                         update_source_label(ud, device);
2410                         ghb_hb_cleanup(TRUE);
2411                         ghb_backend_scan(device, 0);
2412                 }
2413                 else
2414                 {
2415                         ghb_hb_cleanup(TRUE);
2416                         ghb_backend_scan("/dev/null", 0);
2417                 }
2418         }
2419         g_free(device);
2420 }
2421
2422
2423 static gboolean
2424 dbus_init (void)
2425 {
2426         DBusError error;
2427
2428         if (dbus_connection != NULL)
2429                 return TRUE;
2430
2431         dbus_error_init (&error);
2432         if (!(dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) {
2433                 g_debug ("could not get system bus: %s", error.message);
2434                 dbus_error_free (&error);
2435                 return FALSE;
2436         }
2437
2438         //dbus_connection_setup_with_g_main (dbus_connection, NULL);
2439         //dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
2440         //dbus_connection_add_filter (dbus_connection, gvm_dbus_filter_function, NULL, NULL);
2441
2442         return TRUE;
2443 }
2444
2445 void
2446 ghb_hal_init()
2447 {
2448         DBusError error;
2449         char **devices;
2450         int nr;
2451
2452         if (!dbus_init ())
2453                 return;
2454
2455         if (!(hal_ctx = libhal_ctx_new ())) {
2456                 g_warning ("failed to create a HAL context!");
2457                 return;
2458         }
2459
2460         libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
2461         dbus_error_init (&error);
2462         if (!libhal_ctx_init (hal_ctx, &error)) {
2463                 g_warning ("libhal_ctx_init failed: %s", error.message ? error.message : "unknown");
2464                 dbus_error_free (&error);
2465                 libhal_ctx_free (hal_ctx);
2466                 return;
2467         }
2468
2469         /*
2470          * Do something to ping the HAL daemon - the above functions will
2471          * succeed even if hald is not running, so long as DBUS is.  But we
2472          * want to exit silently if hald is not running, to behave on
2473          * pre-2.6 systems.
2474          */
2475         if (!(devices = libhal_get_all_devices (hal_ctx, &nr, &error))) {
2476                 g_warning ("seems that HAL is not running: %s", error.message ? error.message : "unknown");
2477                 dbus_error_free (&error);
2478
2479                 libhal_ctx_shutdown (hal_ctx, NULL);
2480                 libhal_ctx_free (hal_ctx);
2481                 return;
2482         }
2483
2484         libhal_free_string_array (devices);
2485
2486         //gvm_hal_claim_branch ("/org/freedesktop/Hal/devices/local");
2487 }
2488
2489 gboolean 
2490 tweak_setting_cb(
2491         GtkWidget *widget, 
2492         GdkEventButton *event, 
2493         signal_user_data_t *ud)
2494 {
2495         const gchar *name;
2496         gchar *tweak_name;
2497         gboolean ret = FALSE;
2498         gboolean allow_tweaks;
2499
2500         g_debug("press %d %d", event->type, event->button);
2501         allow_tweaks = ghb_settings_get_boolean(ud->settings, "allow_tweaks");
2502         if (allow_tweaks && event->type == GDK_BUTTON_PRESS && event->button == 3)
2503         { // Its a right mouse click
2504                 GtkWidget *dialog;
2505                 GtkEntry *entry;
2506                 GtkResponseType response;
2507                 gchar *tweak = NULL;
2508
2509                 name = gtk_widget_get_name(widget);
2510                 if (g_str_has_prefix(name, "tweak_"))
2511                 {
2512                         tweak_name = g_strdup(name);
2513                 }
2514                 else
2515                 {
2516                         tweak_name = g_strdup_printf("tweak_%s", name);
2517                 }
2518
2519                 tweak = ghb_settings_get_string (ud->settings, tweak_name);
2520                 dialog = GHB_WIDGET(ud->builder, "tweak_dialog");
2521                 gtk_window_set_title(GTK_WINDOW(dialog), tweak_name);
2522                 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "tweak_setting"));
2523                 if (tweak)
2524                 {
2525                         gtk_entry_set_text(entry, tweak);
2526                         g_free(tweak);
2527                 }
2528                 response = gtk_dialog_run(GTK_DIALOG(dialog));
2529                 gtk_widget_hide(dialog);
2530                 if (response == GTK_RESPONSE_OK)
2531                 {
2532                         tweak = (gchar*)gtk_entry_get_text(entry);
2533                         if (ghb_validate_filter_string(tweak, -1))
2534                                 ghb_settings_set_string(ud->settings, tweak_name, tweak);
2535                         else
2536                         {
2537                                 gchar *message;
2538                                 message = g_strdup_printf(
2539                                                         "Invalid Settings:\n%s",
2540                                                         tweak);
2541                                 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2542                                 g_free(message);
2543                         }
2544                 }
2545                 g_free(tweak_name);
2546                 ret = TRUE;
2547         }
2548         return ret;
2549 }
2550
2551 gboolean 
2552 easter_egg_cb(
2553         GtkWidget *widget, 
2554         GdkEventButton *event, 
2555         signal_user_data_t *ud)
2556 {
2557         g_debug("press %d %d", event->type, event->button);
2558         if (event->type == GDK_3BUTTON_PRESS && event->button == 1)
2559         { // Its a tripple left mouse button click
2560                 GtkWidget *widget;
2561                 widget = GHB_WIDGET(ud->builder, "allow_tweaks");
2562                 gtk_widget_show(widget);
2563                 widget = GHB_WIDGET(ud->builder, "hbfd_feature");
2564                 gtk_widget_show(widget);
2565         }
2566         else if (event->type == GDK_BUTTON_PRESS && event->button == 1)
2567         {
2568                 GtkWidget *widget;
2569                 widget = GHB_WIDGET(ud->builder, "allow_tweaks");
2570                 gtk_widget_hide(widget);
2571                 widget = GHB_WIDGET(ud->builder, "hbfd_feature");
2572                 gtk_widget_hide(widget);
2573         }
2574         return FALSE;
2575 }
2576
2577 gchar*
2578 format_deblock_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
2579 {
2580         if (val < 5.0)
2581         {
2582                 return g_strdup_printf("Off");
2583         }
2584         else
2585         {
2586                 return g_strdup_printf("%d", (gint)val);
2587         }
2588 }
2589
2590 gchar*
2591 format_vquality_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
2592 {
2593         if (ghb_settings_get_boolean(ud->settings, "directqp"))
2594         {
2595                 gint vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
2596                 // Only x264 and ffmpeg currently support direct qp/crf entry
2597                 if (vcodec != HB_VCODEC_X264 && vcodec != HB_VCODEC_FFMPEG)
2598                 {
2599                         val *= 100;
2600                         return g_strdup_printf("%.1f", val);
2601                 }
2602                 return g_strdup_printf("%d", (gint)val);
2603         }
2604         else
2605         {
2606                 val *= 100;
2607                 return g_strdup_printf("%.1f", val);
2608         }
2609 }