OSDN Git Service

6625610385169d1ffc21e3929adf516c20f410d3
[handbrake-jp/handbrake-jp-git.git] / gtk / src / settings.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * settings.c
4  * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
5  * 
6  * settings.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 <fcntl.h>
15 #include <unistd.h>
16 #include <glib.h>
17 #include <glib/gstdio.h>
18 #include <string.h>
19 #include <gtk/gtk.h>
20 #include "settings.h"
21 #include "hb-backend.h"
22
23 void dump_settings(GHashTable *settings);
24 void ghb_pref_audio_init(signal_user_data_t *ud);
25
26 GObject*
27 debug_get_object(GtkBuilder* b, const gchar *n)
28 {
29         g_message("name %s\n", n);
30         return gtk_builder_get_object(b, n);
31 }
32
33 static gchar *true_strings[] =
34 {
35         "enable",
36         "yes",
37         "true",
38         "1"
39 };
40
41 static gboolean
42 string_is_true(const gchar *str)
43 {
44         gint count = sizeof(true_strings) / sizeof(gchar*);
45         gint ii;
46         
47         for (ii = 0; ii < count; ii++)
48         {
49                 if (strcmp(str, true_strings[ii]) == 0)
50                 {
51                         return TRUE;
52                 }
53         }
54         return FALSE;
55 }
56
57 static void
58 delete_key(gpointer str)
59 {
60         g_debug("delete_key (%s)\n", (gchar*)str);
61         g_free(str);
62 }
63
64 static void
65 delete_value(gpointer val)
66 {
67         g_debug("delete_value (%s)\n", ((setting_value_t*)val)->svalue);
68         g_free(((setting_value_t*)val)->svalue);
69         g_free(((setting_value_t*)val)->option);
70         g_free(((setting_value_t*)val)->shortOpt);
71         g_free(val);
72 }
73
74 void
75 ghb_free_setting_value(setting_value_t *val)
76 {
77         delete_value((gpointer)val);
78 }
79
80 GHashTable*
81 ghb_settings_new()
82 {
83         GHashTable* settings;
84         
85         g_debug("ghb_settings_new ()\n");
86         settings = g_hash_table_new_full(g_str_hash, g_str_equal, 
87                                                   delete_key, delete_value);
88         return settings;
89 }
90
91 static void
92 settings_set(GHashTable *settings, const gchar *key, 
93                                  const gchar *str, gint val, gdouble dbl)
94 {
95         g_debug("ghb_setting_set () key (%s), svalue (%s), ivalue %d, dvalue %.2g\n", key, str, val, dbl);
96         setting_value_t *value = g_malloc(sizeof(setting_value_t));
97         if (str != NULL)
98                 value->svalue = g_strdup(str);
99         else
100                 value->svalue = g_strdup("");
101         value->option = g_strdup(value->svalue);
102         value->shortOpt = g_strdup(value->svalue);
103         value->index = val;
104         value->ivalue = val;
105         value->dvalue = dbl;
106         g_hash_table_insert(settings, g_strdup(key), value);
107 }
108
109 static setting_value_t*
110 copy_settings_value(const setting_value_t *value)
111 {
112         setting_value_t *copy = g_malloc(sizeof(setting_value_t));
113         copy->index = value->index;
114         copy->ivalue = value->ivalue;
115         copy->dvalue = value->dvalue;
116         copy->svalue = g_strdup(value->svalue);
117         copy->option = g_strdup(value->option);
118         copy->shortOpt = g_strdup(value->shortOpt);
119         return copy;
120 }
121
122 void
123 ghb_settings_set(GHashTable *settings, const gchar *key, setting_value_t *value)
124 {
125         g_debug("ghb_settings_set () key (%s)\n", key);
126         if ((key == NULL) || (value == NULL))
127         {
128                 g_debug("Bad key or value\n");
129                 return;
130         }
131         g_debug("\tkey (%s) -- value (%s)\n", key, value->svalue);
132         g_hash_table_insert(settings, g_strdup(key), value);
133 }
134
135 void
136 ghb_settings_set_string(GHashTable *settings, const gchar *key, const gchar *str)
137 {
138         gdouble dvalue = 0;
139         gchar *end;
140
141         if (str == NULL) str = "";
142         dvalue = g_strtod (str, &end);
143         if ((end == str) && string_is_true (str))
144         {
145                 dvalue = 1;
146         }
147         settings_set(settings, key, str, dvalue, dvalue);
148 }
149
150 void
151 ghb_settings_set_dbl(GHashTable *settings, const gchar *key, gdouble dvalue)
152 {
153         setting_value_t *value;
154         
155         value = g_malloc(sizeof(setting_value_t));
156         value->index = 0;
157         value->dvalue = dvalue;
158         value->option = g_strdup_printf("%.8g", dvalue);
159         value->shortOpt = g_strdup(value->option);
160         value->svalue = g_strdup(value->option);
161         value->ivalue = dvalue;
162         ghb_settings_set( settings, key, value);
163 }
164
165 void
166 ghb_settings_copy(GHashTable *settings, const gchar *key, const setting_value_t *value)
167 {
168         setting_value_t *copy = copy_settings_value(value);
169         g_hash_table_insert(settings, g_strdup(key), copy);
170 }
171
172 const setting_value_t*
173 ghb_settings_get(GHashTable *settings, const gchar *key)
174 {
175         const setting_value_t* value;
176         g_debug("ghb_settings_get () key (%s)\n", key);
177         value = g_hash_table_lookup(settings, key);
178         return value;
179 }
180
181 gboolean
182 ghb_settings_get_bool(GHashTable *settings, const gchar *key)
183 {
184         const setting_value_t* value;
185         g_debug("ghb_settings_get_bool () key (%s)\n", key);
186         value = ghb_settings_get(settings, key);
187         if (value == NULL) 
188         {
189                 g_debug("\tNo value found\n");
190                 return FALSE;
191         }
192         g_debug("\tvalue is %d\n", value->ivalue);
193         return value->ivalue;
194 }
195
196 gint
197 ghb_settings_get_int(GHashTable *settings, const gchar *key)
198 {
199         const setting_value_t* value;
200         g_debug("ghb_settings_get_int () key (%s)\n", key);
201         value = ghb_settings_get(settings, key);
202         if (value == NULL) return 0;
203         return value->ivalue;
204 }
205
206 gint
207 ghb_settings_get_index(GHashTable *settings, const gchar *key)
208 {
209         const setting_value_t* value;
210         g_debug("ghb_settings_get_index () key (%s)\n", key);
211         value = ghb_settings_get(settings, key);
212         if (value == NULL) return 0;
213         return value->index;
214 }
215
216 gdouble
217 ghb_settings_get_dbl(GHashTable *settings, const gchar *key)
218 {
219         const setting_value_t* value;
220         g_debug("ghb_settings_get_dbl () key (%s)\n", key);
221         value = ghb_settings_get(settings, key);
222         if (value == NULL) return 0.0;
223         return value->dvalue;
224 }
225
226 const gchar*
227 ghb_settings_get_string(GHashTable *settings, const gchar *key)
228 {
229         const setting_value_t* value;
230         g_debug("ghb_settings_get_string () key (%s)\n", key);
231         value = ghb_settings_get(settings, key);
232         if (value == NULL) return "";
233         return value->svalue;
234         
235 }
236
237 const gchar*
238 ghb_settings_get_option(GHashTable *settings, const gchar *key)
239 {
240         const setting_value_t* value;
241         g_debug("ghb_settings_get_option () key (%s)\n", key);
242         value = ghb_settings_get(settings, key);
243         if (value == NULL) return "";
244         g_debug("option: (%s)\n", value->option);
245         return value->option;
246 }
247
248 const gchar*
249 ghb_settings_get_short_opt(GHashTable *settings, const gchar *key)
250 {
251         const setting_value_t* value;
252         g_debug("ghb_settings_get_short_opt () key (%s)\n", key);
253         value = ghb_settings_get(settings, key);
254         if (value == NULL) return "";
255         g_debug("shrot option: (%s)\n", value->shortOpt);
256         return value->shortOpt;
257 }
258
259 static void 
260 copy_key_val(gpointer key, gpointer val, gpointer settings)
261 {
262         g_hash_table_insert((GHashTable*)settings, 
263                                                 g_strdup((gchar*)key), 
264                                                 copy_settings_value((setting_value_t*)val));
265 }
266
267 GHashTable*
268 ghb_settings_dup(GHashTable *settings)
269 {
270         GHashTable *dup_settings;
271         
272         if (settings == NULL) return NULL;
273         dup_settings = ghb_settings_new();
274         g_hash_table_foreach (settings, copy_key_val, dup_settings);
275         return dup_settings;
276 }
277
278 // Map widget names to setting keys
279 // Widgets that map to settings have names
280 // of this format: s_<setting key>
281 static const gchar*
282 get_setting_key(GtkWidget *widget)
283 {
284         const gchar *name;
285         
286         g_debug("get_setting_key ()\n");
287         if (widget == NULL) return NULL;
288         if (GTK_IS_ACTION(widget))
289                 name = gtk_action_get_name(GTK_ACTION(widget));
290         else
291                 name = gtk_widget_get_name(widget);
292                 
293         if (name == NULL)
294         {
295                 // Bad widget pointer?  Should never happen.
296                 g_debug("Bad widget\n");
297                 return NULL;
298         }
299         return name;
300 }
301
302 setting_value_t*
303 ghb_widget_value(GtkWidget *widget)
304 {
305         setting_value_t *value;
306         const gchar *name;
307         GType type;
308         
309         if (widget == NULL)
310         {
311                 g_debug("NULL widget\n");
312                 return NULL;
313         }
314         value = g_malloc(sizeof(setting_value_t));
315
316         type = GTK_WIDGET_TYPE(widget);
317         if (GTK_IS_ACTION(widget))
318                 name = gtk_action_get_name(GTK_ACTION(widget));
319         else
320                 name = gtk_widget_get_name(widget);
321         g_debug("ghb_widget_value widget (%s)\n", name);
322         if (type == GTK_TYPE_ENTRY)
323         {
324                 const gchar *str = gtk_entry_get_text((GtkEntry*)widget);
325                 value->option = g_strdup(str);
326                 value->shortOpt = g_strdup(str);
327                 value->svalue = g_strdup(str);
328                 value->dvalue = g_strtod(str, NULL);
329                 value->ivalue = value->dvalue;
330                 value->index = 0;
331         }
332         else if (type == GTK_TYPE_RADIO_BUTTON)
333         {
334                 g_debug("\tradio_button");
335                 value->index = 0;
336                 if (gtk_toggle_button_get_active((GtkToggleButton*)widget))
337                 {
338                         g_debug("\tenable");
339                         value->option = g_strdup("enable");
340                         value->shortOpt = g_strdup("enable");
341                         value->svalue = g_strdup("1");
342                         value->ivalue = 1;
343                         value->dvalue = 1;
344                 }
345                 else
346                 {
347                         g_debug("\tdisable");
348                         value->option = g_strdup("disable");
349                         value->shortOpt = g_strdup("disable");
350                         value->svalue = g_strdup("0");
351                         value->ivalue = 0;
352                         value->dvalue = 0;
353                 }
354         }
355         else if (type == GTK_TYPE_CHECK_BUTTON)
356         {
357                 g_debug("\tcheck_button");
358                 value->index = 0;
359                 if (gtk_toggle_button_get_active((GtkToggleButton*)widget))
360                 {
361                         g_debug("\tenable");
362                         value->option = g_strdup("enable");
363                         value->shortOpt = g_strdup("enable");
364                         value->svalue = g_strdup("1");
365                         value->ivalue = 1;
366                         value->dvalue = 1;
367                 }
368                 else
369                 {
370                         g_debug("\tdisable");
371                         value->option = g_strdup("disable");
372                         value->shortOpt = g_strdup("disable");
373                         value->svalue = g_strdup("0");
374                         value->ivalue = 0;
375                         value->dvalue = 0;
376                 }
377         }
378         else if (type == GTK_TYPE_TOGGLE_ACTION)
379         {
380                 g_debug("\ttoggle action");
381                 value->index = 0;
382                 if (gtk_toggle_action_get_active((GtkToggleAction*)widget))
383                 {
384                         g_debug("\tenable");
385                         value->option = g_strdup("enable");
386                         value->shortOpt = g_strdup("enable");
387                         value->svalue = g_strdup("1");
388                         value->ivalue = 1;
389                         value->dvalue = 1;
390                 }
391                 else
392                 {
393                         g_debug("\tdisable");
394                         value->option = g_strdup("disable");
395                         value->shortOpt = g_strdup("disable");
396                         value->svalue = g_strdup("0");
397                         value->ivalue = 0;
398                         value->dvalue = 0;
399                 }
400         }
401         else if (type == GTK_TYPE_CHECK_MENU_ITEM)
402         {
403                 g_debug("\tcheck_menu_item");
404                 value->index = 0;
405                 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)))
406                 {
407                         g_debug("\tenable");
408                         value->option = g_strdup("enable");
409                         value->shortOpt = g_strdup("enable");
410                         value->svalue = g_strdup("1");
411                         value->ivalue = 1;
412                         value->dvalue = 1;
413                 }
414                 else
415                 {
416                         g_debug("\tdisable");
417                         value->option = g_strdup("disable");
418                         value->shortOpt = g_strdup("disable");
419                         value->svalue = g_strdup("0");
420                         value->ivalue = 0;
421                         value->dvalue = 0;
422                 }
423         }
424         else if (type == GTK_TYPE_COMBO_BOX)
425         {
426                 GtkTreeModel *store;
427                 GtkTreeIter iter;
428                 gchar *shortOpt, *option, *svalue;
429                 gint ivalue;
430                 gint index = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
431
432                 store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
433                 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter))
434                 {
435                         gtk_tree_model_get(store, &iter, 0, &option, 2, &shortOpt, 
436                                                            3, &ivalue, 4, &svalue, -1);
437
438                         g_debug("\tcombo: index %d opt (%s) Short Opt (%s) value %d\n", index, option, shortOpt, ivalue);
439                         value->option = option;
440                         value->shortOpt = shortOpt;
441                         value->svalue = svalue;
442                         value->index = index;
443                         value->ivalue = ivalue;
444                         value->dvalue = ivalue;
445                 }
446                 else
447                 {
448                         value->option = g_strdup("");
449                         value->shortOpt = g_strdup("");
450                         value->svalue = g_strdup("");
451                         value->index = -1;
452                         value->ivalue = 0;
453                         value->dvalue = 0;
454                 }
455         }
456         else if (type == GTK_TYPE_SPIN_BUTTON)
457         {
458                 value->index = 0;
459                 value->dvalue = gtk_spin_button_get_value_as_int((GtkSpinButton*)widget);
460                 value->option = g_strdup_printf("%.8g", value->dvalue);
461                 value->shortOpt = g_strdup_printf("%.8g", value->dvalue);
462                 value->svalue = g_strdup_printf("%.8g", value->dvalue);
463                 value->ivalue = value->dvalue;
464         }
465         else if (type == GTK_TYPE_HSCALE)
466         {
467                 value->index = 0;
468                 value->dvalue = gtk_range_get_value((GtkRange*)widget);
469                 value->option = g_strdup_printf("%.8g", value->dvalue);
470                 value->shortOpt = g_strdup_printf("%.8g", value->dvalue);
471                 value->svalue = g_strdup_printf("%.8g", value->dvalue);
472                 value->ivalue = value->dvalue;
473         }
474         else if (type == GTK_TYPE_TEXT_VIEW)
475         {
476                 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
477                 GtkTextIter start, end;
478                 gtk_text_buffer_get_bounds(buffer, &start, &end);
479                 value->svalue = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
480                 value->option = g_strdup(value->svalue);
481                 value->shortOpt = g_strdup(value->svalue);
482                 value->ivalue = 0;
483                 value->dvalue = 0;
484                 value->index = 0;
485         }
486         else if (type == GTK_TYPE_LABEL)
487         {
488                 value->index = 0;
489                 value->svalue = g_strdup(gtk_label_get_text (GTK_LABEL(widget)));
490                 value->dvalue = g_strtod(value->svalue, NULL);
491                 value->option = g_strdup(value->svalue);
492                 value->shortOpt = g_strdup(value->svalue);
493                 value->ivalue = value->dvalue;
494                 g_debug("label (%s)\n", value->shortOpt);
495         }
496         else
497         {
498                 g_debug("Attempt to set unknown widget type: %s\n", name);
499                 g_free(value);
500                 value = NULL;
501         }
502         return value;
503 }
504
505 gchar*
506 ghb_widget_option(GtkWidget *widget)
507 {
508         setting_value_t *value;
509         gchar *str = NULL;
510         
511         g_debug("ghb_widget_option ()\n");
512         value = ghb_widget_value(widget);
513         if (value != NULL)
514         {
515                 str = g_strdup(value->option);
516                 ghb_free_setting_value (value);
517         }
518         return str;
519 }
520
521 gchar*
522 ghb_widget_short_opt(GtkWidget *widget)
523 {
524         setting_value_t *value;
525         gchar *str = NULL;
526         
527         g_debug("ghb_widget_short_opt ()\n");
528         value = ghb_widget_value(widget);
529         if (value != NULL)
530         {
531                 str = g_strdup(value->shortOpt);
532                 ghb_free_setting_value (value);
533         }
534         return str;
535 }
536
537 gchar*
538 ghb_widget_string(GtkWidget *widget)
539 {
540         setting_value_t *value;
541         gchar *str = NULL;
542         
543         g_debug("ghb_widget_string ()\n");
544         value = ghb_widget_value(widget);
545         if (value != NULL)
546         {
547                 g_debug("str (%s)\n", value->svalue);
548                 str = g_strdup(value->svalue);
549                 ghb_free_setting_value (value);
550         }
551         return str;
552 }
553
554 gdouble
555 ghb_widget_dbl(GtkWidget *widget)
556 {
557         setting_value_t *value;
558         gdouble dbl = 0;
559         
560         g_debug("ghb_widget_dbl ()\n");
561         value = ghb_widget_value(widget);
562         if (value != NULL)
563         {
564                 dbl = value->dvalue;
565                 ghb_free_setting_value (value);
566         }
567         return dbl;
568 }
569
570 gint
571 ghb_widget_int(GtkWidget *widget)
572 {
573         setting_value_t *value;
574         gint ivalue = 0;
575         
576         g_debug("ghb_widget_int ()\n");
577         value = ghb_widget_value(widget);
578         if (value != NULL)
579         {
580                 ivalue = value->ivalue;
581                 ghb_free_setting_value (value);
582         }
583         return ivalue;
584 }
585
586 gint
587 ghb_widget_index(GtkWidget *widget)
588 {
589         setting_value_t *value;
590         gint index = 0;
591         
592         g_debug("ghb_widget_index ()\n");
593         value = ghb_widget_value(widget);
594         if (value != NULL)
595         {
596                 index = value->index;
597                 ghb_free_setting_value (value);
598         }
599         return index;
600 }
601
602 void
603 ghb_widget_to_setting(GHashTable *settings, GtkWidget *widget)
604 {
605         const gchar *key = NULL;
606         setting_value_t *value;
607         
608         g_debug("ghb_widget_to_setting ()\n");
609         if (widget == NULL) return;
610         // Find corresponding setting
611         key = get_setting_key(widget);
612         if (key == NULL) return;
613         value = ghb_widget_value(widget);
614         if (value != NULL)
615         {
616                 ghb_settings_set (settings, key, value);
617         }
618         else
619         {
620                 g_debug("No value found for %s\n", key);
621         }
622         //dump_settings(settings);
623 }
624
625 static void
626 update_widget(GtkWidget *widget, const gchar *parm_svalue, gint parm_ivalue)
627 {
628         GType type;
629         gchar *value;
630
631         g_debug("update_widget");
632         // make a dup of setting value because the setting hash gets 
633         // modified and thus the value pointer can become invalid.
634         if (parm_svalue == NULL)
635         {
636                 value = g_strdup_printf ("%d", parm_ivalue);
637         }
638         else
639         {
640                 value = g_strdup(parm_svalue);
641         }
642         g_debug("update widget value (%s)", value);
643         type = GTK_OBJECT_TYPE(widget);
644         if (type == GTK_TYPE_ENTRY)
645         {
646                 g_debug("entry");
647                 gtk_entry_set_text((GtkEntry*)widget, value);
648         }
649         else if (type == GTK_TYPE_RADIO_BUTTON)
650         {
651                 g_debug("radio button");
652                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), string_is_true(value));
653         }
654         else if (type == GTK_TYPE_CHECK_BUTTON)
655         {
656                 g_debug("check button");
657                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), string_is_true(value));
658         }
659         else if (type == GTK_TYPE_TOGGLE_ACTION)
660         {
661                 g_debug("toggle action");
662                 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(widget), string_is_true(value));
663         }
664         else if (type == GTK_TYPE_CHECK_MENU_ITEM)
665         {
666                 g_debug("check menu item");
667                 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), string_is_true(value));
668         }
669         else if (type == GTK_TYPE_COMBO_BOX)
670         {
671                 GtkTreeModel *store;
672                 GtkTreeIter iter;
673                 gchar *shortOpt;
674                 gint ivalue;
675                 gboolean foundit = FALSE;
676
677                 g_debug("combo");
678                 store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
679                 if (gtk_tree_model_get_iter_first (store, &iter))
680                 {
681                         do
682                         {
683                                 gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1);
684                                 if (parm_svalue == NULL && ivalue == parm_ivalue)
685                                 {
686                                         gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter);
687                                         g_free(shortOpt);
688                                         foundit = TRUE;
689                                         break;
690                                 }
691                                 else if (strcmp(shortOpt, value) == 0)
692                                 {
693                                         gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter);
694                                         g_free(shortOpt);
695                                         foundit = TRUE;
696                                         break;
697                                 }
698                                 g_free(shortOpt);
699                         } while (gtk_tree_model_iter_next (store, &iter));
700                 }
701                 if (!foundit)
702                 {
703                         gtk_combo_box_set_active (GTK_COMBO_BOX(widget), 0);
704                 }
705         }
706         else if (type == GTK_TYPE_SPIN_BUTTON)
707         {
708                 gdouble val;
709                 
710                 g_debug("spin (%s)", value);
711                 val = g_strtod(value, NULL);
712                 gtk_spin_button_set_value((GtkSpinButton*)widget, val);
713         }
714         else if (type == GTK_TYPE_HSCALE)
715         {
716                 gdouble val;
717                 
718                 g_debug("hscale");
719                 val = g_strtod(value, NULL);
720                 gtk_range_set_value((GtkRange*)widget, val);
721         }
722         else if (type == GTK_TYPE_TEXT_VIEW)
723         {
724                 g_debug("textview (%s)", value);
725                 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
726                 gtk_text_buffer_set_text (buffer, value, -1);
727         }
728         else
729         {
730                 g_debug("Attempt to set unknown widget type");
731         }
732         g_free(value);
733 }
734
735 int
736 ghb_ui_update(signal_user_data_t *ud, const gchar *name, const gchar *value)
737 {
738         GObject *object;
739
740         g_debug("ghb_ui_update ()\n");
741         object = GHB_OBJECT(ud->builder, name);
742         if (object == NULL)
743         {
744                 g_debug("Failed to find widget for key: %s\n", name);
745                 return -1;
746         }
747         update_widget((GtkWidget*)object, value, 0);
748         // Its possible the value hasn't changed. Since settings are only
749         // updated when the value changes, I'm initializing settings here as well.
750         ghb_widget_to_setting(ud->settings, (GtkWidget*)object);
751         return 0;
752 }
753
754 int
755 ghb_ui_update_int(signal_user_data_t *ud, const gchar *name, gint ivalue)
756 {
757         GObject *object;
758
759         g_debug("ghb_ui_update_int ()\n");
760         object = GHB_OBJECT(ud->builder, name);
761         if (object == NULL)
762         {
763                 g_debug("Failed to find widget for key: %s\n", name);
764                 return -1;
765         }
766         update_widget((GtkWidget*)object, NULL, ivalue);
767         // Its possible the value hasn't changed. Since settings are only
768         // updated when the value changes, I'm initializing settings here as well.
769         ghb_widget_to_setting(ud->settings, (GtkWidget*)object);
770         return 0;
771 }
772
773 static void
774 show_setting(gpointer key, gpointer value, gpointer user_data)
775 {
776         printf("key (%s) -- value (%s)\n", (gchar*)key, (gchar*)value);
777 }
778
779 void
780 dump_settings(GHashTable *settings)
781 {
782         printf("------------------------------------\n");
783         g_hash_table_foreach(settings, show_setting, NULL);
784 }
785
786 // This is a bit hackish, but effective
787 const gchar defaultSettings[] =
788 #include "internal_defaults.h"
789 ;
790
791 typedef struct
792 {
793         gchar *name;
794         gchar *description;
795         gboolean custom;
796         gboolean defalt;
797         GKeyFile *keyFile;
798 } presets_data_t;
799
800 static GKeyFile *standardKeyFile;
801 static GKeyFile *customKeyFile;
802 static GKeyFile *internalKeyFile;
803 static GKeyFile *prefsKeyFile;
804 static GList *presetsList;
805
806 static gint
807 search_group(const gchar *name, gchar **groups)
808 {
809         gint ii;
810
811         //g_debug("search_group\n");
812         if (groups == NULL) return -1;
813         for (ii = 0; groups[ii] != NULL; ii++)
814         {
815                 //g_debug("%s cmp %s\n", name, groups[ii]);
816                 if (strcmp(name, groups[ii]) == 0)
817                 {
818                         return ii;
819                 }
820         }
821         return -1;
822 }
823
824 presets_data_t *
825 presets_list_search(GList *list, const gchar *name)
826 {
827         GList *link = list;
828         while (link != NULL)
829         {
830                 presets_data_t *data;
831                 data = (presets_data_t*)link->data;
832                 g_debug("search -- %s\n", data->name);
833                 if (strcmp(name, data->name) == 0)
834                 {
835                         return data;
836                 }
837                 link = g_list_next(link);
838         }
839         return NULL;
840 }
841
842 void
843 ghb_set_preset_default(GHashTable *settings)
844 {
845         const gchar *preset;
846         presets_data_t *data;
847         
848         preset = ghb_settings_get_string (settings, "default_preset");
849         data = presets_list_search(presetsList, preset);
850         if (data != NULL)
851         {
852                 data->defalt = FALSE;
853         }
854         preset = ghb_settings_get_string (settings, "preset");
855         data = presets_list_search(presetsList, preset);
856         if (data != NULL)
857         {
858                 data->defalt = TRUE;
859         }
860         ghb_settings_set_string(settings, "default_preset", preset);
861         ghb_prefs_save(settings);
862 }
863
864 gint
865 ghb_presets_list_index(const gchar *name)
866 {
867         GList *link = presetsList;
868         int ii = 0;
869         while (link != NULL)
870         {
871                 presets_data_t *data;
872                 data = (presets_data_t*)link->data;
873                 if (strcmp(name, data->name) == 0)
874                 {
875                         return ii;
876                 }
877                 link = g_list_next(link);
878                 ii++;
879         }
880         return -1;
881 }
882
883 gint
884 ghb_preset_flags(const gchar *name, gint *index)
885 {
886         GList *link = presetsList;
887         int ii = 0;
888         while (link != NULL)
889         {
890                 presets_data_t *data;
891                 data = (presets_data_t*)link->data;
892                 if (strcmp(name, data->name) == 0)
893                 {
894                         gint ret = 0;
895                         
896                         *index = ii;
897                         ret = (data->custom ? PRESET_CUSTOM : 0);
898                         ret |= (data->defalt ? PRESET_DEFAULT : 0);
899                         return ret;
900                 }
901                 link = g_list_next(link);
902                 ii++;
903         }
904         *index = -1;
905         return 0;
906 }
907
908 gchar**
909 ghb_presets_get_names()
910 {
911         gchar **result;
912         GList *link = presetsList;
913         int ii = 0;
914
915         g_debug("ghb_presets_get_names()\n");
916         result = g_malloc((g_list_length(presetsList)+1) * sizeof(gchar*));
917         while (link != NULL)
918         {
919                 presets_data_t *data;
920                 data = (presets_data_t*)link->data;
921                 result[ii++] = g_strdup(data->name);
922                 link = g_list_next(link);
923         }
924         result[ii] = NULL;
925         return result;
926 }
927
928 gchar**
929 ghb_presets_get_descriptions()
930 {
931         gchar **result;
932         GList *link = presetsList;
933         int ii = 0;
934
935         g_debug("ghb_presets_get_names()\n");
936         result = g_malloc((g_list_length(presetsList)+1) * sizeof(gchar*));
937         while (link != NULL)
938         {
939                 presets_data_t *data;
940                 data = (presets_data_t*)link->data;
941                 result[ii++] = g_strdup(data->description);
942                 link = g_list_next(link);
943         }
944         result[ii] = NULL;
945         return result;
946 }
947
948 const gchar*
949 ghb_presets_get_name(gint index)
950 {
951         gchar *result = NULL;
952         GList *link = presetsList;
953         int ii = 0;
954
955         g_debug("ghb_presets_get_name()\n");
956         while ((link != NULL) && (ii < index))
957         {
958                 link = g_list_next(link);
959                 ii++;
960         }
961         if (link != NULL)
962         {
963                 presets_data_t *data;
964                 data = (presets_data_t*)link->data;
965                 result = data->name;
966         }
967         return result;
968 }
969
970 static gboolean
971 init_presets_hash_from_key_file(signal_user_data_t *ud, const gchar *name, GKeyFile *keyFile)
972 {
973         gchar **keys;
974         gsize length;
975         gchar *str;
976         
977         // Get key list from internal default presets.  This way we do not
978         // load any unknown keys.
979         keys = g_key_file_get_keys(internalKeyFile, "Presets", &length, NULL);
980         if (keys != NULL)
981         {
982                 gint ii;
983                 for (ii = 0; keys[ii] != NULL; ii++)
984                 {
985                         g_debug("key (%s)\n", keys[ii]);
986                         str = NULL;
987                         if (name != NULL && keyFile != NULL)
988                         {
989                                 str = g_key_file_get_string(keyFile, name, keys[ii], NULL);
990                                 g_debug("(%s, %s)\n", keys[ii], str);
991                         }
992                         if (str == NULL)
993                         {
994                                 str = g_key_file_get_string(internalKeyFile, "Presets", keys[ii], NULL);
995                         }
996                         if (str != NULL)
997                         {
998                                 g_debug("name (%s): key (%s) -- str (%s)\n", name, keys[ii], str);
999                                 ghb_settings_set_string(ud->settings, keys[ii], str);
1000                                 ghb_ui_update(ud, keys[ii], str);
1001                                 g_free(str);
1002                         }
1003                 }
1004                 g_strfreev(keys);
1005                 return TRUE;
1006         }
1007         return FALSE;
1008 }
1009
1010 static void
1011 preset_to_ui(signal_user_data_t *ud, presets_data_t *data)
1012 {
1013         g_debug("preset_to_settings()\n");
1014         // Initialize the ui from presets file.
1015         if (data == NULL)
1016         {
1017                 // Set defaults
1018                 init_presets_hash_from_key_file(ud, NULL, NULL);
1019                 return;
1020         }
1021         else
1022         {
1023                 g_debug("preset name (%s)\n", data->name);
1024                 // Initialize from preset
1025                 init_presets_hash_from_key_file(ud, data->name, data->keyFile);
1026         }
1027 }
1028
1029 static void
1030 preset_update_ui(signal_user_data_t *ud, presets_data_t *data, const gchar *key)
1031 {
1032         gchar *str;
1033
1034         g_debug("preset_update_settings()\n");
1035         // Initialize the ui from presets file.
1036         if (data == NULL) return;
1037         str = g_key_file_get_string(data->keyFile, data->name, key, NULL);
1038         if (str == NULL)
1039         {
1040                 str = g_key_file_get_string(internalKeyFile, "Presets", key, NULL);
1041         }
1042         if (str != NULL)
1043         {
1044                 ghb_ui_update(ud, key, str);
1045                 g_free(str);
1046         }
1047 }
1048
1049 void
1050 ghb_set_preset(signal_user_data_t *ud, const gchar *name)
1051 {
1052         presets_data_t *data;
1053         
1054         g_debug("ghb_set_preset() %s\n", name);
1055         if (name == NULL)
1056         {
1057                 name = ghb_presets_get_name(0);
1058         }
1059         if (name == NULL)
1060         {
1061                 preset_to_ui(ud, NULL);
1062         }
1063         else
1064         {
1065                 data = presets_list_search(presetsList, name);
1066                 preset_to_ui(ud, data);
1067                 ghb_settings_set_string(ud->settings, "preset", name);
1068         }
1069         ghb_pref_audio_init(ud);
1070 }
1071
1072 void
1073 ghb_update_from_preset(
1074         signal_user_data_t *ud, 
1075         const gchar *name, 
1076         const gchar *key)
1077 {
1078         presets_data_t *data;
1079         
1080         g_debug("ghb_update_from_preset() %s %s\n", name, key);
1081         if (name == NULL) return;
1082         data = presets_list_search(presetsList, name);
1083         preset_update_ui(ud, data, key);
1084 }
1085
1086 static void
1087 build_presets_list(GHashTable *settings)
1088 {
1089         GList *link = presetsList;
1090         presets_data_t *data;
1091         gchar **custom, **standard;
1092         gsize clength, slength;
1093         gint ii, jj;
1094         
1095         g_debug("build_presets_list ()\n");
1096         // First clear out the old presets list
1097         while (link != NULL)
1098         {
1099                 data = (presets_data_t*)link->data;
1100                 g_free(data->name);
1101                 if (data->description != NULL)
1102                         g_free(data->description);
1103                 g_free(data);
1104                 link = g_list_delete_link (link, link);
1105         }
1106         presetsList = NULL;
1107
1108         // Now build up the new list
1109         const gchar *def_name = ghb_settings_get_string(settings, "default_preset");
1110         custom = g_key_file_get_groups(customKeyFile, &clength);
1111         standard = g_key_file_get_groups(standardKeyFile, &slength);
1112         if ((slength + clength) <= 0) return;
1113         jj = 0;
1114         for (ii = 0; ii < slength; ii++)
1115         {
1116                 if (search_group(standard[ii], custom) < 0)
1117                 {
1118                         gchar *desc;
1119                         data = g_malloc(sizeof(presets_data_t));
1120                         data->name = g_strdup(standard[ii]);
1121                         data->keyFile = standardKeyFile;
1122                         data->custom = FALSE;
1123                         data->defalt = FALSE;
1124                         if ((def_name != NULL) && (strcmp(def_name, data->name) == 0))
1125                         {
1126                                 data->defalt = TRUE;
1127                         }
1128                         desc = g_key_file_get_string(standardKeyFile, standard[ii], "preset_description", NULL);
1129                         data->description = desc;
1130                         presetsList = g_list_append(presetsList, data);
1131                 }
1132         }
1133         for (ii = 0; ii < clength; ii++)
1134         {
1135                 gchar *desc;
1136                 data = g_malloc(sizeof(presets_data_t));
1137                 data->name = g_strdup(custom[ii]);
1138                 data->keyFile = customKeyFile;
1139                 data->custom = TRUE;
1140                 data->defalt = FALSE;
1141                 if ((def_name != NULL) && (strcmp(def_name, data->name) == 0))
1142                 {
1143                         data->defalt = TRUE;
1144                 }
1145                 desc = g_key_file_get_string(customKeyFile, custom[ii], "preset_description", NULL);
1146                 data->description = desc;
1147                 presetsList = g_list_append(presetsList, data);
1148         }
1149         g_strfreev(custom);
1150         g_strfreev(standard);
1151 }
1152
1153 static void
1154 store_key_file(GKeyFile *key_file, const gchar *name)
1155 {
1156         gchar *settingsString;
1157         const gchar *dir;
1158         gsize length;
1159         gchar *config;
1160         gint fd;
1161
1162         g_debug("store_key_file ()\n");
1163         settingsString = g_key_file_to_data(key_file, &length, NULL);
1164
1165         dir = g_get_user_config_dir();
1166         config = g_strdup_printf ("%s/ghb", dir);
1167         if (!g_file_test(config, G_FILE_TEST_IS_DIR))
1168         {
1169                 g_mkdir (config, 0755);
1170         }
1171         g_free(config);
1172         config = g_strdup_printf ("%s/ghb/%s", dir, name);
1173         fd = g_open(config, O_RDWR|O_CREAT|O_TRUNC, 0777);
1174         write(fd, settingsString, length);
1175         close(fd);
1176         g_debug("prefs:\n%s\n", settingsString);
1177         g_free(settingsString);
1178 }
1179
1180 void
1181 ghb_prefs_to_ui(signal_user_data_t *ud)
1182 {
1183         const gchar *str;
1184         
1185         str = ghb_settings_get_string(ud->settings, "default_source");
1186         ghb_settings_set_string (ud->settings, "source", str);
1187         str = ghb_settings_get_string(ud->settings, "destination_dir");
1188
1189         gchar *path = g_strdup_printf ("%s/new_video.mp4", str);
1190         ghb_ui_update(ud, "destination", path);
1191         g_free(path);
1192 }
1193
1194 static gboolean prefs_initializing = FALSE;
1195
1196 void
1197 ghb_prefs_save(GHashTable *settings)
1198 {
1199         gint ii;
1200         const gchar *value;
1201     gchar **keys;
1202     gsize length;
1203         
1204         if (prefs_initializing) return;
1205         keys = g_key_file_get_keys(internalKeyFile, "Preferences", &length, NULL);
1206     if (keys != NULL)
1207     {
1208             for (ii = 0; keys[ii] != NULL; ii++)
1209             {
1210                     value = ghb_settings_get_string(settings, keys[ii]);
1211                     if (value != NULL)
1212                     {
1213                             g_key_file_set_value(prefsKeyFile, "Preferences", keys[ii], value);
1214                     }
1215             }
1216         g_strfreev(keys);
1217             store_key_file(prefsKeyFile, "preferences");
1218     }
1219 }
1220
1221 void
1222 ghb_pref_save(GHashTable *settings, const gchar *key)
1223 {
1224         const gchar *value;
1225         
1226         if (prefs_initializing) return;
1227         value = ghb_settings_get_string(settings, key);
1228         if (value != NULL)
1229         {
1230                 g_key_file_set_value(prefsKeyFile, "Preferences", key, value);
1231                 store_key_file(prefsKeyFile, "preferences");
1232         }
1233 }
1234
1235 #if 0
1236 static void
1237 dump_key_file(GKeyFile *keyFile, const gchar *section)
1238 {
1239         gint ii;
1240     gchar **keys;
1241     gsize length;
1242
1243     // Get defaults from internal defaults 
1244         keys = g_key_file_get_keys(keyFile, section, &length, NULL);
1245     if (keys != NULL)
1246     {
1247         for (ii = 0; keys[ii] != NULL; ii++)
1248         {
1249             gchar *str;
1250
1251                         str = g_key_file_get_string(keyFile, section, keys[ii], NULL);
1252                         if (str != NULL)
1253                         {
1254                                 g_message("Preference: key (%s) -- str (%s)\n", keys[ii], str);
1255                                 g_free(str);
1256                         }
1257                         else
1258                         {
1259                                 g_message("Preference: key (%s) -- str **none**\n", keys[ii]);
1260                         }
1261         }
1262         g_strfreev(keys);
1263     }
1264         else
1265         {
1266                 g_message("no keys");
1267         }
1268 }
1269 #endif
1270
1271 void
1272 ghb_prefs_load(signal_user_data_t *ud)
1273 {
1274         gint ii;
1275         const gchar *dir;
1276         gchar *config;
1277         gchar *value;
1278     gchar **keys;
1279     gsize length;
1280         gboolean res;
1281         
1282         prefs_initializing = TRUE;
1283         internalKeyFile = g_key_file_new();
1284         res = g_key_file_load_from_data( internalKeyFile, defaultSettings, 
1285                                                           sizeof(defaultSettings), G_KEY_FILE_NONE, NULL);
1286         if (!res)
1287                 g_warning("Failed to initialize internal defaults\n");
1288
1289         keys = g_key_file_get_keys(internalKeyFile, "Initialization", &length, NULL);
1290         if (keys != NULL)
1291         {
1292                 gint ii;
1293                 for (ii = 0; keys[ii] != NULL; ii++)
1294                 {
1295                         gchar *str;
1296                         
1297                         g_debug("key (%s)\n", keys[ii]);
1298                         str = g_key_file_get_string(internalKeyFile, "Initialization", keys[ii], NULL);
1299                         if (str != NULL)
1300                         {
1301                                 g_debug("Initialization: key (%s) -- str (%s)\n", keys[ii], str);
1302                                 ghb_settings_set_string(ud->settings, keys[ii], str);
1303                                 ghb_ui_update(ud, keys[ii], str);
1304                                 g_free(str);
1305                         }
1306                 }
1307                 g_strfreev(keys);
1308         }
1309         prefsKeyFile = g_key_file_new();
1310         dir = g_get_user_config_dir();
1311         config = g_strdup_printf ("%s/ghb/preferences", dir);
1312         if (g_file_test(config, G_FILE_TEST_IS_REGULAR))
1313         {
1314                 g_key_file_load_from_file( prefsKeyFile, config, G_KEY_FILE_KEEP_COMMENTS, NULL);
1315         }
1316         value = g_key_file_get_value(prefsKeyFile, "Preferences", "version", NULL);
1317     if (value == NULL)
1318     {
1319         gint ii;
1320
1321         // Get defaults from internal defaults 
1322             keys = g_key_file_get_keys(internalKeyFile, "Preferences", &length, NULL);
1323         if (keys != NULL)
1324         {
1325             for (ii = 0; keys[ii] != NULL; ii++)
1326             {
1327                 gchar *str;
1328
1329                             str = g_key_file_get_string(internalKeyFile, "Preferences", keys[ii], NULL);
1330                             if (str != NULL)
1331                             {
1332                                     g_debug("Preference: key (%s) -- str (%s)\n", keys[ii], str);
1333                             g_key_file_set_value(prefsKeyFile, "Preferences", keys[ii], str);
1334                                     g_free(str);
1335                             }
1336             }
1337             g_strfreev(keys);
1338         }
1339                 const gchar *dir = g_get_user_special_dir (G_USER_DIRECTORY_VIDEOS);
1340                 g_key_file_set_value(prefsKeyFile, "Preferences", "destination_dir", dir);
1341                 store_key_file(prefsKeyFile, "preferences");
1342     }
1343         g_free(config);
1344         keys = g_key_file_get_keys(internalKeyFile, "Preferences", &length, NULL);
1345     if (keys != NULL)
1346     {
1347             for (ii = 0; keys[ii] != NULL; ii++)
1348             {
1349                     value = g_key_file_get_value(prefsKeyFile, "Preferences", keys[ii], NULL);
1350                     if (value != NULL)
1351                     {
1352                             ghb_settings_set_string(ud->settings, keys[ii], value);
1353                                 ghb_ui_update(ud, keys[ii], value);
1354                             g_free(value);
1355                     }
1356             else
1357             {
1358                         value = g_key_file_get_value(internalKeyFile, "Preferences", keys[ii], NULL);
1359                         if (value != NULL)
1360                         {
1361                                 ghb_settings_set_string(ud->settings, keys[ii], value);
1362                                         ghb_ui_update(ud, keys[ii], value);
1363                                 g_free(value);
1364                         }
1365             }
1366             }
1367         g_strfreev(keys);
1368     }
1369         gint bval = ghb_settings_get_int(ud->settings, "show_presets");
1370         ghb_ui_update_int(ud, "show_presets", bval);
1371         if (ghb_settings_get_bool(ud->settings, "hbfd_feature"))
1372         {
1373                 GtkAction *action;
1374                 bval = ghb_settings_get_int(ud->settings, "hbfd");
1375                 ghb_ui_update_int(ud, "hbfd", bval);
1376                 action = GHB_ACTION (ud->builder, "hbfd");
1377                 gtk_action_set_visible(action, TRUE);
1378         }
1379         else
1380         {
1381                 ghb_ui_update_int(ud, "hbfd", 0);
1382         }
1383         prefs_initializing = FALSE;
1384 }
1385
1386 void
1387 ghb_presets_load(signal_user_data_t *ud)
1388 {
1389         const gchar *dir;
1390         gchar *config;
1391         GHashTable *settings = ud->settings;
1392
1393         g_debug("ghb_presets_load()\n");
1394         customKeyFile = g_key_file_new();
1395         standardKeyFile = g_key_file_new();
1396         dir = g_get_user_config_dir();
1397         config = g_strdup_printf ("%s/ghb/custom_presets", dir);
1398         if (g_file_test(config, G_FILE_TEST_IS_REGULAR))
1399         {
1400                 g_key_file_load_from_file( customKeyFile, config, 
1401                                                                   G_KEY_FILE_KEEP_COMMENTS, NULL);
1402         }
1403         g_free(config);
1404         // Try current dir first. Makes testing prior to installation easier
1405         if (g_file_test("./standard_presets", G_FILE_TEST_IS_REGULAR))
1406         {
1407                 g_key_file_load_from_file( standardKeyFile, "./standard_presets", 
1408                                                                   G_KEY_FILE_KEEP_COMMENTS, NULL);
1409         }
1410         else
1411         {
1412                 // Try users config dir
1413                 config = g_strdup_printf ("%s/ghb/standard_presets", dir);
1414                 if (g_file_test(config, G_FILE_TEST_IS_REGULAR))
1415                 {
1416                         g_key_file_load_from_file( standardKeyFile, config, 
1417                                                                           G_KEY_FILE_KEEP_COMMENTS, NULL);
1418                         g_free(config);
1419                 }
1420                 else
1421                 {
1422                         const gchar* const *dirs;
1423                         gint ii;
1424                         g_free(config);
1425                         dirs = g_get_system_data_dirs();
1426                         if (dirs != NULL)
1427                         {
1428                                 for (ii = 0; dirs[ii] != NULL; ii++)
1429                                 {
1430                                         config = g_strdup_printf("%s/ghb/standard_presets", dirs[ii]);
1431                                         if (g_file_test(config, G_FILE_TEST_IS_REGULAR))
1432                                         {
1433                                                 g_key_file_load_from_file( standardKeyFile, config, 
1434                                                                                                   G_KEY_FILE_KEEP_COMMENTS, NULL);
1435                                                 break;
1436                                         }
1437                                         g_free(config);
1438                                 }
1439                         }
1440                 }
1441         }
1442         build_presets_list(settings);
1443 }
1444
1445 static void
1446 presets_store()
1447 {
1448         g_debug("presets_store ()\n");
1449         store_key_file(customKeyFile, "custom_presets");
1450 }
1451
1452 typedef struct
1453 {
1454         const gchar *name;
1455         GKeyFile *keyFile;
1456         gboolean autoscale;
1457 } store_key_info_t;
1458
1459 static void
1460 store_to_key_file(gpointer xkey, gpointer xvalue, gpointer xski)
1461 {
1462         store_key_info_t *ski = (store_key_info_t*)xski;
1463         setting_value_t *value = (setting_value_t *)xvalue;
1464         gchar *key = (gchar*)xkey;
1465         gchar *str;
1466
1467         if (!ski->autoscale)
1468         {
1469                 if (strcmp(key, "scale_width"))
1470                 {
1471                         key = "max_width";
1472                 }
1473                 if (strcmp(key, "scale_height"))
1474                 {
1475                         key = "max_height";
1476                 }
1477         }
1478         str = g_key_file_get_string(internalKeyFile, "Presets", key, NULL);
1479         if (str == NULL)
1480         {
1481                 g_debug("Setting (%s) is not in defaults\n", (gchar*)key);
1482                 return;
1483         }
1484         g_debug("comparing: key (%s) -- (%s) == (%s)\n", (gchar*)key, str, value->svalue);
1485         if (strcmp(str, value->shortOpt) != 0)
1486         {
1487                 // Differs from default value.  Store it.
1488                 g_debug("storing: key (%s) -- (%s)\n", (gchar*)key, value->shortOpt);
1489                 gchar *tmp = g_strescape (value->shortOpt, NULL);
1490                 g_key_file_set_value(ski->keyFile, ski->name, (gchar*)key, tmp);
1491                 g_free(tmp);
1492         }
1493         else
1494         {
1495                 // Remove it if it exists already in keyfile
1496                 g_key_file_remove_key (ski->keyFile, ski->name, (gchar*)key, NULL);
1497         }
1498         g_free(str);
1499 }
1500
1501 void
1502 ghb_settings_save(signal_user_data_t *ud, const gchar *name)
1503 {
1504         store_key_info_t ski;
1505
1506         g_debug("ghb_settings_save ()\n");
1507         ski.name = name;
1508         ski.keyFile = customKeyFile;
1509         ski.autoscale = ghb_settings_get_bool (ud->settings, "autoscale");
1510         g_hash_table_foreach(ud->settings, store_to_key_file, &ski);
1511         presets_store();
1512         build_presets_list(ud->settings);
1513         ud->dont_clear_presets = TRUE;
1514         ghb_set_preset (ud, name);
1515         ud->dont_clear_presets = FALSE;
1516 }
1517
1518 // Checks to see if the preset is in standard presets
1519 // I allow standard to be overridden by adding a preset with the
1520 // same name to the custom list.  So to determine if the named 
1521 // preset is standard, I must first check to see if is in the
1522 // custom list.
1523 gboolean
1524 ghb_presets_is_standard(const gchar *name)
1525 {
1526         g_debug("ghb_presets_is_standard()\n");
1527         if (g_key_file_has_group(customKeyFile, name))
1528         {
1529                 // The preset is in the custom list, so it
1530                 // can not be a standard.
1531                 return FALSE;
1532         }
1533         return g_key_file_has_group(standardKeyFile, name);
1534 }
1535
1536 // This function will not remove presets from the standard preset list.
1537 // Return false if attempt is made.
1538 gboolean
1539 ghb_presets_remove(GHashTable *settings, const gchar *name)
1540 {
1541         g_debug("ghb_presets_remove()\n");
1542         if (g_key_file_has_group(customKeyFile, name))
1543         {
1544                 g_debug("\t removing %s\n", name);
1545                 g_key_file_remove_group(customKeyFile, name, NULL);
1546                 presets_store();
1547                 build_presets_list(settings);
1548                 return TRUE;
1549         }
1550         return FALSE;
1551 }
1552
1553 enum
1554 {
1555         X264_OPT_DEBLOCK,
1556         X264_OPT_INT,
1557         X264_OPT_COMBO,
1558         X264_OPT_BOOL,
1559 };
1560
1561 struct x264_opt_map_s
1562 {
1563         gchar **opt_syns;
1564         gchar *name;
1565         gchar *def_val;
1566         gint type;
1567         gboolean found;
1568 };
1569
1570 static gchar *x264_ref_syns[] = {"ref", "frameref", NULL};
1571 static gchar *x264_mixed_syns[] = {"mixed-refs", NULL};
1572 static gchar *x264_bframes_syns[] = {"bframes", NULL};
1573 static gchar *x264_direct_syns[] = {"direct", "direct-pred", NULL};
1574 static gchar *x264_weightb_syns[] = {"weightb", "weight-b", NULL};
1575 static gchar *x264_brdo_syns[] = {"brdo", "b-rdo", NULL};
1576 static gchar *x264_bime_syns[] = {"bime", NULL};
1577 static gchar *x264_bpyramid_syns[] = {"b-pyramid", NULL};
1578 static gchar *x264_me_syns[] = {"me", NULL};
1579 static gchar *x264_merange_syns[] = {"merange", "me-range", NULL};
1580 static gchar *x264_subme_syns[] = {"subme", "subq", NULL};
1581 static gchar *x264_analyse_syns[] = {"analyse", "partitions", NULL};
1582 static gchar *x264_8x8dct_syns[] = {"8x8dct", NULL};
1583 static gchar *x264_deblock_syns[] = {"deblock", "filter", NULL};
1584 static gchar *x264_trellis_syns[] = {"trellis", NULL};
1585 static gchar *x264_pskip_syns[] = {"no-fast-pskip", NULL};
1586 static gchar *x264_decimate_syns[] = {"no-dct-decimate", NULL};
1587 static gchar *x264_cabac_syns[] = {"cabac", NULL};
1588
1589 static gint
1590 find_syn_match(const gchar *opt, gchar **syns)
1591 {
1592         gint ii;
1593         for (ii = 0; syns[ii] != NULL; ii++)
1594         {
1595                 if (strcmp(opt, syns[ii]) == 0)
1596                         return ii;
1597         }
1598         return -1;
1599 }
1600
1601 struct x264_opt_map_s x264_opt_map[] =
1602 {
1603         {x264_ref_syns, "x264_refs", "1", X264_OPT_INT},
1604         {x264_mixed_syns, "x264_mixed_refs", "0", X264_OPT_BOOL},
1605         {x264_bframes_syns, "x264_bframes", "0", X264_OPT_INT},
1606         {x264_direct_syns, "x264_direct", "spatial", X264_OPT_COMBO},
1607         {x264_weightb_syns, "x264_weighted_bframes", "0", X264_OPT_BOOL},
1608         {x264_brdo_syns, "x264_brdo", "0", X264_OPT_BOOL},
1609         {x264_bime_syns, "x264_bime", "0", X264_OPT_BOOL},
1610         {x264_bpyramid_syns, "x264_bpyramid", "0", X264_OPT_BOOL},
1611         {x264_me_syns, "x264_me", "hex", X264_OPT_COMBO},
1612         {x264_merange_syns, "x264_merange", "16", X264_OPT_INT},
1613         {x264_subme_syns, "x264_subme", "5", X264_OPT_COMBO},
1614         {x264_analyse_syns, "x264_analyse", "some", X264_OPT_COMBO},
1615         {x264_8x8dct_syns, "x264_8x8dct", "0", X264_OPT_BOOL},
1616         {x264_deblock_syns, "x264_deblock_alpha", "0,0", X264_OPT_DEBLOCK},
1617         {x264_deblock_syns, "x264_deblock_beta", "0,0", X264_OPT_DEBLOCK},
1618         {x264_trellis_syns, "x264_trellis", "0", X264_OPT_COMBO},
1619         {x264_pskip_syns, "x264_no_fast_pskip", "0", X264_OPT_BOOL},
1620         {x264_decimate_syns, "x264_no_dct_decimate", "0", X264_OPT_BOOL},
1621         {x264_cabac_syns, "x264_cabac", "1", X264_OPT_BOOL},
1622 };
1623 #define X264_OPT_MAP_SIZE (sizeof(x264_opt_map)/sizeof(struct x264_opt_map_s))
1624
1625 static const gchar*
1626 x264_opt_get_default(const gchar *opt)
1627 {
1628         gint jj;
1629         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
1630         {
1631                 if (find_syn_match(opt, x264_opt_map[jj].opt_syns) >= 0)
1632                 {
1633                         return x264_opt_map[jj].def_val;
1634                 }
1635         }
1636         return "";
1637 }
1638
1639 static void
1640 x264_update_int(signal_user_data_t *ud, const gchar *name, const gchar *val)
1641 {
1642         gdouble dvalue;
1643         gchar *end;
1644
1645         if (val == NULL) return;
1646         dvalue = g_strtod (val, &end);
1647         ghb_ui_update_int(ud, name, dvalue);
1648 }
1649
1650 static void
1651 x264_update_bool(signal_user_data_t *ud, const gchar *name, const gchar *val)
1652 {
1653         if (val == NULL)
1654                 ghb_ui_update(ud, name, "1");
1655         else
1656                 ghb_ui_update(ud, name, val);
1657 }
1658
1659 static void
1660 x264_update_combo(signal_user_data_t *ud, const gchar *name, const gchar *val)
1661 {
1662         GtkTreeModel *store;
1663         GtkTreeIter iter;
1664         gchar *shortOpt;
1665         gint ivalue;
1666         gboolean foundit = FALSE;
1667         GtkWidget *widget;
1668
1669         if (val == NULL) return;
1670         widget = GHB_WIDGET(ud->builder, name);
1671         if (widget == NULL)
1672         {
1673                 g_debug("Failed to find widget for key: %s\n", name);
1674                 return;
1675         }
1676         store = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
1677         if (gtk_tree_model_get_iter_first (store, &iter))
1678         {
1679                 do
1680                 {
1681                         gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1);
1682                         if (strcmp(shortOpt, val) == 0)
1683                         {
1684                                 gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter);
1685                                 g_free(shortOpt);
1686                                 foundit = TRUE;
1687                                 break;
1688                         }
1689                         g_free(shortOpt);
1690                 } while (gtk_tree_model_iter_next (store, &iter));
1691         }
1692         if (!foundit)
1693         {
1694                 if (gtk_tree_model_get_iter_first (store, &iter))
1695                 {
1696                         do
1697                         {
1698                                 gtk_tree_model_get(store, &iter, 2, &shortOpt, 3, &ivalue, -1);
1699                                 if (strcmp(shortOpt, "custom") == 0)
1700                                 {
1701                                         gtk_list_store_set(GTK_LIST_STORE(store), &iter, 4, val, -1);
1702                                         gtk_combo_box_set_active_iter (GTK_COMBO_BOX(widget), &iter);
1703                                         g_free(shortOpt);
1704                                         foundit = TRUE;
1705                                         break;
1706                                 }
1707                                 g_free(shortOpt);
1708                         } while (gtk_tree_model_iter_next (store, &iter));
1709                 }
1710         }
1711         // Its possible the value hasn't changed. Since settings are only
1712         // updated when the value changes, I'm initializing settings here as well.
1713         ghb_widget_to_setting(ud->settings, widget);
1714 }
1715
1716 static void
1717 x264_update_deblock(signal_user_data_t *ud, const gchar *xval)
1718 {
1719         gdouble avalue, bvalue;
1720         gchar *end;
1721         gchar *val;
1722         gchar *bval = NULL;
1723
1724         if (xval == NULL) return;
1725         val = g_strdup(xval);
1726         bvalue = avalue = 0;
1727         if (val != NULL) 
1728         {
1729                 gchar *pos = strchr(val, ',');
1730                 if (pos != NULL)
1731                 {
1732                         bval = pos + 1;
1733                         *pos = 0;
1734                 }
1735                 avalue = g_strtod (val, &end);
1736                 if (bval != NULL)
1737                 {
1738                         bvalue = g_strtod (bval, &end);
1739                 }
1740         }
1741         g_free(val);
1742         ghb_ui_update_int(ud, "x264_deblock_alpha", avalue);
1743         ghb_ui_update_int(ud, "x264_deblock_beta", bvalue);
1744 }
1745
1746 void
1747 ghb_x264_parse_options(signal_user_data_t *ud, const gchar *options)
1748 {
1749         gchar **split = g_strsplit(options, ":", -1);
1750         if (split == NULL) return;
1751
1752         gint ii;
1753         gint jj;
1754
1755         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
1756                 x264_opt_map[jj].found = FALSE;
1757
1758         for (ii = 0; split[ii] != NULL; ii++)
1759         {
1760                 gchar *val = NULL;
1761                 gchar *pos = strchr(split[ii], '=');
1762                 if (pos != NULL)
1763                 {
1764                         val = pos + 1;
1765                         *pos = 0;
1766                 }
1767                 for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
1768                 {
1769                         if (find_syn_match(split[ii], x264_opt_map[jj].opt_syns) >= 0)
1770                         {
1771                                 x264_opt_map[jj].found = TRUE;
1772                                 switch(x264_opt_map[jj].type)
1773                                 {
1774                                 case X264_OPT_INT:
1775                                         x264_update_int(ud, x264_opt_map[jj].name, val);
1776                                         break;
1777                                 case X264_OPT_BOOL:
1778                                         x264_update_bool(ud, x264_opt_map[jj].name, val);
1779                                         break;
1780                                 case X264_OPT_COMBO:
1781                                         x264_update_combo(ud, x264_opt_map[jj].name, val);
1782                                         break;
1783                                 case X264_OPT_DEBLOCK:
1784                                         // dirty little hack.  mark deblock_beta found as well
1785                                         x264_opt_map[jj+1].found = TRUE;
1786                                         x264_update_deblock(ud, val);
1787                                         break;
1788                                 }
1789                                 break;
1790                         }
1791                 }
1792         }
1793         // For any options not found in the option string, set ui to
1794         // default values
1795         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
1796         {
1797                 if (!x264_opt_map[jj].found)
1798                 {
1799                         gchar *val = strdup(x264_opt_map[jj].def_val);
1800                         switch(x264_opt_map[jj].type)
1801                         {
1802                         case X264_OPT_INT:
1803                                 x264_update_int(ud, x264_opt_map[jj].name, val);
1804                                 break;
1805                         case X264_OPT_BOOL:
1806                                 x264_update_bool(ud, x264_opt_map[jj].name, val);
1807                                 break;
1808                         case X264_OPT_COMBO:
1809                                 x264_update_combo(ud, x264_opt_map[jj].name, val);
1810                                 break;
1811                         case X264_OPT_DEBLOCK:
1812                                 x264_update_deblock(ud, val);
1813                                 break;
1814                         }
1815                         x264_opt_map[jj].found = TRUE;
1816                         g_free(val);
1817                 }
1818         }
1819         g_strfreev(split);
1820 }
1821
1822 gchar*
1823 get_deblock_val(signal_user_data_t *ud)
1824 {
1825         const gchar *alpha, *beta;
1826         gchar *result;
1827         alpha = ghb_settings_get_string(ud->settings, "x264_deblock_alpha");
1828         beta = ghb_settings_get_string(ud->settings, "x264_deblock_beta");
1829         result = g_strdup_printf("%s,%s", alpha, beta);
1830         return result;
1831 }
1832
1833 void
1834 ghb_x264_opt_update(signal_user_data_t *ud, GtkWidget *widget)
1835 {
1836         gint jj;
1837         const gchar *name = gtk_widget_get_name(widget);
1838         gchar **opt_syns = NULL;
1839         const gchar *def_val = NULL;
1840         gint type;
1841
1842         for (jj = 0; jj < X264_OPT_MAP_SIZE; jj++)
1843         {
1844                 if (strcmp(name, x264_opt_map[jj].name) == 0)
1845                 {
1846                         // found the options that needs updating
1847                         opt_syns = x264_opt_map[jj].opt_syns;
1848                         def_val = x264_opt_map[jj].def_val;
1849                         type = x264_opt_map[jj].type;
1850                         break;
1851                 }
1852         }
1853         if (opt_syns != NULL)
1854         {
1855                 GString *x264opts = g_string_new("");
1856                 const gchar *options;
1857                 options = ghb_settings_get_string(ud->settings, "x264_options");
1858                 gchar **split = g_strsplit(options, ":", -1);
1859                 gint ii;
1860                 gboolean foundit = FALSE;
1861
1862                 if (split == NULL) return;
1863                 for (ii = 0; split[ii] != NULL; ii++)
1864                 {
1865                         gint syn;
1866                         gchar *val = NULL;
1867                         gchar *pos = strchr(split[ii], '=');
1868                         if (pos != NULL)
1869                         {
1870                                 val = pos + 1;
1871                                 *pos = 0;
1872                         }
1873                         syn = find_syn_match(split[ii], opt_syns);
1874                         if (syn >= 0)
1875                         { // Updating this option
1876                                 gchar *val;
1877                                 foundit = TRUE;
1878                                 if (type == X264_OPT_DEBLOCK)
1879                                         val = get_deblock_val(ud);
1880                                 else
1881                                         val = ghb_widget_string(widget);
1882                                 if (strcmp(def_val, val) != 0)
1883                                 {
1884                                         g_string_append_printf(x264opts, "%s=%s:", opt_syns[syn], val);
1885                                 }
1886                                 g_free(val);
1887                         }
1888                         else if (val != NULL)
1889                                 g_string_append_printf(x264opts, "%s=%s:", split[ii], val);
1890                         else
1891                                 g_string_append_printf(x264opts, "%s:", split[ii]);
1892
1893                 }
1894                 if (!foundit)
1895                 {
1896                         gchar *val;
1897                         if (type == X264_OPT_DEBLOCK)
1898                                 val = get_deblock_val(ud);
1899                         else
1900                                 val = ghb_widget_string(widget);
1901                         if (strcmp(def_val, val) != 0)
1902                         {
1903                                 g_string_append_printf(x264opts, "%s=%s:", opt_syns[0], val);
1904                         }
1905                         g_free(val);
1906                 }
1907                 // Update the options value
1908                 // strip the trailing ":"
1909                 gchar *result;
1910                 gint len;
1911                 result = g_string_free(x264opts, FALSE);
1912                 len = strlen(result);
1913                 if (len > 0) result[len - 1] = 0;
1914                 ghb_ui_update(ud, "x264_options", result);
1915         }
1916 }
1917
1918 static void
1919 x264_remove_opt(gchar **opts, gchar **opt_syns)
1920 {
1921         gint ii;
1922         for (ii = 0; opts[ii] != NULL; ii++)
1923         {
1924                 gchar *opt;
1925                 opt = g_strdup(opts[ii]);
1926                 gchar *pos = strchr(opt, '=');
1927                 if (pos != NULL)
1928                 {
1929                         *pos = 0;
1930                 }
1931                 if (find_syn_match(opt, opt_syns) >= 0)
1932                 {
1933                         // Mark as deleted
1934                         opts[ii][0] = 0;
1935                 }
1936                 g_free(opt);
1937         }
1938 }
1939
1940 // Construct the x264 options string
1941 // The result is allocated, so someone must free it at some point.
1942 gchar*
1943 ghb_sanitize_x264opts(signal_user_data_t *ud, const gchar *options)
1944 {
1945         GString *x264opts = g_string_new("");
1946         gchar **split = g_strsplit(options, ":", -1);
1947
1948         // Remove entries that match the defaults
1949         gint ii;
1950         for (ii = 0; split[ii] != NULL; ii++)
1951         {
1952                 gchar *val = NULL;
1953                 gchar *opt = g_strdup(split[ii]);
1954                 gchar *pos = strchr(opt, '=');
1955                 if (pos != NULL)
1956                 {
1957                         val = pos + 1;
1958                         *pos = 0;
1959                 }
1960                 else
1961                 {
1962                         val = "1";
1963                 }
1964                 const gchar *def_val = x264_opt_get_default(opt);
1965                 if (strcmp(val, def_val) == 0)
1966                 {
1967                         // Matches the default, so remove it
1968                         split[ii][0] = 0;
1969                 }
1970                 g_free(opt);
1971         }
1972         gint refs = ghb_settings_get_int(ud->settings, "x264_refs");
1973         if (refs <= 1)
1974         {
1975                 x264_remove_opt(split, x264_mixed_syns);
1976         }
1977         gint subme = ghb_settings_get_int(ud->settings, "x264_subme");
1978         if (subme < 6)
1979         {
1980                 x264_remove_opt(split, x264_brdo_syns);
1981         }
1982         gint bframes = ghb_settings_get_int(ud->settings, "x264_bframes");
1983         if (bframes == 0)
1984         {
1985                 x264_remove_opt(split, x264_weightb_syns);
1986                 x264_remove_opt(split, x264_brdo_syns);
1987                 x264_remove_opt(split, x264_bime_syns);
1988         }
1989         if (bframes <= 1)
1990         {
1991                 x264_remove_opt(split, x264_bpyramid_syns);
1992         }
1993         const gchar *me = ghb_settings_get_string(ud->settings, "x264_me");
1994         if (!(strcmp(me, "umh") == 0 || strcmp(me, "esa") == 0))
1995         {
1996                 x264_remove_opt(split, x264_merange_syns);
1997         }
1998         if (!ghb_settings_get_bool(ud->settings, "x264_cabac"))
1999         {
2000                 x264_remove_opt(split, x264_trellis_syns);
2001         }
2002         gint analyse = ghb_settings_get_int(ud->settings, "x264_analyse");
2003         if (analyse == 1)
2004         {
2005                 x264_remove_opt(split, x264_direct_syns);
2006         }
2007         for (ii = 0; split[ii] != NULL; ii++)
2008         {
2009                 if (split[ii][0] != 0)
2010                         g_string_append_printf(x264opts, "%s:", split[ii]);
2011         }
2012         // strip the trailing ":"
2013         gchar *result;
2014         gint len;
2015         result = g_string_free(x264opts, FALSE);
2016         len = strlen(result);
2017         if (len > 0) result[len - 1] = 0;
2018         return result;
2019 }
2020
2021 static gint pref_acodec[8];
2022 static gint pref_bitrate[8];
2023 static gint pref_rate[8];
2024 static gint pref_mix[8];
2025 static gdouble pref_drc[8];
2026 static gint pref_audio_count = 0;
2027
2028 void
2029 ghb_pref_audio_init(signal_user_data_t *ud)
2030 {
2031         const gchar *acodec, *bitrate, *rate, *mix, *drc;
2032         gchar **split_acodec, **split_bitrate, **split_rate;
2033         gchar **split_mix, **split_drc;
2034
2035         acodec = ghb_settings_get_string(ud->settings, "pref_audio_codec");
2036         bitrate = ghb_settings_get_string(ud->settings, "pref_audio_bitrate");
2037         rate = ghb_settings_get_string(ud->settings, "pref_audio_rate");
2038         mix = ghb_settings_get_string(ud->settings, "pref_audio_mix");
2039         drc = ghb_settings_get_string(ud->settings, "pref_audio_drc");
2040         split_acodec = g_strsplit(acodec, ",", 8);
2041         split_bitrate = g_strsplit(bitrate, ",", 8);
2042         split_rate = g_strsplit(rate, ",", 8);
2043         split_mix = g_strsplit(mix, ",", 8);
2044         split_drc = g_strsplit(drc, ",", 8);
2045         if (split_acodec == NULL)
2046         { // This should never happen, but just in case...
2047                 split_acodec = g_strsplit("faac", ",", -1);
2048         }
2049         gint ii;
2050         for (ii = 0; split_acodec[ii]; ii++)
2051         {
2052                 pref_acodec[ii] = ghb_lookup_acodec(split_acodec[ii]);
2053         }
2054         pref_audio_count = ii;
2055         for (ii = 0; split_bitrate && split_bitrate[ii]; ii++)
2056         {
2057                 pref_bitrate[ii] = ghb_lookup_bitrate(split_bitrate[ii]);
2058         }
2059         for (ii = 0; ii < pref_audio_count; ii++)
2060         {
2061                 pref_bitrate[ii] = pref_bitrate[0];
2062         }
2063         for (ii = 0; split_rate && split_rate[ii]; ii++)
2064         {
2065                 pref_rate[ii] = ghb_lookup_rate(split_rate[ii]);
2066         }
2067         for (ii = 0; ii < pref_audio_count; ii++)
2068         {
2069                 pref_rate[ii] = pref_rate[0];
2070         }
2071         for (ii = 0; split_mix && split_mix[ii]; ii++)
2072         {
2073                 pref_mix[ii] = ghb_lookup_mix(split_mix[ii]);
2074         }
2075         for (ii = 0; ii < pref_audio_count; ii++)
2076         {
2077                 pref_mix[ii] = pref_mix[0];
2078         }
2079         for (ii = 0; split_drc && split_drc[ii]; ii++)
2080         {
2081                 pref_drc[ii] = ghb_lookup_drc(split_drc[ii]);
2082         }
2083         for (ii = 0; ii < pref_audio_count; ii++)
2084         {
2085                 pref_drc[ii] = pref_drc[0];
2086         }
2087 }
2088
2089 gint
2090 ghb_pref_acount()
2091 {
2092         return pref_audio_count;
2093 }
2094
2095 gint
2096 ghb_pref_acodec(gint index)
2097 {
2098         if (index >= pref_audio_count)
2099                 return 0;
2100         return pref_acodec[index];
2101 }
2102
2103 gint
2104 ghb_pref_bitrate(gint index)
2105 {
2106         if (index >= pref_audio_count)
2107                 return 0;
2108         return pref_bitrate[index];
2109 }
2110
2111 gint
2112 ghb_pref_rate(gint index)
2113 {
2114         if (index >= pref_audio_count)
2115                 return 0;
2116         return pref_rate[index];
2117 }
2118
2119 gint
2120 ghb_pref_mix(gint index)
2121 {
2122         if (index >= pref_audio_count)
2123                 return 0;
2124         return pref_mix[index];
2125 }
2126
2127 gdouble
2128 ghb_pref_drc(gint index)
2129 {
2130         if (index >= pref_audio_count)
2131                 return 0;
2132         return pref_drc[index];
2133 }
2134