diff options
author | Lennart Poettering <lennart@poettering.net> | 2008-05-26 22:00:19 +0000 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2008-05-26 22:00:19 +0000 |
commit | d7fd6a45e50475cddf0b8bad8baab01b33cf3c1f (patch) | |
tree | 4f210adb96478280df083b6d4802053f93b59192 /sound-theme-spec.c | |
parent | 48178a5e2813546b61706d1f97fab761934a97f0 (diff) |
move sources to src/ subdir
git-svn-id: file:///home/lennart/svn/public/libcanberra/trunk@12 01b60673-d06a-42c0-afdd-89cb8e0f78ac
Diffstat (limited to 'sound-theme-spec.c')
-rw-r--r-- | sound-theme-spec.c | 632 |
1 files changed, 0 insertions, 632 deletions
diff --git a/sound-theme-spec.c b/sound-theme-spec.c deleted file mode 100644 index fd0f95b..0000000 --- a/sound-theme-spec.c +++ /dev/null @@ -1,632 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of libcanberra. - - Copyright 2008 Lennart Poettering - - libcanberra is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, either version 2.1 of the - License, or (at your option) any later version. - - libcanberra is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with libcanberra. If not, If not, see - <http://www.gnu.org/licenses/>. -***/ - -#include "sound-theme-spec.h" -#include "llist.h" - -#define DEFAULT_THEME "freedesktop" -#define FALLBACK_THEME "freedesktop" -#define DEFAULT_OUTPUT_PROFILE "stereo" -#define N_THEME_DIR_MAX 8 - -typedef struct ca_data_dir ca_data_dir; - -struct ca_data_dir { - CA_LLIST_FIELDS(ca_data_dir); - - char *name; - char *output_profile; -}; - -struct ca_theme_data { - char *name; - - CA_LLIST_HEAD(ca_data_dir, data_dirs); - ca_theme_dir *last_dir; - - unsigned n_theme_dir; - ca_bool_t loaded_fallback_theme; -}; - -static int get_data_home(char **e) { - const char *env, *subdir; - char *r; - ca_return_val_if_fail(e, CA_ERROR_INVALID); - - if ((env = getenv("XDG_DATA_HOME")) && *env == '/') - subdir = ""; - else if ((env = getenv("HOME")) && *env == '/') - subdir = "/.local/share"; - else { - *e = NULL; - return CA_SUCCESS; - } - - if (!(r = ca_new(char, strlen(env) + strlen(subdir) + 1))) - return CA_ERROR_OOM; - - sprintf(r, "%s%s", env, subdir); - *e = r; - - return CA_SUCCESS; -} - -static ca_bool_t data_dir_matches(ca_data_dir *d, const char*output_profile) { - ca_assert(d); - ca_assert(profile); - - /* We might want to add more elaborate matching here eventually */ - - return streq(d->profile, output_profile); -} - -static ca_data_dir* find_data_dir(ca_theme_data *t, const char *name) { - ca_data_dir *d; - - ca_assert(t); - ca_assert(name); - - for (d = t->data_dirs; d; d = d->next) - if (streq(d->name, name)) - return d; - - return NULL; -} - -static int add_data_dir(ca_theme_data *t, const char *name) { - ca_data_dir *d; - - ca_return_val_if_fail(t, CA_ERROR_INVALID); - ca_return_val_if_fail(name, CA_ERROR_INVALID); - - if (find_data_dir(t, name)) - return; - - if (!(d = ca_new0(ca_data_dir, 1))) - return CA_ERROR_OOM; - - if (!(d->name = ca_strdup(name))) { - ca_free(d); - return CA_ERROR_OOM; - } - - CA_LLIST_INSERT_AFTER(ca_data_dir, t->data_dirs, t->last_dir, d); - t->last_dir = d; - - return CA_SUCCESS; -} - -static int load_theme_path(ca_theme_data *t, const char *prefix, const char *name) { - char *fn, *inherits = NULL; - FILE *f; - ca_bool_t in_sound_theme_section = FALSE; - ca_data_dir *current_data_dir = NULL; - - ca_return_val_if_fail(t, CA_ERROR_INVALID); - ca_return_val_if_fail(prefix, CA_ERROR_INVALID); - ca_return_val_if_fail(name, CA_ERROR_INVALID); - - if (!(fn = ca_new(char, strlen(prefix) + sizeof("/sounds/")-1 + strlen(name) + sizeof("index.theme")))) - return CA_ERROR_OOM; - - sprintf(fn, "%s/sounds/%s/index.theme", prefix, name); - f = fopen(fn, "r"); - ca_free(fn); - - if (!f) { - if (errno == ENOENT) - return CA_ERROR_NOTFOUND; - - return CA_ERROR_SYSTEM; - } - - for (;;) { - char ln[1024]; - - if (!(fgets(ln, f))) { - - if (feof(f)) - break; - - ca_assert(ferror(f)); - ret = CA_ERROR_SYSTEM; - goto fail; - } - - ln[strcspn(ln, "\n\r#")] = 0; - - if (!ln[0]) - continue; - - if (streq(ln, "[Sound Theme]")) { - in_sound_theme_section = TRUE; - current_data_dir = NULL; - continue; - } - - if (ln[0] == '[' && ln[strlen(ln-1)] == ']') { - char *d; - - if (!(d = ca_strndup(ln+1, strlen(ln)-2))) { - ret = CA_ERROR_OOM; - goto fail; - } - - current_data_dir = find_data_dir(e, d); - ca_free(d); - - in_sound_theme_section = FALSE; - continue; - } - - ca_assert(!in_sound_theme_section || !current_data_dir); - ca_assert(!current_data_dir || !in_sound_theme_section); - - if (in_sound_theme_section) { - - if (!strncmp(ln, "Inherits", 8)) { - - if (inherits) { - ret = CA_ERROR_CORRUPT; - goto fail; - } - - if (!(inherits = ca_strdup(ln + 8))) { - ret = CA_ERROR_OOM; - goto fail; - } - - continue; - } - - if (!strncmp(ln, "Directories", 11)) { - char *d; - - d = ln+11; - for (;;) { - size_t k = strcspn(d, ", "); - - if (k > 0) { - char *p; - - if (!(p = ca_strndup(d, k))) { - ret = CA_ERROR_OOM; - goto fail; - } - - ret = add_data_dir(t, p); - ca_free(p); - - if (ret != CA_SUCCESS) - goto fail; - } - - if (d[k] == 0) - break; - - = k+1; - } - - continue; - } - } - - if (current_data_dir) { - - if (!strncmp(ln, "OutputProfile", 13)) { - - if (current_data_dir->output_profile && !streq(current_data_dir->output_profile, ln+13)) { - ret = CA_ERROR_CORRUPT; - goto fail; - } - - if (!(current_data_dir->output_profile = ca_strdup(ln+13))) { - ret = CA_ERROR_OOM; - goto fail; - } - - continue; - } - } - } - - t->n_theme_dir ++; - - if (inherits) { - i = inherits; - for (;;) { - size_t k = strcspn(i, ", "); - - if (k > 0) { - char *p; - - if (!(p = ca_strndup(i, k))) { - ret = CA_ERROR_OOM; - goto fail; - } - - ret = load_theme_dir(t, p); - ca_free(p); - - if (ret != CA_SUCCESS) - goto fail; - } - - if (i[k] == 0) - break; - - i = k+1; - } - } - - ret = CA_SUCCESS; - -fail: - - ca_free(inherits); - ca_free(directories); - fclose(f); - - return ret; -} - -static int load_theme_dir(ca_theme_data *t, const char *name) { - ca_return_val_if_fail(t, CA_ERROR_INVALID); - ca_return_val_if_fail(name, CA_ERROR_INVALID); - ca_return_val_if_fail(t->n_theme_dir < N_THEME_DIR_MAX, CA_ERROR_CORRUPT); - - if ((ret = get_data_home(&e)) < 0) - return ret; - - if (streq(name, FALLBACK_THEME)) - t->loaded_fallback_theme = TRUE; - - if (e) { - ret = load_theme_path(t, e, name); - ca_free(e); - - if (ret != CA_ERROR_NOTFOUND) - return ret; - } - - if (!(e = getenv("XDG_DATA_DIRS")) || *e = 0) - e = "/usr/local/share:/usr/share"; - - for (;;) { - size_t k; - - k = strcspn(e, ":"); - - if (e[0] == '/' && k > 0) { - char *p; - - if (!(p = ca_strndup(e, k))) - return CA_ERROR_OOM; - - ret = load_theme_path(t, p, name); - ca_free(p); - - if (ret != CA_ERROR_NOTFOUND) - return ret; - } - - if (e[k] == 0) - break; - - e += k+1; - } - - return CA_ERROR_NOTFOUND; -} - -static int load_theme_data(ca_theme_data **_t, const char *name) { - ca_theme_data *t; - int ret; - - ca_return_val_if_fail(_t, CA_ERROR_INVALID); - ca_return_val_if_fail(name, CA_ERROR_INVALID); - - if (*_t) - if (streq((*_t)->name, name)) - return CA_SUCCESS; - - if (!(t = pa_xnew0(ca_theme_data, 1))) - return CA_ERROR_OOM; - - if (!(t->name = ca_strdup(name))) { - ret = CA_ERROR_OOM; - goto fail; - } - - if ((ret = load_theme_dir(t, name)) < 0) - goto fail; - - if (!t->loaded_fallback_theme) - if ((ret = load_theme_dir(t, FALLBACK_THEME)) < 0) - goto fail; - - if (*_t) - ca_theme_data_free(*_t); - - *_t = t; - - return CA_SUCCESS; - -fail: - - if (t) - ca_theme_data_free(t); - - return ret; -} - -static int find_sound_for_suffix(ca_sound_file **f, ca_theme_data *t, const char *name, const char *path, const char *suffix, const char *locale, const char *subdir) { - const char *fn; - - ca_return_val_if_fail(f, CA_ERROR_INVALID); - ca_return_val_if_fail(name, CA_ERROR_INVALID); - ca_return_val_if_fail(path, CA_ERROR_INVALID); - ca_return_val_if_fail(path[0] == '/', CA_ERROR_INVALID); - ca_return_val_if_fail(suffix, CA_ERROR_INVALID); - - if (!(fn = ca_sprintf_malloc("%s/%s%s%s%s%s%s", - path, - t ? "/" : "", - t ? t->name : "", - subdir ? "/" : "" - subdir ? subdir : "", - locale ? "/" : "", - locale ? locale : "", - name, suffix))) - return CA_ERROR_OOM; - - ret = ca_sound_file_open(f, fn); - ca_free(fn); - - return ret; -} - -static int find_sound_in_path(ca_sound_file **f, ca_theme_data *t, const char *name, const char *path, const char *locale, const char *subdir) { - int ret; - - ca_return_val_if_fail(f, CA_ERROR_INVALID); - ca_return_val_if_fail(name, CA_ERROR_INVALID); - ca_return_val_if_fail(path, CA_ERROR_INVALID); - ca_return_val_if_fail(path[0] == '/', CA_ERROR_INVALID); - - if (!(p = ca_new(char, strlen(path) + sizeof("/sounds")))) - return CA_ERROR_OOM; - - sprintf(p, "%s/sounds", path); - - if ((ret = find_sound_for_suffix(f, t, name, p, ".ogg", locale, subdir)) == CA_ERROR_NOTFOUND) - ret = find_sound_for_suffix(f, t, name, p, ".wav", locale, subdir); - - ca_free(p); - - return ret; -} - -static int find_sound_in_subdir(ca_sound_file **f, ca_theme_data *t, const char *name, const char *locale, const char *subdir) { - int ret; - char *e = NULL; - ca_return_val_if_fail(f, CA_ERROR_INVALID); - ca_return_val_if_fail(name, CA_ERROR_INVALID); - - if ((ret = get_data_home(&e)) < 0) - return ret; - - if (e) { - ret = find_sound_in_path(f, t, name, e, locale, subdir); - ca_free(e); - - if (ret != CA_ERROR_NOTFOUND) - return ret; - } - - if (!(e = getenv("XDG_DATA_DIRS")) || *e = 0) - e = "/usr/local/share:/usr/share"; - - for (;;) { - size_t k; - - k = strcspn(e, ":"); - - if (e[0] == '/' && k > 0) { - char *p; - - if (!(p = ca_strndup(e, k))) - return CA_ERROR_OOM; - - ret = find_sound_in_path(f, t, name, p, locale, subdir); - ca_free(p); - - if (ret != CA_ERROR_NOTFOUND) - return ret; - } - - if (e[k] == 0) - break; - - e += k+1; - } - - return CA_ERROR_NOTFOUND; -} - -static int find_sound_for_profile(ca_sound_file **f, ca_theme_data *t, const char *name, const char *locale, const char *profile) { - ca_data_dir *d; - - ca_return_val_if_fail(f, CA_ERROR_INVALID); - ca_return_val_if_fail(name, CA_ERROR_INVALID); - - if (!t) - return find_sound_in_subdir(f, NULL, name, locale, NULL); - - for (d = t->data_dirs; d; d = d->next) - if (data_dir_matches(d, profile)) { - int ret; - - if ((ret = find_sound_in_subdir(f, t, name, locale, d->name)) != CA_ERROR_NOTFOUND) - return ret; - } - - return CA_ERROR_NOTFOUND; -} - -static int find_sound_in_locale(ca_sound_file **f, ca_theme_data *t, const char *name, const char *locale, const char *profile) { - ca_return_val_if_fail(f, CA_ERROR_INVALID); - ca_return_val_if_fail(name, CA_ERROR_INVALID); - ca_return_val_if_fail(profile, CA_ERROR_INVALID); - - /* First, try the profile def itself */ - if ((ret = find_sound_for_profile(f, t, name, locale, profile)) != CA_ERROR_NOTFOUND) - return ret; - - /* Then, fall back to stereo */ - if (!streq(profile, DEFAULT_OUTPUT_PROFILE)) - if ((ret = find_sound_for_profile(f, t, name, locale, DEFAULT_PROFILE)) != CA_ERROR_NOTFOUND) - return ret; - - /* And fall back to no profile */ - return find_sound_for_profile(f, t, name, locale, NULL); -} - -static int find_sound_for_locale(ca_sound_file **f, ca_theme_data *theme, const char *name, const char *locale, const char *profile) { - const char *e; - - ca_return_val_if_fail(f, CA_ERROR_INVALID); - ca_return_val_if_fail(name, CA_ERROR_INVALID); - ca_return_val_if_fail(locale, CA_ERROR_INVALID); - ca_return_val_if_fail(profile, CA_ERROR_INVALID); - - /* First, try the locale def itself */ - if ((ret = find_sound_in_locale(f, theme, name, locale, profile)) != CA_ERROR_NOTFOUND) - return ret; - - /* Then, try to truncate at the @ */ - if ((e = strchr(locale, '@'))) { - char *t; - - if (!(t = ca_strndup(t, e - locale))) - return CA_ERROR_OOM; - - ret = find_sound_in_locale(f, theme, name, t, profile); - ca_free(t); - - if (ret != CA_ERROR_NOTFOUND) - return ret; - } - - /* Followed by truncating at the _ */ - if ((e = strchr(locale, '_'))) { - char *t; - - if (!(t = ca_strndup(t, e - locale))) - return CA_ERROR_OOM; - - ret = find_sound_in_locale(f, theme, name, t, profile); - ca_free(t); - - if (ret != CA_ERROR_NOTFOUND) - return ret; - } - - /* Then, try "C" as fallback locale */ - if (strcmp(locale, "C")) - if ((ret = find_sound_in_locale(f, theme, name, "C", profile)) != CA_ERROR_NOTFOUND) - return ret; - - /* Try without locale */ - return find_sound_in_locale(f, theme, name, NULL, profile); -} - -static int find_sound_for_theme(ca_sound_file **f, ca_theme_data **t, const char *theme, const char *name, const char *locale, const char *profile) { - int ret; - - ca_return_val_if_fail(f, CA_ERROR_INVALID); - ca_return_val_if_fail(t, CA_ERROR_INVALID); - ca_return_val_if_fail(theme, CA_ERROR_INVALID); - ca_return_val_if_fail(name, CA_ERROR_INVALID); - ca_return_val_if_fail(locale, CA_ERROR_INVALID); - ca_return_val_if_fail(profile, CA_ERROR_INVALID); - - /* First, try in the theme itself */ - if ((ret = load_theme_data(t, theme)) == CA_SUCCESS) - if ((ret = find_sound_in_theme(f, t, name, locale, profile)) != CA_ERROR_NOTFOUND) - return ret; - - /* Then, fall back to "unthemed" files */ - return find_sound_in_theme(f, NULL, name, locale, profile); -} - -int ca_lookup_sound(ca_sound_file **f, ca_theme_data **t, ca_proplist *p) { - int ret; - const char *name, *fname; - - ca_return_val_if_fail(f, CA_ERROR_INVALID); - ca_return_val_if_fail(t, CA_ERROR_INVALID); - ca_return_val_if_fail(p, CA_ERROR_INVALID); - - ca_mutex_lock(p->mutex); - - if ((name = ca_proplist_gets(p, CA_PROP_EVENT_ID))) { - const char *theme, *locale, *profile; - - if (!(theme = ca_proplist_gets(p, CA_PROP_CANBERRA_XDG_THEME_NAME))) - theme = DEFAULT_THEME; - - if (!(locale = ca_proplist_gets(p, CA_PROP_APPLICATION_LANGUAGE))) - if (!(locale = setlocale(LC_MESSAGES, NULL))) - locale = "C"; - - if (!(profile = ca_proplist_gets(p, CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE))) - profile = DEFAULT_OUTPUT_PROFILE; - - ret = find_sound_for_theme(f, t, theme, name, locale, profile); - - } else if ((fname = ca_proplist_gets(p, CA_PROP_MEDIA_FILENAME))) - ret = ca_sound_file_open(f, fname); - else - ret = CA_ERROR_INVALID; - - ca_mutex_unlock(p->mutex); - - return ret; -} - -void ca_theme_data_free(ca_theme_data *t) { - ca_assert(t); - - while (t->data_dirs) { - ca_data_dir *d = t->data_dirs; - - CA_LLIST_REMOVE(ca_data_dir, t->data_dirs, d); - - ca_free(d->name); - ca_free(d->output_profile); - ca_free(d); - } - - ca_free(t->name); - ca_free(t); -} |