Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
config.c
Go to the documentation of this file.
00001 /*
00002  * config.c
00003  * Copyright 2011 John Lindgren
00004  *
00005  * This file is part of Audacious.
00006  *
00007  * Audacious is free software: you can redistribute it and/or modify it under
00008  * the terms of the GNU General Public License as published by the Free Software
00009  * Foundation, version 2 or version 3 of the License.
00010  *
00011  * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
00012  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
00013  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License along with
00016  * Audacious. If not, see <http://www.gnu.org/licenses/>.
00017  *
00018  * The Audacious team does not consider modular code linking to Audacious or
00019  * using our public API to be a derived work.
00020  */
00021 
00022 #include <glib.h>
00023 #include <pthread.h>
00024 #include <stdio.h>
00025 #include <string.h>
00026 
00027 #include <libaudcore/audstrings.h>
00028 #include <libaudcore/hook.h>
00029 
00030 #include "main.h"
00031 #include "misc.h"
00032 
00033 #define DEFAULT_SECTION "audacious"
00034 
00035 static const char * const core_defaults[] = {
00036 
00037  /* general */
00038  "advance_on_delete", "FALSE",
00039  "clear_playlist", "TRUE",
00040  "open_to_temporary", "TRUE",
00041  "resume_playback_on_startup", "FALSE",
00042 
00043  /* equalizer */
00044  "eqpreset_default_file", "",
00045  "eqpreset_extension", "",
00046  "equalizer_active", "FALSE",
00047  "equalizer_autoload", "FALSE",
00048  "equalizer_bands", "0,0,0,0,0,0,0,0,0,0",
00049  "equalizer_preamp", "0",
00050 
00051  /* info popup / info window */
00052  "cover_name_exclude", "back",
00053  "cover_name_include", "album,cover,front,folder",
00054  "filepopup_delay", "5",
00055  "filepopup_showprogressbar", "TRUE",
00056  "recurse_for_cover", "FALSE",
00057  "recurse_for_cover_depth", "0",
00058  "show_filepopup_for_tuple", "TRUE",
00059  "use_file_cover", "FALSE",
00060 
00061  /* network */
00062  "use_proxy", "FALSE",
00063  "use_proxy_auth", "FALSE",
00064 
00065  /* output */
00066  "default_gain", "0",
00067  "enable_replay_gain", "TRUE",
00068  "enable_clipping_prevention", "TRUE",
00069  "output_bit_depth", "16",
00070  "output_buffer_size", "500",
00071  "replay_gain_album", "FALSE",
00072  "replay_gain_preamp", "0",
00073  "software_volume_control", "FALSE",
00074  "sw_volume_left", "100",
00075  "sw_volume_right", "100",
00076 
00077  /* playback */
00078  "no_playlist_advance", "FALSE",
00079  "repeat", "FALSE",
00080  "shuffle", "FALSE",
00081  "stop_after_current_song", "FALSE",
00082 
00083  /* playlist */
00084  "generic_title_format", "${?artist:${artist} - }${?album:${album} - }${title}",
00085  "leading_zero", "FALSE",
00086  "metadata_on_play", "FALSE",
00087  "show_numbers_in_pl", "FALSE",
00088 
00089  NULL};
00090 
00091 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
00092 static GHashTable * defaults;
00093 static GKeyFile * keyfile;
00094 static bool_t modified;
00095 
00096 /* str_unref() may be a macro */
00097 static void str_unref_cb (void * str)
00098 {
00099     str_unref (str);
00100 }
00101 
00102 void config_load (void)
00103 {
00104     g_return_if_fail (! defaults && ! keyfile);
00105     pthread_mutex_lock (& mutex);
00106 
00107     defaults = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
00108      (GDestroyNotify) g_hash_table_destroy);
00109     keyfile = g_key_file_new ();
00110 
00111     char * path = g_strdup_printf ("%s/config", get_path (AUD_PATH_USER_DIR));
00112     if (g_file_test (path, G_FILE_TEST_EXISTS))
00113     {
00114         GError * error = NULL;
00115         if (! g_key_file_load_from_file (keyfile, path, 0, & error))
00116         {
00117             fprintf (stderr, "Error loading config: %s\n", error->message);
00118             g_error_free (error);
00119         }
00120     }
00121     g_free (path);
00122 
00123     modified = FALSE;
00124     pthread_mutex_unlock (& mutex);
00125 
00126     config_set_defaults (NULL, core_defaults);
00127 }
00128 
00129 void config_save (void)
00130 {
00131     g_return_if_fail (defaults && keyfile);
00132     pthread_mutex_lock (& mutex);
00133 
00134     if (! modified)
00135     {
00136         pthread_mutex_unlock (& mutex);
00137         return;
00138     }
00139 
00140     char * path = g_strdup_printf ("%s/config", get_path (AUD_PATH_USER_DIR));
00141     char * data = g_key_file_to_data (keyfile, NULL, NULL);
00142 
00143     GError * error = NULL;
00144     if (! g_file_set_contents (path, data, -1, & error))
00145     {
00146         fprintf (stderr, "Error saving config: %s\n", error->message);
00147         g_error_free (error);
00148     }
00149 
00150     g_free (data);
00151     g_free (path);
00152 
00153     modified = FALSE;
00154     pthread_mutex_unlock (& mutex);
00155 }
00156 
00157 void config_cleanup (void)
00158 {
00159     g_return_if_fail (defaults && keyfile);
00160     pthread_mutex_lock (& mutex);
00161 
00162     g_key_file_free (keyfile);
00163     keyfile = NULL;
00164     g_hash_table_destroy (defaults);
00165     defaults = NULL;
00166 
00167     pthread_mutex_unlock (& mutex);
00168 }
00169 
00170 void config_clear_section (const char * section)
00171 {
00172     g_return_if_fail (defaults && keyfile);
00173     pthread_mutex_lock (& mutex);
00174 
00175     if (! section)
00176         section = DEFAULT_SECTION;
00177 
00178     if (g_key_file_has_group (keyfile, section))
00179     {
00180         g_key_file_remove_group (keyfile, section, NULL);
00181         modified = TRUE;
00182     }
00183 
00184     pthread_mutex_unlock (& mutex);
00185 }
00186 
00187 void config_set_defaults (const char * section, const char * const * entries)
00188 {
00189     g_return_if_fail (defaults && keyfile);
00190     pthread_mutex_lock (& mutex);
00191 
00192     if (! section)
00193         section = DEFAULT_SECTION;
00194 
00195     GHashTable * table = g_hash_table_lookup (defaults, section);
00196     if (! table)
00197     {
00198         table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, str_unref_cb);
00199         g_hash_table_replace (defaults, g_strdup (section), table);
00200     }
00201 
00202     while (1)
00203     {
00204         const char * name = * entries ++;
00205         const char * value = * entries ++;
00206         if (! name || ! value)
00207             break;
00208 
00209         g_hash_table_replace (table, g_strdup (name), str_get (value));
00210     }
00211 
00212     pthread_mutex_unlock (& mutex);
00213 }
00214 
00215 static const char * get_default (const char * section, const char * name)
00216 {
00217     GHashTable * table = g_hash_table_lookup (defaults, section);
00218     const char * def = table ? g_hash_table_lookup (table, name) : NULL;
00219     return def ? def : "";
00220 }
00221 
00222 void set_string (const char * section, const char * name, const char * value)
00223 {
00224     g_return_if_fail (defaults && keyfile);
00225     g_return_if_fail (name && value);
00226     pthread_mutex_lock (& mutex);
00227 
00228     if (! section)
00229         section = DEFAULT_SECTION;
00230 
00231     const char * def = get_default (section, name);
00232     bool_t changed = FALSE;
00233 
00234     if (! strcmp (value, def))
00235     {
00236         if (g_key_file_has_key (keyfile, section, name, NULL))
00237         {
00238             g_key_file_remove_key (keyfile, section, name, NULL);
00239             changed = TRUE;
00240         }
00241     }
00242     else
00243     {
00244         char * old = g_key_file_has_key (keyfile, section, name, NULL) ?
00245          g_key_file_get_value (keyfile, section, name, NULL) : NULL;
00246 
00247         if (! old || strcmp (value, old))
00248         {
00249             g_key_file_set_value (keyfile, section, name, value);
00250             changed = TRUE;
00251         }
00252 
00253         g_free (old);
00254     }
00255 
00256     if (changed)
00257     {
00258         modified = TRUE;
00259 
00260         if (! strcmp (section, DEFAULT_SECTION))
00261         {
00262             char * event = g_strdup_printf ("set %s", name);
00263             event_queue (event, NULL);
00264             g_free (event);
00265         }
00266     }
00267 
00268     pthread_mutex_unlock (& mutex);
00269 }
00270 
00271 char * get_string (const char * section, const char * name)
00272 {
00273     g_return_val_if_fail (defaults && keyfile, g_strdup (""));
00274     g_return_val_if_fail (name, g_strdup (""));
00275     pthread_mutex_lock (& mutex);
00276 
00277     if (! section)
00278         section = DEFAULT_SECTION;
00279 
00280     char * value = g_key_file_has_key (keyfile, section, name, NULL) ?
00281      g_key_file_get_value (keyfile, section, name, NULL) : NULL;
00282 
00283     if (! value)
00284         value = g_strdup (get_default (section, name));
00285 
00286     pthread_mutex_unlock (& mutex);
00287     return value;
00288 }
00289 
00290 void set_bool (const char * section, const char * name, bool_t value)
00291 {
00292     set_string (section, name, value ? "TRUE" : "FALSE");
00293 }
00294 
00295 bool_t get_bool (const char * section, const char * name)
00296 {
00297     char * string = get_string (section, name);
00298     bool_t value = ! strcmp (string, "TRUE");
00299     g_free (string);
00300     return value;
00301 }
00302 
00303 void set_int (const char * section, const char * name, int value)
00304 {
00305     char * string = int_to_string (value);
00306     g_return_if_fail (string);
00307     set_string (section, name, string);
00308     g_free (string);
00309 }
00310 
00311 int get_int (const char * section, const char * name)
00312 {
00313     int value = 0;
00314     char * string = get_string (section, name);
00315     string_to_int (string, & value);
00316     g_free (string);
00317     return value;
00318 }
00319 
00320 void set_double (const char * section, const char * name, double value)
00321 {
00322     char * string = double_to_string (value);
00323     g_return_if_fail (string);
00324     set_string (section, name, string);
00325     g_free (string);
00326 }
00327 
00328 double get_double (const char * section, const char * name)
00329 {
00330     double value = 0;
00331     char * string = get_string (section, name);
00332     string_to_double (string, & value);
00333     g_free (string);
00334     return value;
00335 }