OSDN Git Service

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