enlightenment/src/bin/e_theme.c

494 lines
11 KiB
C

/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#include "e.h"
/* local subsystem functions */
typedef struct _E_Theme_Result E_Theme_Result;
struct _E_Theme_Result
{
char *file;
char *cache;
};
static Evas_Bool _e_theme_mappings_free_cb(Evas_Hash *hash, const char *key, void *data, void *fdata);
static void _e_theme_category_register(const char *category);
static void _e_theme_transition_register(const char *transition);
/* local subsystem globals */
static Evas_Hash *mappings = NULL;
static Evas_Hash *group_cache = NULL;
static Evas_List *categories = NULL;
static Evas_List *transitions = NULL;
/* externally accessible functions */
int
e_theme_init(void)
{
Evas_List *l;
E_Theme_Result *res;
char *category, *p;
/* this is a fallback that is ALWAYS there - if all fails things will */
/* always fall back to the default theme. the rest after this are config */
/* values users can set */
e_theme_file_set("base", "default.edj");
for (l = e_config->themes; l; l = l->next)
{
E_Config_Theme *et;
char buf[256];
et = l->data;
snprintf(buf, sizeof(buf), "base/%s", et->category);
e_theme_file_set(buf, et->file);
}
/* Find transitions */
category = strdup("base/theme/transitions");
if (category)
{
do
{
res = evas_hash_find(mappings, category);
if (res)
{
char *str;
/* if found check cached path */
str = res->cache;
if (!str)
{
/* no cached path */
str = res->file;
/* if its not an absolute path find it */
if (str[0] != '/')
str = e_path_find(path_themes, str);
/* save cached value */
if (str) res->cache = str;
}
if (str)
{
Evas_List *coll, *l;
coll = edje_file_collection_list(str);
if (coll)
{
for (l = coll; l; l = l->next)
{
if (!strncmp(l->data, "transitions", 11))
{
char *trans;
trans = strdup(l->data);
p = strchr(trans, '/');
if (p)
{
p++;
_e_theme_transition_register(p);
}
free(trans);
}
}
edje_file_collection_list_free(coll);
}
}
}
p = strrchr(category, '/');
if (p) *p = 0;
}
while (p);
free(category);
}
return 1;
}
/*
* this is used to sewt the theme for a CATEGORY of e17. "base" is always set
* to the default theme - because if a selected theme for lest say base/theme
* does not provide theme elements it can default back to the default theme.
*
* the idea is you can actually set a different theme for different parts of
* the desktop... :)
*
* other possible categories...
* e_theme_file_set("base/theme/about", "default.edj");
* e_theme_file_set("base/theme/borders", "default.edj");
* e_theme_file_set("base/theme/background", "default.edj");
* e_theme_file_set("base/theme/configure", "default.edj");
* e_theme_file_set("base/theme/dialog", "default.edj");
* e_theme_file_set("base/theme/menus", "default.edj");
* e_theme_file_set("base/theme/error", "default.edj");
* e_theme_file_set("base/theme/gadman", "default.edj");
* e_theme_file_set("base/theme/dnd", "default.edj");
* e_theme_file_set("base/theme/icons", "default.edj");
* e_theme_file_set("base/theme/pointer", "default.edj");
* e_theme_file_set("base/theme/transitions", "default.edj");
* e_theme_file_set("base/theme/widgets", "default.edj");
* e_theme_file_set("base/theme/winlist", "default.edj");
* e_theme_file_set("base/theme/modules", "default.edj");
* e_theme_file_set("base/theme/modules/pager", "default.edj");
* e_theme_file_set("base/theme/modules/ibar", "default.edj");
* e_theme_file_set("base/theme/modules/ibox", "default.edj");
* e_theme_file_set("base/theme/modules/clock", "default.edj");
* e_theme_file_set("base/theme/modules/battery", "default.edj");
* e_theme_file_set("base/theme/modules/cpufreq", "default.edj");
* e_theme_file_set("base/theme/modules/start", "default.edj");
* e_theme_file_set("base/theme/modules/temperature", "default.edj");
*/
int
e_theme_shutdown(void)
{
if (mappings)
{
evas_hash_foreach(mappings, _e_theme_mappings_free_cb, NULL);
evas_hash_free(mappings);
mappings = NULL;
}
if (group_cache)
{
evas_hash_free(group_cache);
group_cache = NULL;
}
while (categories)
{
free(categories->data);
categories = evas_list_remove_list(categories, categories);
}
while (transitions)
{
free(transitions->data);
transitions = evas_list_remove_list(transitions, transitions);
}
return 1;
}
int
e_theme_edje_object_set(Evas_Object *o, char *category, char *group)
{
E_Theme_Result *res;
char buf[256];
char *p;
/* find category -> edje mapping */
_e_theme_category_register(category);
res = evas_hash_find(mappings, category);
if (res)
{
char *str;
/* if found check cached path */
str = res->cache;
if (!str)
{
/* no cached path */
str = res->file;
/* if its not an absolute path find it */
if (str[0] != '/')
str = e_path_find(path_themes, str);
/* save cached value */
if (str) res->cache = str;
}
if (str)
{
void *tres;
int ok;
snprintf(buf, sizeof(buf), "%s/::/%s", str, group);
tres = evas_hash_find(group_cache, buf);
if (!tres)
{
ok = edje_object_file_set(o, str, group);
/* save in the group cache hash */
if (ok)
group_cache = evas_hash_add(group_cache, buf, res);
else
group_cache = evas_hash_add(group_cache, buf, (void *)1);
}
else if (tres == (void *)1)
ok = 0;
else
ok = 1;
if (ok)
{
if (tres)
edje_object_file_set(o, str, group);
return 1;
}
}
}
/* no mapping or set failed - fall back */
strncpy(buf, category, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = 0;
/* shorten string up to and not including last / char */
p = strrchr(buf, '/');
if (p) *p = 0;
/* no / anymore - we are already as far back as we can go */
else return 0;
/* try this category */
return e_theme_edje_object_set(o, buf, group);
}
const char *
e_theme_edje_file_get(char *category, char *group)
{
E_Theme_Result *res;
char buf[4096];
char *p;
/* find category -> edje mapping */
_e_theme_category_register(category);
res = evas_hash_find(mappings, category);
if (res)
{
char *str;
/* if found check cached path */
str = res->cache;
if (!str)
{
/* no cached path */
str = res->file;
/* if its not an absolute path find it */
if (str[0] != '/')
str = e_path_find(path_themes, str);
/* save cached value */
if (str) res->cache = str;
}
if (str)
{
void *tres;
Evas_List *coll, *l;
int ok;
snprintf(buf, sizeof(buf), "%s/::/%s", str, group);
tres = evas_hash_find(group_cache, buf);
if (!tres)
{
/* if the group exists - return */
coll = edje_file_collection_list(str);
ok = 0;
for (l = coll; l; l = l->next)
{
if (!strcmp(l->data, group))
{
ok = 1;
break;
}
}
if (coll) edje_file_collection_list_free(coll);
/* save in the group cache hash */
if (ok)
group_cache = evas_hash_add(group_cache, buf, res);
else
group_cache = evas_hash_add(group_cache, buf, (void *)1);
}
else if (tres == (void *)1) /* special pointer "1" == not there */
ok = 0;
else
ok = 1;
if (ok) return str;
}
}
/* no mapping or set failed - fall back */
strncpy(buf, category, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = 0;
/* shorten string up to and not including last / char */
p = strrchr(buf, '/');
if (p) *p = 0;
/* no / anymore - we are already as far back as we can go */
else return "";
/* try this category */
return e_theme_edje_file_get(buf, group);
}
void
e_theme_file_set(char *category, char *file)
{
E_Theme_Result *res;
if (group_cache)
{
evas_hash_free(group_cache);
group_cache = NULL;
}
_e_theme_category_register(category);
res = evas_hash_find(mappings, category);
if (res)
{
mappings = evas_hash_del(mappings, category, res);
E_FREE(res->file);
E_FREE(res->cache);
free(res);
}
res = calloc(1, sizeof(E_Theme_Result));
res->file = strdup(file);
mappings = evas_hash_add(mappings, category, res);
}
int
e_theme_config_set(const char *category, const char *file)
{
E_Config_Theme *ect;
Evas_List *next;
/* Don't accept unused categories */
#if 0
if (!e_theme_category_find(category)) return 0;
#endif
/* search for the category */
for (next = e_config->themes; next; next = next->next)
{
ect = evas_list_data(next);
if (!strcmp(ect->category, category))
{
E_FREE(ect->file);
ect->file = strdup(file);
return 1;
}
}
/* the text class doesnt exist */
ect = E_NEW(E_Config_Theme, 1);
ect->category = strdup(category);
ect->file = strdup(file);
e_config->themes = evas_list_append(e_config->themes, ect);
return 1;
}
/*
* returns a pointer to the data, return null if nothing if found.
*/
E_Config_Theme *
e_theme_config_get(const char *category)
{
E_Config_Theme *ect = NULL;
Evas_List *next;
/* search for the category */
for (next = e_config->themes; next; next = next->next)
{
ect = evas_list_data(next);
if (!strcmp(ect->category, category))
{
return ect;
}
}
return NULL;
}
int
e_theme_config_remove(const char *category)
{
E_Config_Theme *ect;
Evas_List *next;
/* search for the category */
for (next = e_config->themes; next; next = next->next)
{
ect = evas_list_data(next);
if (!strcmp(ect->category, category))
{
e_config->themes = evas_list_remove_list(
e_config->themes, next);
E_FREE(ect->category);
E_FREE(ect->file);
E_FREE(ect);
return 1;
}
}
return 1;
}
Evas_List *
e_theme_config_list(void)
{
return e_config->themes;
}
int
e_theme_category_find(const char *category)
{
Evas_List *l;
for (l = categories; l; l = l->next)
{
if (!strcmp(category, l->data))
return 1;
}
return 0;
}
Evas_List *
e_theme_category_list(void)
{
return categories;
}
int
e_theme_transition_find(const char *transition)
{
Evas_List *l;
for (l = transitions; l; l = l->next)
{
if (!strcmp(transition, l->data))
return 1;
}
return 0;
}
Evas_List *
e_theme_transition_list(void)
{
return transitions;
}
/* local subsystem functions */
static Evas_Bool
_e_theme_mappings_free_cb(Evas_Hash *hash, const char *key, void *data, void *fdata)
{
E_Theme_Result *res;
res = data;
E_FREE(res->file);
E_FREE(res->cache);
free(res);
return 1;
}
static void
_e_theme_category_register(const char *category)
{
Evas_List *l;
for (l = categories; l; l = l->next)
{
if (!strcmp(category, l->data))
return;
}
categories = evas_list_append(categories, strdup(category));
}
static void
_e_theme_transition_register(const char *transition)
{
Evas_List *l;
for (l = transitions; l; l = l->next)
{
if (!strcmp(transition, l->data))
return;
}
transitions = evas_list_append(transitions, strdup(transition));
}