OSDN Git Service

SunOS support fixed with new ffmpeg and x264
[handbrake-jp/handbrake-jp-git.git] / gtk / src / queuehandler.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 #include <gtk/gtk.h>
15 #include <gdk/gdkkeysyms.h>
16 #include <glib/gstdio.h>
17 #include <gio/gio.h>
18 #include "hb.h"
19 #include "settings.h"
20 #include "hb-backend.h"
21 #include "values.h"
22 #include "callbacks.h"
23 #include "presets.h"
24 #include "ghb-dvd.h"
25
26 void
27 queue_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
28 {
29         GtkTreeModel *store;
30         GtkTreeIter iter, piter;
31         
32         g_debug("queue_list_selection_changed_cb ()");
33         // A queue entry is made up of a parent and multiple
34         // children that are visible when expanded.  When and entry
35         // is selected, I want the parent to be selected.
36         // This is purely cosmetic.
37         if (gtk_tree_selection_get_selected(selection, &store, &iter))
38         {
39                 GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_edit");
40                 gtk_widget_set_sensitive (widget, TRUE);
41                 if (gtk_tree_model_iter_parent (store, &piter, &iter))
42                 {
43                         GtkTreePath *path;
44                         GtkTreeView *treeview;
45                         
46                         gtk_tree_selection_select_iter (selection, &piter);
47                         path = gtk_tree_model_get_path (store, &piter);
48                         treeview = gtk_tree_selection_get_tree_view (selection);
49                         // Make the parent visible in scroll window if it is not.
50                         gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
51                         gtk_tree_path_free(path);
52                 }
53         }
54         else
55         {
56                 GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_edit");
57                 gtk_widget_set_sensitive (widget, FALSE);
58         }
59 }
60
61 static void
62 add_to_queue_list(signal_user_data_t *ud, GValue *settings, GtkTreeIter *piter)
63 {
64         GtkTreeView *treeview;
65         GtkTreeIter iter;
66         GtkTreeStore *store;
67         gchar *info;
68         gint status;
69         GtkTreeIter citer;
70         gchar *dest, *preset, *vol_name, *basename;
71         const gchar *vcodec, *container;
72         gchar *fps, *vcodec_abbr;
73         gint title, start_chapter, end_chapter, width, height, vqvalue;
74         gint source_width, source_height;
75         gboolean pass2, anamorphic, round_dim, keep_aspect, vqtype, turbo;
76         gboolean tweaks;
77         
78         g_debug("update_queue_list ()");
79         if (settings == NULL) return;
80         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
81         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
82                 
83         tweaks = ghb_settings_get_boolean(settings, "allow_tweaks");
84         title = ghb_settings_combo_int(settings, "title");
85         start_chapter = ghb_settings_get_int(settings, "start_chapter");
86         end_chapter = ghb_settings_get_int(settings, "end_chapter");
87         pass2 = ghb_settings_get_boolean(settings, "two_pass");
88         vol_name = ghb_settings_get_string(settings, "volume_label");
89         dest = ghb_settings_get_string(settings, "destination");
90         basename = g_path_get_basename(dest);
91         info = g_strdup_printf 
92         (
93                 "<big><b>%s</b></big> "
94                 "<small>(Title %d, Chapters %d through %d, %d Video %s)"
95                 " --> %s</small>",
96                  vol_name, title+1, start_chapter, end_chapter, 
97                  pass2 ? 2:1, pass2 ? "Passes":"Pass", basename
98         );
99
100         if (piter)
101                 iter = *piter;
102         else
103                 gtk_tree_store_append(store, &iter, NULL);
104
105         gtk_tree_store_set(store, &iter, 1, info, 2, "hb-queue-delete", -1);
106         g_free(info);
107         status = ghb_settings_get_int(settings, "job_status");
108         switch (status)
109         {
110                 case GHB_QUEUE_PENDING:
111                         gtk_tree_store_set(store, &iter, 0, "hb-queue-job", -1);
112                         break;
113                 case GHB_QUEUE_CANCELED:
114                         gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
115                         break;
116                 case GHB_QUEUE_RUNNING:
117                         gtk_tree_store_set(store, &iter, 0, "hb-working0", -1);
118                         break;
119                 case GHB_QUEUE_DONE:
120                         gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
121                         break;
122                 default:
123                         gtk_tree_store_set(store, &iter, 0, "hb-queue-job", -1);
124                         break;
125         }
126
127         GString *str = g_string_new("");
128         gboolean markers;
129         gboolean preset_modified;
130         gint mux;
131         const GValue *path;
132
133         container = ghb_settings_combo_option(settings, "container");
134         mux = ghb_settings_combo_int(settings, "container");
135         preset_modified = ghb_settings_get_boolean(settings, "preset_modified");
136         path = ghb_settings_get_value(settings, "preset");
137         preset = ghb_preset_path_string(path);
138         markers = ghb_settings_get_boolean(settings, "chapter_markers");
139
140         if (preset_modified)
141                 g_string_append_printf(str, 
142                         "<b>Customized Preset Based On:</b> <small>%s</small>\n", 
143                         preset);
144         else
145                 g_string_append_printf(str, 
146                         "<b>Preset:</b> <small>%s</small>\n", 
147                         preset);
148
149         if (markers)
150         {
151                 g_string_append_printf(str, 
152                         "<b>Format:</b> <small>%s Container, Chapter Markers</small>\n", 
153                         container);
154         }
155         else
156         {
157                 g_string_append_printf(str, 
158                         "<b>Format:</b> <small>%s Container</small>\n", container);
159         }
160         if (mux == HB_MUX_MP4)
161         {
162                 gboolean ipod, http, large;
163
164                 ipod = ghb_settings_get_boolean(settings, "ipod_file");
165                 http = ghb_settings_get_boolean(settings, "http_optimize_mp4");
166                 large = ghb_settings_get_boolean(settings, "large_mp4");
167                 if (http || ipod || large)
168                 {
169                         g_string_append_printf(str, "<b>MP4 Options:</b><small>");
170                         if (ipod)
171                                 g_string_append_printf(str, " - iPod 5G Support");
172                         if (http)
173                                 g_string_append_printf(str, " - Web Optimized");
174                         if (large)
175                                 g_string_append_printf(str, " - Large File Size (>4GB)");
176                         g_string_append_printf(str, "</small>\n");
177                 }
178         }
179         g_string_append_printf(str, 
180                 "<b>Destination:</b> <small>%s</small>\n", dest);
181
182         width = ghb_settings_get_int(settings, "scale_width");
183         height = ghb_settings_get_int(settings, "scale_height");
184         anamorphic = ghb_settings_get_boolean(settings, "anamorphic");
185         round_dim = ghb_settings_get_boolean(settings, "round_dimensions");
186         keep_aspect = ghb_settings_get_boolean(settings, "keep_aspect");
187
188         gchar *aspect_desc;
189         if (anamorphic)
190         {
191                 if (round_dim)
192                 {
193                         aspect_desc = "(Anamorphic)";
194                 }
195                 else
196                 {
197                         aspect_desc = "(Strict Anamorphic)";
198                 }
199         }
200         else
201         {
202                 if (keep_aspect)
203                 {
204                         aspect_desc = "(Aspect Preserved)";
205                 }
206                 else
207                 {
208                         aspect_desc = "(Aspect Lost)";
209                 }
210         }
211         vqtype = ghb_settings_get_boolean(settings, "vquality_type_constant");
212         vqvalue = 0;
213
214         gchar *vq_desc = "Error";
215         gchar *vq_units = "";
216         if (!vqtype)
217         {
218                 vqtype = ghb_settings_get_boolean(settings, "vquality_type_target");
219                 if (!vqtype)
220                 {
221                         // Has to be bitrate
222                         vqvalue = ghb_settings_get_int(settings, "video_bitrate");
223                         vq_desc = "Bitrate:";
224                         vq_units = "kbps";
225                 }
226                 else
227                 {
228                         // Target file size
229                         vqvalue = ghb_settings_get_int(settings, "video_target_size");
230                         vq_desc = "Target Size:";
231                         vq_units = "MB";
232                 }
233         }
234         else
235         {
236                 // Constant quality
237                 vqvalue = ghb_settings_get_int(settings, "video_quality");
238                 vq_desc = "Constant Quality:";
239         }
240         fps = ghb_settings_get_string(settings, "framerate");
241         if (strcmp("source", fps) == 0)
242         {
243                 g_free(fps);
244                 if (ghb_settings_get_boolean(settings, "detelecine"))
245                         fps = g_strdup("Same As Source (vfr detelecine)");
246                 else
247                         fps = g_strdup("Same As Source (variable)");
248         }
249         else
250         {
251                 gchar *tmp;
252                 tmp = g_strdup_printf("%s (constant frame rate)", fps);
253                 g_free(fps);
254                 fps = tmp;
255         }
256         vcodec = ghb_settings_combo_option(settings, "video_codec");
257         vcodec_abbr = ghb_settings_get_string(settings, "video_codec");
258         source_width = ghb_settings_get_int(settings, "source_width");
259         source_height = ghb_settings_get_int(settings, "source_height");
260         g_string_append_printf(str,
261                 "<b>Picture:</b> Source: <small>%d x %d, Output %d x %d %s</small>\n",
262                  source_width, source_height, width, height, aspect_desc);
263
264         gboolean decomb;
265         gboolean filters = FALSE;
266
267         decomb = ghb_settings_get_boolean(settings, "decomb");
268         g_string_append_printf(str, "<b>Filters:</b><small>");
269         if (ghb_settings_get_boolean(settings, "detelecine"))
270         {
271                 g_string_append_printf(str, " - Detelecine");
272                 filters = TRUE;
273         }
274         if (decomb)
275         {
276                 g_string_append_printf(str, " - Decomb");
277                 filters = TRUE;
278         }
279         else
280         {
281                 gint deint = ghb_settings_combo_int(settings, 
282                                         tweaks ? "tweak_deinterlace":"deinterlace");
283                 if (deint)
284                 {
285                         const gchar *opt = ghb_settings_combo_option(settings,
286                                         tweaks ? "tweak_deinterlace":"deinterlace");
287                         g_string_append_printf(str, " - Deinterlace: %s", opt);
288                         filters = TRUE;
289                 }
290         }
291         gint denoise = ghb_settings_combo_int(settings, 
292                                 tweaks ? "tweak_denoise":"denoise");
293         if (denoise)
294         {
295                 const gchar *opt = ghb_settings_combo_option(settings,
296                                 tweaks ? "tweak_denoise":"denoise");
297                 g_string_append_printf(str, " - Denoise: %s", opt);
298                 filters = TRUE;
299         }
300         gint deblock = ghb_settings_get_int(settings, "deblock");
301         if (deblock >= 5)
302         {
303                 g_string_append_printf(str, " - Deblock (%d)", deblock);
304                 filters = TRUE;
305         }
306         if (ghb_settings_get_boolean(settings, "grayscale"))
307         {
308                 g_string_append_printf(str, " - Grayscale");
309                 filters = TRUE;
310         }
311         if (!filters)
312                 g_string_append_printf(str, " None");
313         g_string_append_printf(str, "</small>\n");
314
315         g_string_append_printf(str,
316                 "<b>Video:</b> <small>%s, Framerate: %s, %s %d%s</small>\n",
317                  vcodec, fps, vq_desc, vqvalue, vq_units);
318
319         turbo = ghb_settings_get_boolean(settings, "turbo");
320         if (turbo)
321         {
322                 g_string_append_printf(str, "<b>Turbo:</b> <small>On</small>\n");
323         }
324         if (strcmp(vcodec_abbr, "x264") == 0)
325         {
326                 gchar *x264opts = ghb_build_x264opts_string(settings);
327                 g_string_append_printf(str, 
328                         "<b>x264 Options:</b> <small>%s</small>\n", x264opts);
329                 g_free(x264opts);
330         }
331         // Add the audios
332         gint count, ii;
333         const GValue *audio_list;
334
335         audio_list = ghb_settings_get_value(settings, "audio_list");
336         count = ghb_array_len(audio_list);
337         for (ii = 0; ii < count; ii++)
338         {
339                 gchar *bitrate, *samplerate, *track;
340                 const gchar *acodec, *mix;
341                 GValue *asettings;
342
343                 asettings = ghb_array_get_nth(audio_list, ii);
344
345                 acodec = ghb_settings_combo_option(asettings, "audio_codec");
346                 bitrate = ghb_settings_get_string(asettings, "audio_bitrate");
347                 samplerate = ghb_settings_get_string(asettings, "audio_rate");
348                 if (strcmp("source", samplerate) == 0)
349                 {
350                         g_free(samplerate);
351                         samplerate = g_strdup("Same As Source");
352                 }
353                 track = ghb_settings_get_string(asettings, "audio_track_long");
354                 mix = ghb_settings_combo_option(asettings, "audio_mix");
355                 g_string_append_printf(str,
356                         "<b>Audio:</b><small> %s, Encoder: %s, Mixdown: %s, SampleRate: %s, Bitrate: %s</small>",
357                          track, acodec, mix, samplerate, bitrate);
358                 if (ii < count-1)
359                         g_string_append_printf(str, "\n");
360                 g_free(track);
361                 g_free(bitrate);
362                 g_free(samplerate);
363         }
364         info = g_string_free(str, FALSE);
365         gtk_tree_store_append(store, &citer, &iter);
366         gtk_tree_store_set(store, &citer, 1, info, -1);
367         g_free(info);
368         g_free(fps);
369         g_free(vcodec_abbr);
370         g_free(vol_name);
371         g_free(dest);
372         g_free(preset);
373 }
374
375 static gint64
376 estimate_file_size(signal_user_data_t *ud)
377 {
378         ghb_title_info_t tinfo;
379         gint duration;
380         gint bitrate;
381         gint64 size;
382         gint titleindex;
383
384         titleindex = ghb_settings_combo_int(ud->settings, "title");
385         if (titleindex < 0) return 0;
386                         
387         if (!ghb_get_title_info(&tinfo, titleindex)) return 0;
388         duration = ((tinfo.hours*60)+tinfo.minutes)*60+tinfo.seconds;
389         bitrate = ghb_guess_bitrate(ud->settings);
390         size = (gint64)duration * (gint64)bitrate/8;
391         return size;
392 }
393
394 void
395 audio_list_refresh(signal_user_data_t *ud)
396 {
397         GtkTreeView *treeview;
398         GtkTreeIter iter;
399         GtkListStore *store;
400         gboolean done;
401         gint row = 0;
402         GValue *audio_list;
403
404         g_debug("ghb_audio_list_refresh ()");
405         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
406         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
407         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
408         {
409                 do
410                 {
411                         const gchar *track, *codec, *br, *sr, *mix;
412                         gchar *drc, *s_track, *s_codec, *s_br, *s_sr, *s_mix;
413                         gdouble s_drc;
414                         GValue *asettings;
415
416                         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
417                         if (row >= ghb_array_len(audio_list))
418                                 return;
419                         asettings = ghb_array_get_nth(audio_list, row);
420
421                         track = ghb_settings_combo_option(asettings, "audio_track");
422                         codec = ghb_settings_combo_option(asettings, "audio_codec");
423                         br = ghb_settings_combo_option(asettings, "audio_bitrate");
424                         sr = ghb_settings_combo_option(asettings, "audio_rate");
425                         mix = ghb_settings_combo_option(asettings, "audio_mix");
426                         drc = ghb_settings_get_string(asettings, "audio_drc");
427
428                         s_track = ghb_settings_get_string(asettings, "audio_track");
429                         s_codec = ghb_settings_get_string(asettings, "audio_codec");
430                         s_br = ghb_settings_get_string(asettings, "audio_bitrate");
431                         s_sr = ghb_settings_get_string(asettings, "audio_rate");
432                         s_mix = ghb_settings_get_string(asettings, "audio_mix");
433                         s_drc = ghb_settings_get_double(asettings, "audio_drc");
434
435                         gtk_list_store_set(GTK_LIST_STORE(store), &iter, 
436                                 // These are displayed in list
437                                 0, track,
438                                 1, codec,
439                                 2, br,
440                                 3, sr,
441                                 4, mix,
442                                 // These are used to set combo values when an item is selected
443                                 5, drc,
444                                 6, s_track,
445                                 7, s_codec,
446                                 8, s_br,
447                                 9, s_sr,
448                                 10, s_mix,
449                                 11, s_drc,
450                                 -1);
451                         g_free(drc);
452                         g_free(s_track);
453                         g_free(s_codec);
454                         g_free(s_br);
455                         g_free(s_sr);
456                         g_free(s_mix);
457                         done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
458                         row++;
459                 } while (!done);
460         }
461 }
462
463 static gboolean
464 validate_settings(signal_user_data_t *ud)
465 {
466         // Check to see if the dest file exists or is
467         // already in the queue
468         gchar *message, *dest;
469         gint count, ii;
470         gint titleindex;
471
472         titleindex = ghb_settings_combo_int(ud->settings, "title");
473         if (titleindex < 0) return FALSE;
474         dest = ghb_settings_get_string(ud->settings, "destination");
475         count = ghb_array_len(ud->queue);
476         for (ii = 0; ii < count; ii++)
477         {
478                 GValue *js;
479                 gchar *filename;
480
481                 js = ghb_array_get_nth(ud->queue, ii);
482                 filename = ghb_settings_get_string(js, "destination");
483                 if (strcmp(dest, filename) == 0)
484                 {
485                         message = g_strdup_printf(
486                                                 "Destination: %s\n\n"
487                                                 "Another queued job has specified the same destination.\n"
488                                                 "Do you want to overwrite?",
489                                                 dest);
490                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
491                         {
492                                 g_free(filename);
493                                 g_free(dest);
494                                 g_free(message);
495                                 return FALSE;
496                         }
497                         g_free(message);
498                         break;
499                 }
500                 g_free(filename);
501         }
502         gchar *destdir = g_path_get_dirname(dest);
503         if (!g_file_test(destdir, G_FILE_TEST_IS_DIR))
504         {
505                 message = g_strdup_printf(
506                                         "Destination: %s\n\n"
507                                         "This is not a valid directory.",
508                                         destdir);
509                 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
510                 g_free(dest);
511                 g_free(message);
512                 g_free(destdir);
513                 return FALSE;
514         }
515         if (g_access(destdir, R_OK|W_OK) != 0)
516         {
517                 message = g_strdup_printf(
518                                         "Destination: %s\n\n"
519                                         "Can not read or write the directory.",
520                                         destdir);
521                 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
522                 g_free(dest);
523                 g_free(message);
524                 g_free(destdir);
525                 return FALSE;
526         }
527         GFile *gfile;
528         GFileInfo *info;
529         guint64 size;
530         gchar *resolved = ghb_resolve_symlink(destdir);
531
532         gfile = g_file_new_for_path(resolved);
533         info = g_file_query_filesystem_info(gfile, 
534                                                 G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, NULL);
535         if (info != NULL)
536         {
537                 if (g_file_info_has_attribute(info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE))
538                 {
539                         size = g_file_info_get_attribute_uint64(info, 
540                                                                         G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
541                         
542                         gint64 fsize = estimate_file_size(ud);
543                         if (size < fsize)
544                         {
545                                 message = g_strdup_printf(
546                                                         "Destination filesystem is almost full: %uM free\n\n"
547                                                         "Encode may be incomplete if you proceed.\n",
548                                                         (guint)(size / (1024L*1024L)));
549                                 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Proceed"))
550                                 {
551                                         g_free(dest);
552                                         g_free(message);
553                                         return FALSE;
554                                 }
555                                 g_free(message);
556                         }
557                 }
558                 g_object_unref(info);
559         }
560         g_object_unref(gfile);
561         g_free(resolved);
562         g_free(destdir);
563         if (g_file_test(dest, G_FILE_TEST_EXISTS))
564         {
565                 message = g_strdup_printf(
566                                         "Destination: %s\n\n"
567                                         "File already exhists.\n"
568                                         "Do you want to overwrite?",
569                                         dest);
570                 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
571                 {
572                         g_free(dest);
573                         g_free(message);
574                         return FALSE;
575                 }
576                 g_free(message);
577                 g_unlink(dest);
578         }
579         g_free(dest);
580         // Validate video quality is in a reasonable range
581         if (!ghb_validate_vquality(ud->settings))
582         {
583                 return FALSE;
584         }
585         // Validate audio settings
586         if (!ghb_validate_audio(ud))
587         {
588                 return FALSE;
589         }
590         // Validate video settings
591         if (!ghb_validate_video(ud))
592         {
593                 return FALSE;
594         }
595         // Validate container settings
596         if (!ghb_validate_container(ud))
597         {
598                 return FALSE;
599         }
600         // Validate filter settings
601         if (!ghb_validate_filters(ud))
602         {
603                 return FALSE;
604         }
605         audio_list_refresh(ud);
606         return TRUE;
607 }
608
609 static gboolean
610 queue_add(signal_user_data_t *ud)
611 {
612         // Add settings to the queue
613         GValue *settings;
614         gint titleindex;
615         gint titlenum;
616         
617         g_debug("queue_add ()");
618         if (!validate_settings(ud))
619         {
620                 return FALSE;
621         }
622         if (ud->queue == NULL)
623                 ud->queue = ghb_array_value_new(32);
624         // Make a copy of current settings to be used for the new job
625         settings = ghb_value_dup(ud->settings);
626         ghb_settings_set_int(settings, "job_status", GHB_QUEUE_PENDING);
627         ghb_settings_set_int(settings, "job_unique_id", 0);
628         titleindex = ghb_settings_combo_int(settings, "title");
629         titlenum = ghb_get_title_number(titleindex);
630         ghb_settings_set_int(settings, "titlenum", titlenum);
631         ghb_array_append(ud->queue, settings);
632         add_to_queue_list(ud, settings, NULL);
633         ghb_save_queue(ud->queue);
634
635         return TRUE;
636 }
637
638 void
639 queue_add_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
640 {
641         g_debug("queue_add_clicked_cb ()");
642         queue_add(ud);
643 }
644
645 void
646 queue_remove_clicked_cb(GtkWidget *widget, gchar *path, signal_user_data_t *ud)
647 {
648         GtkTreeView *treeview;
649         GtkTreePath *treepath;
650         GtkTreeModel *store;
651         GtkTreeIter iter;
652         gint row;
653         gint *indices;
654         gint unique_id;
655         GValue *settings;
656         gint status;
657
658         g_debug("queue_remove_clicked_cb ()");
659         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
660         store = gtk_tree_view_get_model(treeview);
661         treepath = gtk_tree_path_new_from_string (path);
662         if (gtk_tree_path_get_depth(treepath) > 1) return;
663         if (gtk_tree_model_get_iter(store, &iter, treepath))
664         {
665                 // Find the entry in the queue
666                 indices = gtk_tree_path_get_indices (treepath);
667                 row = indices[0];
668                 // Can only free the treepath After getting what I need from
669                 // indices since this points into treepath somewhere.
670                 gtk_tree_path_free (treepath);
671                 if (row < 0) return;
672                 if (row >= ghb_array_len(ud->queue))
673                         return;
674                 settings = ghb_array_get_nth(ud->queue, row);
675                 status = ghb_settings_get_int(settings, "job_status");
676                 if (status == GHB_QUEUE_RUNNING)
677                 {
678                         // Ask if wants to stop encode.
679                         if (!ghb_cancel_encode(NULL))
680                         {
681                                 return;
682                         }
683                         unique_id = ghb_settings_get_int(settings, "job_unique_id");
684                         ghb_remove_job(unique_id);
685                 }
686                 // Remove the selected item
687                 gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
688                 // Remove the corresponding item from the queue list
689                 GValue *old = ghb_array_get_nth(ud->queue, row);
690                 ghb_value_free(old);
691                 ghb_array_remove(ud->queue, row);
692                 ghb_save_queue(ud->queue);
693         }
694         else
695         {       
696                 gtk_tree_path_free (treepath);
697         }
698 }
699
700 static gint
701 find_last_finished(GValue *queue)
702 {
703         GValue *js;
704         gint ii, count;
705         gint status;
706         
707         g_debug("find_last_finished");
708         count = ghb_array_len(queue);
709         for (ii = 0; ii < count; ii++)
710         {
711                 js = ghb_array_get_nth(queue, ii);
712                 status = ghb_settings_get_int(js, "job_status");
713                 if (status != GHB_QUEUE_DONE && status != GHB_QUEUE_RUNNING)
714                 {
715                         return ii-1;
716                 }
717         }
718         return -1;
719 }
720
721 // This little bit is needed to prevent the default drag motion
722 // handler from expanding rows if you hover over them while
723 // dragging.
724 // Also controls where valid drop locations are
725 gboolean
726 queue_drag_motion_cb(
727         GtkTreeView *tv,
728         GdkDragContext *ctx,
729         gint x,
730         gint y,
731         guint time,
732         signal_user_data_t *ud)
733 {
734         GtkTreePath *path = NULL;
735         GtkTreeViewDropPosition pos;
736         gint *indices, row, status, finished;
737         GValue *js;
738         GtkTreeIter iter;
739         GtkTreeView *srctv;
740         GtkTreeModel *model;
741         GtkTreeSelection *select;
742
743         // This bit checks to see if the source is allowed to be
744         // moved.  Only pending and canceled items may be moved.
745         srctv = GTK_TREE_VIEW(gtk_drag_get_source_widget(ctx));
746         select = gtk_tree_view_get_selection (srctv);
747         gtk_tree_selection_get_selected (select, &model, &iter);
748         path = gtk_tree_model_get_path (model, &iter);
749         indices = gtk_tree_path_get_indices(path);
750         row = indices[0];
751         gtk_tree_path_free(path);
752         js = ghb_array_get_nth(ud->queue, row);
753         status = ghb_settings_get_int(js, "job_status");
754         if (status != GHB_QUEUE_PENDING && status != GHB_QUEUE_CANCELED)
755         {
756                 gdk_drag_status(ctx, 0, time);
757                 return TRUE;
758         }
759
760         // The reset checks that the destination is a valid position
761         // in the list.  Can not move above any finished or running items
762         gtk_tree_view_get_dest_row_at_pos (tv, x, y, &path, &pos);
763         if (path == NULL)
764         {
765                 gdk_drag_status(ctx, GDK_ACTION_MOVE, time);
766                 return TRUE;
767         }
768         // Don't allow *drop into*
769         if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
770                 pos = GTK_TREE_VIEW_DROP_BEFORE;
771         if (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
772                 pos = GTK_TREE_VIEW_DROP_AFTER;
773         // Don't allow droping int child items
774         if (gtk_tree_path_get_depth(path) > 1)
775         {
776                 gtk_tree_path_up(path);
777                 pos = GTK_TREE_VIEW_DROP_AFTER;
778         }
779         indices = gtk_tree_path_get_indices(path);
780         row = indices[0];
781         js = ghb_array_get_nth(ud->queue, row);
782
783         finished = find_last_finished(ud->queue);
784         if (row < finished)
785         {
786                 gtk_tree_path_free(path);
787                 gdk_drag_status(ctx, 0, time);
788                 return TRUE;
789         }
790         if (pos != GTK_TREE_VIEW_DROP_AFTER && 
791                 row == finished)
792         {
793                 gtk_tree_path_free(path);
794                 gdk_drag_status(ctx, 0, time);
795                 return TRUE;
796         }
797         gtk_tree_view_set_drag_dest_row(tv, path, pos);
798         gtk_tree_path_free(path);
799         gdk_drag_status(ctx, GDK_ACTION_MOVE, time);
800         return TRUE;
801 }
802
803 void 
804 queue_drag_cb(
805         GtkTreeView *dstwidget, 
806         GdkDragContext *dc, 
807         gint x, gint y, 
808         GtkSelectionData *selection_data, 
809         guint info, guint t, 
810         signal_user_data_t *ud)
811 {
812         GtkTreePath *path = NULL;
813         //GtkTreeModel *model;
814         GtkTreeViewDropPosition pos;
815         GtkTreeIter dstiter, srciter;
816         gint *indices, row;
817         GValue *js;
818         
819         GtkTreeModel *dstmodel = gtk_tree_view_get_model(dstwidget);
820                         
821         g_debug("queue_drag_cb ()");
822         // This doesn't work here for some reason...
823         // gtk_tree_view_get_drag_dest_row(dstwidget, &path, &pos);
824         gtk_tree_view_get_dest_row_at_pos (dstwidget, x, y, &path, &pos);
825         // This little hack is needed because attempting to drop after
826         // the last item gives us no path or pos.
827         if (path == NULL)
828         {
829                 gint n_children;
830
831                 n_children = gtk_tree_model_iter_n_children(dstmodel, NULL);
832                 if (n_children)
833                 {
834                         pos = GTK_TREE_VIEW_DROP_AFTER;
835                         path = gtk_tree_path_new_from_indices(n_children-1, -1);
836                 }
837                 else
838                 {
839                         pos = GTK_TREE_VIEW_DROP_BEFORE;
840                         path = gtk_tree_path_new_from_indices(0, -1);
841                 }
842         }
843         if (path)
844         {
845                 if (gtk_tree_path_get_depth(path) > 1)
846                         gtk_tree_path_up(path);
847                 if (gtk_tree_model_get_iter (dstmodel, &dstiter, path))
848                 {
849                         GtkTreeIter iter;
850                         GtkTreeView *srcwidget;
851                         GtkTreeModel *srcmodel;
852                         GtkTreeSelection *select;
853                         GtkTreePath *srcpath = NULL;
854                         GtkTreePath *dstpath = NULL;
855
856                         srcwidget = GTK_TREE_VIEW(gtk_drag_get_source_widget(dc));
857                         //srcmodel = gtk_tree_view_get_model(srcwidget);
858                         select = gtk_tree_view_get_selection (srcwidget);
859                         gtk_tree_selection_get_selected (select, &srcmodel, &srciter);
860
861                         srcpath = gtk_tree_model_get_path (srcmodel, &srciter);
862                         indices = gtk_tree_path_get_indices(srcpath);
863                         row = indices[0];
864                         gtk_tree_path_free(srcpath);
865                         js = ghb_array_get_nth(ud->queue, row);
866
867                         switch (pos)
868                         {
869                                 case GTK_TREE_VIEW_DROP_BEFORE:
870                                 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
871                                         gtk_tree_store_insert_before (GTK_TREE_STORE (dstmodel), 
872                                                                                                         &iter, NULL, &dstiter);
873                                         break;
874
875                                 case GTK_TREE_VIEW_DROP_AFTER:
876                                 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
877                                         gtk_tree_store_insert_after (GTK_TREE_STORE (dstmodel), 
878                                                                                                         &iter, NULL, &dstiter);
879                                         break;
880
881                                 default:
882                                         break;
883                         }
884                         // Reset job to pending
885                         ghb_settings_set_int(js, "job_status", GHB_QUEUE_PENDING);
886                         add_to_queue_list(ud, js, &iter);
887
888                         dstpath = gtk_tree_model_get_path (dstmodel, &iter);
889                         indices = gtk_tree_path_get_indices(dstpath);
890                         row = indices[0];
891                         gtk_tree_path_free(dstpath);
892                         ghb_array_insert(ud->queue, row, js);
893
894                         srcpath = gtk_tree_model_get_path (srcmodel, &srciter);
895                         indices = gtk_tree_path_get_indices(srcpath);
896                         row = indices[0];
897                         gtk_tree_path_free(srcpath);
898                         ghb_array_remove(ud->queue, row);
899                         gtk_tree_store_remove (GTK_TREE_STORE (srcmodel), &srciter);
900                         ghb_save_queue(ud->queue);
901                 }
902                 gtk_tree_path_free(path);
903         }
904 }
905
906 void
907 ghb_queue_buttons_grey(signal_user_data_t *ud, gboolean working)
908 {
909         GtkWidget *widget;
910         GtkAction *action;
911         gint queue_count;
912         gint titleindex;
913         gboolean title_ok;
914
915         queue_count = ghb_array_len(ud->queue);
916         titleindex = ghb_settings_combo_int(ud->settings, "title");
917         title_ok = (titleindex >= 0);
918
919         widget = GHB_WIDGET (ud->builder, "queue_start1");
920         gtk_widget_set_sensitive (widget, !working && (title_ok || queue_count));
921         widget = GHB_WIDGET (ud->builder, "queue_start2");
922         gtk_widget_set_sensitive (widget, !working && (title_ok || queue_count));
923         action = GHB_ACTION (ud->builder, "queue_start_menu");
924         gtk_action_set_sensitive (action, !working && (title_ok || queue_count));
925         widget = GHB_WIDGET (ud->builder, "queue_pause1");
926         gtk_widget_set_sensitive (widget, working);
927         widget = GHB_WIDGET (ud->builder, "queue_pause2");
928         gtk_widget_set_sensitive (widget, working);
929         action = GHB_ACTION (ud->builder, "queue_pause_menu");
930         gtk_action_set_sensitive (action, working);
931         widget = GHB_WIDGET (ud->builder, "queue_stop");
932         gtk_widget_set_sensitive (widget, working);
933         action = GHB_ACTION (ud->builder, "queue_stop_menu");
934         gtk_action_set_sensitive (action, working);
935 }
936
937 void
938 queue_list_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, GtkCellRenderer *cell)
939 {
940         GtkTreeViewColumn *column;
941         gint width;
942         
943         column = gtk_tree_view_get_column (GTK_TREE_VIEW(widget), 0);
944         width = gtk_tree_view_column_get_width(column);
945         g_debug("col width %d alloc width %d", width, allocation->width);
946         // Set new wrap-width.  Shave a little off to accomidate the icons
947         // that share this column.
948         if (width >= 564) // Don't allow below a certain size
949                 g_object_set(cell, "wrap-width", width-70, NULL);
950 }
951
952 void
953 queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
954 {
955         GValue *js;
956         gboolean running = FALSE;
957         gint count, ii;
958         gint status;
959         gint state;
960
961         count = ghb_array_len(ud->queue);
962         for (ii = 0; ii < count; ii++)
963         {
964                 js = ghb_array_get_nth(ud->queue, ii);
965                 status = ghb_settings_get_int(js, "job_status");
966                 if ((status == GHB_QUEUE_RUNNING) || 
967                         (status == GHB_QUEUE_PENDING))
968                 {
969                         running = TRUE;
970                         break;
971                 }
972         }
973         if (!running)
974         {
975                 // The queue has no running or pending jobs.
976                 // Add current settings to the queue, then run.
977                 if (!queue_add(ud))
978                         return;
979         }
980         state = ghb_get_queue_state();
981         if (state == GHB_STATE_IDLE)
982         {
983                 // Add the first pending queue item and start
984                 ud->current_job = ghb_start_next_job(ud, TRUE);
985         }
986 }
987
988 void
989 queue_stop_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
990 {
991         ud->cancel_encode = TRUE;
992         ghb_cancel_encode(NULL);
993 }
994
995 void
996 queue_pause_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
997 {
998         ghb_pause_queue();
999 }
1000
1001 gboolean
1002 ghb_reload_queue(signal_user_data_t *ud)
1003 {
1004         GValue *queue;
1005         gint unfinished = 0;
1006         gint count, ii;
1007         gint status;
1008         GValue *settings;
1009         gchar *message;
1010
1011         g_debug("ghb_reload_queue");
1012         queue = ghb_load_queue();
1013         // Look for unfinished entries
1014         count = ghb_array_len(queue);
1015         for (ii = 0; ii < count; ii++)
1016         {
1017                 settings = ghb_array_get_nth(queue, ii);
1018                 status = ghb_settings_get_int(settings, "job_status");
1019                 if (status != GHB_QUEUE_DONE && status != GHB_QUEUE_CANCELED)
1020                 {
1021                         unfinished++;
1022                 }
1023         }
1024         if (unfinished)
1025         {
1026                 message = g_strdup_printf(
1027                                         "You have %d unfinished job%s in a saved queue.\n\n"
1028                                         "Would you like to reload %s?",
1029                                         unfinished, 
1030                                         (unfinished > 1) ? "s" : "",
1031                                         (unfinished > 1) ? "them" : "it");
1032                 if (ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "No", "Yes"))
1033                 {
1034                         GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
1035                         gtk_widget_show (widget);
1036
1037                         ud->queue = queue;
1038                         // First get rid of any old items we don't want
1039                         for (ii = count-1; ii >= 0; ii--)
1040                         {
1041                                 settings = ghb_array_get_nth(queue, ii);
1042                                 status = ghb_settings_get_int(settings, "job_status");
1043                                 if (status == GHB_QUEUE_DONE || status == GHB_QUEUE_CANCELED)
1044                                 {
1045                                         GValue *old = ghb_array_get_nth(queue, ii);
1046                                         ghb_value_free(old);
1047                                         ghb_array_remove(queue, ii);
1048                                 }
1049                         }
1050                         count = ghb_array_len(queue);
1051                         for (ii = 0; ii < count; ii++)
1052                         {
1053                                 settings = ghb_array_get_nth(queue, ii);
1054                                 ghb_settings_set_int(settings, "job_unique_id", 0);
1055                                 ghb_settings_set_int(settings, "job_status", GHB_QUEUE_PENDING);
1056                                 add_to_queue_list(ud, settings, NULL);
1057                         }
1058                         ghb_queue_buttons_grey(ud, FALSE);
1059                 }
1060                 else
1061                 {
1062                         ghb_value_free(queue);
1063                         ghb_remove_queue_file();
1064                 }
1065                 g_free(message);
1066         }
1067         return FALSE;
1068 }
1069
1070 gboolean 
1071 queue_key_press_cb(
1072         GtkWidget *widget, 
1073         GdkEventKey *event,
1074         signal_user_data_t *ud)
1075 {
1076         GtkTreeView *treeview;
1077         GtkTreeSelection *selection;
1078         GtkTreeModel *store;
1079         GtkTreeIter iter;
1080         gint row;
1081         gint *indices;
1082         gint unique_id;
1083         GValue *settings;
1084         gint status;
1085
1086         g_debug("queue_key_press_cb ()");
1087         if (event->keyval != GDK_Delete)
1088                 return FALSE;
1089         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
1090         store = gtk_tree_view_get_model(treeview);
1091
1092         selection = gtk_tree_view_get_selection (treeview);
1093         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1094         {
1095                 GtkTreePath *treepath;
1096
1097                 treepath = gtk_tree_model_get_path (store, &iter);
1098                 // Find the entry in the queue
1099                 indices = gtk_tree_path_get_indices (treepath);
1100                 row = indices[0];
1101                 // Can only free the treepath After getting what I need from
1102                 // indices since this points into treepath somewhere.
1103                 gtk_tree_path_free (treepath);
1104                 if (row < 0) return FALSE;
1105                 if (row >= ghb_array_len(ud->queue))
1106                         return FALSE;
1107                 settings = ghb_array_get_nth(ud->queue, row);
1108                 status = ghb_settings_get_int(settings, "job_status");
1109                 if (status == GHB_QUEUE_RUNNING)
1110                 {
1111                         // Ask if wants to stop encode.
1112                         if (!ghb_cancel_encode(NULL))
1113                         {
1114                                 return TRUE;
1115                         }
1116                         unique_id = ghb_settings_get_int(settings, "job_unique_id");
1117                         ghb_remove_job(unique_id);
1118                 }
1119                 // Remove the selected item
1120                 gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
1121                 // Remove the corresponding item from the queue list
1122                 GValue *old = ghb_array_get_nth(ud->queue, row);
1123                 ghb_value_free(old);
1124                 ghb_array_remove(ud->queue, row);
1125                 ghb_save_queue(ud->queue);
1126                 return TRUE;
1127         }
1128         return FALSE;
1129 }
1130
1131 GValue *ghb_queue_edit_settings = NULL;
1132
1133 void
1134 queue_edit_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1135 {
1136         GtkTreeView *treeview;
1137         GtkTreeSelection *selection;
1138         GtkTreeModel *store;
1139         GtkTreeIter iter;
1140         gint row;
1141         gint *indices;
1142         gint status;
1143
1144         g_debug("queue_key_press_cb ()");
1145         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
1146         store = gtk_tree_view_get_model(treeview);
1147
1148         selection = gtk_tree_view_get_selection (treeview);
1149         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1150         {
1151                 GtkTreePath *treepath;
1152
1153                 treepath = gtk_tree_model_get_path (store, &iter);
1154                 // Find the entry in the queue
1155                 indices = gtk_tree_path_get_indices (treepath);
1156                 row = indices[0];
1157                 // Can only free the treepath After getting what I need from
1158                 // indices since this points into treepath somewhere.
1159                 gtk_tree_path_free (treepath);
1160                 if (row < 0) return;
1161                 if (row >= ghb_array_len(ud->queue))
1162                         return;
1163                 ghb_queue_edit_settings = ghb_array_get_nth(ud->queue, row);
1164                 status = ghb_settings_get_int(ghb_queue_edit_settings, "job_status");
1165                 if (status == GHB_QUEUE_PENDING)
1166                 {
1167                         // Remove the selected item
1168                         gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
1169                         // Remove the corresponding item from the queue list
1170                         ghb_array_remove(ud->queue, row);
1171                 }
1172                 gchar *source;
1173                 source = ghb_settings_get_string(ghb_queue_edit_settings, "source");
1174                 ghb_do_scan(ud, source, FALSE);
1175                 g_free(source);
1176         }
1177 }
1178