diff options
| -rw-r--r-- | canberra.h | 54 | ||||
| -rw-r--r-- | sound-theme-spec.c | 636 | ||||
| -rw-r--r-- | sound-theme-spec.h | 34 | 
3 files changed, 556 insertions, 168 deletions
@@ -80,32 +80,34 @@  #endif  /** Context, event, and playback properties */ -#define CA_PROP_MEDIA_NAME                  "media.name" -#define CA_PROP_MEDIA_TITLE                 "media.title" -#define CA_PROP_MEDIA_ARTIST                "media.artist" -#define CA_PROP_MEDIA_LANGUAGE              "media.language" -#define CA_PROP_MEDIA_FILENAME              "media.filename" -#define CA_PROP_MEDIA_ICON                  "media.icon" -#define CA_PROP_MEDIA_ICON_NAME             "media.icon_name" -#define CA_PROP_MEDIA_ROLE                  "media.role" -#define CA_PROP_EVENT_ID                    "event.id" -#define CA_PROP_EVENT_MOUSE_X               "event.mouse.x" -#define CA_PROP_EVENT_MOUSE_Y               "event.mouse.y" -#define CA_PROP_EVENT_MOUSE_BUTTON          "event.mouse.button" -#define CA_PROP_WINDOW_X11_DISPLAY          "window.x11.display" -#define CA_PROP_WINDOW_X11_XID              "window.x11.xid" -#define CA_PROP_APPLICATION_NAME            "application.name" -#define CA_PROP_APPLICATION_ID              "application.id" -#define CA_PROP_APPLICATION_VERSION         "application.version" -#define CA_PROP_APPLICATION_ICON            "application.icon" -#define CA_PROP_APPLICATION_ICON_NAME       "application.icon_name" -#define CA_PROP_APPLICATION_LANGUAGE        "application.language" -#define CA_PROP_APPLICATION_PROCESS_ID      "application.process.id" -#define CA_PROP_APPLICATION_PROCESS_BINARY  "application.process.binary" -#define CA_PROP_APPLICATION_PROCESS_USER    "application.process.user" -#define CA_PROP_APPLICATION_PROCESS_HOST    "application.process.host" -#define CA_PROP_CANBERRA_CONTROL_CACHE      "canberra.control.cache"    /* permanent, volatile, never */ -#define CA_PROP_CANBERRA_CONTROL_VOLUME     "canberra.control.volume"   /* decibel */ +#define CA_PROP_MEDIA_NAME                         "media.name" +#define CA_PROP_MEDIA_TITLE                        "media.title" +#define CA_PROP_MEDIA_ARTIST                       "media.artist" +#define CA_PROP_MEDIA_LANGUAGE                     "media.language" +#define CA_PROP_MEDIA_FILENAME                     "media.filename" +#define CA_PROP_MEDIA_ICON                         "media.icon" +#define CA_PROP_MEDIA_ICON_NAME                    "media.icon_name" +#define CA_PROP_MEDIA_ROLE                         "media.role" +#define CA_PROP_EVENT_ID                           "event.id" +#define CA_PROP_EVENT_MOUSE_X                      "event.mouse.x" +#define CA_PROP_EVENT_MOUSE_Y                      "event.mouse.y" +#define CA_PROP_EVENT_MOUSE_BUTTON                 "event.mouse.button" +#define CA_PROP_WINDOW_X11_DISPLAY                 "window.x11.display" +#define CA_PROP_WINDOW_X11_XID                     "window.x11.xid" +#define CA_PROP_APPLICATION_NAME                   "application.name" +#define CA_PROP_APPLICATION_ID                     "application.id" +#define CA_PROP_APPLICATION_VERSION                "application.version" +#define CA_PROP_APPLICATION_ICON                   "application.icon" +#define CA_PROP_APPLICATION_ICON_NAME              "application.icon_name" +#define CA_PROP_APPLICATION_LANGUAGE               "application.language" +#define CA_PROP_APPLICATION_PROCESS_ID             "application.process.id" +#define CA_PROP_APPLICATION_PROCESS_BINARY         "application.process.binary" +#define CA_PROP_APPLICATION_PROCESS_USER           "application.process.user" +#define CA_PROP_APPLICATION_PROCESS_HOST           "application.process.host" +#define CA_PROP_CANBERRA_CACHE_CONTROL             "canberra.cache-control"             /* permanent, volatile, never */ +#define CA_PROP_CANBERRA_VOLUME                    "canberra.volume"                    /* decibel */ +#define CA_PROP_CANBERRA_XDG_THEME_NAME            "canberra.xdg-theme.name"            /* XDG theme name */ +#define CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE  "canberra.xdg-theme.output-profile"  /* XDG theme profile */  /* Context object */  typedef struct ca_context ca_context; diff --git a/sound-theme-spec.c b/sound-theme-spec.c index 0a82ef2..fd0f95b 100644 --- a/sound-theme-spec.c +++ b/sound-theme-spec.c @@ -1,20 +1,397 @@ +/* $Id$ */ -#define DEFAULT_THEME "dudeldidei" -#define DEFAULT_PROFILE "stereo" +/*** +  This file is part of libcanberra. -static int find_sound_for_suffix(ca_sound_file **f, const char *path, const char *name, const char *suffix, const char *theme, const char *locale, const char *subdir) { +  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(name, 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, -                                 theme ? "/" : "", -                                 theme ? theme : "", +                                 t ? "/" : "", +                                 t ? t->name : "",                                   subdir ? "/" : ""                                   subdir ? subdir : "",                                   locale ? "/" : "", @@ -28,85 +405,113 @@ static int find_sound_for_suffix(ca_sound_file **f, const char *path, const char      return ret;  } -static int find_sound_in_path(ca_sound_file **f, const char *path, const char *name, const char *theme, const char *locale, const char *subdir) { +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); -    ca_return_val_if_fail(name, CA_ERROR_INVALID); -    if ((ret = find_sound_for_suffix(f, path, name, ".ogg", theme, locale, subdir)) != CA_ERROR_NOTFOUND) -        return ret; +    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 find_sound_for_suffix(f, path, name, ".wav", theme, locale, subdir); +    return ret;  } -static int find_sound_in_theme(ca_sound_file **f, const char *name, const char *theme, const char *locale, const char *subdir) { +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; -    const char *e; +    char *e = NULL;      ca_return_val_if_fail(f, CA_ERROR_INVALID);      ca_return_val_if_fail(name, CA_ERROR_INVALID); -    if ((e = getenv("XDG_DATA_DIRS"))) { -        for (;;) { -            const char *r; -            char *p; +    if ((ret = get_data_home(&e)) < 0) +        return ret; -            if (!(r = strchr(e, ':'))) -                break; +    if (e) { +        ret = find_sound_in_path(f, t, name, e, locale, subdir); +        ca_free(e); + +        if (ret != CA_ERROR_NOTFOUND) +            return ret; +    } -            if (!(p = ca_strndup(e, r-e))) +    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, p, name, theme, locale, subdir); +            ret = find_sound_in_path(f, t, name, p, locale, subdir);              ca_free(p);              if (ret != CA_ERROR_NOTFOUND)                  return ret; - -            e = r+1;          } + +        if (e[k] == 0) +            break; + +        e += k+1;      } -    if ((e = getenv("HOME"))) { -        char *p; -        #define SUBDIR "/.share/sounds" +    return CA_ERROR_NOTFOUND; +} -        if (!(p = ca_new(char, strlen(e) + sizeof(SUBDIR)))) -            return CA_ERROR_OOM; +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; -        sprintf(p, "%s" SUBDIR, e); +    ca_return_val_if_fail(f, CA_ERROR_INVALID); +    ca_return_val_if_fail(name, CA_ERROR_INVALID); -        ret = find_sound_in_path(f, p, name, theme, locale, subdir); -        ca_free(p); +    if (!t) +        return find_sound_in_subdir(f, NULL, name, locale, NULL); -        if (ret != CA_ERROR_NOTFOUND) -            return ret; -    } +    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, const char *name, const char *theme, const char *locale, const char *profile) { +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_in_profile(f, name, theme, locale, profile)) != CA_ERROR_NOTFOUND) +    if ((ret = find_sound_for_profile(f, t, name, locale, profile)) != CA_ERROR_NOTFOUND)          return ret;      /* Then, fall back to stereo */ -    if (strcmp(profile, "stereo")) -        if ((ret = find_sound_in_profile(f, name, theme, locale, "stereo")) != CA_ERROR_NOTFOUND) +    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_in_profile(f, name, theme, locale, NULL); +    return find_sound_for_profile(f, t, name, locale, NULL);  } -static int find_sound_in_theme(ca_sound_file **f, const char *name, const char *theme, const char *locale, const char *profile) { +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); @@ -115,7 +520,7 @@ static int find_sound_in_theme(ca_sound_file **f, const char *name, const char *      ca_return_val_if_fail(profile, CA_ERROR_INVALID);      /* First, try the locale def itself */ -    if ((ret = find_sound_in_locale(f, name, theme, locale, profile)) != CA_ERROR_NOTFOUND) +    if ((ret = find_sound_in_locale(f, theme, name, locale, profile)) != CA_ERROR_NOTFOUND)          return ret;      /* Then, try to truncate at the @ */ @@ -125,7 +530,7 @@ static int find_sound_in_theme(ca_sound_file **f, const char *name, const char *          if (!(t = ca_strndup(t, e - locale)))              return CA_ERROR_OOM; -        ret = find_sound_in_locale(f, name, theme, t, profile); +        ret = find_sound_in_locale(f, theme, name, t, profile);          ca_free(t);          if (ret != CA_ERROR_NOTFOUND) @@ -139,7 +544,7 @@ static int find_sound_in_theme(ca_sound_file **f, const char *name, const char *          if (!(t = ca_strndup(t, e - locale)))              return CA_ERROR_OOM; -        ret = find_sound_in_locale(f, name, theme, t, profile); +        ret = find_sound_in_locale(f, theme, name, t, profile);          ca_free(t);          if (ret != CA_ERROR_NOTFOUND) @@ -148,133 +553,80 @@ static int find_sound_in_theme(ca_sound_file **f, const char *name, const char *      /* Then, try "C" as fallback locale */      if (strcmp(locale, "C")) -        if ((ret = find_sound_in_locale(f, name, theme, "C", profile)) != CA_ERROR_NOTFOUND) +        if ((ret = find_sound_in_locale(f, theme, name, "C", profile)) != CA_ERROR_NOTFOUND)              return ret;      /* Try without locale */ -    if ((ret = find_sound_in_locale(f, name, theme, NULL, profile))) -        return ret; - -    /* Try to find an inherited theme */ - +    return find_sound_in_locale(f, theme, name, NULL, profile);  } -int find_sound(ca_sound_file **f, const char *name, const char *theme, const char *locale, const char *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); - -    if (!theme) -        theme = DEFAULT_THEME; - -    if (!locale) -        locale = setlocale(LC_MESSAGES, NULL); - -    if (!locale) -        locale = "C"; - -    if (!profile) -        profile = DEFAULT_PROFILE; +    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 = find_sound_in_theme(f, name, theme, locale, profile)) != CA_ERROR_NOTFOUND) -        return ret; - -    /* Then, fall back to the magic freedesktop theme */ -    if (strcmp(theme, "freedesktop")) -        if ((ret = find_sound_in_theme(f, name, "freedesktop", locale, profile)) != CA_ERROR_NOTFOUND) +    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; -    /* Finally, fall back to "unthemed" files */ -    return find_sound_in_theme(f, name, NULL, locale, profile); +    /* Then, fall back to "unthemed" files */ +    return find_sound_in_theme(f, NULL, name, locale, profile);  } -FindSound(sound, locale) { -  filename = FindSoundHelper(sound, locale, soundsystem, user selected theme); -  if filename != none -    return filename +int ca_lookup_sound(ca_sound_file **f, ca_theme_data **t, ca_proplist *p) { +    int ret; +    const char *name, *fname; -  filename = FindSoundHelper(sound, locale, soundsystem, "freedesktop"); -  if filename != none -    return filename +    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); -  return LookupFallbackSound (sound) -} +    ca_mutex_lock(p->mutex); -FindSoundHelper(sound, locale, soundsystem, theme) { -  filename = LookupSound (sound, locale, soundsystem, theme) -  if filename != none -    return filename +    if ((name = ca_proplist_gets(p, CA_PROP_EVENT_ID))) { +        const char *theme, *locale, *profile; -  if theme has parents -    parents = theme.parents +        if (!(theme = ca_proplist_gets(p, CA_PROP_CANBERRA_XDG_THEME_NAME))) +            theme = DEFAULT_THEME; -  for parent in parents { -    filename = FindSoundHelper (sound, locale, soundsystem, parent) -    if filename != none -      return filename -  } -  return none -} +        if (!(locale = ca_proplist_gets(p, CA_PROP_APPLICATION_LANGUAGE))) +            if (!(locale = setlocale(LC_MESSAGES, NULL))) +                locale = "C"; -LookupSound (sound, locale, soundsystem, theme) { -  // lookup localized version -  for each subdir in $(theme subdir list) { -    for each directory in $(basename list) { -      for system in (soundsystem, "stereo") { -        if DirectoryMatchesSoundSystem(subdir, system) { -          for extension in ("wav", "ogg") { -	    filename = directory/$(themename)/subdir/$locale/sound.extension -            if exist filename -              return filename -          } -        } -      } -    } -  } - - // lookup unlocalized version -  for each subdir in $(theme subdir list) { -    for each directory in $(basename list) { -      for system in (soundsystem, "stereo") { -        if DirectoryMatchesSoundSystem(subdir, system) { -          for extension in ("wav", "ogg") { -	    filename = directory/$(themename)/subdir/sound.extension -            if exist filename -              return filename -          } -        } -      } -    } -  } +        if (!(profile = ca_proplist_gets(p, CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE))) +            profile = DEFAULT_OUTPUT_PROFILE; -  return none -} +        ret = find_sound_for_theme(f, t, theme, name, locale, profile); -LookupFallbackSound (sound) { -  for each directory in $(basename list) { -    for extension in ("wav", "ogg") { -      if exists directory/sound.extension -        return directory/sound.extension -    } -  } -  return none -} +    } else if ((fname = ca_proplist_gets(p, CA_PROP_MEDIA_FILENAME))) +        ret = ca_sound_file_open(f, fname); +    else +        ret = CA_ERROR_INVALID; -DirectoryMatchesSoundSystem(subdir, system) { -  read SoundSystem from subdir -  if SoundSystem == system -    return true -  return false -} +    ca_mutex_unlock(p->mutex); +    return ret; +} -int ca_resolve_file(ca_sound_file *f, ca_proplist *p) { -    ca_return_val_if_fail(f, CA_ERROR_INVALID); -    ca_return_val_if_fail(p, CA_ERROR_INVALID); +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);  } diff --git a/sound-theme-spec.h b/sound-theme-spec.h new file mode 100644 index 0000000..527ad11 --- /dev/null +++ b/sound-theme-spec.h @@ -0,0 +1,34 @@ +#ifndef foocasoundthemespechfoo +#define foocasoundthemespechfoo + +/* $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 "read-sound-file.h" +#include "proplist.h" + +typedef struct ca_theme_data ca_theme_data; + +int ca_lookup_sound(ca_sound_file **f, ca_theme_data **t, ca_proplist *p); +void ca_theme_data_free(ca_theme_data *t); + +#endif  | 
