1 /* wavbreaker - A tool to split a wave file up into multiple waves.
2  * Copyright (C) 2002-2004 Timothy Robinson
3  * Copyright (C) 2007 Thomas Perl
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 
20 #include <config.h>
21 
22 #include "appconfig.h"
23 #include "sample.h"
24 #include "popupmessage.h"
25 
26 #include "gettext.h"
27 
28 #include "aoaudio.h"
29 
30 #include <gtk/gtk.h>
31 #include <glib.h>
32 
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 
37 static GtkWidget *window;
38 
39 static gboolean loading_ui = FALSE;
40 
41 static int config_file_version = 2;
42 
43 /* Function pointers to the currently selected audio driver. */
44 static AudioFunctionPointers audio_function_pointers;
45 
46 /* Output directory for wave files. */
47 static int use_outputdir = 0;
48 static GtkWidget *use_outputdir_toggle = NULL;
49 static char *outputdir = NULL;
50 static GtkWidget *outputdir_entry = NULL;
51 static GtkWidget *browse_button = NULL;
52 
53 /* Etree filename suffix */
54 /* Filename suffix (not extension) for wave files. */
55 static int use_etree_filename_suffix = 0;
56 
57 static char *etree_filename_suffix = NULL;
58 static GtkWidget *etree_filename_suffix_label = NULL;
59 static GtkWidget *etree_filename_suffix_entry = NULL;
60 
61 /* Radio buttons */
62 static GtkWidget *radio1 = NULL;
63 static GtkWidget *radio2 = NULL;
64 
65 /* Prepend File Number for wave files. */
66 static int prepend_file_number = 0;
67 static GtkWidget *prepend_file_number_toggle = NULL;
68 
69 /* CD Length disc cutoff. */
70 static char *etree_cd_length = NULL;
71 static GtkWidget *etree_cd_length_label = NULL;
72 static GtkWidget *etree_cd_length_entry = NULL;
73 
74 /* Config Filename */
75 static char *config_filename = NULL;
76 
77 /* Window and pane sizes. */
78 static int main_window_xpos = -1;
79 static int main_window_ypos = -1;
80 static int main_window_width = -1;
81 static int main_window_height = -1;
82 static int vpane1_position = -1;
83 static int vpane2_position = -1;
84 
85 /* Percentage for silence detection */
86 static int silence_percentage = 2;
87 static GtkWidget *silence_spin_button = NULL;
88 
89 /* Draw moodbar in main window */
90 static int show_moodbar = 1;
91 
92 /* function prototypes */
93 static int appconfig_read_file();
94 static void default_all_strings();
95 static void open_select_outputdir();
96 
appconfig_get_config_file_version()97 int appconfig_get_config_file_version()
98 {
99     return config_file_version;
100 }
101 
appconfig_set_config_file_version(int x)102 void appconfig_set_config_file_version(int x)
103 {
104     config_file_version = x;
105 }
106 
get_audio_function_pointers()107 AudioFunctionPointers *get_audio_function_pointers()
108 {
109     return &audio_function_pointers;
110 }
111 
set_audio_close_device(void (* f))112 void set_audio_close_device(void (*f))
113 {
114     audio_function_pointers.audio_close_device = f;
115 }
116 
set_audio_open_device(void (* f))117 void set_audio_open_device(void (*f))
118 {
119     audio_function_pointers.audio_open_device = f;
120 }
121 
set_audio_write(void (* f))122 void set_audio_write(void (*f))
123 {
124     audio_function_pointers.audio_write = f;
125 }
126 
set_audio_function_pointers()127 void set_audio_function_pointers()
128 {
129     set_audio_close_device(ao_audio_close_device);
130     set_audio_open_device(ao_audio_open_device);
131     set_audio_write(ao_audio_write);
132 }
133 
appconfig_get_main_window_xpos()134 int appconfig_get_main_window_xpos()
135 {
136     return main_window_xpos;
137 }
138 
appconfig_set_main_window_xpos(int x)139 void appconfig_set_main_window_xpos(int x)
140 {
141     main_window_xpos = x;
142 }
143 
appconfig_get_main_window_ypos()144 int appconfig_get_main_window_ypos()
145 {
146     return main_window_ypos;
147 }
148 
appconfig_set_main_window_ypos(int x)149 void appconfig_set_main_window_ypos(int x)
150 {
151     main_window_ypos = x;
152 }
153 
appconfig_get_main_window_width()154 int appconfig_get_main_window_width()
155 {
156     return main_window_width;
157 }
158 
appconfig_set_main_window_width(int x)159 void appconfig_set_main_window_width(int x)
160 {
161     main_window_width = x;
162 }
163 
appconfig_get_main_window_height()164 int appconfig_get_main_window_height()
165 {
166     return main_window_height;
167 }
168 
appconfig_set_main_window_height(int x)169 void appconfig_set_main_window_height(int x)
170 {
171     main_window_height = x;
172 }
173 
appconfig_get_vpane1_position()174 int appconfig_get_vpane1_position()
175 {
176     return vpane1_position;
177 }
178 
appconfig_set_vpane1_position(int x)179 void appconfig_set_vpane1_position(int x)
180 {
181     vpane1_position = x;
182 }
183 
appconfig_get_vpane2_position()184 int appconfig_get_vpane2_position()
185 {
186     return vpane2_position;
187 }
188 
appconfig_set_vpane2_position(int x)189 void appconfig_set_vpane2_position(int x)
190 {
191     vpane2_position = x;
192 }
193 
appconfig_get_silence_percentage()194 int appconfig_get_silence_percentage()
195 {
196     return silence_percentage;
197 }
198 
appconfig_set_silence_percentage(int x)199 void appconfig_set_silence_percentage(int x)
200 {
201     silence_percentage = x;
202 }
203 
appconfig_get_show_moodbar()204 int appconfig_get_show_moodbar() {
205     return show_moodbar;
206 }
207 
appconfig_set_show_moodbar(int x)208 void appconfig_set_show_moodbar(int x)
209 {
210     show_moodbar = x;
211 }
212 
appconfig_get_use_outputdir()213 int appconfig_get_use_outputdir()
214 {
215     return use_outputdir;
216 }
217 
appconfig_set_use_outputdir(int x)218 void appconfig_set_use_outputdir(int x)
219 {
220     use_outputdir = x;
221 }
222 
appconfig_get_outputdir()223 char *appconfig_get_outputdir()
224 {
225     return outputdir;
226 }
227 
appconfig_set_outputdir(const char * val)228 void appconfig_set_outputdir(const char *val)
229 {
230     if (outputdir != NULL) {
231         g_free(outputdir);
232     }
233     outputdir = g_strdup(val);
234 }
235 
appconfig_get_use_etree_filename_suffix()236 int appconfig_get_use_etree_filename_suffix()
237 {
238     return use_etree_filename_suffix;
239 }
240 
appconfig_set_use_etree_filename_suffix(int x)241 void appconfig_set_use_etree_filename_suffix(int x)
242 {
243     use_etree_filename_suffix = x;
244 }
245 
appconfig_get_etree_filename_suffix()246 char *appconfig_get_etree_filename_suffix()
247 {
248     return etree_filename_suffix;
249 }
250 
appconfig_set_etree_filename_suffix(const char * val)251 void appconfig_set_etree_filename_suffix(const char *val)
252 {
253     if (etree_filename_suffix != NULL) {
254         g_free(etree_filename_suffix);
255     }
256     etree_filename_suffix = g_strdup(val);
257 }
258 
appconfig_get_prepend_file_number()259 int appconfig_get_prepend_file_number()
260 {
261     return prepend_file_number;
262 }
263 
appconfig_set_prepend_file_number(int x)264 void appconfig_set_prepend_file_number(int x)
265 {
266     prepend_file_number = x;
267 }
268 
appconfig_get_etree_cd_length()269 char *appconfig_get_etree_cd_length()
270 {
271     return etree_cd_length;
272 }
273 
appconfig_set_etree_cd_length(const char * val)274 void appconfig_set_etree_cd_length(const char *val)
275 {
276     if (etree_cd_length != NULL) {
277         g_free(etree_cd_length);
278     }
279     etree_cd_length = g_strdup(val);
280 }
281 
get_config_filename()282 char *get_config_filename()
283 {
284     return config_filename;
285 }
286 
set_config_filename(const char * val)287 void set_config_filename(const char *val)
288 {
289     if (config_filename != NULL) {
290         g_free(config_filename);
291     }
292     config_filename = g_strdup(val);
293 }
294 
use_outputdir_toggled(GtkWidget * widget,gpointer user_data)295 static void use_outputdir_toggled(GtkWidget *widget, gpointer user_data)
296 {
297     if (loading_ui) {
298         return;
299     }
300 
301     if (appconfig_get_use_outputdir()) {
302         // disable the output dir widget
303         gtk_widget_set_sensitive(outputdir_entry, FALSE);
304         gtk_widget_set_sensitive(browse_button, FALSE);
305         appconfig_set_use_outputdir(0);
306     } else {
307         // enable the output dir widget
308         gtk_widget_set_sensitive(outputdir_entry, TRUE);
309         gtk_widget_set_sensitive(browse_button, TRUE);
310         appconfig_set_use_outputdir(1);
311     }
312 }
313 
use_etree_filename_suffix_toggled(GtkWidget * widget,gpointer user_data)314 static void use_etree_filename_suffix_toggled(GtkWidget *widget, gpointer user_data)
315 {
316     if (appconfig_get_use_etree_filename_suffix()) {
317         appconfig_set_use_etree_filename_suffix(0);
318     } else {
319         appconfig_set_use_etree_filename_suffix(1);
320     }
321 }
322 
radio_buttons_toggled(GtkWidget * widget,gpointer user_data)323 static void radio_buttons_toggled(GtkWidget *widget, gpointer user_data)
324 {
325     if (loading_ui) {
326         return;
327     }
328 
329     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio1)) == TRUE) {
330         gtk_widget_set_sensitive( prepend_file_number_toggle, TRUE);
331         gtk_widget_set_sensitive( etree_filename_suffix_entry, TRUE);
332         gtk_widget_set_sensitive( etree_filename_suffix_label, TRUE);
333         gtk_widget_set_sensitive( etree_cd_length_entry, FALSE);
334         gtk_widget_set_sensitive( etree_cd_length_label, FALSE);
335     } else {
336         gtk_widget_set_sensitive( prepend_file_number_toggle, FALSE);
337         gtk_widget_set_sensitive( etree_filename_suffix_entry, FALSE);
338         gtk_widget_set_sensitive( etree_filename_suffix_label, FALSE);
339         gtk_widget_set_sensitive( etree_cd_length_entry, TRUE);
340         gtk_widget_set_sensitive( etree_cd_length_label, TRUE);
341     }
342 }
343 
prepend_file_number_toggled(GtkWidget * widget,gpointer user_data)344 static void prepend_file_number_toggled(GtkWidget *widget, gpointer user_data)
345 {
346     if (loading_ui) {
347         return;
348     }
349 
350     if (appconfig_get_prepend_file_number()) {
351         appconfig_set_prepend_file_number(0);
352     } else {
353         appconfig_set_prepend_file_number(1);
354     }
355 }
356 
appconfig_hide(GtkWidget * main_window)357 static void appconfig_hide(GtkWidget *main_window)
358 {
359     gtk_widget_destroy(main_window);
360 }
361 
browse_button_clicked(GtkWidget * widget,gpointer user_data)362 static void browse_button_clicked(GtkWidget *widget, gpointer user_data)
363 {
364     open_select_outputdir();
365 }
366 
open_select_outputdir()367 static void open_select_outputdir() {
368     GtkWidget *dialog;
369 
370     dialog = gtk_file_chooser_dialog_new(_("Select Output Directory"),
371         GTK_WINDOW(window), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
372         _("Cancel"), GTK_RESPONSE_CANCEL,
373         _("Open"), GTK_RESPONSE_ACCEPT,
374         NULL);
375     gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
376         gtk_entry_get_text(GTK_ENTRY(outputdir_entry)));
377 
378     if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
379         char *filename;
380 
381         filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
382         gtk_entry_set_text(GTK_ENTRY(outputdir_entry), filename);
383         g_free(filename);
384     }
385 
386     gtk_widget_destroy(dialog);
387 }
388 
389 static void
on_appconfig_close(GtkWidget * widget,GdkEvent * event,gpointer user_data)390 on_appconfig_close(GtkWidget *widget, GdkEvent *event, gpointer user_data)
391 {
392     appconfig_set_outputdir(gtk_entry_get_text(GTK_ENTRY(outputdir_entry)));
393     appconfig_set_etree_filename_suffix(gtk_entry_get_text(GTK_ENTRY(etree_filename_suffix_entry)));
394     appconfig_set_etree_cd_length(gtk_entry_get_text(GTK_ENTRY(etree_cd_length_entry)));
395     appconfig_set_silence_percentage( gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON(silence_spin_button)));
396     set_audio_function_pointers();
397 
398     track_break_rename( FALSE);
399     appconfig_hide(GTK_WIDGET(user_data));
400     appconfig_write_file();
401 }
402 
appconfig_show(GtkWidget * main_window)403 void appconfig_show(GtkWidget *main_window)
404 {
405     GtkWidget *vbox;
406     GtkWidget *grid;
407     GtkWidget *label;
408 
409     GtkWidget *stack;
410 
411     window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
412     gtk_window_set_modal(GTK_WINDOW(window), TRUE);
413     gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(main_window));
414     gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
415     gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ON_PARENT);
416 
417     GtkWidget *header_bar = gtk_header_bar_new();
418     gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(header_bar), TRUE);
419     gtk_header_bar_set_title(GTK_HEADER_BAR(header_bar), _("Preferences"));
420     gtk_window_set_titlebar(GTK_WINDOW(window), header_bar);
421 
422     /* create the vbox for the first tab */
423     vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
424     gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
425     gtk_container_add( GTK_CONTAINER(window), vbox);
426 
427     stack = gtk_stack_new();
428     gtk_container_add(GTK_CONTAINER(vbox), stack);
429 
430     GtkWidget *stack_switcher = gtk_stack_switcher_new();
431     gtk_stack_switcher_set_stack(GTK_STACK_SWITCHER(stack_switcher), GTK_STACK(stack));
432     gtk_header_bar_set_custom_title(GTK_HEADER_BAR(header_bar), stack_switcher);
433 
434     /* Selectable Output Directory */
435     grid = gtk_grid_new();
436     gtk_container_set_border_width(GTK_CONTAINER(grid), 10);
437     gtk_grid_set_row_spacing(GTK_GRID(grid), 5);
438     gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
439     gtk_stack_add_titled(GTK_STACK(stack), grid, "general", _("General"));
440 
441     use_outputdir_toggle = gtk_check_button_new_with_label(_("Save output files in folder:"));
442     gtk_grid_attach(GTK_GRID(grid), use_outputdir_toggle,
443             0, 0, 2, 1);
444     g_signal_connect(G_OBJECT(use_outputdir_toggle), "toggled",
445         G_CALLBACK(use_outputdir_toggled), NULL);
446 
447     outputdir_entry = gtk_entry_new();
448     g_object_set(outputdir_entry, "hexpand", TRUE, NULL);
449     gtk_entry_set_text(GTK_ENTRY(outputdir_entry), outputdir);
450     gtk_entry_set_width_chars(GTK_ENTRY(outputdir_entry), 40);
451     gtk_grid_attach(GTK_GRID(grid), outputdir_entry,
452         0, 1, 1, 1);
453 
454     browse_button = gtk_button_new_with_label(_("Browse"));
455     gtk_grid_attach(GTK_GRID(grid), browse_button,
456         1, 1, 1, 1);
457     g_signal_connect(G_OBJECT(browse_button), "clicked",
458             (GCallback)browse_button_clicked, window);
459 
460     silence_spin_button = (GtkWidget*)gtk_spin_button_new_with_range( 1.0, 100.0, 1.0);
461     gtk_spin_button_set_digits( GTK_SPIN_BUTTON(silence_spin_button), 0);
462     gtk_spin_button_set_value( GTK_SPIN_BUTTON(silence_spin_button), appconfig_get_silence_percentage());
463 
464     label = gtk_label_new( _("Maximum volume considered silence (in percent):"));
465     g_object_set(G_OBJECT(label), "xalign", 0.0f, "yalign", 0.5f, NULL);
466 
467     gtk_grid_attach(GTK_GRID(grid), label,
468         0, 2, 1, 1);
469     gtk_grid_attach(GTK_GRID(grid), silence_spin_button,
470         1, 2, 1, 1);
471 
472     /* Etree Filename Suffix */
473 
474     grid = gtk_grid_new();
475     gtk_container_set_border_width(GTK_CONTAINER(grid), 10);
476     gtk_grid_set_row_spacing(GTK_GRID(grid), 5);
477     gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
478     gtk_stack_add_titled(GTK_STACK(stack), grid, "naming", _("File Naming"));
479 
480     radio1 = gtk_radio_button_new_with_label(NULL, _("Standard (##)"));
481     gtk_grid_attach(GTK_GRID(grid), radio1, 0, 0, 3, 1);
482     g_signal_connect(G_OBJECT(radio1), "toggled",
483         G_CALLBACK(radio_buttons_toggled), NULL);
484 
485     etree_filename_suffix_label = gtk_label_new(_("Separator:"));
486     g_object_set(G_OBJECT(etree_filename_suffix_label), "xalign", 0.0f, "yalign", 0.5f, NULL);
487     gtk_grid_attach(GTK_GRID(grid), etree_filename_suffix_label,
488             1, 1, 1, 1);
489 
490     etree_filename_suffix_entry = gtk_entry_new();
491     g_object_set(etree_filename_suffix_entry, "hexpand", TRUE, NULL);
492     gtk_entry_set_text(GTK_ENTRY(etree_filename_suffix_entry), etree_filename_suffix);
493     gtk_entry_set_width_chars(GTK_ENTRY(etree_filename_suffix_entry), 10);
494     gtk_grid_attach(GTK_GRID(grid), etree_filename_suffix_entry,
495             2, 1, 1, 1);
496 
497     label = gtk_label_new("   ");
498     g_object_set(G_OBJECT(label), "xalign", 0.0f, "yalign", 0.5f, NULL);
499     gtk_grid_attach(GTK_GRID(grid), label,
500             0, 2, 1, 1);
501 
502     prepend_file_number_toggle = gtk_check_button_new_with_label(_("Prepend number before filename"));
503     gtk_grid_attach(GTK_GRID(grid), prepend_file_number_toggle,
504             1, 2, 2, 1);
505     g_signal_connect(G_OBJECT(prepend_file_number_toggle), "toggled",
506         G_CALLBACK(prepend_file_number_toggled), NULL);
507 
508     radio2 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio1),
509             _("etree.org (d#t##)"));
510     gtk_grid_attach(GTK_GRID(grid), radio2, 0, 3, 3, 1);
511 
512     etree_cd_length_label = gtk_label_new(_("CD Length:"));
513     g_object_set(G_OBJECT(etree_cd_length_label), "xalign", 0.0f, "yalign", 0.5f, NULL);
514     gtk_grid_attach(GTK_GRID(grid), etree_cd_length_label,
515             1, 4, 1, 1);
516 
517     etree_cd_length_entry = gtk_entry_new();
518     gtk_entry_set_text(GTK_ENTRY(etree_cd_length_entry), etree_cd_length);
519     gtk_entry_set_width_chars(GTK_ENTRY(etree_cd_length_entry), 10);
520     gtk_grid_attach(GTK_GRID(grid), etree_cd_length_entry,
521             2, 4, 1, 1);
522 
523     g_signal_connect(G_OBJECT(window),
524         "delete-event", G_CALLBACK(on_appconfig_close), window);
525 
526     g_signal_connect(G_OBJECT(radio2), "toggled",
527         G_CALLBACK(use_etree_filename_suffix_toggled), NULL);
528 
529     loading_ui = TRUE;
530 
531     gboolean use_output_dir = appconfig_get_use_outputdir() ? TRUE : FALSE;
532     gtk_widget_set_sensitive(outputdir_entry, use_output_dir);
533     gtk_widget_set_sensitive(browse_button, use_output_dir);
534     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(use_outputdir_toggle), use_output_dir);
535 
536     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(prepend_file_number_toggle),
537             appconfig_get_prepend_file_number() ? TRUE : FALSE);
538 
539     gboolean use_etree = appconfig_get_use_etree_filename_suffix() ? TRUE : FALSE;
540     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio1), !use_etree);
541     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio2), use_etree);
542 
543     loading_ui = FALSE;
544 
545     gtk_widget_show_all(window);
546     set_audio_function_pointers();
547     radio_buttons_toggled( NULL, NULL);
548 }
549 
550 enum ConfigOptionType {
551     INVALID = 0,
552     STRING,
553     INTEGER,
554     BOOLEAN,
555 };
556 
557 typedef struct ConfigOption_ ConfigOption;
558 
559 struct ConfigOption_ {
560     const char *key;
561     enum ConfigOptionType type;
562     void *setter;
563     void *getter;
564 } config_options[] = {
565 #define OPTION(name, type) { #name, type, appconfig_set_ ## name, appconfig_get_ ## name }
566     OPTION(config_file_version, INTEGER),
567 
568     OPTION(use_outputdir, BOOLEAN),
569     OPTION(outputdir, STRING),
570 
571     OPTION(use_etree_filename_suffix, BOOLEAN),
572     OPTION(etree_filename_suffix, STRING),
573     OPTION(etree_cd_length, STRING),
574     OPTION(prepend_file_number, BOOLEAN),
575 
576     OPTION(main_window_xpos, INTEGER),
577     OPTION(main_window_ypos, INTEGER),
578     OPTION(main_window_width, INTEGER),
579     OPTION(main_window_height, INTEGER),
580 
581     OPTION(vpane1_position, INTEGER),
582     OPTION(vpane2_position, INTEGER),
583 
584     OPTION(silence_percentage, INTEGER),
585     OPTION(show_moodbar, BOOLEAN),
586 #undef OPTION
587     { NULL, INVALID, NULL, NULL },
588 };
589 
590 
config_option_set_string(ConfigOption * option,gchar * value)591 void config_option_set_string(ConfigOption *option, gchar *value)
592 {
593     ((void (*)(const char *))(option->setter))(value);
594     g_free(value);
595 }
596 
config_option_set_integer(ConfigOption * option,int value)597 void config_option_set_integer(ConfigOption *option, int value)
598 {
599     ((void (*)(int))(option->setter))(value);
600 }
601 
config_option_get_string(ConfigOption * option)602 const char *config_option_get_string(ConfigOption *option)
603 {
604     return ((const char *(*)())(option->getter))();
605 }
606 
config_option_get_integer(ConfigOption * option)607 int config_option_get_integer(ConfigOption *option)
608 {
609     return ((int (*)())(option->getter))();
610 }
611 
appconfig_read_file()612 static int appconfig_read_file() {
613     GKeyFile *keyfile = g_key_file_new();
614 
615     if (!g_key_file_load_from_file(keyfile, config_filename, G_KEY_FILE_NONE, NULL)) {
616         g_key_file_free(keyfile);
617         return 0;
618     }
619 
620     ConfigOption *option = config_options;
621     for (option=config_options; option->key; option++) {
622         switch (option->type) {
623             case INTEGER:
624                 config_option_set_integer(option,
625                         g_key_file_get_integer(keyfile, "wavbreaker", option->key, NULL));
626                 break;
627             case BOOLEAN:
628                 config_option_set_integer(option,
629                         g_key_file_get_boolean(keyfile, "wavbreaker", option->key, NULL));
630                 break;
631             case STRING:
632                 config_option_set_string(option,
633                         g_key_file_get_string(keyfile, "wavbreaker", option->key, NULL));
634                 break;
635             default:
636                 g_warning("Invalid option type: %d\n", option->type);
637                 break;
638         }
639     }
640 
641     g_key_file_free(keyfile);
642 
643     return 1;
644 }
645 
646 
appconfig_write_file()647 void appconfig_write_file() {
648     GKeyFile *keyfile = g_key_file_new();
649 
650     g_key_file_load_from_file(keyfile, config_filename, G_KEY_FILE_KEEP_COMMENTS, NULL);
651 
652     ConfigOption *option = config_options;
653     for (option=config_options; option->key; option++) {
654         switch (option->type) {
655             case INTEGER:
656                 g_key_file_set_integer(keyfile, "wavbreaker", option->key,
657                         config_option_get_integer(option));
658                 break;
659             case BOOLEAN:
660                 g_key_file_set_boolean(keyfile, "wavbreaker", option->key,
661                         config_option_get_integer(option));
662                 break;
663             case STRING:
664                 g_key_file_set_string(keyfile, "wavbreaker", option->key,
665                         config_option_get_string(option));
666                 break;
667             default:
668                 g_warning("Invalid option type: %d\n", option->type);
669                 break;
670         }
671     }
672 
673     if (!g_key_file_save_to_file(keyfile, config_filename, NULL)) {
674         g_warning("Could not save settings");
675     }
676 
677     g_key_file_free(keyfile);
678 }
679 
appconfig_init()680 void appconfig_init()
681 {
682     gchar *config_filename = g_build_path("/", g_get_user_config_dir(),
683             "wavbreaker", "wavbreaker.conf", NULL);
684     set_config_filename(config_filename);
685 
686     gchar *config_dir = g_path_get_dirname(config_filename);
687     if (g_mkdir_with_parents(config_dir, 0700) != 0) {
688         g_warning("Could not create configuration directory: %s", config_dir);
689     }
690     g_free(config_dir);
691     g_free(config_filename);
692 
693     if (!appconfig_read_file()) {
694         default_all_strings();
695         appconfig_write_file();
696     } else {
697         default_all_strings();
698     }
699 }
700 
default_all_strings()701 void default_all_strings() {
702     /* default any values that where not in the config file */
703     if (appconfig_get_outputdir() == NULL) {
704         outputdir = g_strdup(getenv("PWD"));
705     }
706     if (appconfig_get_etree_filename_suffix() == NULL) {
707         etree_filename_suffix = g_strdup("-");
708     }
709     if (appconfig_get_etree_cd_length() == NULL) {
710         etree_cd_length = g_strdup("80");
711     }
712 
713     set_audio_function_pointers();
714 }
715