summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2008-05-24 20:54:21 +0000
committerLennart Poettering <lennart@poettering.net>2008-05-24 20:54:21 +0000
commit9010c443230c167398e22ffa3fa7643dfc252f00 (patch)
treeb62679d0558f1078dedf8e034ef88609876acb7c
parent9b324b65f4aae8f7e4b182df59da625aa751e800 (diff)
finish sound theme spec implementation
git-svn-id: file:///home/lennart/svn/public/libcanberra/trunk@8 01b60673-d06a-42c0-afdd-89cb8e0f78ac
-rw-r--r--canberra.h54
-rw-r--r--sound-theme-spec.c636
-rw-r--r--sound-theme-spec.h34
3 files changed, 556 insertions, 168 deletions
diff --git a/canberra.h b/canberra.h
index b4783a9..110c4b9 100644
--- a/canberra.h
+++ b/canberra.h
@@ -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