OSDN Git Service

LinGui: fix Gtk-CRITICAL warning when logging invalid utf-8 characters
[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 <fcntl.h>
20 #include <sys/stat.h>
21 #include <time.h>
22
23 #if !defined(_WIN32)
24 #include <poll.h>
25 #include <libhal-storage.h>
26 #include <dbus/dbus-glib.h>
27 #include <dbus/dbus-glib-lowlevel.h>
28
29 #include <netinet/in.h>
30 #include <netdb.h>
31 #if defined(_OLD_WEBKIT)
32 #include <webkit.h>
33 #else
34 #include <webkit/webkit.h>
35 #endif
36 #include <libnotify/notify.h>
37 #include <gdk/gdkx.h>
38 #else
39 #define WINVER 0x0500
40 #include <winsock2.h>
41 #include <dbt.h>
42 #endif
43
44 #include <gtk/gtk.h>
45 #include <gdk/gdkkeysyms.h>
46 #include <glib/gstdio.h>
47 #include <gio/gio.h>
48
49 #include "hb.h"
50 #include "callbacks.h"
51 #include "queuehandler.h"
52 #include "audiohandler.h"
53 #include "subtitlehandler.h"
54 #include "resources.h"
55 #include "settings.h"
56 #include "presets.h"
57 #include "preview.h"
58 #include "values.h"
59 #include "plist.h"
60 #include "appcast.h"
61 #include "hb-backend.h"
62 #include "ghb-dvd.h"
63 #include "ghbcellrenderertext.h"
64
65 static void reset_chapter_list(signal_user_data_t *ud, GValue *settings);
66 static void update_chapter_list(signal_user_data_t *ud);
67 static GList* dvd_device_list();
68 static void prune_logs(signal_user_data_t *ud);
69 void ghb_notify_done(signal_user_data_t *ud);
70 gpointer ghb_check_update(signal_user_data_t *ud);
71 static gboolean ghb_can_shutdown_gsm();
72 static void ghb_shutdown_gsm();
73 static gboolean ghb_can_suspend_gpm();
74 static void ghb_suspend_gpm();
75 static gboolean appcast_busy = FALSE;
76
77 // This is a dependency map used for greying widgets
78 // that are dependent on the state of another widget.
79 // The enable_value comes from the values that are
80 // obtained from ghb_widget_value().  For combo boxes
81 // you will have to look further to combo box options
82 // maps in hb-backend.c
83
84 GValue *dep_map;
85 GValue *rev_map;
86
87 void
88 ghb_init_dep_map()
89 {
90         dep_map = ghb_resource_get("widget-deps");
91         rev_map = ghb_resource_get("widget-reverse-deps");
92 }
93
94 static gboolean
95 dep_check(signal_user_data_t *ud, const gchar *name, gboolean *out_hide)
96 {
97         GtkWidget *widget;
98         GObject *dep_object;
99         gint ii;
100         gint count;
101         gboolean result = TRUE;
102         GValue *array, *data;
103         gchar *widget_name;
104         
105         g_debug("dep_check () %s", name);
106
107         if (rev_map == NULL) return TRUE;
108         array = ghb_dict_lookup(rev_map, name);
109         count = ghb_array_len(array);
110         *out_hide = FALSE;
111         for (ii = 0; ii < count; ii++)
112         {
113                 data = ghb_array_get_nth(array, ii);
114                 widget_name = ghb_value_string(ghb_array_get_nth(data, 0));
115                 widget = GHB_WIDGET(ud->builder, widget_name);
116                 dep_object = gtk_builder_get_object(ud->builder, name);
117                 g_free(widget_name);
118                 if (!GTK_WIDGET_SENSITIVE(widget))
119                         continue;
120                 if (dep_object == NULL)
121                 {
122                         g_message("Failed to find widget");
123                 }
124                 else
125                 {
126                         gchar *value;
127                         gint jj = 0;
128                         gchar **values;
129                         gboolean sensitive = FALSE;
130                         gboolean die, hide;
131
132                         die = ghb_value_boolean(ghb_array_get_nth(data, 2));
133                         hide = ghb_value_boolean(ghb_array_get_nth(data, 3));
134                         value = ghb_value_string(ghb_array_get_nth(data, 1));
135                         values = g_strsplit(value, "|", 10);
136                         g_free(value);
137
138                         if (widget)
139                                 value = ghb_widget_string(widget);
140                         else
141                                 value = ghb_settings_get_string(ud->settings, name);
142                         while (values && values[jj])
143                         {
144                                 if (values[jj][0] == '>')
145                                 {
146                                         gdouble dbl = g_strtod (&values[jj][1], NULL);
147                                         gdouble dvalue = ghb_widget_double(widget);
148                                         if (dvalue > dbl)
149                                         {
150                                                 sensitive = TRUE;
151                                                 break;
152                                         }
153                                 }
154                                 else if (values[jj][0] == '<')
155                                 {
156                                         gdouble dbl = g_strtod (&values[jj][1], NULL);
157                                         gdouble dvalue = ghb_widget_double(widget);
158                                         if (dvalue < dbl)
159                                         {
160                                                 sensitive = TRUE;
161                                                 break;
162                                         }
163                                 }
164                                 if (strcmp(values[jj], value) == 0)
165                                 {
166                                         sensitive = TRUE;
167                                         break;
168                                 }
169                                 jj++;
170                         }
171                         sensitive = die ^ sensitive;
172                         if (!sensitive)
173                         {
174                                 result = FALSE;
175                                 *out_hide |= hide;
176                         }
177                         g_strfreev (values);
178                         g_free(value);
179                 }
180         }
181         return result;
182 }
183
184 void
185 ghb_check_dependency(signal_user_data_t *ud, GtkWidget *widget)
186 {
187         GObject *dep_object;
188         const gchar *name;
189         GValue *array, *data;
190         gint count, ii;
191         gchar *dep_name;
192         GType type;
193
194         type = GTK_WIDGET_TYPE(widget);
195         if (type == GTK_TYPE_COMBO_BOX || type == GTK_TYPE_COMBO_BOX_ENTRY)
196                 if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) < 0) return;
197
198         name = gtk_widget_get_name(widget);
199         g_debug("ghb_check_dependency () %s", name);
200
201         if (dep_map == NULL) return;
202         array = ghb_dict_lookup(dep_map, name);
203         count = ghb_array_len(array);
204         for (ii = 0; ii < count; ii++)
205         {
206                 gboolean sensitive;
207                 gboolean hide;
208
209                 data = ghb_array_get_nth(array, ii);
210                 dep_name = ghb_value_string(data);
211                 dep_object = gtk_builder_get_object(ud->builder, dep_name);
212                 if (dep_object == NULL)
213                 {
214                         g_message("Failed to find dependent widget %s", dep_name);
215                         g_free(dep_name);
216                         continue;
217                 }
218                 sensitive = dep_check(ud, dep_name, &hide);
219                 g_free(dep_name);
220                 if (GTK_IS_ACTION(dep_object))
221                 {
222                         gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
223                         gtk_action_set_visible(GTK_ACTION(dep_object), sensitive || !hide);
224                 }
225                 else
226                 {
227                         gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
228                         if (!sensitive && hide)
229                         {
230                                 gtk_widget_hide(GTK_WIDGET(dep_object));
231                         }
232                         else
233                         {
234                                 gtk_widget_show_now(GTK_WIDGET(dep_object));
235                         }
236                 }
237         }
238 }
239
240 void
241 ghb_check_all_depencencies(signal_user_data_t *ud)
242 {
243         GHashTableIter iter;
244         gchar *dep_name;
245         GValue *value;
246         GObject *dep_object;
247
248         g_debug("ghb_check_all_depencencies ()");
249         if (rev_map == NULL) return;
250         ghb_dict_iter_init(&iter, rev_map);
251         // middle (void*) cast prevents gcc warning "defreferencing type-punned
252         // pointer will break strict-aliasing rules"
253         while (g_hash_table_iter_next(
254                         &iter, (gpointer*)(void*)&dep_name, (gpointer*)(void*)&value))
255         {
256                 gboolean sensitive;
257                 gboolean hide;
258
259                 dep_object = gtk_builder_get_object (ud->builder, dep_name);
260                 if (dep_object == NULL)
261                 {
262                         g_message("Failed to find dependent widget %s", dep_name);
263                         continue;
264                 }
265                 sensitive = dep_check(ud, dep_name, &hide);
266                 if (GTK_IS_ACTION(dep_object))
267                 {
268                         gtk_action_set_sensitive(GTK_ACTION(dep_object), sensitive);
269                         gtk_action_set_visible(GTK_ACTION(dep_object), sensitive || !hide);
270                 }
271                 else
272                 {
273                         gtk_widget_set_sensitive(GTK_WIDGET(dep_object), sensitive);
274                         if (!sensitive && hide)
275                         {
276                                 gtk_widget_hide(GTK_WIDGET(dep_object));
277                         }
278                         else
279                         {
280                                 gtk_widget_show_now(GTK_WIDGET(dep_object));
281                         }
282                 }
283         }
284 }
285
286 G_MODULE_EXPORT void
287 on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud)
288 {
289         gint state = ghb_get_queue_state();
290         g_debug("on_quit1_activate ()");
291         if (state & GHB_STATE_WORKING)
292         {
293                 if (ghb_cancel_encode2(ud, "Closing HandBrake will terminate encoding.\n"))
294                 {
295                         ghb_hb_cleanup(FALSE);
296                         prune_logs(ud);
297                         gtk_main_quit();
298                         return;
299                 }
300                 return;
301         }
302         ghb_hb_cleanup(FALSE);
303         prune_logs(ud);
304         gtk_main_quit();
305 }
306
307 gboolean
308 uppers_and_unders(gchar *str)
309 {
310         if (str == NULL) return FALSE;
311         str = g_strchomp(g_strchug(str));
312         while (*str)
313         {
314                 if (*str == ' ')
315                 {
316                         return FALSE;
317                 }
318                 if (*str >= 'a' && *str <= 'z')
319                 {
320                         return FALSE;
321                 }
322                 str++;
323         }
324         return TRUE;
325 }
326
327 enum
328 {
329         CAMEL_FIRST_UPPER,
330         CAMEL_OTHER
331 };
332
333 void
334 camel_convert(gchar *str)
335 {
336         gint state = CAMEL_OTHER;
337         
338         if (str == NULL) return;
339         while (*str)
340         {
341                 if (*str == '_') *str = ' ';
342                 switch (state)
343                 {
344                         case CAMEL_OTHER:
345                         {
346                                 if (*str >= 'A' && *str <= 'Z')
347                                         state = CAMEL_FIRST_UPPER;
348                                 else
349                                         state = CAMEL_OTHER;
350                                 
351                         } break;
352                         case CAMEL_FIRST_UPPER:
353                         {
354                                 if (*str >= 'A' && *str <= 'Z')
355                                         *str = *str - 'A' + 'a';
356                                 else
357                                         state = CAMEL_OTHER;
358                         } break;
359                 }
360                 str++;
361         }
362 }
363
364 #if defined(_WIN32)
365 static gchar*
366 get_dvd_device_name(gchar *device)
367 {
368         return g_strdup(device);
369 }
370 #else
371 static gchar*
372 get_dvd_device_name(GDrive *gd)
373 {
374         return g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
375 }
376 #endif
377
378 static GHashTable *volname_hash = NULL;
379 static GMutex     *volname_mutex = NULL;
380
381 static void
382 free_volname_key(gpointer data)
383 {
384         if (data != NULL)
385                 g_free(data);
386 }
387
388 static void
389 free_volname_value(gpointer data)
390 {
391         if (data != NULL)
392                 g_free(data);
393 }
394
395 #if defined(_WIN32)
396 static gchar*
397 get_direct_dvd_volume_name(const gchar *drive)
398 {
399         gchar *result = NULL;
400         gchar vname[51], fsname[51];
401
402         if (GetVolumeInformation(drive, vname, 50, NULL, NULL, NULL, fsname, 50))
403         {
404                 result = g_strdup_printf("%s", vname);
405         }
406         return result;
407 }
408 #else
409 static gchar*
410 get_direct_dvd_volume_name(const gchar *drive)
411 {
412         gchar *result;
413
414         result = ghb_dvd_volname (drive);
415         return result;
416 }
417 #endif
418
419 static gchar*
420 get_dvd_volume_name(gpointer gd)
421 {
422         gchar *label = NULL;
423         gchar *result;
424         gchar *drive;
425
426         drive = get_dvd_device_name(gd);
427         g_mutex_lock(volname_mutex);
428         label = g_strdup(g_hash_table_lookup(volname_hash, drive));
429         g_mutex_unlock(volname_mutex);
430         if (label != NULL)
431         {
432                 if (uppers_and_unders(label))
433                 {
434                         camel_convert(label);
435                 }
436 #if defined(_WIN32)
437                 result = g_strdup_printf("%s (%s)", label, drive);
438 #else
439                 result = g_strdup_printf("%s - %s", drive, label);
440 #endif
441                 g_free(label);
442         }
443         else
444         {
445                 result = g_strdup_printf("%s", drive);
446         }
447         g_free(drive);
448         return result;
449 }
450
451 void
452 ghb_volname_cache_init(void)
453 {
454         volname_mutex = g_mutex_new();
455         volname_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
456                                                                                 free_volname_key, free_volname_value);
457 }
458
459 static void
460 free_drive(gpointer drive)
461 {
462 #if defined(_WIN32)
463                 g_free(drive);
464 #else
465                 g_object_unref(drive);
466 #endif
467 }
468
469 gpointer
470 ghb_cache_volnames(signal_user_data_t *ud)
471 {
472         GList *link, *drives;
473
474         g_debug("ghb_cache_volnames()");
475         link = drives = dvd_device_list();
476         if (drives == NULL)
477                 return NULL;
478
479         g_mutex_lock(volname_mutex);
480         g_hash_table_remove_all(volname_hash);
481         while (link != NULL)
482         {
483                 gchar *name, *drive;
484
485 #if !defined(_WIN32)
486                 if (!g_drive_has_media (link->data))
487                 {
488                         g_object_unref(link->data);
489                         link = link->next;
490                         continue;
491                 }
492 #endif
493                 drive = get_dvd_device_name(link->data);
494                 name = get_direct_dvd_volume_name(drive);
495
496                 if (drive != NULL && name != NULL)
497                 {
498                         g_hash_table_insert(volname_hash, drive, name);
499                 }
500                 else
501                 {
502                         if (drive != NULL)
503                                 g_free(drive);
504                         if (name != NULL)
505                                 g_free(name);
506                 }
507         
508                 free_drive(link->data);
509                 link = link->next;
510         }
511         g_mutex_unlock(volname_mutex);
512
513         g_list_free(drives);
514
515         g_idle_add((GSourceFunc)ghb_file_menu_add_dvd, ud);
516
517         return NULL;
518 }
519
520 static const gchar*
521 get_extension(signal_user_data_t *ud)
522 {
523         int container;
524         const gchar *extension = "error";
525         GValue *audio_list;
526         GValue *subtitle_list;
527
528         container = ghb_settings_combo_int(ud->settings, "FileFormat");
529         if (container == HB_MUX_MP4)
530         {
531                 extension = "mp4";
532                 audio_list = ghb_settings_get_value(ud->settings, "audio_list");
533                 subtitle_list = ghb_settings_get_value(ud->settings, "subtitle_list");
534                 if (ghb_ac3_in_audio_list(audio_list) ||
535                         ghb_soft_in_subtitle_list(subtitle_list) ||
536                         ghb_settings_get_boolean(ud->settings, "ChapterMarkers") ||
537                         ghb_settings_get_boolean(ud->settings, "UseM4v"))
538                 {
539                         extension = "m4v";
540                 }
541         }
542         else if (container == HB_MUX_MKV)
543         {
544                 extension = "mkv";
545         }
546         return extension;
547 }
548
549 static void
550 set_destination(signal_user_data_t *ud)
551 {
552         g_debug("set_destination");
553         if (ghb_settings_get_boolean(ud->settings, "use_source_name"))
554         {
555                 GString *str = g_string_new("");
556                 gchar *vol_name, *filename;
557                 const gchar *extension;
558                 gchar *new_name;
559                 gint title;
560                 
561                 filename = ghb_settings_get_string(ud->settings, "dest_file");
562                 extension = get_extension(ud);
563                 vol_name = ghb_settings_get_string(ud->settings, "volume_label");
564                 g_string_append_printf(str, "%s", vol_name);
565                 title = ghb_settings_combo_int(ud->settings, "title");
566                 if (title >= 0)
567                 {
568                         if (ghb_settings_get_boolean(
569                                         ud->settings, "title_no_in_destination"))
570                         {
571
572                                 title = ghb_settings_combo_int(ud->settings, "title");
573                                 g_string_append_printf(str, " - %d", title+1);
574                         }
575                         if (ghb_settings_get_boolean(
576                                         ud->settings, "chapters_in_destination"))
577                         {
578                                 gint start, end;
579
580                                 if (!ghb_settings_get_boolean(
581                                                 ud->settings, "title_no_in_destination"))
582                                 {
583                                         g_string_append_printf(str, " -");
584                                 }
585                                 start = ghb_settings_get_int(ud->settings, "start_chapter");
586                                 end = ghb_settings_get_int(ud->settings, "end_chapter");
587                                 if (start == end)
588                                         g_string_append_printf(str, " Ch %d", start);
589                                 else
590                                         g_string_append_printf(str, " Ch %d-%d", start, end);
591                         }
592                 }
593                 g_string_append_printf(str, ".%s", extension);
594                 new_name = g_string_free(str, FALSE);
595                 ghb_ui_update(ud, "dest_file", ghb_string_value(new_name));
596                 g_free(filename);
597                 g_free(vol_name);
598                 g_free(new_name);
599         }
600 }
601
602 static gchar*
603 get_file_label(const gchar *filename)
604 {
605         gchar *base, *pos, *end;
606
607         base = g_path_get_basename(filename);
608         pos = strrchr(base, '.');
609         if (pos != NULL)
610         {
611                 // If the last '.' is within 4 chars of end of name, assume
612                 // there is an extension we want to strip.
613                 end = &base[strlen(base) - 1];
614                 if (end - pos <= 4)
615                         *pos = 0;
616         }
617         return base;
618 }
619
620 static gchar*
621 resolve_drive_name(gchar *filename)
622 {
623 #if defined(_WIN32)
624         if (filename[1] == ':')
625         {
626                 gchar drive[4];
627                 gchar *name;
628                 gint dtype;
629
630                 g_strlcpy(drive, filename, 4);
631                 dtype = GetDriveType(drive);
632                 if (dtype == DRIVE_CDROM)
633                 {
634                         gchar vname[51], fsname[51];
635                         GetVolumeInformation(drive, vname, 50, NULL, 
636                                                                 NULL, NULL, fsname, 50);
637                         name = g_strdup(vname);
638                         return name;
639                 }
640         }
641         return NULL;
642 #else
643         return NULL;
644 #endif
645 }
646
647 static gboolean
648 update_source_label(signal_user_data_t *ud, const gchar *source, gboolean update_dest)
649 {
650         gchar *label = NULL;
651         gint len;
652         gchar **path;
653         gchar *start;
654         gchar *filename = g_strdup(source);
655         
656         g_debug("update_source_label()");
657         len = strlen(filename);
658         if (g_file_test(filename, G_FILE_TEST_IS_DIR))
659         {
660                 // Skip dos drive letters
661 #if defined(_WIN32)
662                 start = strchr(filename, ':');
663 #else
664                 start = filename;
665 #endif
666                 label = resolve_drive_name(filename);
667                 if (label != NULL)
668                 {
669                         if (uppers_and_unders(label))
670                         {
671                                 camel_convert(label);
672                         }
673                 }
674                 else
675                 {
676                         if (filename[len-1] == G_DIR_SEPARATOR) filename[len-1] = 0;
677                         if (start != NULL)
678                                 start++;
679                         else
680                                 start = filename;
681                         
682                         path = g_strsplit(start, G_DIR_SEPARATOR_S, -1);
683                         len = g_strv_length (path);
684                         if ((len > 1) && (strcmp("VIDEO_TS", path[len-1]) == 0))
685                         {
686                                 label = g_strdup(path[len-2]);
687                                 if (uppers_and_unders(label))
688                                 {
689                                         camel_convert(label);
690                                 }
691                         }
692                         else if (len > 0)
693                         {
694                                 if (path[len-1][0] != 0)
695                                 {
696                                         label = g_strdup(path[len-1]);
697                                         if (uppers_and_unders(label))
698                                         {
699                                                 camel_convert(label);
700                                         }
701                                 }
702                                 else
703                                         label = g_strdup("new_video");
704                         }
705                         else
706                                 label = g_strdup("new_video");
707                         g_strfreev (path);
708                 }
709         }
710         else
711         {
712                 // Is regular file or block dev.
713                 // Check to see if it is a dvd image
714                 label = ghb_dvd_volname (filename);
715                 if (label == NULL)
716                 {
717                         label = get_file_label(filename);
718                 }
719                 else
720                 {
721                         if (uppers_and_unders(label))
722                         {
723                                 camel_convert(label);
724                         }
725                 }
726         }
727         g_free(filename);
728         GtkWidget *widget = GHB_WIDGET (ud->builder, "source_title");
729         if (label != NULL)
730         {
731                 gtk_label_set_text (GTK_LABEL(widget), label);
732                 ghb_settings_set_string(ud->settings, "volume_label", label);
733                 g_free(label);
734                 if (update_dest)
735                         set_destination(ud);
736         }
737         else
738         {
739                 label = "No Title Found";
740                 gtk_label_set_text (GTK_LABEL(widget), label);
741                 ghb_settings_set_string(ud->settings, "volume_label", label);
742                 return FALSE;
743         }
744         return TRUE;
745 }
746
747 G_MODULE_EXPORT void
748 chooser_file_selected_cb(GtkFileChooser *dialog, signal_user_data_t *ud)
749 {
750         gchar *name = gtk_file_chooser_get_filename (dialog);
751         GtkTreeModel *store;
752         GtkTreeIter iter;
753         const gchar *device;
754         gboolean foundit = FALSE;
755         GtkComboBox *combo;
756         
757         if (name == NULL) return;
758         combo = GTK_COMBO_BOX(GHB_WIDGET(ud->builder, "source_device"));
759         store = gtk_combo_box_get_model(combo);
760         if (gtk_tree_model_get_iter_first(store, &iter))
761         {
762                 do
763                 {
764                         gtk_tree_model_get(store, &iter, 0, &device, -1);
765                         if (strcmp(name, device) == 0)
766                         {
767                                 foundit = TRUE;
768                                 break;
769                         }
770                 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
771         }
772         if (foundit)
773                 gtk_combo_box_set_active_iter (combo, &iter);
774         else
775                 gtk_combo_box_set_active (combo, 0);
776
777         g_free(name);
778 }
779
780 G_MODULE_EXPORT void
781 dvd_device_changed_cb(GtkComboBox *combo, signal_user_data_t *ud)
782 {
783         GtkWidget *dialog;
784         gint ii;
785
786         ii = gtk_combo_box_get_active (combo);
787         if (ii > 0)
788         {
789                 const gchar *device;
790                 gchar *name;
791
792                 dialog = GHB_WIDGET(ud->builder, "source_dialog");
793                 device = gtk_combo_box_get_active_text (combo);
794                 name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog));
795                 if (name == NULL || strcmp(name, device) != 0)
796                         gtk_file_chooser_select_filename (GTK_FILE_CHOOSER(dialog), device);
797                 if (name != NULL)
798                         g_free(name);
799         }
800 }
801
802 G_MODULE_EXPORT void
803 source_type_changed_cb(GtkToggleButton *toggle, signal_user_data_t *ud)
804 {
805         gchar *folder;
806         GtkFileChooser *chooser;
807         GtkWidget *dvd_device_combo;
808         
809         g_debug("source_type_changed_cb ()");
810         chooser = GTK_FILE_CHOOSER(GHB_WIDGET(ud->builder, "source_dialog"));
811         dvd_device_combo = GHB_WIDGET(ud->builder, "source_device");
812         folder = gtk_file_chooser_get_current_folder (chooser);
813         if (gtk_toggle_button_get_active (toggle))
814         {
815                 gtk_file_chooser_set_action (chooser, 
816                                                                         GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
817                 gtk_widget_set_sensitive (dvd_device_combo, FALSE);
818                 gtk_combo_box_set_active (GTK_COMBO_BOX(dvd_device_combo), 0);
819         }
820         else
821         {
822                 gtk_file_chooser_set_action (chooser, GTK_FILE_CHOOSER_ACTION_OPEN);
823                 gtk_widget_set_sensitive (dvd_device_combo, TRUE);
824         }
825         if (folder != NULL)
826         {
827                 gtk_file_chooser_set_current_folder(chooser, folder);
828                 g_free(folder);
829         }
830 }
831
832 static void
833 source_dialog_extra_widgets(
834         signal_user_data_t *ud,
835         GtkWidget *dialog, 
836         gboolean checkbutton_active)
837 {
838         GtkToggleButton *checkbutton;
839         GtkComboBox *combo;
840         GList *drives, *link;
841         
842         checkbutton = GTK_TOGGLE_BUTTON(
843                 GHB_WIDGET(ud->builder, "source_folder_flag"));
844         gtk_toggle_button_set_active(checkbutton, checkbutton_active);
845         combo = GTK_COMBO_BOX(GHB_WIDGET(ud->builder, "source_device"));
846         gtk_list_store_clear(GTK_LIST_STORE(
847                                                 gtk_combo_box_get_model(combo)));
848
849         link = drives = dvd_device_list();
850         gtk_combo_box_append_text (combo, "Not Selected");
851         while (link != NULL)
852         {
853                 gchar *name = get_dvd_device_name(link->data);
854                 gtk_combo_box_append_text(combo, name);
855                 g_free(name);
856                 free_drive(link->data);
857                 link = link->next;
858         }
859         g_list_free(drives);
860 }
861
862 extern GValue *ghb_queue_edit_settings;
863 static gchar *last_scan_file = NULL;
864
865 static void 
866 show_scan_progress(signal_user_data_t *ud)
867 {
868         GtkProgressBar *progress;
869         GtkLabel *label;
870
871         progress = GTK_PROGRESS_BAR(GHB_WIDGET(ud->builder, "scan_prog"));
872         gtk_progress_bar_set_fraction (progress, 0);
873         gtk_widget_show(GTK_WIDGET(progress));
874
875         label = GTK_LABEL(GHB_WIDGET(ud->builder, "source_title"));
876         gtk_label_set_text( label, "Scanning ..." );
877 }
878
879 static void
880 start_scan(
881         signal_user_data_t *ud, 
882         const gchar *path, 
883         gint titlenum, 
884         gint preview_count)
885 {
886         GtkWidget *widget;
887         GtkAction *action;
888         ghb_status_t status;
889
890         ghb_get_status(&status);
891         if (status.scan.state != GHB_STATE_IDLE)
892                 return;
893
894         widget = GHB_WIDGET(ud->builder, "sourcetoolbutton");
895         gtk_widget_set_sensitive(widget, FALSE);
896         action = GHB_ACTION(ud->builder, "source_action");
897         gtk_action_set_sensitive(action, FALSE);
898         action = GHB_ACTION(ud->builder, "source_single_action");
899         gtk_action_set_sensitive(action, FALSE);
900         ghb_backend_scan(path, titlenum, preview_count);
901 }
902
903 void
904 ghb_do_scan(
905         signal_user_data_t *ud, 
906         const gchar *filename, 
907         gint titlenum, 
908         gboolean force)
909 {
910         g_debug("ghb_do_scan()");
911         if (!force && last_scan_file != NULL &&
912                 strcmp(last_scan_file, filename) == 0)
913         {
914                 if (ghb_queue_edit_settings)
915                 {
916                         ghb_settings_to_ui(ud, ghb_queue_edit_settings);
917                         ghb_set_audio(ud, ghb_queue_edit_settings);
918                         ghb_reset_subtitles(ud, ghb_queue_edit_settings);
919                         reset_chapter_list(ud, ghb_queue_edit_settings);
920                         ghb_value_free(ghb_queue_edit_settings);
921                         ghb_queue_edit_settings = NULL;
922                 }
923                 return;
924         }
925         if (last_scan_file != NULL)
926                 g_free(last_scan_file);
927         last_scan_file = NULL;
928         if (filename != NULL)
929         {
930                 last_scan_file = g_strdup(filename);
931                 ghb_settings_set_string(ud->settings, "source", filename);
932                 if (update_source_label(ud, filename, TRUE))
933                 {
934                         gchar *path;
935                         gint preview_count;
936
937                         show_scan_progress(ud);
938                         path = ghb_settings_get_string( ud->settings, "source");
939                         prune_logs(ud);
940
941                         preview_count = ghb_settings_get_int(ud->settings, "preview_count");
942                         start_scan(ud, path, titlenum, preview_count);
943                         g_free(path);
944                 }
945                 else
946                 {
947                         // TODO: error dialog
948                 }
949         }
950 }
951
952 static gboolean 
953 update_source_name(gpointer data)
954 {
955         signal_user_data_t *ud = (signal_user_data_t*)data;
956         GtkWidget *dialog;
957         gchar *sourcename;
958
959         sourcename = ghb_settings_get_string(ud->settings, "source");
960         dialog = GHB_WIDGET(ud->builder, "source_dialog");
961         gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), sourcename);
962         g_free(sourcename);
963         return FALSE;
964 }
965
966 static void
967 do_source_dialog(GtkButton *button, gboolean single, signal_user_data_t *ud)
968 {
969         GtkWidget *dialog;
970         gchar *sourcename;
971         gint    response;
972         GtkFileChooserAction action;
973         gboolean checkbutton_active;
974
975         g_debug("source_browse_clicked_cb ()");
976         sourcename = ghb_settings_get_string(ud->settings, "source");
977         checkbutton_active = FALSE;
978         if (g_file_test(sourcename, G_FILE_TEST_IS_DIR))
979         {
980                 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
981                 checkbutton_active = TRUE;
982         }
983         else
984         {
985                 action = GTK_FILE_CHOOSER_ACTION_OPEN;
986         }
987         GtkWidget *widget;
988         widget = GHB_WIDGET(ud->builder, "single_title_box");
989         if (single)
990                 gtk_widget_show(widget);
991         else
992                 gtk_widget_hide(widget);
993         dialog = GHB_WIDGET(ud->builder, "source_dialog");
994         source_dialog_extra_widgets(ud, dialog, checkbutton_active);
995         gtk_file_chooser_set_action(GTK_FILE_CHOOSER(dialog), action);
996         // Updating the filename in the file chooser dialog doesn't seem
997         // to work unless the dialog is running for some reason.
998         // So handle it in an "idle" event.
999         //gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), sourcename);
1000         g_idle_add((GSourceFunc)update_source_name, ud);
1001         response = gtk_dialog_run(GTK_DIALOG (dialog));
1002         gtk_widget_hide(dialog);
1003         if (response == GTK_RESPONSE_ACCEPT)
1004         {
1005                 gchar *filename;
1006
1007                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1008                 if (filename != NULL)
1009                 {
1010                         gint titlenum;
1011
1012                         if (single)
1013                                 titlenum = ghb_settings_get_int(ud->settings, "single_title");
1014                         else
1015                                 titlenum = 0;
1016                         ghb_do_scan(ud, filename, titlenum, TRUE);
1017                         if (strcmp(sourcename, filename) != 0)
1018                         {
1019                                 ghb_settings_set_string (ud->settings, 
1020                                                                                 "default_source", filename);
1021                                 ghb_pref_save (ud->settings, "default_source");
1022                                 ghb_dvd_set_current (filename, ud);
1023                         }
1024                         g_free(filename);
1025                 }
1026         }
1027         g_free(sourcename);
1028 }
1029
1030 G_MODULE_EXPORT void
1031 source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
1032 {
1033         do_source_dialog(button, FALSE, ud);
1034 }
1035
1036 G_MODULE_EXPORT void
1037 single_title_source_cb(GtkButton *button, signal_user_data_t *ud)
1038 {
1039         do_source_dialog(button, TRUE, ud);
1040 }
1041
1042 G_MODULE_EXPORT void
1043 dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
1044 {
1045         const gchar *filename;
1046         gchar *sourcename;
1047
1048         sourcename = ghb_settings_get_string(ud->settings, "source");
1049         filename = gtk_action_get_name(action);
1050         ghb_do_scan(ud, filename, 0, TRUE);
1051         if (strcmp(sourcename, filename) != 0)
1052         {
1053                 ghb_settings_set_string (ud->settings, "default_source", filename);
1054                 ghb_pref_save (ud->settings, "default_source");
1055                 ghb_dvd_set_current (filename, ud);
1056         }
1057         g_free(sourcename);
1058 }
1059
1060 void
1061 ghb_update_destination_extension(signal_user_data_t *ud)
1062 {
1063         static gchar *containers[] = {".mkv", ".mp4", ".m4v", NULL};
1064         gchar *filename;
1065         const gchar *extension;
1066         gint ii;
1067         GtkEntry *entry;
1068         static gboolean busy = FALSE;
1069
1070         g_debug("ghb_update_destination_extension ()");
1071         // Since this function modifies the thing that triggers it's
1072         // invocation, check to see if busy to prevent accidental infinite
1073         // recursion.
1074         if (busy)
1075                 return;
1076         busy = TRUE;
1077         extension = get_extension(ud);
1078         entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "dest_file"));
1079         filename = g_strdup(gtk_entry_get_text(entry));
1080         for (ii = 0; containers[ii] != NULL; ii++)
1081         {
1082                 if (g_str_has_suffix(filename, containers[ii]))
1083                 {
1084                         gchar *pos;
1085                         gchar *new_name;
1086                         
1087                         pos = g_strrstr( filename, "." );
1088                         if (pos == NULL)
1089                         {
1090                                 // No period? shouldn't happen
1091                                 break;
1092                         }
1093                         *pos = 0;
1094                         if (strcmp(extension, &pos[1]) == 0)
1095                         {
1096                                 // Extension is already correct
1097                                 break;
1098                         }
1099                         new_name = g_strjoin(".", filename, extension, NULL); 
1100                         ghb_ui_update(ud, "dest_file", ghb_string_value(new_name));
1101                         g_free(new_name);
1102                         break;
1103                 }
1104         }
1105         g_free(filename);
1106         busy = FALSE;
1107 }
1108
1109 static void
1110 destination_select_title(GtkEntry *entry)
1111 {
1112         const gchar *dest;
1113         gint start, end;
1114
1115         dest = gtk_entry_get_text(entry);
1116         for (end = strlen(dest)-1; end > 0; end--)
1117         {
1118                 if (dest[end] == '.')
1119                 {
1120                         break;
1121                 }
1122         }
1123         for (start = end; start >= 0; start--)
1124         {
1125                 if (dest[start] == G_DIR_SEPARATOR)
1126                 {
1127                         start++;
1128                         break;
1129                 }
1130         }
1131         if (start < 0) start = 0;
1132         if (start < end)
1133         {
1134                 gtk_editable_select_region(GTK_EDITABLE(entry), start, end);
1135         }
1136 }
1137
1138 G_MODULE_EXPORT gboolean
1139 destination_grab_cb(
1140         GtkEntry *entry, 
1141         signal_user_data_t *ud)
1142 {
1143         destination_select_title(entry);
1144         return FALSE;
1145 }
1146
1147 static gboolean update_default_destination = FALSE;
1148
1149 G_MODULE_EXPORT void
1150 dest_dir_set_cb(GtkFileChooserButton *dest_chooser, signal_user_data_t *ud)
1151 {
1152         gchar *dest_file, *dest_dir, *dest;
1153         
1154         g_debug("dest_dir_set_cb ()");
1155         ghb_widget_to_setting(ud->settings, (GtkWidget*)dest_chooser);
1156         dest_file = ghb_settings_get_string(ud->settings, "dest_file");
1157         dest_dir = ghb_settings_get_string(ud->settings, "dest_dir");
1158         dest = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dest_dir, dest_file);
1159         ghb_settings_set_string(ud->settings, "destination", dest);
1160         g_free(dest_file);
1161         g_free(dest_dir);
1162         g_free(dest);
1163         update_default_destination = TRUE;
1164 }
1165
1166 G_MODULE_EXPORT void
1167 dest_file_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
1168 {
1169         gchar *dest_file, *dest_dir, *dest;
1170         
1171         g_debug("dest_file_changed_cb ()");
1172         ghb_update_destination_extension(ud);
1173         ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
1174         // This signal goes off with ever keystroke, so I'm putting this
1175         // update on the timer.
1176         dest_file = ghb_settings_get_string(ud->settings, "dest_file");
1177         dest_dir = ghb_settings_get_string(ud->settings, "dest_dir");
1178         dest = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dest_dir, dest_file);
1179         ghb_settings_set_string(ud->settings, "destination", dest);
1180         g_free(dest_file);
1181         g_free(dest_dir);
1182         g_free(dest);
1183         update_default_destination = TRUE;
1184 }
1185
1186 G_MODULE_EXPORT void
1187 destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
1188 {
1189         GtkWidget *dialog;
1190         GtkEntry *entry;
1191         gchar *destname;
1192         gchar *basename;
1193
1194         g_debug("destination_browse_clicked_cb ()");
1195         destname = ghb_settings_get_string(ud->settings, "destination");
1196         dialog = gtk_file_chooser_dialog_new ("Choose Destination",
1197                                           NULL,
1198                                           GTK_FILE_CHOOSER_ACTION_SAVE,
1199                                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1200                                           GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1201                                           NULL);
1202         gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), destname);
1203         basename = g_path_get_basename(destname);
1204         g_free(destname);
1205         gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
1206         g_free(basename);
1207         if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
1208         {
1209                 char *filename, *dirname;
1210                 GtkFileChooser *dest_chooser;
1211                 
1212                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1213                 basename = g_path_get_basename(filename);
1214                 dirname = g_path_get_dirname(filename);
1215                 entry = (GtkEntry*)GHB_WIDGET(ud->builder, "dest_file");
1216                 gtk_entry_set_text(entry, basename);
1217                 dest_chooser = GTK_FILE_CHOOSER(GHB_WIDGET(ud->builder, "dest_dir"));
1218                 gtk_file_chooser_set_filename(dest_chooser, dirname);
1219                 g_free (dirname);
1220                 g_free (basename);
1221                 g_free (filename);
1222         }
1223         gtk_widget_destroy(dialog);
1224 }
1225
1226 G_MODULE_EXPORT gboolean
1227 window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
1228 {
1229         g_debug("window_destroy_event_cb ()");
1230         ghb_hb_cleanup(FALSE);
1231         prune_logs(ud);
1232         gtk_main_quit();
1233         return FALSE;
1234 }
1235
1236 G_MODULE_EXPORT gboolean
1237 window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
1238 {
1239         gint state = ghb_get_queue_state();
1240         g_debug("window_delete_event_cb ()");
1241         if (state & GHB_STATE_WORKING)
1242         {
1243                 if (ghb_cancel_encode2(ud, "Closing HandBrake will terminate encoding.\n"))
1244                 {
1245                         ghb_hb_cleanup(FALSE);
1246                         prune_logs(ud);
1247                         gtk_main_quit();
1248                         return FALSE;
1249                 }
1250                 return TRUE;
1251         }
1252         ghb_hb_cleanup(FALSE);
1253         prune_logs(ud);
1254         gtk_main_quit();
1255         return FALSE;
1256 }
1257
1258 static void
1259 update_acodec_combo(signal_user_data_t *ud)
1260 {
1261         ghb_grey_combo_options (ud->builder);
1262 }
1263
1264 G_MODULE_EXPORT void
1265 container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1266 {
1267         g_debug("container_changed_cb ()");
1268         ghb_widget_to_setting(ud->settings, widget);
1269         ghb_check_dependency(ud, widget);
1270         update_acodec_combo(ud);
1271         ghb_update_destination_extension(ud);
1272         ghb_clear_presets_selection(ud);
1273         ghb_live_reset(ud);
1274         ghb_subtitle_prune(ud);
1275         ghb_audio_list_refresh_selected(ud);
1276 }
1277
1278 static gchar*
1279 get_aspect_string(gint aspect_n, gint aspect_d)
1280 {
1281         gchar *aspect;
1282
1283         if (aspect_d < 10)
1284         {
1285                 aspect = g_strdup_printf("%d:%d", aspect_n, aspect_d);
1286         }
1287         else
1288         {
1289                 gdouble aspect_nf = (gdouble)aspect_n / aspect_d;
1290                 aspect = g_strdup_printf("%.2f:1", aspect_nf);
1291         }
1292         return aspect;
1293 }
1294
1295 static gchar*
1296 get_rate_string(gint rate_base, gint rate)
1297 {
1298         gdouble rate_f = (gdouble)rate / rate_base;
1299         gchar *rate_s;
1300
1301         rate_s = g_strdup_printf("%.6g", rate_f);
1302         return rate_s;
1303 }
1304 static void
1305 show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
1306 {
1307         GtkWidget *widget;
1308         gchar *text;
1309
1310         ud->dont_clear_presets = TRUE;
1311         widget = GHB_WIDGET (ud->builder, "title_duration");
1312         if (tinfo->duration != 0)
1313         {
1314                 text = g_strdup_printf ("%02d:%02d:%02d", tinfo->hours, 
1315                                 tinfo->minutes, tinfo->seconds);
1316         }
1317         else
1318         {
1319                 text = g_strdup_printf ("Unknown");
1320         }
1321         gtk_label_set_text (GTK_LABEL(widget), text);
1322         g_free(text);
1323         widget = GHB_WIDGET (ud->builder, "source_dimensions");
1324         text = g_strdup_printf ("%d x %d", tinfo->width, tinfo->height);
1325         gtk_label_set_text (GTK_LABEL(widget), text);
1326         ghb_settings_set_int(ud->settings, "source_width", tinfo->width);
1327         ghb_settings_set_int(ud->settings, "source_height", tinfo->height);
1328         g_free(text);
1329         widget = GHB_WIDGET (ud->builder, "source_aspect");
1330         text = get_aspect_string(tinfo->aspect_n, tinfo->aspect_d);
1331         gtk_label_set_text (GTK_LABEL(widget), text);
1332         g_free(text);
1333
1334         widget = GHB_WIDGET (ud->builder, "source_frame_rate");
1335         text = (gchar*)get_rate_string(tinfo->rate_base, tinfo->rate);
1336         gtk_label_set_text (GTK_LABEL(widget), text);
1337         g_free(text);
1338
1339         ghb_ui_update(ud, "scale_width", 
1340                 ghb_int64_value(tinfo->width - tinfo->crop[2] - tinfo->crop[3]));
1341         // If anamorphic or keep_aspect, the hight will be automatically calculated
1342         gboolean keep_aspect;
1343         gint pic_par;
1344         keep_aspect = ghb_settings_get_boolean(ud->settings, "PictureKeepRatio");
1345         pic_par = ghb_settings_combo_int(ud->settings, "PicturePAR");
1346         if (!(keep_aspect || pic_par) || pic_par == 3)
1347         {
1348                 ghb_ui_update(ud, "scale_height", 
1349                         ghb_int64_value(tinfo->height - tinfo->crop[0] - tinfo->crop[1]));
1350         }
1351
1352         // Set the limits of cropping.  hb_set_anamorphic_size crashes if
1353         // you pass it a cropped width or height == 0.
1354         gint bound;
1355         bound = tinfo->height / 2 - 2;
1356         widget = GHB_WIDGET (ud->builder, "PictureTopCrop");
1357         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1358         widget = GHB_WIDGET (ud->builder, "PictureBottomCrop");
1359         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1360         bound = tinfo->width / 2 - 2;
1361         widget = GHB_WIDGET (ud->builder, "PictureLeftCrop");
1362         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1363         widget = GHB_WIDGET (ud->builder, "PictureRightCrop");
1364         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1365         if (ghb_settings_get_boolean(ud->settings, "PictureAutoCrop"))
1366         {
1367                 ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(tinfo->crop[0]));
1368                 ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(tinfo->crop[1]));
1369                 ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(tinfo->crop[2]));
1370                 ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(tinfo->crop[3]));
1371         }
1372         ghb_set_scale (ud, GHB_PIC_KEEP_PAR);
1373         gint width, height, crop[4];
1374         crop[0] = ghb_settings_get_int(ud->settings, "PictureTopCrop");
1375         crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
1376         crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
1377         crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
1378         width = tinfo->width - crop[2] - crop[3];
1379         height = tinfo->height - crop[0] - crop[1];
1380         widget = GHB_WIDGET (ud->builder, "crop_dimensions");
1381         text = g_strdup_printf ("%d x %d", width, height);
1382         gtk_label_set_text (GTK_LABEL(widget), text);
1383         g_free(text);
1384
1385         g_debug("setting max end chapter %d", tinfo->num_chapters);
1386         widget = GHB_WIDGET (ud->builder, "end_chapter");
1387         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters);
1388         gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), tinfo->num_chapters);
1389         widget = GHB_WIDGET (ud->builder, "start_chapter");
1390         gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1);
1391         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters);
1392
1393         widget = GHB_WIDGET (ud->builder, "angle");
1394         gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1);
1395         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->angle_count);
1396         ud->dont_clear_presets = FALSE;
1397 }
1398
1399 static gboolean update_preview = FALSE;
1400
1401 G_MODULE_EXPORT void
1402 title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1403 {
1404         ghb_title_info_t tinfo;
1405         gint titleindex;
1406         
1407         g_debug("title_changed_cb ()");
1408         ghb_widget_to_setting(ud->settings, widget);
1409         ghb_check_dependency(ud, widget);
1410
1411         titleindex = ghb_settings_combo_int(ud->settings, "title");
1412         ghb_update_ui_combo_box (ud, "AudioTrack", titleindex, FALSE);
1413         ghb_update_ui_combo_box (ud, "SubtitleTrack", titleindex, FALSE);
1414
1415         if (ghb_get_title_info (&tinfo, titleindex))
1416         {
1417                 show_title_info(ud, &tinfo);
1418         }
1419         update_chapter_list (ud);
1420         ghb_adjust_audio_rate_combos(ud);
1421         ghb_set_pref_audio(titleindex, ud);
1422         ghb_set_pref_subtitle(titleindex, ud);
1423         if (ghb_settings_get_boolean(ud->settings, "vquality_type_target"))
1424         {
1425                 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1426                 ghb_ui_update(ud, "VideoAvgBitrate", ghb_int64_value(bitrate));
1427         }
1428
1429         // Unfortunately, there is no way to query how many frames were
1430         // actually generated during the scan.
1431         // If I knew how many were generated, I would adjust the spin
1432         // control range here.
1433         // I do know how many were asked for.
1434         gint preview_count;
1435         preview_count = ghb_settings_get_int(ud->settings, "preview_count");
1436         widget = GHB_WIDGET(ud->builder, "preview_frame");
1437         gtk_range_set_range (GTK_RANGE(widget), 1, preview_count);
1438         ghb_ui_update(ud, "preview_frame", ghb_int64_value(2));
1439
1440         ghb_set_preview_image (ud);
1441         if (ghb_settings_get_boolean(ud->settings, "title_no_in_destination"))
1442         {
1443                 set_destination(ud);
1444         }
1445 }
1446
1447 G_MODULE_EXPORT void
1448 setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1449 {
1450         ghb_widget_to_setting(ud->settings, widget);
1451         ghb_check_dependency(ud, widget);
1452         ghb_clear_presets_selection(ud);
1453         ghb_live_reset(ud);
1454 }
1455
1456 G_MODULE_EXPORT void
1457 chapter_markers_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1458 {
1459         ghb_widget_to_setting(ud->settings, widget);
1460         ghb_check_dependency(ud, widget);
1461         ghb_clear_presets_selection(ud);
1462         ghb_live_reset(ud);
1463         ghb_update_destination_extension(ud);
1464 }
1465
1466 G_MODULE_EXPORT void
1467 vquality_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1468 {
1469         ghb_widget_to_setting(ud->settings, widget);
1470         ghb_check_dependency(ud, widget);
1471         ghb_clear_presets_selection(ud);
1472         ghb_live_reset(ud);
1473
1474         gint vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
1475         gdouble step;
1476         if (vcodec == HB_VCODEC_X264)
1477         {
1478                 step = ghb_settings_combo_double(ud->settings, 
1479                                                                                         "VideoQualityGranularity");
1480         }
1481         else
1482         {
1483                 step = 1;
1484         }
1485         gdouble val = gtk_range_get_value(GTK_RANGE(widget));
1486         val = ((int)((val + step / 2) / step)) * step;
1487         gtk_range_set_value(GTK_RANGE(widget), val);
1488 }
1489
1490 G_MODULE_EXPORT void
1491 http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1492 {
1493         ghb_widget_to_setting(ud->settings, widget);
1494         ghb_check_dependency(ud, widget);
1495         ghb_clear_presets_selection(ud);
1496         ghb_live_reset(ud);
1497         // AC3 is not allowed when Web optimized
1498         ghb_grey_combo_options (ud->builder);
1499 }
1500
1501 G_MODULE_EXPORT void
1502 vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1503 {
1504         gdouble vqmin, vqmax, step, page;
1505         gboolean inverted;
1506         gint digits;
1507
1508         ghb_widget_to_setting(ud->settings, widget);
1509         ghb_check_dependency(ud, widget);
1510         ghb_clear_presets_selection(ud);
1511         ghb_live_reset(ud);
1512         ghb_vquality_range(ud, &vqmin, &vqmax, &step, &page, &digits, &inverted);
1513         GtkWidget *qp = GHB_WIDGET(ud->builder, "VideoQualitySlider");
1514         gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1515         gtk_range_set_increments (GTK_RANGE(qp), step, page);
1516         gtk_scale_set_digits(GTK_SCALE(qp), digits);
1517         gtk_range_set_inverted (GTK_RANGE(qp), inverted);
1518 }
1519
1520 G_MODULE_EXPORT void
1521 target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1522 {
1523         const gchar *name = gtk_widget_get_name(widget);
1524         g_debug("target_size_changed_cb () %s", name);
1525         ghb_widget_to_setting(ud->settings, widget);
1526         ghb_check_dependency(ud, widget);
1527         ghb_clear_presets_selection(ud);
1528         ghb_live_reset(ud);
1529         if (ghb_settings_get_boolean(ud->settings, "vquality_type_target"))
1530         {
1531                 gint titleindex;
1532                 titleindex = ghb_settings_combo_int(ud->settings, "title");
1533                 gint bitrate = ghb_calculate_target_bitrate (ud->settings, titleindex);
1534                 ghb_ui_update(ud, "VideoAvgBitrate", ghb_int64_value(bitrate));
1535         }
1536 }
1537
1538 G_MODULE_EXPORT void
1539 start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1540 {
1541         gint start, end;
1542         const gchar *name = gtk_widget_get_name(widget);
1543
1544         g_debug("start_chapter_changed_cb () %s", name);
1545         ghb_widget_to_setting(ud->settings, widget);
1546         start = ghb_settings_get_int(ud->settings, "start_chapter");
1547         end = ghb_settings_get_int(ud->settings, "end_chapter");
1548         if (start > end)
1549                 ghb_ui_update(ud, "end_chapter", ghb_int_value(start));
1550         ghb_check_dependency(ud, widget);
1551         if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
1552         {
1553                 set_destination(ud);
1554         }
1555         widget = GHB_WIDGET (ud->builder, "chapters_tab");
1556         // End may have been changed above, get it again
1557         end = ghb_settings_get_int(ud->settings, "end_chapter");
1558         if (start == end)
1559         {
1560                 gtk_widget_hide(widget);
1561         }
1562         else
1563         {
1564                 gtk_widget_show(widget);
1565         }
1566 }
1567
1568 G_MODULE_EXPORT void
1569 end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1570 {
1571         gint start, end;
1572         const gchar *name = gtk_widget_get_name(widget);
1573
1574         g_debug("end_chapter_changed_cb () %s", name);
1575         ghb_widget_to_setting(ud->settings, widget);
1576         start = ghb_settings_get_int(ud->settings, "start_chapter");
1577         end = ghb_settings_get_int(ud->settings, "end_chapter");
1578         if (start > end)
1579                 ghb_ui_update(ud, "start_chapter", ghb_int_value(end));
1580         ghb_check_dependency(ud, widget);
1581         if (ghb_settings_get_boolean(ud->settings, "chapters_in_destination"))
1582         {
1583                 set_destination(ud);
1584         }
1585         widget = GHB_WIDGET (ud->builder, "chapters_tab");
1586         // Start may have been changed above, get it again
1587         start = ghb_settings_get_int(ud->settings, "start_chapter");
1588         if (start == end)
1589         {
1590                 gtk_widget_hide(widget);
1591         }
1592         else
1593         {
1594                 gtk_widget_show(widget);
1595         }
1596 }
1597
1598 G_MODULE_EXPORT void
1599 scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1600 {
1601         g_debug("scale_width_changed_cb ()");
1602         ghb_widget_to_setting(ud->settings, widget);
1603         ghb_check_dependency(ud, widget);
1604         ghb_clear_presets_selection(ud);
1605         if (GTK_WIDGET_SENSITIVE(widget))
1606                 ghb_set_scale (ud, GHB_PIC_KEEP_WIDTH);
1607         update_preview = TRUE;
1608         gchar *text;
1609         gint width = ghb_settings_get_int(ud->settings, "scale_width");
1610         gint height = ghb_settings_get_int(ud->settings, "scale_height");
1611         widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1612         text = g_strdup_printf ("%d x %d", width, height);
1613         gtk_label_set_text (GTK_LABEL(widget), text);
1614         g_free(text);
1615         ghb_live_reset(ud);
1616 }
1617
1618 G_MODULE_EXPORT void
1619 scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1620 {
1621         g_debug("scale_height_changed_cb ()");
1622         ghb_widget_to_setting(ud->settings, widget);
1623         ghb_check_dependency(ud, widget);
1624         ghb_clear_presets_selection(ud);
1625         if (GTK_WIDGET_SENSITIVE(widget))
1626                 ghb_set_scale (ud, GHB_PIC_KEEP_HEIGHT);
1627         update_preview = TRUE;
1628         gchar *text;
1629         gint width = ghb_settings_get_int(ud->settings, "scale_width");
1630         gint height = ghb_settings_get_int(ud->settings, "scale_height");
1631         widget = GHB_WIDGET (ud->builder, "scale_dimensions");
1632         text = g_strdup_printf ("%d x %d", width, height);
1633         gtk_label_set_text (GTK_LABEL(widget), text);
1634         g_free(text);
1635         ghb_live_reset(ud);
1636 }
1637
1638 G_MODULE_EXPORT void
1639 crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1640 {
1641         gint titleindex, crop[4];
1642         ghb_title_info_t tinfo;
1643         
1644         g_debug("crop_changed_cb ()");
1645         ghb_widget_to_setting(ud->settings, widget);
1646         ghb_check_dependency(ud, widget);
1647         ghb_clear_presets_selection(ud);
1648         if (GTK_WIDGET_SENSITIVE(widget))
1649                 ghb_set_scale (ud, 0);
1650
1651         crop[0] = ghb_settings_get_int(ud->settings, "PictureTopCrop");
1652         crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
1653         crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
1654         crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
1655         titleindex = ghb_settings_combo_int(ud->settings, "title");
1656         if (ghb_get_title_info (&tinfo, titleindex))
1657         {
1658                 gint width, height;
1659                 gchar *text;
1660                 
1661                 width = tinfo.width - crop[2] - crop[3];
1662                 height = tinfo.height - crop[0] - crop[1];
1663                 widget = GHB_WIDGET (ud->builder, "crop_dimensions");
1664                 text = g_strdup_printf ("%d x %d", width, height);
1665                 gtk_label_set_text (GTK_LABEL(widget), text);
1666                 widget = GHB_WIDGET (ud->builder, "crop_dimensions2");
1667                 gtk_label_set_text (GTK_LABEL(widget), text);
1668                 g_free(text);
1669         }
1670         gchar *text;
1671         widget = GHB_WIDGET (ud->builder, "crop_values");
1672         text = g_strdup_printf ("%d:%d:%d:%d", crop[0], crop[1], crop[2], crop[3]);
1673         gtk_label_set_text (GTK_LABEL(widget), text);
1674         g_free(text);
1675         update_preview = TRUE;
1676         ghb_live_reset(ud);
1677 }
1678
1679 G_MODULE_EXPORT void
1680 display_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1681 {
1682         g_debug("display_width_changed_cb ()");
1683         ghb_widget_to_setting(ud->settings, widget);
1684         ghb_check_dependency(ud, widget);
1685         ghb_clear_presets_selection(ud);
1686         ghb_live_reset(ud);
1687         if (GTK_WIDGET_SENSITIVE(widget))
1688                 ghb_set_scale (ud, GHB_PIC_KEEP_DISPLAY_WIDTH);
1689
1690         update_preview = TRUE;
1691 }
1692
1693 G_MODULE_EXPORT void
1694 display_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1695 {
1696         g_debug("display_height_changed_cb ()");
1697         ghb_widget_to_setting(ud->settings, widget);
1698         ghb_check_dependency(ud, widget);
1699         ghb_clear_presets_selection(ud);
1700         ghb_live_reset(ud);
1701         if (GTK_WIDGET_SENSITIVE(widget))
1702                 ghb_set_scale (ud, GHB_PIC_KEEP_DISPLAY_HEIGHT);
1703
1704         update_preview = TRUE;
1705 }
1706
1707 G_MODULE_EXPORT void
1708 par_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1709 {
1710         g_debug("par_changed_cb ()");
1711         ghb_widget_to_setting(ud->settings, widget);
1712         ghb_check_dependency(ud, widget);
1713         ghb_clear_presets_selection(ud);
1714         ghb_live_reset(ud);
1715         if (GTK_WIDGET_SENSITIVE(widget))
1716                 ghb_set_scale (ud, GHB_PIC_KEEP_PAR);
1717
1718         update_preview = TRUE;
1719 }
1720
1721 G_MODULE_EXPORT void
1722 scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1723 {
1724         g_debug("scale_changed_cb ()");
1725         ghb_widget_to_setting(ud->settings, widget);
1726         ghb_check_dependency(ud, widget);
1727         ghb_clear_presets_selection(ud);
1728         ghb_live_reset(ud);
1729         if (GTK_WIDGET_SENSITIVE(widget))
1730                 ghb_set_scale (ud, 0);
1731         update_preview = TRUE;
1732         
1733         gchar *text;
1734         
1735         text = ghb_settings_get_boolean(ud->settings, "PictureAutoCrop") ? "On" : "Off";
1736         widget = GHB_WIDGET (ud->builder, "crop_auto");
1737         gtk_label_set_text (GTK_LABEL(widget), text);
1738         text = ghb_settings_get_boolean(ud->settings, "autoscale") ? "On" : "Off";
1739         widget = GHB_WIDGET (ud->builder, "scale_auto");
1740         gtk_label_set_text (GTK_LABEL(widget), text);
1741         switch (ghb_settings_combo_int(ud->settings, "PicturePAR"))
1742         {
1743                 case 0:
1744                         text = "Off";
1745                         break;
1746                 case 1:
1747                         text = "Strict";
1748                         break;
1749                 case 2:
1750                         text = "Loose";
1751                         break;
1752                 case 3:
1753                         text = "Custom";
1754                         break;
1755                 default:
1756                         text = "Unknown";
1757                         break;
1758         }
1759         widget = GHB_WIDGET (ud->builder, "scale_anamorphic");
1760         gtk_label_set_text (GTK_LABEL(widget), text);
1761 }
1762
1763 G_MODULE_EXPORT void
1764 show_crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
1765 {
1766         g_debug("show_crop_changed_cb ()");
1767         ghb_widget_to_setting(ud->settings, widget);
1768         ghb_check_dependency(ud, widget);
1769         ghb_live_reset(ud);
1770         if (GTK_WIDGET_SENSITIVE(widget))
1771                 ghb_set_scale (ud, 0);
1772         update_preview = TRUE;
1773 }
1774
1775 G_MODULE_EXPORT void
1776 generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
1777 {
1778         // Normally (due to user input) I only want to process the entry
1779         // when editing is done and the focus-out signal is sent.
1780         // But... there's always a but.
1781         // If the entry is changed by software, the focus-out signal is not sent.
1782         // The changed signal is sent ... so here we are.
1783         // I don't want to process upon every keystroke, so I prevent processing
1784         // while the widget has focus.
1785         g_debug("generic_entry_changed_cb ()");
1786         if (!GTK_WIDGET_HAS_FOCUS((GtkWidget*)entry))
1787         {
1788                 ghb_widget_to_setting(ud->settings, (GtkWidget*)entry);
1789         }
1790 }
1791
1792 G_MODULE_EXPORT void
1793 prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1794 {
1795         GtkWidget *dialog;
1796         GtkResponseType response;
1797
1798         g_debug("prefs_dialog_cb ()");
1799         dialog = GHB_WIDGET(ud->builder, "prefs_dialog");
1800         response = gtk_dialog_run(GTK_DIALOG(dialog));
1801         gtk_widget_hide(dialog);
1802 }
1803
1804 typedef struct
1805 {
1806         GtkMessageDialog *dlg;
1807         const gchar *msg;
1808         const gchar *action;
1809         gint timeout;
1810 } countdown_t;
1811
1812 static gboolean
1813 shutdown_cb(countdown_t *cd)
1814 {
1815         gchar *str;
1816
1817         cd->timeout--;
1818         if (cd->timeout == 0)
1819         {
1820                 ghb_shutdown_gsm();
1821                 gtk_main_quit();
1822                 return FALSE;
1823         }
1824         str = g_strdup_printf("%s\n\n%s in %d seconds ...", 
1825                                                         cd->msg, cd->action, cd->timeout);
1826         gtk_message_dialog_set_markup(cd->dlg, str);
1827         g_free(str);
1828         return TRUE;
1829 }
1830
1831 static gboolean
1832 suspend_cb(countdown_t *cd)
1833 {
1834         gchar *str;
1835
1836         cd->timeout--;
1837         if (cd->timeout == 0)
1838         {
1839                 gtk_widget_destroy (GTK_WIDGET(cd->dlg));
1840                 ghb_suspend_gpm();
1841                 return FALSE;
1842         }
1843         str = g_strdup_printf("%s\n\n%s in %d seconds ...", 
1844                                                         cd->msg, cd->action, cd->timeout);
1845         gtk_message_dialog_set_markup(cd->dlg, str);
1846         g_free(str);
1847         return TRUE;
1848 }
1849
1850 void
1851 ghb_countdown_dialog(
1852         GtkMessageType type, 
1853         const gchar *message, 
1854         const gchar *action, 
1855         const gchar *cancel, 
1856         GSourceFunc action_func,
1857         gint timeout)
1858 {
1859         GtkWidget *dialog;
1860         GtkResponseType response;
1861         guint timeout_id;
1862         countdown_t cd;
1863                         
1864         cd.msg = message;
1865         cd.action = action;
1866         cd.timeout = timeout;
1867
1868         // Toss up a warning dialog
1869         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1870                                                         type, GTK_BUTTONS_NONE,
1871                                                         "%s\n\n%s in %d seconds ...", 
1872                                                         message, action, timeout);
1873         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
1874                                                    cancel, GTK_RESPONSE_CANCEL,
1875                                                    NULL);
1876
1877         cd.dlg = GTK_MESSAGE_DIALOG(dialog);
1878         timeout_id = g_timeout_add(1000, action_func, &cd);
1879         response = gtk_dialog_run(GTK_DIALOG(dialog));
1880         gtk_widget_destroy (dialog);
1881         if (response == GTK_RESPONSE_CANCEL)
1882         {
1883                 GMainContext *mc;
1884                 GSource *source;
1885
1886                 mc = g_main_context_default();
1887                 source = g_main_context_find_source_by_id(mc, timeout_id);
1888                 if (source != NULL)
1889                         g_source_destroy(source);
1890         }
1891 }
1892
1893 gboolean
1894 ghb_message_dialog(GtkMessageType type, const gchar *message, const gchar *no, const gchar *yes)
1895 {
1896         GtkWidget *dialog;
1897         GtkResponseType response;
1898                         
1899         // Toss up a warning dialog
1900         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1901                                                         type, GTK_BUTTONS_NONE,
1902                                                         "%s", message);
1903         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
1904                                                    no, GTK_RESPONSE_NO,
1905                                                    yes, GTK_RESPONSE_YES, NULL);
1906         response = gtk_dialog_run(GTK_DIALOG(dialog));
1907         gtk_widget_destroy (dialog);
1908         if (response == GTK_RESPONSE_NO)
1909         {
1910                 return FALSE;
1911         }
1912         return TRUE;
1913 }
1914
1915 void
1916 ghb_error_dialog(GtkMessageType type, const gchar *message, const gchar *cancel)
1917 {
1918         GtkWidget *dialog;
1919         GtkResponseType response;
1920                         
1921         // Toss up a warning dialog
1922         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1923                                                         type, GTK_BUTTONS_NONE,
1924                                                         "%s", message);
1925         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
1926                                                    cancel, GTK_RESPONSE_CANCEL, NULL);
1927         response = gtk_dialog_run(GTK_DIALOG(dialog));
1928         gtk_widget_destroy (dialog);
1929 }
1930
1931 void
1932 ghb_cancel_encode(signal_user_data_t *ud, const gchar *extra_msg)
1933 {
1934         GtkWidget *dialog;
1935         GtkResponseType response;
1936         
1937         if (extra_msg == NULL) extra_msg = "";
1938         // Toss up a warning dialog
1939         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1940                                 GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
1941                                 "%sYour movie will be lost if you don't continue encoding.",
1942                                 extra_msg);
1943         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
1944                                                    "Cancel Current and Stop", 1,
1945                                                    "Cancel Current, Start Next", 2,
1946                                                    "Finish Current, then Stop", 3,
1947                                                    "Continue Encoding", 4,
1948                                                    NULL);
1949         response = gtk_dialog_run(GTK_DIALOG(dialog));
1950         gtk_widget_destroy (dialog);
1951         switch (response)
1952         {
1953                 case 1:
1954                         ghb_stop_queue();
1955                         ud->cancel_encode = GHB_CANCEL_ALL;
1956                         break;
1957                 case 2:
1958                         ghb_stop_queue();
1959                         ud->cancel_encode = GHB_CANCEL_CURRENT;
1960                         break;
1961                 case 3:
1962                         ud->cancel_encode = GHB_CANCEL_FINISH;
1963                         break;
1964                 case 4:
1965                 default:
1966                         ud->cancel_encode = GHB_CANCEL_NONE;
1967                         break;
1968         }
1969 }
1970
1971 gboolean
1972 ghb_cancel_encode2(signal_user_data_t *ud, const gchar *extra_msg)
1973 {
1974         GtkWidget *dialog;
1975         GtkResponseType response;
1976         
1977         if (extra_msg == NULL) extra_msg = "";
1978         // Toss up a warning dialog
1979         dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1980                                 GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
1981                                 "%sYour movie will be lost if you don't continue encoding.",
1982                                 extra_msg);
1983         gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
1984                                                    "Cancel Current and Stop", 1,
1985                                                    "Continue Encoding", 4,
1986                                                    NULL);
1987         response = gtk_dialog_run(GTK_DIALOG(dialog));
1988         gtk_widget_destroy (dialog);
1989         switch (response)
1990         {
1991                 case 1:
1992                         ghb_stop_queue();
1993                         ud->cancel_encode = GHB_CANCEL_ALL;
1994                         return TRUE;
1995                 case 4:
1996                 default:
1997                         break;
1998         }
1999         return FALSE;
2000 }
2001
2002 static void
2003 submit_job(GValue *settings)
2004 {
2005         static gint unique_id = 1;
2006         gchar *type, *modified, *preset;
2007         const GValue *path;
2008         gboolean preset_modified;
2009
2010         g_debug("submit_job");
2011         if (settings == NULL) return;
2012         preset_modified = ghb_settings_get_boolean(settings, "preset_modified");
2013         path = ghb_settings_get_value(settings, "preset");
2014         preset = ghb_preset_path_string(path);
2015         type = ghb_preset_is_custom() ? "Custom " : "";
2016         modified = preset_modified ? "Modified " : "";
2017         ghb_log("%s%sPreset: %s", modified, type, preset);
2018         g_free(preset);
2019
2020         ghb_settings_set_int(settings, "job_unique_id", unique_id);
2021         ghb_settings_set_int(settings, "job_status", GHB_QUEUE_RUNNING);
2022         ghb_add_job (settings, unique_id);
2023         ghb_start_queue();
2024         unique_id++;
2025 }
2026
2027 static void
2028 prune_logs(signal_user_data_t *ud)
2029 {
2030         gchar *dest_dir;
2031         gint days;
2032
2033         // Only prune logs stored in the default config dir location
2034         days = ghb_settings_combo_int(ud->settings, "LogLongevity");
2035         if (days > 365)
2036                 return;
2037
2038         dest_dir = ghb_get_user_config_dir("EncodeLogs");
2039         if (g_file_test(dest_dir, G_FILE_TEST_IS_DIR))
2040         {
2041                 const gchar *file;
2042                 gint duration = days * 24 * 60 * 60;
2043                 
2044                 GDir *gdir = g_dir_open(dest_dir, 0, NULL);
2045                 time_t now;
2046
2047                 now = time(NULL);
2048                 file = g_dir_read_name(gdir);
2049                 while (file)
2050                 {
2051                         gchar *path;
2052                         struct stat stbuf;
2053
2054                         path = g_strdup_printf("%s/%s", dest_dir, file);
2055                         g_stat(path, &stbuf);
2056                         if (now - stbuf.st_mtime > duration)
2057                         {
2058                                 g_unlink(path);
2059                         }
2060                         g_free(path);
2061                         file = g_dir_read_name(gdir);
2062                 }
2063                 g_dir_close(gdir);
2064         }
2065         g_free(dest_dir);
2066         ghb_preview_cleanup(ud);
2067 }
2068
2069 static void
2070 queue_scan(signal_user_data_t *ud, GValue *js)
2071 {
2072         gchar *path;
2073         gint titlenum;
2074         time_t  _now;
2075         struct tm *now;
2076         gchar *log_path, *pos, *destname, *basename, *dest_dir;
2077
2078         _now = time(NULL);
2079         now = localtime(&_now);
2080         destname = ghb_settings_get_string(js, "destination");
2081         basename = g_path_get_basename(destname);
2082         if (ghb_settings_get_boolean(ud->settings, "EncodeLogLocation"))
2083         {
2084                 dest_dir = g_path_get_dirname (destname);
2085         }
2086         else
2087         {
2088                 dest_dir = ghb_get_user_config_dir("EncodeLogs");
2089         }
2090         g_free(destname);
2091         pos = g_strrstr( basename, "." );
2092         if (pos != NULL)
2093         {
2094                 *pos = 0;
2095         }
2096         log_path = g_strdup_printf("%s/%s %d-%02d-%02d %02d-%02d-%02d.log",
2097                 dest_dir,
2098                 basename,
2099                 now->tm_year + 1900, now->tm_mon + 1, now->tm_mday,
2100                 now->tm_hour, now->tm_min, now->tm_sec);
2101         g_free(basename);
2102         g_free(dest_dir);
2103         if (ud->job_activity_log)
2104                 g_io_channel_unref(ud->job_activity_log);
2105         ud->job_activity_log = g_io_channel_new_file (log_path, "w", NULL);
2106         if (ud->job_activity_log)
2107         {
2108                 gchar *ver_str;
2109
2110                 ver_str = g_strdup_printf("Handbrake Version: %s (%d)\n", 
2111                                                                         hb_get_version(NULL), hb_get_build(NULL));
2112                 g_io_channel_write_chars (ud->job_activity_log, ver_str, 
2113                                                                         -1, NULL, NULL);
2114                 g_free(ver_str);
2115         }
2116         g_free(log_path);
2117
2118         path = ghb_settings_get_string( js, "source");
2119         titlenum = ghb_settings_get_int(js, "titlenum");
2120         ghb_backend_queue_scan(path, titlenum);
2121         g_free(path);
2122 }
2123
2124 static gint
2125 queue_pending_count(GValue *queue)
2126 {
2127         gint nn, ii, count;
2128         GValue *js;
2129         gint status;
2130
2131         nn = 0;
2132         count = ghb_array_len(queue);
2133         for (ii = 0; ii < count; ii++)
2134         {
2135
2136                 js = ghb_array_get_nth(queue, ii);
2137                 status = ghb_settings_get_int(js, "job_status");
2138                 if (status == GHB_QUEUE_PENDING)
2139                 {
2140                         nn++;
2141                 }
2142         }
2143         return nn;
2144 }
2145
2146 void
2147 ghb_update_pending(signal_user_data_t *ud)
2148 {
2149         GtkLabel *label;
2150         gint pending;
2151         gchar *str;
2152
2153         label = GTK_LABEL(GHB_WIDGET(ud->builder, "pending_status"));
2154         pending = queue_pending_count(ud->queue);
2155         str = g_strdup_printf("%d encode(s) pending", pending);
2156         gtk_label_set_text(label, str);
2157         g_free(str);
2158 }
2159
2160 GValue* 
2161 ghb_start_next_job(signal_user_data_t *ud, gboolean find_first)
2162 {
2163         static gint current = 0;
2164         gint count, ii, jj;
2165         GValue *js;
2166         gint status;
2167         GtkWidget *prog;
2168
2169         g_debug("start_next_job");
2170         prog = GHB_WIDGET(ud->builder, "progressbar");
2171         gtk_widget_show(prog);
2172
2173         count = ghb_array_len(ud->queue);
2174         if (find_first)
2175         {       // Start the first pending item in the queue
2176                 current = 0;
2177                 for (ii = 0; ii < count; ii++)
2178                 {
2179
2180                         js = ghb_array_get_nth(ud->queue, ii);
2181                         status = ghb_settings_get_int(js, "job_status");
2182                         if (status == GHB_QUEUE_PENDING)
2183                         {
2184                                 current = ii;
2185                                 ghb_inhibit_gsm(ud);
2186                                 queue_scan(ud, js);
2187                                 ghb_update_pending(ud);
2188                                 return js;
2189                         }
2190                 }
2191                 // Nothing pending
2192                 ghb_uninhibit_gsm();
2193                 ghb_notify_done(ud);
2194                 return NULL;
2195         }
2196         // Find the next pending item after the current running item
2197         for (ii = 0; ii < count-1; ii++)
2198         {
2199                 js = ghb_array_get_nth(ud->queue, ii);
2200                 status = ghb_settings_get_int(js, "job_status");
2201                 if (status == GHB_QUEUE_RUNNING)
2202                 {
2203                         for (jj = ii+1; jj < count; jj++)
2204                         {
2205                                 js = ghb_array_get_nth(ud->queue, jj);
2206                                 status = ghb_settings_get_int(js, "job_status");
2207                                 if (status == GHB_QUEUE_PENDING)
2208                                 {
2209                                         current = jj;
2210                                         ghb_inhibit_gsm(ud);
2211                                         queue_scan(ud, js);
2212                                         ghb_update_pending(ud);
2213                                         return js;
2214                                 }
2215                         }
2216                 }
2217         }
2218         // No running item found? Maybe it was deleted
2219         // Look for a pending item starting from the last index we started
2220         for (ii = current; ii < count; ii++)
2221         {
2222                 js = ghb_array_get_nth(ud->queue, ii);
2223                 status = ghb_settings_get_int(js, "job_status");
2224                 if (status == GHB_QUEUE_PENDING)
2225                 {
2226                         current = ii;
2227                         ghb_inhibit_gsm(ud);
2228                         queue_scan(ud, js);
2229                         ghb_update_pending(ud);
2230                         return js;
2231                 }
2232         }
2233         // Nothing found
2234         ghb_uninhibit_gsm();
2235         ghb_notify_done(ud);
2236         ghb_update_pending(ud);
2237         gtk_widget_hide(prog);
2238         return NULL;
2239 }
2240
2241 static gint
2242 find_queue_job(GValue *queue, gint unique_id, GValue **job)
2243 {
2244         GValue *js;
2245         gint ii, count;
2246         gint job_unique_id;
2247         
2248         *job = NULL;
2249         g_debug("find_queue_job");
2250         if (unique_id == 0)  // Invalid Id
2251                 return -1;
2252
2253         count = ghb_array_len(queue);
2254         for (ii = 0; ii < count; ii++)
2255         {
2256                 js = ghb_array_get_nth(queue, ii);
2257                 job_unique_id = ghb_settings_get_int(js, "job_unique_id");
2258                 if (job_unique_id == unique_id)
2259                 {
2260                         *job = js;
2261                         return ii;
2262                 }
2263         }
2264         return -1;
2265 }
2266
2267 gchar*
2268 working_status_string(signal_user_data_t *ud, ghb_instance_status_t *status)
2269 {
2270         gchar *task_str, *job_str, *status_str;
2271         gint qcount;
2272         gint index;
2273         GValue *js;
2274         gboolean subtitle_scan = FALSE;
2275
2276         qcount = ghb_array_len(ud->queue);
2277         index = find_queue_job(ud->queue, status->unique_id, &js);
2278         if (js != NULL)
2279         {
2280                 subtitle_scan = ghb_settings_get_boolean(js, "subtitle_scan");
2281         }
2282         if (qcount > 1)
2283         {
2284                 job_str = g_strdup_printf("job %d of %d, ", index+1, qcount);
2285         }
2286         else
2287         {
2288                 job_str = g_strdup("");
2289         }
2290         if (status->job_count > 1)
2291         {
2292                 if (status->job_cur == 1 && subtitle_scan)
2293                 {
2294                         task_str = g_strdup_printf("pass %d (subtitle scan) of %d, ", 
2295                                 status->job_cur, status->job_count);
2296                 }
2297                 else
2298                 {
2299                         task_str = g_strdup_printf("pass %d of %d, ", 
2300                                 status->job_cur, status->job_count);
2301                 }
2302         }
2303         else
2304         {
2305                 task_str = g_strdup("");
2306         }
2307         if(status->seconds > -1)
2308         {
2309                 status_str= g_strdup_printf(
2310                         "Encoding: %s%s%.2f %%"
2311                         " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)",
2312                         job_str, task_str,
2313                         100.0 * status->progress,
2314                         status->rate_cur, status->rate_avg, status->hours, 
2315                         status->minutes, status->seconds );
2316         }
2317         else
2318         {
2319                 status_str= g_strdup_printf(
2320                         "Encoding: %s%s%.2f %%",
2321                         job_str, task_str,
2322                         100.0 * status->progress );
2323         }
2324         g_free(task_str);
2325         g_free(job_str);
2326         return status_str;
2327 }
2328
2329 static void
2330 ghb_backend_events(signal_user_data_t *ud)
2331 {
2332         ghb_status_t status;
2333         gchar *status_str;
2334         GtkProgressBar *progress;
2335         GtkLabel       *work_status;
2336         gint titleindex;
2337         GValue *js;
2338         gint index;
2339         GtkTreeView *treeview;
2340         GtkTreeStore *store;
2341         GtkTreeIter iter;
2342         static gint prev_scan_state = 0;
2343         static gint prev_queue_state = 0;
2344         
2345         ghb_track_status();
2346         ghb_get_status(&status);
2347         if (prev_scan_state != status.scan.state ||
2348                 prev_queue_state != status.queue.state)
2349         {
2350                 ghb_queue_buttons_grey(ud);
2351                 prev_scan_state = status.scan.state;
2352                 prev_queue_state = status.queue.state;
2353         }
2354         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
2355         work_status = GTK_LABEL(GHB_WIDGET (ud->builder, "work_status"));
2356         if (status.scan.state == GHB_STATE_IDLE && 
2357                 status.queue.state == GHB_STATE_IDLE)
2358         {
2359                 static gboolean prev_dvdnav;
2360                 gboolean dvdnav = ghb_settings_get_boolean(ud->settings, "use_dvdnav");
2361                 if (dvdnav != prev_dvdnav)
2362                 {
2363                         hb_dvd_set_dvdnav(dvdnav);
2364                         prev_dvdnav = dvdnav;
2365                 }
2366         }
2367         // First handle the status of title scans
2368         // Then handle the status of the queue
2369         if (status.scan.state & GHB_STATE_SCANNING)
2370         {
2371                 GtkProgressBar *scan_prog;
2372                 GtkLabel *label;
2373
2374                 scan_prog = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "scan_prog"));
2375                 label = GTK_LABEL(GHB_WIDGET (ud->builder, "source_title"));
2376
2377                 if (status.scan.title_cur == 0)
2378                 {
2379                         status_str = g_strdup ("Scanning...");
2380                 }
2381                 else
2382                 {
2383                         status_str = g_strdup_printf ("Scanning title %d of %d...", 
2384                                                           status.scan.title_cur, status.scan.title_count );
2385                 }
2386                 gtk_label_set_text (label, status_str);
2387                 g_free(status_str);
2388                 if (status.scan.title_count > 0)
2389                 {
2390                         gtk_progress_bar_set_fraction (scan_prog, 
2391                                 (gdouble)status.scan.title_cur / status.scan.title_count);
2392                 }
2393         }
2394         else if (status.scan.state & GHB_STATE_SCANDONE)
2395         {
2396                 gchar *source;
2397                 GtkProgressBar *scan_prog;
2398                 GtkLabel *label;
2399
2400                 GtkWidget *widget;
2401                 GtkAction *action;
2402
2403                 widget = GHB_WIDGET(ud->builder, "sourcetoolbutton");
2404                 gtk_widget_set_sensitive(widget, TRUE);
2405                 action = GHB_ACTION(ud->builder, "source_action");
2406                 gtk_action_set_sensitive(action, TRUE);
2407                 action = GHB_ACTION(ud->builder, "source_single_action");
2408                 gtk_action_set_sensitive(action, TRUE);
2409
2410                 source = ghb_settings_get_string(ud->settings, "source");
2411                 update_source_label(ud, source, FALSE);
2412
2413                 scan_prog = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "scan_prog"));
2414                 gtk_progress_bar_set_fraction (scan_prog, 1.0);
2415                 gtk_widget_hide(GTK_WIDGET(scan_prog));
2416
2417                 ghb_title_info_t tinfo;
2418                         
2419                 ghb_update_ui_combo_box(ud, "title", 0, FALSE);
2420                 titleindex = ghb_longest_title();
2421                 ghb_ui_update(ud, "title", ghb_int64_value(titleindex));
2422
2423                 label = GTK_LABEL(GHB_WIDGET (ud->builder, "source_title"));
2424                 // Are there really any titles.
2425                 if (!ghb_get_title_info(&tinfo, titleindex))
2426                 {
2427                         gtk_label_set_text(label, "None");
2428                 }
2429                 ghb_clear_scan_state(GHB_STATE_SCANDONE);
2430                 if (ghb_queue_edit_settings)
2431                 {
2432                         ghb_settings_to_ui(ud, ghb_queue_edit_settings);
2433                         ghb_set_audio(ud, ghb_queue_edit_settings);
2434                         ghb_reset_subtitles(ud, ghb_queue_edit_settings);
2435                         reset_chapter_list(ud, ghb_queue_edit_settings);
2436                         ghb_value_free(ghb_queue_edit_settings);
2437                         ghb_queue_edit_settings = NULL;
2438                 }
2439         }
2440
2441         if (status.queue.state & GHB_STATE_SCANNING)
2442         {
2443                 // This needs to be in scanning and working since scanning
2444                 // happens fast enough that it can be missed
2445                 gtk_label_set_text (work_status, "Scanning ...");
2446                 gtk_progress_bar_set_fraction (progress, 0);
2447         }
2448         else if (status.queue.state & GHB_STATE_SCANDONE)
2449         {
2450                 ghb_clear_queue_state(GHB_STATE_SCANDONE);
2451                 usleep(2000000);
2452                 submit_job(ud->current_job);
2453                 ghb_update_pending(ud);
2454         }
2455         else if (status.queue.state & GHB_STATE_PAUSED)
2456         {
2457                 gtk_label_set_text (work_status, "Paused");
2458         }
2459         else if (status.queue.state & GHB_STATE_WORKING)
2460         {
2461                 static gint working = 0;
2462
2463                 // This needs to be in scanning and working since scanning
2464                 // happens fast enough that it can be missed
2465                 index = find_queue_job(ud->queue, status.queue.unique_id, &js);
2466                 if (status.queue.unique_id != 0 && index >= 0)
2467                 {
2468                         gchar working_icon[] = "hb-working0";
2469                         working_icon[10] = '0' + working;
2470                         working = (working+1) % 6;
2471                         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2472                         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2473                         gchar *path = g_strdup_printf ("%d", index);
2474                         if (gtk_tree_model_get_iter_from_string(
2475                                         GTK_TREE_MODEL(store), &iter, path))
2476                         {
2477                                 gtk_tree_store_set(store, &iter, 0, working_icon, -1);
2478                         }
2479                         g_free(path);
2480                 }
2481                 GtkLabel *label;
2482                 gchar *status_str;
2483
2484                 status_str = working_status_string(ud, &status.queue);
2485                 label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_status"));
2486                 gtk_label_set_text (label, status_str);
2487 #if !GTK_CHECK_VERSION(2, 16, 0)
2488                 GtkStatusIcon *si;
2489
2490                 si = GTK_STATUS_ICON(GHB_OBJECT(ud->builder, "hb_status"));
2491                 gtk_status_icon_set_tooltip(si, status_str);
2492 #endif
2493                 gtk_label_set_text (work_status, status_str);
2494                 gtk_progress_bar_set_fraction (progress, status.queue.progress);
2495                 g_free(status_str);
2496         }
2497         else if (status.queue.state & GHB_STATE_WORKDONE)
2498         {
2499                 gint qstatus;
2500
2501                 index = find_queue_job(ud->queue, status.queue.unique_id, &js);
2502                 treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
2503                 store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2504                 if (ud->cancel_encode == GHB_CANCEL_ALL || 
2505                         ud->cancel_encode == GHB_CANCEL_CURRENT)
2506                         status.queue.error = GHB_ERROR_CANCELED;
2507                 switch( status.queue.error )
2508                 {
2509                         case GHB_ERROR_NONE:
2510                                 gtk_label_set_text (work_status, "Rip Done!");
2511                                 qstatus = GHB_QUEUE_DONE;
2512                                 if (js != NULL)
2513                                 {
2514                                         gchar *path = g_strdup_printf ("%d", index);
2515                                         if (gtk_tree_model_get_iter_from_string(
2516                                                         GTK_TREE_MODEL(store), &iter, path))
2517                                         {
2518                                                 gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
2519                                         }
2520                                         g_free(path);
2521                                 }
2522                                 break;
2523                         case GHB_ERROR_CANCELED:
2524                                 gtk_label_set_text (work_status, "Rip Canceled.");
2525                                 qstatus = GHB_QUEUE_CANCELED;
2526                                 if (js != NULL)
2527                                 {
2528                                         gchar *path = g_strdup_printf ("%d", index);
2529                                         if (gtk_tree_model_get_iter_from_string(
2530                                                         GTK_TREE_MODEL(store), &iter, path))
2531                                         {
2532                                                 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
2533                                         }
2534                                         g_free(path);
2535                                 }
2536                                 break;
2537                         default:
2538                                 gtk_label_set_text (work_status, "Rip Failed.");
2539                                 qstatus = GHB_QUEUE_CANCELED;
2540                                 if (js != NULL)
2541                                 {
2542                                         gchar *path = g_strdup_printf ("%d", index);
2543                                         if (gtk_tree_model_get_iter_from_string(
2544                                                         GTK_TREE_MODEL(store), &iter, path))
2545                                         {
2546                                                 gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
2547                                         }
2548                                         g_free(path);
2549                                 }
2550                 }
2551                 gtk_progress_bar_set_fraction (progress, 1.0);
2552                 ghb_clear_queue_state(GHB_STATE_WORKDONE);
2553                 if (ud->job_activity_log)
2554                         g_io_channel_unref(ud->job_activity_log);
2555                 ud->job_activity_log = NULL;
2556                 if (ud->cancel_encode != GHB_CANCEL_ALL &&
2557                         ud->cancel_encode != GHB_CANCEL_FINISH)
2558                 {
2559                         ud->current_job = ghb_start_next_job(ud, FALSE);
2560                 }
2561                 else
2562                 {
2563                         ghb_uninhibit_gsm();
2564                         ud->current_job = NULL;
2565                         gtk_widget_hide(GTK_WIDGET(progress));
2566                 }
2567                 if (js)
2568                         ghb_settings_set_int(js, "job_status", qstatus);
2569                 ghb_save_queue(ud->queue);
2570                 ud->cancel_encode = GHB_CANCEL_NONE;
2571 #if !GTK_CHECK_VERSION(2, 16, 0)
2572                 GtkStatusIcon *si;
2573
2574                 si = GTK_STATUS_ICON(GHB_OBJECT(ud->builder, "hb_status"));
2575                 gtk_status_icon_set_tooltip(si, "HandBrake");
2576 #endif
2577         }
2578         else if (status.queue.state & GHB_STATE_MUXING)
2579         {
2580                 gtk_label_set_text (work_status, "Muxing: This may take a while...");
2581         }
2582
2583         if (status.scan.state & GHB_STATE_WORKING)
2584         {
2585                 GtkProgressBar *live_progress;
2586                 live_progress = GTK_PROGRESS_BAR(
2587                         GHB_WIDGET(ud->builder, "live_encode_progress"));
2588                 status_str = working_status_string(ud, &status.scan);
2589                 gtk_progress_bar_set_text (live_progress, status_str);
2590                 gtk_progress_bar_set_fraction (live_progress, status.scan.progress);
2591                 g_free(status_str);
2592         }
2593         if (status.scan.state & GHB_STATE_WORKDONE)
2594         {
2595                 switch( status.scan.error )
2596                 {
2597                         case GHB_ERROR_NONE:
2598                         {
2599                                 ghb_live_encode_done(ud, TRUE);
2600                         } break;
2601                         default:
2602                         {
2603                                 ghb_live_encode_done(ud, FALSE);
2604                         } break;
2605                 }
2606                 ghb_clear_scan_state(GHB_STATE_WORKDONE);
2607         }
2608 }
2609
2610 #if GTK_CHECK_VERSION(2, 16, 0)
2611 G_MODULE_EXPORT gboolean
2612 status_icon_query_tooltip_cb(
2613         GtkStatusIcon *si,
2614         gint           x,
2615         gint           y,
2616         gboolean       kbd_mode,
2617         GtkTooltip    *tt,
2618         signal_user_data_t *ud)
2619 {
2620         ghb_status_t status;
2621         gchar *status_str;
2622
2623         ghb_get_status(&status);
2624         if (status.queue.state & GHB_STATE_WORKING)
2625                 status_str = working_status_string(ud, &status.queue);
2626         else if (status.queue.state & GHB_STATE_WORKDONE)
2627                 status_str = g_strdup("Encode Complete");
2628         else
2629                 status_str = g_strdup("HandBrake");
2630
2631         gtk_tooltip_set_text(tt, status_str);
2632         gtk_tooltip_set_icon_from_icon_name(tt, "hb-icon", GTK_ICON_SIZE_BUTTON);
2633         g_free(status_str);
2634         return TRUE;
2635 }
2636 #endif
2637
2638 G_MODULE_EXPORT gboolean
2639 ghb_timer_cb(gpointer data)
2640 {
2641         signal_user_data_t *ud = (signal_user_data_t*)data;
2642
2643         ghb_live_preview_progress(ud);
2644         ghb_backend_events(ud);
2645         if (update_default_destination)
2646         {
2647                 gchar *dest, *dest_dir, *def_dest;
2648                 dest = ghb_settings_get_string(ud->settings, "destination");
2649                 dest_dir = g_path_get_dirname (dest);
2650                 def_dest = ghb_settings_get_string(ud->settings, "destination_dir");
2651                 if (strcmp(dest_dir, def_dest) != 0)
2652                 {
2653                         ghb_settings_set_string (ud->settings, "destination_dir", dest_dir);
2654                         ghb_pref_save (ud->settings, "destination_dir");
2655                 }
2656                 g_free(dest);
2657                 g_free(dest_dir);
2658                 g_free(def_dest);
2659                 update_default_destination = FALSE;
2660         }
2661         if (update_preview)
2662         {
2663                 g_debug("Updating preview\n");
2664                 ghb_set_preview_image (ud);
2665                 update_preview = FALSE;
2666         }
2667
2668         if (!appcast_busy)
2669         {
2670                 gchar *updates;
2671                 updates = ghb_settings_get_string(ud->settings, "check_updates");
2672                 gint64 duration = 0;
2673                 if (strcmp(updates, "daily") == 0)
2674                         duration = 60 * 60 * 24;
2675                 else if (strcmp(updates, "weekly") == 0)
2676                         duration = 60 * 60 * 24 * 7;
2677                 else if (strcmp(updates, "monthly") == 0)
2678                         duration = 60 * 60 * 24 * 7;
2679
2680                 g_free(updates);
2681                 if (duration != 0)
2682                 {
2683                         gint64 last;
2684                         time_t tt;
2685
2686                         last = ghb_settings_get_int64(ud->settings, "last_update_check");
2687                         time(&tt);
2688                         if (last + duration < tt)
2689                         {
2690                                 ghb_settings_set_int64(ud->settings, 
2691                                                                                 "last_update_check", tt);
2692                                 ghb_pref_save(ud->settings, "last_update_check");
2693                                 g_thread_create((GThreadFunc)ghb_check_update, ud, 
2694                                                                 FALSE, NULL);
2695                         }
2696                 }
2697         }
2698         return TRUE;
2699 }
2700
2701 G_MODULE_EXPORT gboolean
2702 ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
2703 {
2704         gchar *text = NULL;
2705         gsize length, outlength;
2706         GtkTextView *textview;
2707         GtkTextBuffer *buffer;
2708         GtkTextIter iter;
2709         GtkTextMark *mark;
2710         GError *gerror = NULL;
2711         GIOStatus status;
2712         
2713         signal_user_data_t *ud = (signal_user_data_t*)data;
2714
2715         status = g_io_channel_read_line (source, &text, &length, NULL, &gerror);
2716         // Trim nils from end of text, they cause g_io_channel_write_chars to
2717         // fail with an assertion that aborts
2718         while (length > 0 && text[length-1] == 0)
2719                 length--;
2720         if (text != NULL && length > 0)
2721         {
2722                 GdkWindow *window;
2723                 gint width, height;
2724                 gint x, y;
2725                 gboolean bottom = FALSE;
2726                 gchar *utf8_text;
2727
2728                 textview = GTK_TEXT_VIEW(GHB_WIDGET (ud->builder, "activity_view"));
2729                 buffer = gtk_text_view_get_buffer (textview);
2730                 // I would like to auto-scroll the window when the scrollbar
2731                 // is at the bottom, 
2732                 // must determine whether the insert point is at
2733                 // the bottom of the window 
2734                 window = gtk_text_view_get_window(textview, GTK_TEXT_WINDOW_TEXT);
2735                 if (window != NULL)
2736                 {
2737                         gdk_drawable_get_size(GDK_DRAWABLE(window), &width, &height);
2738                         gtk_text_view_window_to_buffer_coords(textview, 
2739                                 GTK_TEXT_WINDOW_TEXT, width, height, &x, &y);
2740                         gtk_text_view_get_iter_at_location(textview, &iter, x, y);
2741                         if (gtk_text_iter_is_end(&iter))
2742                         {
2743                                 bottom = TRUE;
2744                         }
2745                 }
2746                 else
2747                 {
2748                         // If the window isn't available, assume bottom
2749                         bottom = TRUE;
2750                 }
2751                 gtk_text_buffer_get_end_iter(buffer, &iter);
2752                 utf8_text = g_convert_with_fallback(text, -1, "UTF-8", "ISO-8859-1",
2753                                                                                         "?", NULL, &length, NULL);
2754                 if (utf8_text != NULL)
2755                 {
2756                         gtk_text_buffer_insert(buffer, &iter, utf8_text, -1);
2757                         if (bottom)
2758                         {
2759                                 gtk_text_buffer_get_end_iter(buffer, &iter);
2760                                 mark = gtk_text_buffer_create_mark(buffer, NULL, &iter, FALSE);
2761                                 gtk_text_view_scroll_mark_onscreen(textview, mark);
2762                                 gtk_text_buffer_delete_mark(buffer, mark);
2763                         }
2764 #if defined(_WIN32)
2765                         gsize one = 1;
2766                         utf8_text[length-1] = '\r';
2767 #endif
2768                         g_io_channel_write_chars (ud->activity_log, utf8_text, 
2769                                                                         length, &outlength, NULL);
2770 #if defined(_WIN32)
2771                         g_io_channel_write_chars (ud->activity_log, "\n", 
2772                                                                         one, &one, NULL);
2773 #endif
2774                         g_io_channel_flush(ud->activity_log, NULL);
2775                         if (ud->job_activity_log)
2776                         {
2777                                 g_io_channel_write_chars (ud->job_activity_log, utf8_text, 
2778                                                                                 length, &outlength, NULL);
2779 #if defined(_WIN32)
2780                                 g_io_channel_write_chars (ud->activity_log, "\n", 
2781                                                                                 one, &outlength, NULL);
2782 #endif
2783                                 g_io_channel_flush(ud->job_activity_log, NULL);
2784                         }
2785                         g_free(utf8_text);
2786                 }
2787         }
2788         if (text != NULL)
2789                 g_free(text);
2790
2791         if (status != G_IO_STATUS_NORMAL)
2792         {
2793                 // This should never happen, but if it does I would get into an
2794                 // infinite loop.  Returning false removes this callback.
2795                 g_warning("Error while reading activity from pipe");
2796                 if (gerror != NULL)
2797                 {
2798                         g_warning("%s", gerror->message);
2799                         g_error_free (gerror);
2800                 }
2801                 return FALSE;
2802         }
2803         if (gerror != NULL)
2804                 g_error_free (gerror);
2805         return TRUE;
2806 }
2807
2808 static void
2809 set_visible(GtkWidget *widget, gboolean visible)
2810 {
2811         if (visible)
2812         {
2813                 gtk_widget_show_now(widget);
2814         }
2815         else
2816         {
2817                 gtk_widget_hide(widget);
2818         }
2819 }
2820
2821 G_MODULE_EXPORT void
2822 show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2823 {
2824         GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
2825         set_visible(widget, gtk_toggle_tool_button_get_active(
2826                                                 GTK_TOGGLE_TOOL_BUTTON(xwidget)));
2827 }
2828
2829 G_MODULE_EXPORT void
2830 show_activity_menu_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2831 {
2832         GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
2833         set_visible(widget, TRUE);
2834         widget = GHB_WIDGET (ud->builder, "show_activity");
2835         gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(widget), TRUE);
2836 }
2837
2838 G_MODULE_EXPORT gboolean
2839 activity_window_delete_cb(GtkWidget *xwidget, GdkEvent *event, signal_user_data_t *ud)
2840 {
2841         set_visible(xwidget, FALSE);
2842         GtkWidget *widget = GHB_WIDGET (ud->builder, "show_activity");
2843         gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(widget), FALSE);
2844         return TRUE;
2845 }
2846
2847 void
2848 ghb_log(gchar *log, ...)
2849 {
2850         va_list args;
2851         time_t _now;
2852     struct tm *now;
2853         gchar fmt[362];
2854
2855         _now = time(NULL);
2856         now = localtime( &_now );
2857         snprintf(fmt, 362, "[%02d:%02d:%02d] gtkgui: %s\n", 
2858                         now->tm_hour, now->tm_min, now->tm_sec, log);
2859         va_start(args, log);
2860         vfprintf(stderr, fmt, args);
2861         va_end(args);
2862 }
2863
2864 static void
2865 browse_url(const gchar *url)
2866 {
2867         gboolean result;
2868         char *argv[] = 
2869                 {"xdg-open",NULL,NULL,NULL};
2870         argv[1] = (gchar*)url;
2871         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2872                                 NULL, NULL, NULL);
2873         if (result) return;
2874
2875         argv[0] = "gnome-open";
2876         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2877                                 NULL, NULL, NULL);
2878         if (result) return;
2879
2880         argv[0] = "kfmclient";
2881         argv[1] = "exec";
2882         argv[2] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2883         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2884                                 NULL, NULL, NULL);
2885         if (result) return;
2886
2887         argv[0] = "firefox";
2888         argv[1] = "http://trac.handbrake.fr/wiki/HandBrakeGuide";
2889         argv[2] = NULL;
2890         result = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
2891                                 NULL, NULL, NULL);
2892 }
2893
2894 void
2895 about_web_hook(GtkAboutDialog *about, const gchar *link, gpointer data)
2896 {
2897         browse_url(link);
2898 }
2899
2900 G_MODULE_EXPORT void
2901 about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2902 {
2903         GtkWidget *widget = GHB_WIDGET (ud->builder, "hb_about");
2904         gchar *ver;
2905
2906         ver = g_strdup_printf("%s (%s)", HB_PROJECT_VERSION, HB_PROJECT_BUILD_ARCH);
2907         gtk_about_dialog_set_url_hook(about_web_hook, NULL, NULL);
2908         gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(widget), ver);
2909         g_free(ver);
2910         gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(widget), 
2911                                                                 HB_PROJECT_URL_WEBSITE);
2912         gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(widget), 
2913                                                                                 HB_PROJECT_URL_WEBSITE);
2914         gtk_widget_show (widget);
2915 }
2916
2917 G_MODULE_EXPORT void
2918 guide_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2919 {
2920         browse_url("http://trac.handbrake.fr/wiki/HandBrakeGuide");
2921 }
2922
2923 G_MODULE_EXPORT void
2924 hb_about_response_cb(GtkWidget *widget, gint response, signal_user_data_t *ud)
2925 {
2926         gtk_widget_hide (widget);
2927 }
2928
2929 G_MODULE_EXPORT void
2930 show_queue_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2931 {
2932         GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
2933         set_visible(widget, gtk_toggle_tool_button_get_active(
2934                                                 GTK_TOGGLE_TOOL_BUTTON(xwidget)));
2935 }
2936
2937 G_MODULE_EXPORT void
2938 show_queue_menu_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
2939 {
2940         GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
2941         set_visible(widget, TRUE);
2942         widget = GHB_WIDGET (ud->builder, "show_queue");
2943         gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(widget), TRUE);
2944 }
2945
2946 G_MODULE_EXPORT gboolean
2947 queue_window_delete_cb(GtkWidget *xwidget, GdkEvent *event, signal_user_data_t *ud)
2948 {
2949         set_visible(xwidget, FALSE);
2950         GtkWidget *widget = GHB_WIDGET (ud->builder, "show_queue");
2951         gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(widget), FALSE);
2952         return TRUE;
2953 }
2954
2955 G_MODULE_EXPORT void
2956 show_presets_toggled_cb(GtkWidget *action, signal_user_data_t *ud)
2957 {
2958         GtkWidget *widget;
2959         GtkWindow *hb_window;
2960         
2961         g_debug("show_presets_clicked_cb ()");
2962         widget = GHB_WIDGET (ud->builder, "presets_frame");
2963         ghb_widget_to_setting(ud->settings, action);
2964         if (ghb_settings_get_boolean(ud->settings, "show_presets"))
2965         {
2966                 gtk_widget_show_now(widget);
2967         }
2968         else
2969         {
2970                 gtk_widget_hide(widget);
2971                 hb_window = GTK_WINDOW(GHB_WIDGET (ud->builder, "hb_window"));
2972                 gtk_window_resize(hb_window, 16, 16);
2973         }
2974         ghb_pref_save(ud->settings, "show_presets");
2975 }
2976
2977 static void
2978 reset_chapter_list(signal_user_data_t *ud, GValue *settings)
2979 {
2980         GtkTreeView *treeview;
2981         GtkTreeIter iter;
2982         GtkListStore *store;
2983         gboolean done;
2984         GValue *chapters;
2985         gint titleindex, ii;
2986         gint count;
2987         
2988         g_debug("reset_chapter_list ()");
2989         chapters = ghb_value_dup(ghb_settings_get_value(settings, "chapter_list"));
2990         count = ghb_array_len(chapters);
2991         ghb_settings_set_value(ud->settings, "chapter_list", chapters);
2992         titleindex = ghb_settings_combo_int(ud->settings, "title");
2993         
2994         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
2995         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
2996         ii = 0;
2997         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
2998         {
2999                 do
3000                 {
3001
3002                         if (ii < count)
3003                         {
3004                                 gchar *chapter, *duration;
3005                                 gint hh, mm, ss;
3006
3007                                 // Update row with settings data
3008                                 g_debug("Updating row");
3009                                 chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
3010                                 ghb_get_chapter_duration(titleindex, ii, &hh, &mm, &ss);
3011                                 duration = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss);
3012                                 gtk_list_store_set(store, &iter, 
3013                                         0, ii+1,
3014                                         1, duration,
3015                                         2, chapter,
3016                                         3, TRUE,
3017                                         -1);
3018                                 g_free(chapter);
3019                                 g_free(duration);
3020                                 ii++;
3021                                 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
3022                         }
3023                         else
3024                         {
3025                                 // No more settings data, remove row
3026                                 g_debug("Removing row");
3027                                 done = !gtk_list_store_remove(store, &iter);
3028                         }
3029                 } while (!done);
3030         }
3031         while (ii < count)
3032         {
3033                 gchar *chapter, *duration;
3034                 gint hh, mm, ss;
3035
3036                 // Additional settings, add row
3037                 g_debug("Adding row");
3038                 chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
3039                 ghb_get_chapter_duration(titleindex, ii, &hh, &mm, &ss);
3040                 duration = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss);
3041                 gtk_list_store_append(store, &iter);
3042                 gtk_list_store_set(store, &iter, 
3043                         0, ii+1,
3044                         1, duration,
3045                         2, chapter,
3046                         3, TRUE,
3047                         -1);
3048                 g_free(chapter);
3049                 g_free(duration);
3050                 ii++;
3051         }
3052 }
3053
3054 static void
3055 update_chapter_list(signal_user_data_t *ud)
3056 {
3057         GtkTreeView *treeview;
3058         GtkTreeIter iter;
3059         GtkListStore *store;
3060         gboolean done;
3061         GValue *chapters;
3062         gint titleindex, ii;
3063         gint count;
3064         
3065         g_debug("update_chapter_list ()");
3066         titleindex = ghb_settings_combo_int(ud->settings, "title");
3067         chapters = ghb_get_chapters(titleindex);
3068         count = ghb_array_len(chapters);
3069         if (chapters)
3070                 ghb_settings_set_value(ud->settings, "chapter_list", chapters);
3071         
3072         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
3073         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
3074         ii = 0;
3075         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
3076         {
3077                 do
3078                 {
3079
3080                         if (ii < count)
3081                         {
3082                                 gchar *chapter, *duration;
3083                                 gint hh, mm, ss;
3084
3085                                 // Update row with settings data
3086                                 g_debug("Updating row");
3087                                 chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
3088                                 ghb_get_chapter_duration(titleindex, ii, &hh, &mm, &ss);
3089                                 duration = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss);
3090                                 gtk_list_store_set(store, &iter, 
3091                                         0, ii+1,
3092                                         1, duration,
3093                                         2, chapter,
3094                                         3, TRUE,
3095                                         -1);
3096                                 g_free(chapter);
3097                                 g_free(duration);
3098                                 ii++;
3099                                 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
3100                         }
3101                         else
3102                         {
3103                                 // No more settings data, remove row
3104                                 g_debug("Removing row");
3105                                 done = !gtk_list_store_remove(store, &iter);
3106                         }
3107                 } while (!done);
3108         }
3109         while (ii < count)
3110         {
3111                 gchar *chapter, *duration;
3112                 gint hh, mm, ss;
3113
3114                 // Additional settings, add row
3115                 g_debug("Adding row");
3116                 chapter = ghb_value_string(ghb_array_get_nth(chapters, ii));
3117                 ghb_get_chapter_duration(titleindex, ii, &hh, &mm, &ss);
3118                 duration = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss);
3119                 gtk_list_store_append(store, &iter);
3120                 gtk_list_store_set(store, &iter, 
3121                         0, ii+1,
3122                         1, duration,
3123                         2, chapter,
3124                         3, TRUE,
3125                         -1);
3126                 g_free(chapter);
3127                 g_free(duration);
3128                 ii++;
3129         }
3130 }
3131
3132 static gint chapter_edit_key = 0;
3133
3134 G_MODULE_EXPORT gboolean
3135 chapter_keypress_cb(
3136         GhbCellRendererText *cell,
3137         GdkEventKey *event,
3138         signal_user_data_t *ud)
3139 {
3140         chapter_edit_key = event->keyval;
3141         return FALSE;
3142 }
3143
3144 G_MODULE_EXPORT void
3145 chapter_edited_cb(
3146         GhbCellRendererText *cell, 
3147         gchar *path, 
3148         gchar *text, 
3149         signal_user_data_t *ud)
3150 {
3151         GtkTreePath *treepath;
3152         GtkListStore *store;
3153         GtkTreeView *treeview;
3154         GtkTreeIter iter;
3155         gint index;
3156         gint *pi;
3157         gint row;
3158         
3159         g_debug("chapter_edited_cb ()");
3160         g_debug("path (%s)", path);
3161         g_debug("text (%s)", text);
3162         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
3163         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
3164         treepath = gtk_tree_path_new_from_string (path);
3165         pi = gtk_tree_path_get_indices(treepath);
3166         row = pi[0];
3167         gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
3168         gtk_list_store_set(store, &iter, 
3169                 2, text,
3170                 3, TRUE,
3171                 -1);
3172         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &index, -1);
3173
3174         const GValue *chapters;
3175         GValue *chapter;
3176
3177         chapters = ghb_settings_get_value(ud->settings, "chapter_list");
3178         chapter = ghb_array_get_nth(chapters, index-1);
3179         g_value_set_string(chapter, text);
3180         if ((chapter_edit_key == GDK_Return || chapter_edit_key == GDK_Down) &&
3181                 gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
3182         {
3183                 GtkTreeViewColumn *column;
3184
3185                 gtk_tree_path_next(treepath);
3186                 // When a cell has been edited, I want to advance to the
3187                 // next cell and start editing it automaitcally.
3188                 // Unfortunately, we may not be in a state here where
3189                 // editing is allowed.  This happens when the user selects
3190                 // a new cell with the mouse instead of just hitting enter.
3191                 // Some kind of Gtk quirk.  widget_editable==NULL assertion.
3192                 // Editing is enabled again once the selection event has been
3193                 // processed.  So I'm queueing up a callback to be called
3194                 // when things go idle.  There, I will advance to the next
3195                 // cell and initiate editing.
3196                 //
3197                 // Now, you might be asking why I don't catch the keypress
3198                 // event and determine what action to take based on that.
3199                 // The Gtk developers in their infinite wisdom have made the 
3200                 // actual GtkEdit widget being used a private member of
3201                 // GtkCellRendererText, so it can not be accessed to hang a
3202                 // signal handler off of.  And they also do not propagate the
3203                 // keypress signals in any other way.  So that information is lost.
3204                 //g_idle_add((GSourceFunc)next_cell, ud);
3205                 //
3206                 // Keeping the above comment for posterity.
3207                 // I got industrious and made my own CellTextRendererText that
3208                 // passes on the key-press-event. So now I have much better
3209                 // control of this.
3210                 column = gtk_tree_view_get_column(treeview, 2);
3211                 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
3212         }
3213         else if (chapter_edit_key == GDK_Up && row > 0)
3214         {
3215                 GtkTreeViewColumn *column;
3216                 gtk_tree_path_prev(treepath);
3217                 column = gtk_tree_view_get_column(treeview, 2);
3218                 gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
3219         }
3220         gtk_tree_path_free (treepath);
3221 }
3222
3223 void
3224 debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data)
3225 {
3226         signal_user_data_t *ud = (signal_user_data_t*)data;
3227         
3228         if (ud->debug)
3229         {
3230                 printf("%s: %s\n", domain, msg);
3231         }
3232 }
3233
3234 void
3235 warn_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data)
3236 {
3237         printf("%s: %s\n", domain, msg);
3238 }
3239
3240 void
3241 ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
3242 {
3243         GtkWidget *widget;
3244         g_debug("ghb_hbfd");
3245         widget = GHB_WIDGET(ud->builder, "queue_pause1");
3246         set_visible(widget, !hbfd);
3247         widget = GHB_WIDGET(ud->builder, "queue_add");
3248         set_visible(widget, !hbfd);
3249         widget = GHB_WIDGET(ud->builder, "show_queue");
3250         set_visible(widget, !hbfd);
3251         widget = GHB_WIDGET(ud->builder, "show_activity");
3252         set_visible(widget, !hbfd);
3253
3254         widget = GHB_WIDGET(ud->builder, "chapter_box");
3255         set_visible(widget, !hbfd);
3256         widget = GHB_WIDGET(ud->builder, "container_box");
3257         set_visible(widget, !hbfd);
3258         widget = GHB_WIDGET(ud->builder, "settings_box");
3259         set_visible(widget, !hbfd);
3260         widget = GHB_WIDGET(ud->builder, "presets_save");
3261         set_visible(widget, !hbfd);
3262         widget = GHB_WIDGET(ud->builder, "presets_remove");
3263         set_visible(widget, !hbfd);
3264         widget = GHB_WIDGET (ud->builder, "hb_window");
3265         gtk_window_resize(GTK_WINDOW(widget), 16, 16);
3266
3267 }
3268
3269 G_MODULE_EXPORT void
3270 hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
3271 {
3272         g_debug("hbfd_toggled_cb");
3273         ghb_widget_to_setting (ud->settings, widget);
3274         gboolean hbfd = ghb_settings_get_boolean(ud->settings, "hbfd");
3275         ghb_hbfd(ud, hbfd);
3276         ghb_pref_save(ud->settings, "hbfd");
3277 }
3278
3279 G_MODULE_EXPORT void
3280 pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3281 {
3282         g_debug("pref_changed_cb");
3283         ghb_widget_to_setting (ud->settings, widget);
3284         ghb_check_dependency(ud, widget);
3285         const gchar *name = gtk_widget_get_name(widget);
3286         ghb_pref_save(ud->settings, name);
3287 }
3288
3289 G_MODULE_EXPORT void
3290 use_m4v_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3291 {
3292         g_debug("use_m4v_changed_cb");
3293         ghb_widget_to_setting (ud->settings, widget);
3294         ghb_check_dependency(ud, widget);
3295         const gchar *name = gtk_widget_get_name(widget);
3296         ghb_pref_save(ud->settings, name);
3297         ghb_update_destination_extension(ud);
3298 }
3299
3300 G_MODULE_EXPORT void
3301 show_status_cb(GtkWidget *widget, signal_user_data_t *ud)
3302 {
3303         g_debug("show_status_cb");
3304         ghb_widget_to_setting (ud->settings, widget);
3305         ghb_check_dependency(ud, widget);
3306         const gchar *name = gtk_widget_get_name(widget);
3307         ghb_pref_save(ud->settings, name);
3308
3309         GtkStatusIcon *si;
3310
3311         si = GTK_STATUS_ICON(GHB_OBJECT (ud->builder, "hb_status"));
3312         gtk_status_icon_set_visible(si,
3313                         ghb_settings_get_boolean(ud->settings, "show_status"));
3314 }
3315
3316 G_MODULE_EXPORT void
3317 vqual_granularity_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3318 {
3319         g_debug("vqual_granularity_changed_cb");
3320         ghb_widget_to_setting (ud->settings, widget);
3321         ghb_check_dependency(ud, widget);
3322
3323         const gchar *name = gtk_widget_get_name(widget);
3324         ghb_pref_save(ud->settings, name);
3325
3326         gdouble vqmin, vqmax, step, page;
3327         gboolean inverted;
3328         gint digits;
3329
3330         ghb_vquality_range(ud, &vqmin, &vqmax, &step, &page, &digits, &inverted);
3331         GtkWidget *qp = GHB_WIDGET(ud->builder, "VideoQualitySlider");
3332         gtk_range_set_increments (GTK_RANGE(qp), step, page);
3333 }
3334
3335 G_MODULE_EXPORT void
3336 tweaks_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3337 {
3338         g_debug("tweaks_changed_cb");
3339         ghb_widget_to_setting (ud->settings, widget);
3340         const gchar *name = gtk_widget_get_name(widget);
3341         ghb_pref_save(ud->settings, name);
3342 }
3343
3344 G_MODULE_EXPORT void
3345 hbfd_feature_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3346 {
3347         g_debug("hbfd_feature_changed_cb");
3348         ghb_widget_to_setting (ud->settings, widget);
3349         const gchar *name = gtk_widget_get_name(widget);
3350         ghb_pref_save(ud->settings, name);
3351
3352         gboolean hbfd = ghb_settings_get_boolean(ud->settings, "hbfd_feature");
3353         GtkAction *action;
3354         if (hbfd)
3355         {
3356                 const GValue *val;
3357                 val = ghb_settings_get_value(ud->settings, "hbfd");
3358                 ghb_ui_update(ud, "hbfd", val);
3359         }
3360         action = GHB_ACTION (ud->builder, "hbfd");
3361         gtk_action_set_visible(action, hbfd);
3362 }
3363
3364 gboolean
3365 ghb_file_menu_add_dvd(signal_user_data_t *ud)
3366 {
3367         GList *link, *drives;
3368         static GtkActionGroup *agroup = NULL;
3369         static gint merge_id;
3370
3371         g_debug("ghb_file_menu_add_dvd()");
3372         link = drives = dvd_device_list();
3373         if (drives != NULL)
3374         {
3375                 GtkUIManager *ui = GTK_UI_MANAGER(
3376                         gtk_builder_get_object(ud->builder, "uimanager1"));
3377
3378                 if (agroup == NULL)
3379                 {
3380                         agroup = gtk_action_group_new("dvdgroup");
3381                         gtk_ui_manager_insert_action_group(ui, agroup, 0);
3382                 }
3383                 else
3384                         gtk_ui_manager_remove_ui(ui, merge_id);
3385
3386                 merge_id = gtk_ui_manager_new_merge_id(ui);
3387                 // Add separator
3388                 gtk_ui_manager_add_ui(ui, merge_id, 
3389                         "ui/menubar1/menuitem1/quit1", "dvdsep", NULL,
3390                         GTK_UI_MANAGER_SEPARATOR, TRUE);
3391
3392                 while (link != NULL)
3393                 {
3394                         GtkAction *action;
3395                         gchar *drive = get_dvd_device_name(link->data);
3396                         gchar *name = get_dvd_volume_name(link->data);
3397                 
3398                         action = gtk_action_group_get_action(agroup, drive);
3399                         if (action != NULL)
3400                         {
3401                                 gtk_action_group_remove_action(agroup, action);
3402                                 g_object_unref(G_OBJECT(action));
3403                         }
3404                         // Create action for this drive
3405                         action = gtk_action_new(drive, name,
3406                                 "Scan this DVD source", "gtk-cdrom");
3407                         // Add action to action group
3408                         gtk_action_group_add_action_with_accel(agroup, action, NULL);
3409                         // Add to ui manager
3410                         gtk_ui_manager_add_ui(ui, merge_id, 
3411                                 "ui/menubar1/menuitem1/dvdsep", drive, drive,
3412                                 GTK_UI_MANAGER_AUTO, TRUE);
3413                         // Connect signal to action (menu item)
3414                         g_signal_connect(action, "activate", 
3415                                 (GCallback)dvd_source_activate_cb, ud);
3416                         g_free(name);
3417                         g_free(drive);
3418                         free_drive(link->data);
3419                         link = link->next;
3420                 }
3421                 g_list_free(drives);
3422         }
3423         return FALSE;
3424 }
3425
3426 gboolean ghb_is_cd(GDrive *gd);
3427
3428 static GList*
3429 dvd_device_list()
3430 {
3431         GList *dvd_devices = NULL;
3432
3433 #if defined(_WIN32)
3434         gint ii, drives;
3435         gchar drive[5];
3436
3437         strcpy(drive, "A:" G_DIR_SEPARATOR_S);
3438         drives = GetLogicalDrives();
3439         for (ii = 0; ii < 26; ii++)
3440         {
3441                 if (drives & 0x01)
3442                 {
3443                         guint dtype;
3444
3445                         drive[0] = 'A' + ii;
3446                         dtype = GetDriveType(drive);
3447                         if (dtype == DRIVE_CDROM)
3448                         {
3449                                 dvd_devices = g_list_append(dvd_devices, 
3450                                                 (gpointer)g_strdup(drive));
3451                         }
3452                 }
3453                 drives >>= 1;
3454         }
3455 #else
3456         GVolumeMonitor *gvm;
3457         GList *drives, *link;
3458         
3459         gvm = g_volume_monitor_get ();
3460         drives = g_volume_monitor_get_connected_drives (gvm);
3461         link = drives;
3462         while (link != NULL)
3463         {
3464                 GDrive *gd;
3465                 
3466                 gd = (GDrive*)link->data;
3467                 if (ghb_is_cd(gd))
3468                 {
3469                         dvd_devices = g_list_append(dvd_devices, gd);
3470                 }
3471                 else
3472                         g_object_unref (gd);
3473                 link = link->next;
3474         }
3475         g_list_free(drives);
3476 #endif
3477
3478         return dvd_devices;
3479 }
3480
3481 #if !defined(_WIN32)
3482 static LibHalContext *hal_ctx;
3483 #endif
3484
3485 gboolean
3486 ghb_is_cd(GDrive *gd)
3487 {
3488 #if !defined(_WIN32)
3489         gchar *device;
3490         LibHalDrive *halDrive;
3491         LibHalDriveType dtype;
3492
3493         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3494         if (device == NULL)
3495                 return FALSE;
3496         halDrive = libhal_drive_from_device_file (hal_ctx, device);
3497         g_free(device);
3498         if (halDrive == NULL)
3499                 return FALSE;
3500         dtype = libhal_drive_get_type(halDrive);
3501         libhal_drive_free(halDrive);
3502         return (dtype == LIBHAL_DRIVE_TYPE_CDROM);
3503 #else
3504         return FALSE;
3505 #endif
3506 }
3507
3508 #if defined(_WIN32)
3509 static void
3510 handle_media_change(const gchar *device, gboolean insert, signal_user_data_t *ud)
3511 {
3512         guint dtype;
3513         static gint ins_count = 0;
3514         static gint rem_count = 0;
3515
3516         // The media change event in windows bounces around a bit
3517         // so I debounce it here
3518         // DVD insertion detected.  Scan it.
3519         dtype = GetDriveType(device);
3520         if (dtype != DRIVE_CDROM)
3521                 return;
3522         if (insert)
3523         {
3524                 rem_count = 0;
3525                 ins_count++;
3526                 if (ins_count == 2)
3527                 {
3528                         g_thread_create((GThreadFunc)ghb_cache_volnames, ud, FALSE, NULL);
3529                         if (ghb_settings_get_boolean(ud->settings, "AutoScan") &&
3530                                 ud->current_dvd_device != NULL &&
3531                                 strcmp(device, ud->current_dvd_device) == 0)
3532                         {
3533                                 show_scan_progress(ud);
3534                                 update_source_label(ud, device, TRUE);
3535                                 gint preview_count;
3536                                 preview_count = ghb_settings_get_int(ud->settings, "preview_count");
3537                                 ghb_settings_set_string(ud->settings, "source", device);
3538                                 start_scan(ud, device, 0, preview_count);
3539                         }
3540                 }
3541         }
3542         else
3543         {
3544                 ins_count = 0;
3545                 rem_count++;
3546                 if (rem_count == 2)
3547                 {
3548                         g_thread_create((GThreadFunc)ghb_cache_volnames, ud, FALSE, NULL);
3549                         if (ud->current_dvd_device != NULL &&
3550                                 strcmp(device, ud->current_dvd_device) == 0)
3551                         {
3552                                 ghb_hb_cleanup(TRUE);
3553                                 prune_logs(ud);
3554                                 ghb_settings_set_string(ud->settings, "source", "/dev/null");
3555                                 start_scan(ud, "/dev/null", 0, 1);
3556                         }
3557                 }
3558         }
3559 }
3560
3561 static gchar
3562 FindDriveFromMask(ULONG unitmask)
3563 {
3564         gchar cc;
3565         for (cc = 0; cc < 26; cc++)
3566         {
3567                 if (unitmask & 0x01)
3568                         return 'A' + cc;
3569                 unitmask >>= 1;
3570         }
3571         return 0;
3572 }
3573
3574 void
3575 wm_drive_changed(MSG *msg, signal_user_data_t *ud)
3576 {
3577         PDEV_BROADCAST_HDR bch = (PDEV_BROADCAST_HDR)msg->lParam;
3578         gchar drive[4];
3579
3580         g_strlcpy(drive, "A:" G_DIR_SEPARATOR_S, 4);
3581         switch (msg->wParam)
3582         {
3583                 case DBT_DEVICEARRIVAL:
3584                 {
3585                         if (bch->dbch_devicetype == DBT_DEVTYP_VOLUME)
3586                         {
3587                                 PDEV_BROADCAST_VOLUME bcv = (PDEV_BROADCAST_VOLUME)bch;
3588
3589                                 if (bcv->dbcv_flags & DBTF_MEDIA)
3590                                 {
3591                                         drive[0] = FindDriveFromMask(bcv->dbcv_unitmask);
3592                                         handle_media_change(drive, TRUE, ud);
3593                                 }
3594                         }
3595                 } break;
3596
3597                 case DBT_DEVICEREMOVECOMPLETE:
3598                 {
3599                         if (bch->dbch_devicetype == DBT_DEVTYP_VOLUME)
3600                         {
3601                                 PDEV_BROADCAST_VOLUME bcv = (PDEV_BROADCAST_VOLUME)bch;
3602
3603                                 if (bcv->dbcv_flags & DBTF_MEDIA)
3604                                 {
3605                                         drive[0] = FindDriveFromMask(bcv->dbcv_unitmask);
3606                                         handle_media_change(drive, FALSE, ud);
3607                                 }
3608                         }
3609                 } break;
3610                 default: ;
3611         }
3612 }
3613
3614 #else
3615
3616 G_MODULE_EXPORT void
3617 drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
3618 {
3619         gchar *device;
3620         gint state;
3621
3622         g_debug("drive_changed_cb()");
3623         g_thread_create((GThreadFunc)ghb_cache_volnames, ud, FALSE, NULL);
3624
3625         state = ghb_get_scan_state();
3626         device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
3627         if (ud->current_dvd_device == NULL ||
3628                 strcmp(device, ud->current_dvd_device) != 0 ||
3629                 state != GHB_STATE_IDLE )
3630         {
3631                 return;
3632         }
3633         if (g_drive_has_media(gd))
3634         {
3635                 if (ghb_settings_get_boolean(ud->settings, "AutoScan"))
3636                 {
3637                         show_scan_progress(ud);
3638                         update_source_label(ud, device, TRUE);
3639                         gint preview_count;
3640                         preview_count = ghb_settings_get_int(ud->settings, "preview_count");
3641                         ghb_settings_set_string(ud->settings, "source", device);
3642                         start_scan(ud, device, 0, preview_count);
3643                 }
3644         }
3645         else
3646         {
3647                 ghb_hb_cleanup(TRUE);
3648                 prune_logs(ud);
3649                 ghb_settings_set_string(ud->settings, "source", "/dev/null");
3650                 start_scan(ud, "/dev/null", 0, 1);
3651         }
3652 }
3653 #endif
3654
3655 #if !defined(_WIN32)
3656 static void
3657 dbus_init (void)
3658 {
3659         dbus_g_thread_init();
3660 }
3661
3662 #define GPM_DBUS_PM_SERVICE                     "org.freedesktop.PowerManagement"
3663 #define GPM_DBUS_PM_PATH                        "/org/freedesktop/PowerManagement"
3664 #define GPM_DBUS_PM_INTERFACE           "org.freedesktop.PowerManagement"
3665 #define GPM_DBUS_INHIBIT_PATH           "/org/freedesktop/PowerManagement/Inhibit"
3666 #define GPM_DBUS_INHIBIT_INTERFACE      "org.freedesktop.PowerManagement.Inhibit" 
3667 static gboolean gpm_inhibited = FALSE;
3668 static guint gpm_cookie = -1;
3669 #endif
3670
3671 static gboolean
3672 ghb_can_suspend_gpm()
3673 {
3674         gboolean can_suspend = FALSE;
3675 #if !defined(_WIN32)
3676         DBusGConnection *conn;
3677         DBusGProxy      *proxy;
3678         GError *error = NULL;
3679         gboolean res;
3680         
3681
3682         g_debug("ghb_can_suspend_gpm()");
3683         conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
3684         if (error != NULL)
3685         {
3686                 g_warning("DBUS cannot connect: %s", error->message);
3687                 g_error_free(error);
3688                 return FALSE;
3689         }
3690         proxy = dbus_g_proxy_new_for_name(conn, GPM_DBUS_PM_SERVICE,
3691                                                         GPM_DBUS_PM_PATH, GPM_DBUS_PM_INTERFACE);
3692         if (proxy == NULL)
3693         {
3694                 g_warning("Could not get DBUS proxy: %s", GPM_DBUS_PM_SERVICE);
3695                 dbus_g_connection_unref(conn);
3696                 return FALSE;
3697         }
3698         res = dbus_g_proxy_call(proxy, "CanSuspend", &error,
3699                                                         G_TYPE_INVALID,
3700                                                         G_TYPE_BOOLEAN, &can_suspend,
3701                                                         G_TYPE_INVALID);
3702         if (!res)
3703         {
3704                 if (error != NULL)
3705                 {
3706                         g_warning("CanSuspend failed: %s", error->message);
3707                         g_error_free(error);
3708                 }
3709                 else
3710                         g_warning("CanSuspend failed");
3711                 // Try to shutdown anyway
3712                 can_suspend = TRUE;
3713         }
3714         g_object_unref(G_OBJECT(proxy));
3715         dbus_g_connection_unref(conn);
3716 #endif
3717         return can_suspend;
3718 }
3719
3720 static void
3721 ghb_suspend_gpm()
3722 {
3723 #if !defined(_WIN32)
3724         DBusGConnection *conn;
3725         DBusGProxy      *proxy;
3726         GError *error = NULL;
3727         gboolean res;
3728         
3729
3730         g_debug("ghb_suspend_gpm()");
3731         conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
3732         if (error != NULL)
3733         {
3734                 g_warning("DBUS cannot connect: %s", error->message);
3735                 g_error_free(error);
3736                 return;
3737         }
3738         proxy = dbus_g_proxy_new_for_name(conn, GPM_DBUS_PM_SERVICE,
3739                                                         GPM_DBUS_PM_PATH, GPM_DBUS_PM_INTERFACE);
3740         if (proxy == NULL)
3741         {
3742                 g_warning("Could not get DBUS proxy: %s", GPM_DBUS_PM_SERVICE);
3743                 dbus_g_connection_unref(conn);
3744                 return;
3745         }
3746         res = dbus_g_proxy_call(proxy, "Suspend", &error,
3747                                                         G_TYPE_INVALID,
3748                                                         G_TYPE_INVALID);
3749         if (!res)
3750         {
3751                 if (error != NULL)
3752                 {
3753                         g_warning("Suspend failed: %s", error->message);
3754                         g_error_free(error);
3755                 }
3756                 else
3757                         g_warning("Suspend failed");
3758         }
3759         g_object_unref(G_OBJECT(proxy));
3760         dbus_g_connection_unref(conn);
3761 #endif
3762 }
3763
3764 static gboolean
3765 ghb_can_shutdown_gpm()
3766 {
3767         gboolean can_shutdown = FALSE;
3768 #if !defined(_WIN32)
3769         DBusGConnection *conn;
3770         DBusGProxy      *proxy;
3771         GError *error = NULL;
3772         gboolean res;
3773         
3774
3775         g_debug("ghb_can_shutdown_gpm()");
3776         conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
3777         if (error != NULL)
3778         {
3779                 g_warning("DBUS cannot connect: %s", error->message);
3780                 g_error_free(error);
3781                 return FALSE;
3782         }
3783         proxy = dbus_g_proxy_new_for_name(conn, GPM_DBUS_PM_SERVICE,
3784                                                         GPM_DBUS_PM_PATH, GPM_DBUS_PM_INTERFACE);
3785         if (proxy == NULL)
3786         {
3787                 g_warning("Could not get DBUS proxy: %s", GPM_DBUS_PM_SERVICE);
3788                 dbus_g_connection_unref(conn);
3789                 return FALSE;
3790         }
3791         res = dbus_g_proxy_call(proxy, "CanShutdown", &error,
3792                                                         G_TYPE_INVALID,
3793                                                         G_TYPE_BOOLEAN, &can_shutdown,
3794                                                         G_TYPE_INVALID);
3795         if (!res)
3796         {
3797                 if (error != NULL)
3798                 {
3799                         g_warning("CanShutdown failed: %s", error->message);
3800                         g_error_free(error);
3801                 }
3802                 else
3803                         g_warning("CanShutdown failed");
3804                 // Try to shutdown anyway
3805                 can_shutdown = TRUE;
3806         }
3807         g_object_unref(G_OBJECT(proxy));
3808         dbus_g_connection_unref(conn);
3809 #endif
3810         return can_shutdown;
3811 }
3812
3813 static void
3814 ghb_shutdown_gpm()
3815 {
3816 #if !defined(_WIN32)
3817         DBusGConnection *conn;
3818         DBusGProxy      *proxy;
3819         GError *error = NULL;
3820         gboolean res;
3821         
3822
3823         g_debug("ghb_shutdown_gpm()");
3824         conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
3825         if (error != NULL)
3826         {
3827                 g_warning("DBUS cannot connect: %s", error->message);
3828                 g_error_free(error);
3829                 return;
3830         }
3831         proxy = dbus_g_proxy_new_for_name(conn, GPM_DBUS_PM_SERVICE,
3832                                                         GPM_DBUS_PM_PATH, GPM_DBUS_PM_INTERFACE);
3833         if (proxy == NULL)
3834         {
3835                 g_warning("Could not get DBUS proxy: %s", GPM_DBUS_PM_SERVICE);
3836                 dbus_g_connection_unref(conn);
3837                 return;
3838         }
3839         res = dbus_g_proxy_call(proxy, "Shutdown", &error,
3840                                                         G_TYPE_INVALID,
3841                                                         G_TYPE_INVALID);
3842         if (!res)
3843         {
3844                 if (error != NULL)
3845                 {
3846                         g_warning("Shutdown failed: %s", error->message);
3847                         g_error_free(error);
3848                 }
3849                 else
3850                         g_warning("Shutdown failed");
3851         }
3852         g_object_unref(G_OBJECT(proxy));
3853         dbus_g_connection_unref(conn);
3854 #endif
3855 }
3856
3857 void
3858 ghb_inhibit_gpm()
3859 {
3860 #if !defined(_WIN32)
3861         DBusGConnection *conn;
3862         DBusGProxy      *proxy;
3863         GError *error = NULL;
3864         gboolean res;
3865         
3866
3867         if (gpm_inhibited)
3868         {
3869                 // Already inhibited
3870                 return;
3871         }
3872         g_debug("ghb_inhibit_gpm()");
3873         conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
3874         if (error != NULL)
3875         {
3876                 g_warning("DBUS cannot connect: %s", error->message);
3877                 g_error_free(error);
3878                 return;
3879         }
3880         proxy = dbus_g_proxy_new_for_name(conn, GPM_DBUS_PM_SERVICE,
3881                                                         GPM_DBUS_INHIBIT_PATH, GPM_DBUS_INHIBIT_INTERFACE);
3882         if (proxy == NULL)
3883         {
3884                 g_warning("Could not get DBUS proxy: %s", GPM_DBUS_PM_SERVICE);
3885                 dbus_g_connection_unref(conn);
3886                 return;
3887         }
3888         res = dbus_g_proxy_call(proxy, "Inhibit", &error,
3889                                                         G_TYPE_STRING, "ghb",
3890                                                         G_TYPE_STRING, "Encoding",
3891                                                         G_TYPE_INVALID,
3892                                                         G_TYPE_UINT, &gpm_cookie,
3893                                                         G_TYPE_INVALID);
3894         gpm_inhibited = TRUE;
3895         if (!res)
3896         {
3897                 if (error != NULL)
3898                 {
3899                         g_warning("Inhibit failed: %s", error->message);
3900                         g_error_free(error);
3901                         gpm_cookie = -1;
3902                 }
3903                 else
3904                         g_warning("Inhibit failed");
3905                 gpm_cookie = -1;
3906                 gpm_inhibited = FALSE;
3907         }
3908         g_object_unref(G_OBJECT(proxy));
3909         dbus_g_connection_unref(conn);
3910 #endif
3911 }
3912
3913 void
3914 ghb_uninhibit_gpm()
3915 {
3916 #if !defined(_WIN32)
3917         DBusGConnection *conn;
3918         DBusGProxy      *proxy;
3919         GError *error = NULL;
3920         gboolean res;
3921         
3922         g_debug("ghb_uninhibit_gpm() gpm_cookie %u", gpm_cookie);
3923
3924         if (!gpm_inhibited)
3925         {
3926                 // Not inhibited
3927                 return;
3928         }
3929         conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
3930         if (error != NULL)
3931         {
3932                 g_warning("DBUS cannot connect: %s", error->message);
3933                 g_error_free(error);
3934                 return;
3935         }
3936         proxy = dbus_g_proxy_new_for_name(conn, GPM_DBUS_PM_SERVICE,
3937                                                         GPM_DBUS_INHIBIT_PATH, GPM_DBUS_INHIBIT_INTERFACE);
3938         if (proxy == NULL)
3939         {
3940                 g_warning("Could not get DBUS proxy: %s", GPM_DBUS_PM_SERVICE);
3941                 dbus_g_connection_unref(conn);
3942                 return;
3943         }
3944         res = dbus_g_proxy_call(proxy, "UnInhibit", &error,
3945                                                         G_TYPE_UINT, gpm_cookie,
3946                                                         G_TYPE_INVALID,
3947                                                         G_TYPE_INVALID);
3948         if (!res)
3949         {
3950                 if (error != NULL)
3951                 {
3952                         g_warning("UnInhibit failed: %s", error->message);
3953                         g_error_free(error);
3954                 }
3955                 else
3956                         g_warning("UnInhibit failed");
3957         }
3958         gpm_inhibited = FALSE;
3959         dbus_g_connection_unref(conn);
3960         g_object_unref(G_OBJECT(proxy));
3961 #endif
3962 }
3963
3964 #if !defined(_WIN32)
3965
3966 // For inhibit and shutdown
3967 #define GPM_DBUS_SM_SERVICE                     "org.gnome.SessionManager"
3968 #define GPM_DBUS_SM_PATH                        "/org/gnome/SessionManager"
3969 #define GPM_DBUS_SM_INTERFACE           "org.gnome.SessionManager"
3970
3971 #endif
3972
3973 static gboolean
3974 ghb_can_shutdown_gsm()
3975 {
3976         gboolean can_shutdown = FALSE;
3977 #if !defined(_WIN32)
3978         DBusGConnection *conn;
3979         DBusGProxy      *proxy;
3980         GError *error = NULL;
3981         gboolean res;
3982         
3983
3984         g_debug("ghb_can_shutdown_gpm()");
3985         conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
3986         if (error != NULL)
3987         {
3988                 g_warning("DBUS cannot connect: %s", error->message);
3989                 g_error_free(error);
3990                 return FALSE;
3991         }
3992         proxy = dbus_g_proxy_new_for_name(conn, GPM_DBUS_SM_SERVICE,
3993                                                         GPM_DBUS_SM_PATH, GPM_DBUS_SM_INTERFACE);
3994         if (proxy == NULL)
3995         {
3996                 g_warning("Could not get DBUS proxy: %s", GPM_DBUS_SM_SERVICE);
3997                 dbus_g_connection_unref(conn);
3998                 return FALSE;
3999         }
4000         res = dbus_g_proxy_call(proxy, "CanShutdown", &error,
4001                                                         G_TYPE_INVALID,
4002                                                         G_TYPE_BOOLEAN, &can_shutdown,
4003                                                         G_TYPE_INVALID);
4004         g_object_unref(G_OBJECT(proxy));
4005         dbus_g_connection_unref(conn);
4006         if (!res)
4007         {
4008                 if (error != NULL)
4009                 {
4010                         g_error_free(error);
4011                 }
4012                 // Try to shutdown anyway
4013                 can_shutdown = TRUE;
4014                 // Try the gpm version
4015                 return ghb_can_shutdown_gpm();
4016         }
4017 #endif
4018         return can_shutdown;
4019 }
4020
4021 static void
4022 ghb_shutdown_gsm()
4023 {
4024 #if !defined(_WIN32)
4025         DBusGConnection *conn;
4026         DBusGProxy      *proxy;
4027         GError *error = NULL;
4028         gboolean res;
4029         
4030
4031         g_debug("ghb_shutdown_gpm()");
4032         conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
4033         if (error != NULL)
4034         {
4035                 g_warning("DBUS cannot connect: %s", error->message);
4036                 g_error_free(error);
4037                 return;
4038         }
4039         proxy = dbus_g_proxy_new_for_name(conn, GPM_DBUS_SM_SERVICE,
4040                                                         GPM_DBUS_SM_PATH, GPM_DBUS_SM_INTERFACE);
4041         if (proxy == NULL)
4042         {
4043                 g_warning("Could not get DBUS proxy: %s", GPM_DBUS_SM_SERVICE);
4044                 dbus_g_connection_unref(conn);
4045                 return;
4046         }
4047         res = dbus_g_proxy_call(proxy, "Shutdown", &error,
4048                                                         G_TYPE_INVALID,
4049                                                         G_TYPE_INVALID);
4050         g_object_unref(G_OBJECT(proxy));
4051         dbus_g_connection_unref(conn);
4052         if (!res)
4053         {
4054                 if (error != NULL)
4055                 {
4056                         g_error_free(error);
4057                 }
4058                 // Try the gpm version
4059                 ghb_shutdown_gpm();
4060         }
4061 #endif
4062 }
4063
4064 void
4065 ghb_inhibit_gsm(signal_user_data_t *ud)
4066 {
4067 #if !defined(_WIN32)
4068         DBusGConnection *conn;
4069         DBusGProxy      *proxy;
4070         GError *error = NULL;
4071         gboolean res;
4072         guint xid;
4073         GtkWidget *widget;
4074         
4075
4076         if (gpm_inhibited)
4077         {
4078                 // Already inhibited
4079                 return;
4080         }
4081         g_debug("ghb_inhibit_gsm()");
4082         conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
4083         if (error != NULL)
4084         {
4085                 g_warning("DBUS cannot connect: %s", error->message);
4086                 g_error_free(error);
4087                 return;
4088         }
4089         proxy = dbus_g_proxy_new_for_name(conn, GPM_DBUS_SM_SERVICE,
4090                                                         GPM_DBUS_SM_PATH, GPM_DBUS_SM_INTERFACE);
4091         if (proxy == NULL)
4092         {
4093                 g_warning("Could not get DBUS proxy: %s", GPM_DBUS_SM_SERVICE);
4094                 dbus_g_connection_unref(conn);
4095                 return;
4096         }
4097         widget = GHB_WIDGET(ud->builder, "hb_window");
4098         xid = GDK_DRAWABLE_XID(widget->window);
4099         res = dbus_g_proxy_call(proxy, "Inhibit", &error,
4100                                                         G_TYPE_STRING, "ghb",
4101                                                         G_TYPE_UINT, xid,
4102                                                         G_TYPE_STRING, "Encoding",
4103                                                         G_TYPE_UINT, 1 | 4,
4104                                                         G_TYPE_INVALID,
4105                                                         G_TYPE_UINT, &gpm_cookie,
4106                                                         G_TYPE_INVALID);
4107         gpm_inhibited = TRUE;
4108         g_object_unref(G_OBJECT(proxy));
4109         dbus_g_connection_unref(conn);
4110         if (!res)
4111         {
4112                 if (error != NULL)
4113                 {
4114                         g_error_free(error);
4115                         gpm_cookie = -1;
4116                 }
4117                 gpm_cookie = -1;
4118                 gpm_inhibited = FALSE;
4119                 // Try the gpm version
4120                 ghb_inhibit_gpm();
4121         }
4122 #endif
4123 }
4124
4125 void
4126 ghb_uninhibit_gsm()
4127 {
4128 #if !defined(_WIN32)
4129         DBusGConnection *conn;
4130         DBusGProxy      *proxy;
4131         GError *error = NULL;
4132         gboolean res;
4133         
4134         g_debug("ghb_uninhibit_gsm() gpm_cookie %u", gpm_cookie);
4135
4136         if (!gpm_inhibited)
4137         {
4138                 // Not inhibited
4139                 return;
4140         }
4141         conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
4142         if (error != NULL)
4143         {
4144                 g_warning("DBUS cannot connect: %s", error->message);
4145                 g_error_free(error);
4146                 return;
4147         }
4148         proxy = dbus_g_proxy_new_for_name(conn, GPM_DBUS_SM_SERVICE,
4149                                                         GPM_DBUS_SM_PATH, GPM_DBUS_SM_INTERFACE);
4150         if (proxy == NULL)
4151         {
4152                 g_warning("Could not get DBUS proxy: %s", GPM_DBUS_SM_SERVICE);
4153                 dbus_g_connection_unref(conn);
4154                 return;
4155         }
4156         res = dbus_g_proxy_call(proxy, "Uninhibit", &error,
4157                                                         G_TYPE_UINT, gpm_cookie,
4158                                                         G_TYPE_INVALID,
4159                                                         G_TYPE_INVALID);
4160         dbus_g_connection_unref(conn);
4161         g_object_unref(G_OBJECT(proxy));
4162         if (!res)
4163         {
4164                 if (error != NULL)
4165                 {
4166                         g_error_free(error);
4167                 }
4168                 ghb_uninhibit_gpm();
4169         }
4170         gpm_inhibited = FALSE;
4171 #endif
4172 }
4173
4174 void
4175 ghb_hal_init()
4176 {
4177 #if !defined(_WIN32)
4178         DBusGConnection *gconn;
4179         DBusConnection *conn;
4180         GError *gerror = NULL;
4181         DBusError error;
4182         char **devices;
4183         int nr;
4184
4185         dbus_init ();
4186
4187         if (!(hal_ctx = libhal_ctx_new ())) {
4188                 g_warning ("failed to create a HAL context!");
4189                 return;
4190         }
4191
4192         gconn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &gerror);
4193         if (gerror != NULL)
4194         {
4195                 g_warning("DBUS cannot connect: %s", gerror->message);
4196                 g_error_free(gerror);
4197                 return;
4198         }
4199         conn = dbus_g_connection_get_connection(gconn);
4200         libhal_ctx_set_dbus_connection (hal_ctx, conn);
4201         dbus_error_init (&error);
4202         if (!libhal_ctx_init (hal_ctx, &error)) {
4203                 g_warning ("libhal_ctx_init failed: %s", error.message ? error.message : "unknown");
4204                 dbus_error_free (&error);
4205                 libhal_ctx_free (hal_ctx);
4206                 dbus_g_connection_unref(gconn);
4207                 return;
4208         }
4209
4210         /*
4211          * Do something to ping the HAL daemon - the above functions will
4212          * succeed even if hald is not running, so long as DBUS is.  But we
4213          * want to exit silently if hald is not running, to behave on
4214          * pre-2.6 systems.
4215          */
4216         if (!(devices = libhal_get_all_devices (hal_ctx, &nr, &error))) {
4217                 g_warning ("seems that HAL is not running: %s", error.message ? error.message : "unknown");
4218                 dbus_error_free (&error);
4219
4220                 libhal_ctx_shutdown (hal_ctx, NULL);
4221                 libhal_ctx_free (hal_ctx);
4222                 dbus_g_connection_unref(gconn);
4223                 return;
4224         }
4225
4226         libhal_free_string_array (devices);
4227         dbus_g_connection_unref(gconn);
4228 #endif
4229 }
4230
4231 G_MODULE_EXPORT gboolean 
4232 tweak_setting_cb(
4233         GtkWidget *widget, 
4234         GdkEventButton *event, 
4235         signal_user_data_t *ud)
4236 {
4237         const gchar *name;
4238         gchar *tweak_name;
4239         gboolean ret = FALSE;
4240         gboolean allow_tweaks;
4241
4242         g_debug("press %d %d", event->type, event->button);
4243         allow_tweaks = ghb_settings_get_boolean(ud->settings, "allow_tweaks");
4244         if (allow_tweaks && event->type == GDK_BUTTON_PRESS && event->button == 3)
4245         { // Its a right mouse click
4246                 GtkWidget *dialog;
4247                 GtkEntry *entry;
4248                 GtkResponseType response;
4249                 gchar *tweak = NULL;
4250
4251                 name = gtk_widget_get_name(widget);
4252                 if (g_str_has_prefix(name, "tweak_"))
4253                 {
4254                         tweak_name = g_strdup(name);
4255                 }
4256                 else
4257                 {
4258                         tweak_name = g_strdup_printf("tweak_%s", name);
4259                 }
4260
4261                 tweak = ghb_settings_get_string (ud->settings, tweak_name);
4262                 dialog = GHB_WIDGET(ud->builder, "tweak_dialog");
4263                 gtk_window_set_title(GTK_WINDOW(dialog), tweak_name);
4264                 entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "tweak_setting"));
4265                 if (tweak)
4266                 {
4267                         gtk_entry_set_text(entry, tweak);
4268                         g_free(tweak);
4269                 }
4270                 response = gtk_dialog_run(GTK_DIALOG(dialog));
4271                 gtk_widget_hide(dialog);
4272                 if (response == GTK_RESPONSE_OK)
4273                 {
4274                         tweak = (gchar*)gtk_entry_get_text(entry);
4275                         if (ghb_validate_filter_string(tweak, -1))
4276                                 ghb_settings_set_string(ud->settings, tweak_name, tweak);
4277                         else
4278                         {
4279                                 gchar *message;
4280                                 message = g_strdup_printf(
4281                                                         "Invalid Settings:\n%s",
4282                                                         tweak);
4283                                 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
4284                                 g_free(message);
4285                         }
4286                 }
4287                 g_free(tweak_name);
4288                 ret = TRUE;
4289         }
4290         return ret;
4291 }
4292
4293 G_MODULE_EXPORT gboolean 
4294 easter_egg_cb(
4295         GtkWidget *widget, 
4296         GdkEventButton *event, 
4297         signal_user_data_t *ud)
4298 {
4299         g_debug("press %d %d", event->type, event->button);
4300         if (event->type == GDK_3BUTTON_PRESS && event->button == 1)
4301         { // Its a tripple left mouse button click
4302                 GtkWidget *widget;
4303                 widget = GHB_WIDGET(ud->builder, "allow_tweaks");
4304                 gtk_widget_show(widget);
4305                 widget = GHB_WIDGET(ud->builder, "hbfd_feature");
4306                 gtk_widget_show(widget);
4307         }
4308         else if (event->type == GDK_BUTTON_PRESS && event->button == 1)
4309         {
4310                 GtkWidget *widget;
4311                 widget = GHB_WIDGET(ud->builder, "allow_tweaks");
4312                 gtk_widget_hide(widget);
4313                 widget = GHB_WIDGET(ud->builder, "hbfd_feature");
4314                 gtk_widget_hide(widget);
4315         }
4316         return FALSE;
4317 }
4318
4319 G_MODULE_EXPORT gchar*
4320 format_deblock_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
4321 {
4322         if (val < 5.0)
4323         {
4324                 return g_strdup_printf("Off");
4325         }
4326         else
4327         {
4328                 return g_strdup_printf("%d", (gint)val);
4329         }
4330 }
4331
4332 G_MODULE_EXPORT gchar*
4333 format_drc_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
4334 {
4335         if (val <= 0.0)
4336         {
4337                 return g_strdup_printf("Off");
4338         }
4339         else
4340         {
4341                 return g_strdup_printf("%.1f", val);
4342         }
4343 }
4344
4345 G_MODULE_EXPORT gchar*
4346 format_vquality_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
4347 {
4348         gdouble percent;
4349
4350         gint vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
4351         switch (vcodec)
4352         {
4353                 case HB_VCODEC_X264:
4354                 {
4355                         gboolean crf;
4356                         crf = ghb_settings_get_boolean(ud->settings, "constant_rate_factor");
4357                         percent = 100. * (51 - val) / 51.;
4358                         if (crf)
4359                                 return g_strdup_printf("RF: %.4g (%.0f%%)", val, percent);
4360                         else
4361                                 return g_strdup_printf("QP: %.4g (%.0f%%)", val, percent);
4362                 } break;
4363
4364                 case HB_VCODEC_FFMPEG:
4365                 {
4366                         percent = 100. * (30 - (val - 1)) / 30.;
4367                         return g_strdup_printf("QP: %d (%.0f%%)", (int)val, percent);
4368                 } break;
4369
4370                 case HB_VCODEC_THEORA:
4371                 {
4372                         percent = 100. * val / 63.;
4373                         return g_strdup_printf("QP: %d (%.0f%%)", (int)val, percent);
4374                 } break;
4375
4376                 default:
4377                 {
4378                         percent = 0;
4379                 } break;
4380         }
4381         return g_strdup_printf("QP: %.1f / %.1f%%", val, percent);
4382 }
4383
4384 static void
4385 process_appcast(signal_user_data_t *ud)
4386 {
4387         gchar *description = NULL, *build = NULL, *version = NULL, *msg;
4388 #if !defined(_WIN32)
4389         GtkWidget *window;
4390         static GtkWidget *html = NULL;
4391 #endif
4392         GtkWidget *dialog, *label;
4393         gint    response, ibuild = 0, skip;
4394
4395         if (ud->appcast == NULL || ud->appcast_len < 15 || 
4396                 strncmp(&(ud->appcast[9]), "200 OK", 6))
4397         {
4398                 goto done;
4399         }
4400         ghb_appcast_parse(ud->appcast, &description, &build, &version);
4401         if (build)
4402                 ibuild = g_strtod(build, NULL);
4403         skip = ghb_settings_get_int(ud->settings, "update_skip_version");
4404         if (description == NULL || build == NULL || version == NULL 
4405                 || ibuild <= hb_get_build(NULL) || skip == ibuild)
4406         {
4407                 goto done;
4408         }
4409         msg = g_strdup_printf("HandBrake %s/%s is now available (you have %s/%d).",
4410                         version, build, hb_get_version(NULL), hb_get_build(NULL));
4411         label = GHB_WIDGET(ud->builder, "update_message");
4412         gtk_label_set_text(GTK_LABEL(label), msg);
4413
4414 #if !defined(_WIN32)
4415         if (html == NULL)
4416         {
4417                 html = webkit_web_view_new();
4418                 window = GHB_WIDGET(ud->builder, "update_scroll");
4419                 gtk_container_add(GTK_CONTAINER(window), html);
4420                 // Show it
4421                 gtk_widget_set_size_request(html, 420, 240);
4422                 gtk_widget_show(html);
4423         }
4424         webkit_web_view_open(WEBKIT_WEB_VIEW(html), description);
4425 #endif
4426         dialog = GHB_WIDGET(ud->builder, "update_dialog");
4427         response = gtk_dialog_run(GTK_DIALOG(dialog));
4428         gtk_widget_hide(dialog);
4429         if (response == GTK_RESPONSE_OK)
4430         {
4431                 // Skip
4432                 ghb_settings_set_int(ud->settings, "update_skip_version", ibuild);
4433                 ghb_pref_save(ud->settings, "update_skip_version");
4434         }
4435         g_free(msg);
4436
4437 done:
4438         if (description) g_free(description);
4439         if (build) g_free(build);
4440         if (version) g_free(version);
4441         g_free(ud->appcast);
4442         ud->appcast_len = 0;
4443         ud->appcast = NULL;
4444         appcast_busy = FALSE;
4445 }
4446
4447 void
4448 ghb_net_close(GIOChannel *ioc)
4449 {
4450         gint fd;
4451
4452         g_debug("ghb_net_close");
4453         if (ioc == NULL) return;
4454         fd = g_io_channel_unix_get_fd(ioc);
4455         close(fd);
4456         g_io_channel_unref(ioc);
4457 }
4458
4459 G_MODULE_EXPORT gboolean
4460 ghb_net_recv_cb(GIOChannel *ioc, GIOCondition cond, gpointer data)
4461 {
4462         gchar buf[2048];
4463         gsize len;
4464         GError *gerror = NULL;
4465         GIOStatus status;
4466         
4467         g_debug("ghb_net_recv_cb");
4468         signal_user_data_t *ud = (signal_user_data_t*)data;
4469
4470         status = g_io_channel_read_chars (ioc, buf, 2048, &len, &gerror);
4471         if ((status == G_IO_STATUS_NORMAL || status == G_IO_STATUS_EOF) &&
4472                 len > 0)
4473         {
4474                 gint new_len = ud->appcast_len + len;
4475                 ud->appcast = g_realloc(ud->appcast, new_len + 1);
4476                 memcpy(&(ud->appcast[ud->appcast_len]), buf, len);
4477                 ud->appcast_len = new_len;
4478         }
4479         if (status == G_IO_STATUS_EOF)
4480         {
4481                 ud->appcast[ud->appcast_len] = 0;
4482                 ghb_net_close(ioc);
4483                 process_appcast(ud);
4484                 return FALSE;
4485         }
4486         return TRUE;
4487 }
4488
4489 GIOChannel*
4490 ghb_net_open(signal_user_data_t *ud, gchar *address, gint port)
4491 {
4492         GIOChannel *ioc;
4493         gint fd;
4494
4495         struct sockaddr_in   sock;
4496         struct hostent     * host;
4497
4498         g_debug("ghb_net_open");
4499         if( !( host = gethostbyname( address ) ) )
4500         {
4501                 g_warning( "gethostbyname failed (%s)", address );
4502                 appcast_busy = FALSE;
4503                 return NULL;
4504         }
4505
4506         memset( &sock, 0, sizeof( struct sockaddr_in ) );
4507         sock.sin_family = host->h_addrtype;
4508         sock.sin_port   = htons( port );
4509         memcpy( &sock.sin_addr, host->h_addr, host->h_length );
4510
4511         fd = socket(host->h_addrtype, SOCK_STREAM, 0);
4512         if( fd < 0 )
4513         {
4514                 g_debug( "socket failed" );
4515                 appcast_busy = FALSE;
4516                 return NULL;
4517         }
4518
4519         if(connect(fd, (struct sockaddr*)&sock, sizeof(struct sockaddr_in )) < 0 )
4520         {
4521                 g_debug( "connect failed" );
4522                 appcast_busy = FALSE;
4523                 return NULL;
4524         }
4525         ioc = g_io_channel_unix_new(fd);
4526         g_io_channel_set_encoding (ioc, NULL, NULL);
4527         g_io_channel_set_flags(ioc, G_IO_FLAG_NONBLOCK, NULL);
4528         g_io_add_watch (ioc, G_IO_IN, ghb_net_recv_cb, (gpointer)ud );
4529
4530         return ioc;
4531 }
4532
4533 gpointer
4534 ghb_check_update(signal_user_data_t *ud)
4535 {
4536         gchar *query;
4537         gsize len;
4538         GIOChannel *ioc;
4539         GError *gerror = NULL;
4540         GRegex *regex;
4541         GMatchInfo *mi;
4542         gchar *host, *appcast;
4543
4544         g_debug("ghb_check_update");
4545         appcast_busy = TRUE;
4546         regex = g_regex_new("^http://(.+)/(.+)$", 0, 0, NULL);
4547         if (!g_regex_match(regex, HB_PROJECT_URL_APPCAST, 0, &mi))
4548         {
4549                 return NULL;
4550         }
4551
4552         host = g_match_info_fetch(mi, 1);
4553         appcast = g_match_info_fetch(mi, 2);
4554
4555         if (host == NULL || appcast == NULL)
4556                 return NULL;
4557
4558         query = g_strdup_printf( "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n",
4559                                                         appcast, host);
4560
4561         ioc = ghb_net_open(ud, host, 80);
4562         if (ioc == NULL)
4563                 return NULL;
4564
4565         g_io_channel_write_chars(ioc, query, strlen(query), &len, &gerror);
4566         g_io_channel_flush(ioc, &gerror);
4567         g_free(query);
4568         g_free(host);
4569         g_free(appcast);
4570         g_match_info_free(mi);
4571         g_regex_unref(regex);
4572         return NULL;
4573 }
4574
4575 G_MODULE_EXPORT gboolean
4576 hb_visibility_event_cb(
4577         GtkWidget *widget, 
4578         GdkEventVisibility *vs, 
4579         signal_user_data_t *ud)
4580 {
4581         ud->hb_visibility = vs->state;
4582         return FALSE;
4583 }
4584
4585 G_MODULE_EXPORT void
4586 status_activate_cb(GtkStatusIcon *si, signal_user_data_t *ud)
4587 {
4588         GtkWindow *window;
4589         GdkWindowState state;
4590
4591         window = GTK_WINDOW(GHB_WIDGET(ud->builder, "hb_window"));
4592         state = gdk_window_get_state(GTK_WIDGET(window)->window);
4593         if ((state & GDK_WINDOW_STATE_ICONIFIED) ||
4594                 (ud->hb_visibility != GDK_VISIBILITY_UNOBSCURED))
4595         {
4596                 gtk_window_present(window);
4597                 gtk_window_set_skip_taskbar_hint(window, FALSE);
4598         }
4599         else
4600         {
4601                 gtk_window_set_skip_taskbar_hint(window, TRUE);
4602                 gtk_window_iconify(window);
4603         }
4604 }
4605
4606 #if !defined(_WIN32)
4607 G_MODULE_EXPORT void
4608 notify_closed_cb(NotifyNotification *notification, signal_user_data_t *ud)
4609 {
4610         g_object_unref(G_OBJECT(notification));
4611 }
4612 #endif
4613
4614 void
4615 ghb_notify_done(signal_user_data_t *ud)
4616 {
4617         GtkStatusIcon *si;
4618
4619         if (ghb_settings_combo_int(ud->settings, "WhenComplete") == 0)
4620                 return;
4621
4622         si = GTK_STATUS_ICON(GHB_OBJECT(ud->builder, "hb_status"));
4623
4624 #if !defined(_WIN32)
4625         NotifyNotification *notification;
4626         notification = notify_notification_new(
4627                 "Encode Complete",
4628                 "Put down that cocktail, Your HandBrake queue is done!",
4629                 "hb-icon",
4630                 NULL);
4631         notify_notification_attach_to_status_icon(notification, si);
4632         g_signal_connect(notification, "closed", (GCallback)notify_closed_cb, ud);
4633         notify_notification_show(notification, NULL);
4634 #endif
4635
4636         if (ghb_settings_combo_int(ud->settings, "WhenComplete") == 3)
4637         {
4638                 if (ghb_can_shutdown_gsm())
4639                 {
4640                         ghb_countdown_dialog(GTK_MESSAGE_WARNING, 
4641                                 "Your encode is complete.",
4642                                 "Shutting down the computer", 
4643                                 "Cancel", (GSourceFunc)shutdown_cb, 60);
4644                 }
4645         }
4646         if (ghb_settings_combo_int(ud->settings, "WhenComplete") == 2)
4647         {
4648                 if (ghb_can_suspend_gpm())
4649                 {
4650                         ghb_countdown_dialog(GTK_MESSAGE_WARNING, 
4651                                 "Your encode is complete.",
4652                                 "Putting computer to sleep", 
4653                                 "Cancel", (GSourceFunc)suspend_cb, 60);
4654                 }
4655         }
4656 }