OSDN Git Service

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