efl/src/lib/elementary/elm_prefs_data.c

1073 lines
28 KiB
C

#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include "elm_priv.h"
#define ELM_PREFS_DATA_CHECK(prefs_data) \
do \
{ \
EINA_SAFETY_ON_NULL_RETURN(prefs_data); \
if (!EINA_MAGIC_CHECK(prefs_data, ELM_PREFS_DATA_MAGIC)) \
{ \
EINA_MAGIC_FAIL(prefs_data, ELM_PREFS_DATA_MAGIC); \
return; \
} \
EINA_SAFETY_ON_TRUE_RETURN(prefs_data->refcount <= 0); \
} \
while (0)
#define ELM_PREFS_DATA_CHECK_OR_RETURN_VAL(prefs_data, retval) \
do \
{ \
EINA_SAFETY_ON_NULL_RETURN_VAL(prefs_data, retval); \
if (!EINA_MAGIC_CHECK(prefs_data, ELM_PREFS_DATA_MAGIC)) \
{ \
EINA_MAGIC_FAIL(prefs_data, ELM_PREFS_DATA_MAGIC); \
return retval; \
} \
EINA_SAFETY_ON_TRUE_RETURN_VAL(prefs_data->refcount <= 0, retval); \
} \
while (0)
/* EET-bound data */
static struct
{
Elm_Prefs_Item_Type t;
const char *name;
} eet_mapping[] = {
{ ELM_PREFS_TYPE_BOOL, "boolean" },
{ ELM_PREFS_TYPE_INT, "integer" },
{ ELM_PREFS_TYPE_FLOAT, "float" },
{ ELM_PREFS_TYPE_TEXT, "text" },
{ ELM_PREFS_TYPE_TEXTAREA, "text" },
{ ELM_PREFS_TYPE_DATE, "date" },
{ ELM_PREFS_TYPE_PAGE, "page" },
{ ELM_PREFS_TYPE_UNKNOWN, NULL }
};
typedef struct _Eet_Boolean_Item
{
Eina_Bool b;
} Eet_Boolean_Item;
typedef struct _Eet_Integer_Item
{
int i;
} Eet_Integer_Item;
typedef struct _Eet_Float_Item
{
float f;
} Eet_Float_Item;
typedef struct _Eet_String_Item
{
const char *s;
} Eet_String_Item;
typedef struct _Eet_Date_Item
{
unsigned int d;
unsigned int m;
unsigned int y;
} Eet_Date_Item;
typedef struct _Eet_Data_Item
{
Elm_Prefs_Item_Type type;
const char *name;
union
{
/* why structs here? ask to who designed eet unions */
Eet_Boolean_Item b;
Eet_Integer_Item i;
Eet_Float_Item f;
Eet_String_Item s;
Eet_Date_Item d;
} value;
} Eet_Data_Item;
typedef struct _Eet_Data_Value
{
unsigned int version;
Eina_List *values;
} Eet_Data_Value;
/* Run time data */
typedef struct _Elm_Prefs_Data_Item
{
Elm_Prefs_Item_Type type;
Eina_Value value;
} Elm_Prefs_Data_Item;
typedef struct _Elm_Prefs_Data_Event
{
EINA_INLIST;
Elm_Prefs_Data_Event_Type type;
Elm_Prefs_Data_Event_Cb cb;
const void *data;
Eina_Bool deleted : 1;
} Elm_Prefs_Data_Event;
struct _Elm_Prefs_Data
{
EINA_MAGIC;
Eina_Hash *keys;
unsigned int version;
const char *data_file;
const char *key;
Eet_File_Mode mode;
int refcount;
Ecore_Poller *saving_poller;
int walking;
Eina_Inlist *event_cbs;
Eina_List *deleted;
Eina_Bool autosave : 1;
Eina_Bool dirty : 1;
};
static int _elm_prefs_data_init_count = 0;
static Eet_Data_Descriptor *_bool_value_edd;
static Eet_Data_Descriptor *_int_value_edd;
static Eet_Data_Descriptor *_float_value_edd;
static Eet_Data_Descriptor *_str_value_edd;
static Eet_Data_Descriptor *_date_value_edd;
static Eet_Data_Descriptor *_values_edd;
static Eet_Data_Descriptor *_item_edd;
static Eet_Data_Descriptor *_item_unified_edd;
static const char *
_union_type_get(const void *data,
Eina_Bool *unknow)
{
const Elm_Prefs_Item_Type *t = data;
int i;
if (unknow)
*unknow = EINA_FALSE;
for (i = 0; eet_mapping[i].name != NULL; ++i)
if (*t == eet_mapping[i].t)
return eet_mapping[i].name;
if (unknow)
*unknow = EINA_TRUE;
return NULL;
}
static Eina_Bool
_union_type_set(const char *type,
void *data,
Eina_Bool unknow)
{
Elm_Prefs_Item_Type *t = data;
int i;
if (unknow)
return EINA_FALSE;
for (i = 0; eet_mapping[i].name != NULL; ++i)
if (strcmp(eet_mapping[i].name, type) == 0)
{
*t = eet_mapping[i].t;
return EINA_TRUE;
}
return EINA_FALSE;
}
static void
_data_keys_hash_free_cb(void *data)
{
Eina_Hash *values = data;
eina_hash_free(values);
}
static void
_data_values_hash_free_cb(void *data)
{
Elm_Prefs_Data_Item *it = data;
eina_value_flush(&(it->value));
free(it);
}
static void
_eet_data_load(Elm_Prefs_Data *prefs_data,
Eet_File *eet_file,
const char *key)
{
Eina_Hash *map;
Eet_Data_Item *it;
Eet_Data_Value *values = eet_data_read(eet_file, _values_edd, key);
map = eina_hash_string_superfast_new(_data_values_hash_free_cb);
eina_hash_set(prefs_data->keys, key, map);
if (!values)
{
INF("problem while reading from file %s,"
" starting with no data", prefs_data->data_file);
return;
}
else
prefs_data->version = values->version;
EINA_LIST_FREE(values->values, it)
{
Elm_Prefs_Data_Item *item = malloc(sizeof(*item));
if (!item) continue;
Eina_Bool skip = EINA_FALSE;
Eina_Bool set_err = EINA_FALSE;
Eina_Bool setup_err = EINA_FALSE;
item->type = it->type;
switch (it->type)
{
case ELM_PREFS_TYPE_BOOL:
if (!eina_value_setup(&(item->value), EINA_VALUE_TYPE_UCHAR))
setup_err = EINA_TRUE;
else if (!eina_value_set(&(item->value), it->value.b.b))
set_err = EINA_TRUE;
break;
case ELM_PREFS_TYPE_INT:
if (!eina_value_setup(&(item->value), EINA_VALUE_TYPE_INT))
setup_err = EINA_TRUE;
else if (!eina_value_set(&(item->value), it->value.i.i))
set_err = EINA_TRUE;
break;
case ELM_PREFS_TYPE_FLOAT:
if (!eina_value_setup(&(item->value), EINA_VALUE_TYPE_FLOAT))
setup_err = EINA_TRUE;
else if (!eina_value_set(&(item->value), it->value.f.f))
set_err = EINA_TRUE;
break;
case ELM_PREFS_TYPE_DATE:
{
struct timeval val;
struct tm t;
memset(&val, 0, sizeof val);
memset(&t, 0, sizeof t);
t.tm_year = it->value.d.y - 1900;
t.tm_mon = it->value.d.m - 1;
t.tm_mday = it->value.d.d;
val.tv_sec = mktime(&t);
if (!eina_value_setup(&(item->value), EINA_VALUE_TYPE_TIMEVAL))
setup_err = EINA_TRUE;
else if (!eina_value_set(&(item->value), val))
set_err = EINA_TRUE;
}
break;
case ELM_PREFS_TYPE_PAGE:
_eet_data_load(prefs_data, eet_file, it->value.s.s);
EINA_FALLTHROUGH;
case ELM_PREFS_TYPE_TEXTAREA:
case ELM_PREFS_TYPE_TEXT: /* using text type for all
* text-like data */
if (!eina_value_setup(&(item->value), EINA_VALUE_TYPE_STRINGSHARE))
setup_err = EINA_TRUE;
else if (!eina_value_set(&(item->value), it->value.s.s))
set_err = EINA_TRUE;
eina_stringshare_del(it->value.s.s);
break;
default:
ERR("bad item (type = %d) fetched from data file %s, skipping it",
it->type, prefs_data->data_file);
ELM_SAFE_FREE(item, free);
skip = EINA_TRUE;
break;
}
if (setup_err || set_err)
{
ERR("failed to set value for item %s, skipping it", it->name);
skip = EINA_TRUE;
if (set_err) eina_value_flush(&(item->value));
ELM_SAFE_FREE(item, free);
}
if (!skip) eina_hash_set(map, it->name, item);
eina_stringshare_del(it->name);
free(it);
}
free(values);
}
EAPI Elm_Prefs_Data *
elm_prefs_data_new(const char *data_file,
const char *key,
Eet_File_Mode mode)
{
Eet_File *eet_file;
Elm_Prefs_Data *prefs_data;
EINA_SAFETY_ON_TRUE_RETURN_VAL(mode <= EET_FILE_MODE_INVALID, NULL);
EINA_SAFETY_ON_TRUE_RETURN_VAL(mode > EET_FILE_MODE_READ_WRITE, NULL);
prefs_data = calloc(1, sizeof(*prefs_data));
EINA_MAGIC_SET(prefs_data, ELM_PREFS_DATA_MAGIC);
prefs_data->mode = mode;
prefs_data->refcount = 1;
if (mode == EET_FILE_MODE_READ)
prefs_data->autosave = EINA_FALSE;
if (data_file) prefs_data->data_file = eina_stringshare_add(data_file);
else
prefs_data->data_file = eina_stringshare_printf
("%s/%s", efreet_config_home_get(), _elm_appname);
prefs_data->key = eina_stringshare_add(key ? key : "main");
prefs_data->keys = eina_hash_string_superfast_new(_data_keys_hash_free_cb);
/* we can only start from scratch (ignore input) and (over)write on
* save in this case, so skip input reading */
if (mode == EET_FILE_MODE_WRITE)
{
INF("write-only data mode on %s starting prefs with no data",
prefs_data->data_file);
return prefs_data;
}
eet_file = eet_open(prefs_data->data_file, prefs_data->mode);
if (!eet_file)
{
char bkp[PATH_MAX];
snprintf(bkp, sizeof(bkp), "%s.bkp", prefs_data->data_file);
WRN("failed to load from requested file, trying backup one: %s\n",
bkp);
eet_file = eet_open(bkp, EET_FILE_MODE_READ);
}
if (eet_file)
{
_eet_data_load(prefs_data, eet_file, prefs_data->key);
eet_close(eet_file);
}
return prefs_data;
}
EAPI unsigned int
elm_prefs_data_version_get(const Elm_Prefs_Data *prefs_data)
{
ELM_PREFS_DATA_CHECK_OR_RETURN_VAL(prefs_data, -1);
return prefs_data->version;
}
static void
_eet_data_save(const Elm_Prefs_Data *prefs_data,
Eet_File *eet_file,
const char *key)
{
Eet_Data_Value edv;
Eet_Data_Item *it;
Elm_Prefs_Data_Item *item;
Eina_Hash *values;
Eina_Iterator *itr;
Eina_Hash_Tuple *tuple;
/* now we have to translate our prefs_data->values hash of
* Elm_Prefs_Data_Item values into an Eet_Data_Value node, so that
* we can serialize the latter */
edv.version = prefs_data->version;
edv.values = NULL;
values = eina_hash_find(prefs_data->keys, key);
itr = eina_hash_iterator_tuple_new(values);
EINA_ITERATOR_FOREACH(itr, tuple)
{
Eina_Bool err = EINA_FALSE;
item = (Elm_Prefs_Data_Item*) tuple->data;
it = malloc(sizeof(*it));
it->name = tuple->key;
it->type = item->type;
if (it->type == ELM_PREFS_TYPE_PAGE)
{
const char *n;
if (eina_value_get(&item->value, &n))
_eet_data_save(prefs_data, eet_file, n);
else
err = EINA_TRUE;
}
const Eina_Value_Type *t = eina_value_type_get(&(item->value));
if (t == EINA_VALUE_TYPE_UCHAR)
{
if (!eina_value_get(&(item->value), &(it->value.b.b)))
err = EINA_TRUE;
}
else if (t == EINA_VALUE_TYPE_INT)
{
if (!eina_value_get(&(item->value), &(it->value.i.i)))
err = EINA_TRUE;
}
else if (t == EINA_VALUE_TYPE_FLOAT)
{
if (!eina_value_get(&(item->value), &(it->value.f.f)))
err = EINA_TRUE;
}
else if (t == EINA_VALUE_TYPE_STRINGSHARE)
{
if (!eina_value_get(&(item->value), &(it->value.s.s)))
err = EINA_TRUE;
}
else if (t == EINA_VALUE_TYPE_TIMEVAL)
{
struct timeval val;
struct tm *tm;
if (eina_value_get(&(item->value), &val))
{
time_t gmt = val.tv_sec;
tm = gmtime(&gmt);
it->value.d.y = tm->tm_year + 1900;
it->value.d.m = tm->tm_mon + 1;
it->value.d.d = tm->tm_mday;
}
else
err = EINA_TRUE;
}
else
{
ERR("bad value found on elm prefs data, skipping it");
free(it);
continue;
}
if (err)
{
ERR("failed to get value from %s, skipping it", it->name);
free(it);
continue;
}
edv.values = eina_list_append(edv.values, it);
}
eina_iterator_free(itr);
if (!(eet_data_write(eet_file, _values_edd, key, &edv,
EET_COMPRESSION_DEFAULT)))
ERR("failed to write elm prefs data!");
EINA_LIST_FREE(edv.values, it)
free(it);
}
static void
_elm_prefs_data_save_do(const Elm_Prefs_Data *prefs_data,
const char *file,
const char *key)
{
char bkp[PATH_MAX];
Eet_File *eet_file;
snprintf(bkp, sizeof(bkp), "%s.bkp", file);
ecore_file_unlink(bkp);
ecore_file_mv(file, bkp);
eet_file = eet_open(file, EET_FILE_MODE_WRITE);
if (eet_file)
{
_eet_data_save(prefs_data, eet_file, key);
eet_close(eet_file);
}
else
{
ERR("failed to open elm prefs data file to write!");
ecore_file_mv(bkp, file);
}
}
static void
_event_cbs_clear(Elm_Prefs_Data *prefs_data)
{
Elm_Prefs_Data_Event *evt;
EINA_LIST_FREE(prefs_data->deleted, evt)
{
prefs_data->event_cbs =
eina_inlist_remove(prefs_data->event_cbs, EINA_INLIST_GET(evt));
free(evt);
}
}
static void
_elm_prefs_data_event_callback_call(Elm_Prefs_Data *prefs_data,
Elm_Prefs_Data_Event_Type type,
void *event_info)
{
Elm_Prefs_Data_Event *evt;
prefs_data->walking++;
EINA_INLIST_FOREACH(prefs_data->event_cbs, evt)
{
if ((evt->type == type) && (!evt->deleted))
evt->cb((void *)evt->data, evt->type, prefs_data, event_info);
}
prefs_data->walking--;
if (!prefs_data->walking)
_event_cbs_clear(prefs_data);
}
static Eina_Bool
_elm_prefs_data_save(void *d)
{
Elm_Prefs_Data *prefs_data = d;
if (!prefs_data->dirty) goto end;
if (prefs_data->saving_poller) /* only then we are auto-saving */
_elm_prefs_data_event_callback_call
(prefs_data, ELM_PREFS_DATA_EVENT_GROUP_AUTOSAVED,
(char *)prefs_data->key);
_elm_prefs_data_save_do(prefs_data, prefs_data->data_file, prefs_data->key);
prefs_data->dirty = EINA_FALSE;
end:
prefs_data->saving_poller = NULL;
return ECORE_CALLBACK_CANCEL;
}
static void
_elm_prefs_data_mark_as_dirty(Elm_Prefs_Data *prefs_data)
{
prefs_data->dirty = EINA_TRUE;
if ((prefs_data->autosave) && (prefs_data->mode != EET_FILE_MODE_READ))
{
if (prefs_data->saving_poller) return;
prefs_data->saving_poller = ecore_poller_add
(ECORE_POLLER_CORE, 1, _elm_prefs_data_save, prefs_data);
}
}
EAPI Eina_Bool
elm_prefs_data_version_set(Elm_Prefs_Data *prefs_data,
unsigned int version)
{
ELM_PREFS_DATA_CHECK_OR_RETURN_VAL(prefs_data, EINA_FALSE);
prefs_data->version = version;
_elm_prefs_data_mark_as_dirty(prefs_data);
return EINA_TRUE;
}
EAPI Elm_Prefs_Data *
elm_prefs_data_ref(Elm_Prefs_Data *prefs_data)
{
ELM_PREFS_DATA_CHECK_OR_RETURN_VAL(prefs_data, NULL);
prefs_data->refcount++;
return prefs_data;
}
static void
_elm_prefs_data_del(Elm_Prefs_Data *prefs_data)
{
if (prefs_data->saving_poller) ecore_poller_del(prefs_data->saving_poller);
if (prefs_data->mode != EET_FILE_MODE_READ)
_elm_prefs_data_save(prefs_data);
while (prefs_data->event_cbs)
{
Elm_Prefs_Data_Event *ecb = EINA_INLIST_CONTAINER_GET
(prefs_data->event_cbs, Elm_Prefs_Data_Event);
prefs_data->event_cbs = eina_inlist_remove
(prefs_data->event_cbs, prefs_data->event_cbs);
free(ecb);
}
eina_hash_free(prefs_data->keys);
eina_stringshare_del(prefs_data->data_file);
eina_stringshare_del(prefs_data->key);
free(prefs_data);
}
EAPI void
elm_prefs_data_unref(Elm_Prefs_Data *prefs_data)
{
ELM_PREFS_DATA_CHECK(prefs_data);
prefs_data->refcount--;
if (prefs_data->refcount == 0)
_elm_prefs_data_del(prefs_data);
}
EAPI Eina_Bool
elm_prefs_data_value_set(Elm_Prefs_Data *prefs_data,
const char *path,
const Elm_Prefs_Item_Type type,
const Eina_Value *value)
{
char key[PATH_MAX];
char *name;
size_t n;
Eina_Value tmp;
Eina_Hash *values;
Elm_Prefs_Data_Item *item;
Elm_Prefs_Data_Event_Changed evt_info;
ELM_PREFS_DATA_CHECK_OR_RETURN_VAL(prefs_data, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(path, EINA_FALSE);
/* if there is a value, try to set it to a temporary value,
* otherwise fail immediately */
if (value)
{
if (!eina_value_copy(value, &tmp))
{
ERR("failed to set item '%s' to value %p", path, value);
return EINA_FALSE;
}
}
name = strrchr(path, ':');
if (!name)
{
ERR("invalid item path: %s", path);
return EINA_FALSE;
}
else
{
n = name - path;
strncpy(key, path, n);
key[n] = '\0';
name++;
}
values = eina_hash_find(prefs_data->keys, key);
if (!values)
{
/* new key, must add one */
values = eina_hash_string_superfast_new(_data_values_hash_free_cb);
eina_hash_set(prefs_data->keys, key, values);
}
item = eina_hash_find(values, name);
if (item)
{
eina_value_flush(&(item->value));
if (!value) /* had an item, but should delete */
{
eina_hash_del_by_key(values, name);
free(item);
/* THERE IS NO RETURN IN HERE, we need to emit changed signal */
}
}
else
{
if (!value) return EINA_TRUE; /* nothing to do, success.
no signal to emit */
/* had no item, but must add one */
item = calloc(1, sizeof(*item));
item->type = type;
eina_hash_set(values, name, item);
}
/* there's an item, but its value is already flushed or
* uninitialized, set it from tmp memory -- this is valid and
* correct and it works */
if (value) memcpy(&(item->value), &tmp, sizeof(tmp));
/* emit signal to say it was changed (value == NULL is deleted) */
evt_info.key = path;
evt_info.value = value;
_elm_prefs_data_event_callback_call
(prefs_data, ELM_PREFS_DATA_EVENT_ITEM_CHANGED, &evt_info);
_elm_prefs_data_mark_as_dirty(prefs_data);
return EINA_TRUE;
}
EAPI Eina_Bool
elm_prefs_data_value_get(const Elm_Prefs_Data *prefs_data,
const char *path,
Elm_Prefs_Item_Type *type,
Eina_Value *value)
{
char key[PATH_MAX];
char *name;
size_t n;
Eina_Hash *values;
Elm_Prefs_Data_Item *item;
ELM_PREFS_DATA_CHECK_OR_RETURN_VAL(prefs_data, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(path, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
name = strrchr(path, ':');
if (!name)
{
ERR("invalid item path: %s", path);
return EINA_FALSE;
}
else
{
n = name - path;
strncpy(key, path, n);
key[n] = '\0';
name++;
}
values = eina_hash_find(prefs_data->keys, key);
if (!values) return EINA_FALSE;
item = eina_hash_find(values, name);
if (!item) return EINA_FALSE;
if (!eina_value_copy(&(item->value), value))
{
ERR("failed to fetch the value of '%s' key", name);
return EINA_FALSE;
}
if (type) *type = item->type;
return EINA_TRUE;
}
EAPI Eina_Bool
elm_prefs_data_event_callback_add(Elm_Prefs_Data *prefs_data,
Elm_Prefs_Data_Event_Type type,
Elm_Prefs_Data_Event_Cb cb,
const void *cb_data)
{
Elm_Prefs_Data_Event *evt;
ELM_PREFS_DATA_CHECK_OR_RETURN_VAL(prefs_data, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
EINA_SAFETY_ON_TRUE_RETURN_VAL
(type >= ELM_PREFS_DATA_EVENT_LAST, EINA_FALSE);
evt = malloc(sizeof(*evt));
evt->cb = cb;
evt->data = cb_data;
evt->type = type;
evt->deleted = EINA_FALSE;
prefs_data->event_cbs = eina_inlist_append
(prefs_data->event_cbs, EINA_INLIST_GET(evt));
return EINA_TRUE;
}
EAPI Eina_Bool
elm_prefs_data_event_callback_del(Elm_Prefs_Data *prefs_data,
Elm_Prefs_Data_Event_Type type,
Elm_Prefs_Data_Event_Cb cb,
const void *cb_data)
{
Elm_Prefs_Data_Event *evt, *found = NULL;
ELM_PREFS_DATA_CHECK_OR_RETURN_VAL(prefs_data, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
EINA_INLIST_FOREACH(prefs_data->event_cbs, evt)
{
if (!evt->deleted &&
evt->cb == cb && evt->data == cb_data && evt->type == type)
{
found = evt;
break;
}
}
if (!found)
return EINA_FALSE;
if (prefs_data->walking > 0)
{
found->deleted = EINA_TRUE;
prefs_data->deleted = eina_list_append(prefs_data->deleted, found);
return EINA_TRUE;
}
prefs_data->event_cbs =
eina_inlist_remove(prefs_data->event_cbs, EINA_INLIST_GET(found));
free(found);
return EINA_TRUE;
}
EAPI void
elm_prefs_data_autosave_set(Elm_Prefs_Data *prefs_data,
Eina_Bool autosave)
{
ELM_PREFS_DATA_CHECK(prefs_data);
if (prefs_data->mode == EET_FILE_MODE_READ) return;
prefs_data->autosave = !!autosave;
if (prefs_data->autosave == autosave) return;
if ((prefs_data->autosave) && (prefs_data->dirty))
{
if (prefs_data->saving_poller) return;
prefs_data->saving_poller = ecore_poller_add
(ECORE_POLLER_CORE, 1, _elm_prefs_data_save, prefs_data);
}
else if ((!prefs_data->autosave) && (prefs_data->saving_poller))
{
ecore_poller_del(prefs_data->saving_poller);
prefs_data->saving_poller = NULL;
_elm_prefs_data_save(prefs_data);
}
}
EAPI Eina_Bool
elm_prefs_data_autosave_get(const Elm_Prefs_Data *prefs_data)
{
ELM_PREFS_DATA_CHECK_OR_RETURN_VAL(prefs_data, EINA_FALSE);
return prefs_data->autosave;
}
EAPI Eina_Bool
elm_prefs_data_save(const Elm_Prefs_Data *prefs_data,
const char *file,
const char *key)
{
ELM_PREFS_DATA_CHECK_OR_RETURN_VAL(prefs_data, EINA_FALSE);
if (!key) key = prefs_data->key;
if (file)
{
_elm_prefs_data_save_do(prefs_data, file, key);
}
else
{
if (prefs_data->mode == EET_FILE_MODE_READ)
{
ERR("read only file %s, we can't save", prefs_data->data_file);
return EINA_FALSE;
}
if (prefs_data->saving_poller)
{
ecore_poller_del(prefs_data->saving_poller);
((Elm_Prefs_Data *)prefs_data)->saving_poller = NULL;
}
_elm_prefs_data_save_do
(prefs_data, prefs_data->data_file, prefs_data->key);
/* we only clean the dirty flag if we save to our original
* file */
((Elm_Prefs_Data *)prefs_data)->dirty = EINA_FALSE;
}
return EINA_TRUE;
}
#define DESC_NEW(_type, _desc) \
EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, _type); \
_desc = eet_data_descriptor_stream_new(&eddc)
static Eet_Data_Descriptor *
_bool_desc_new(void)
{
Eet_Data_Descriptor_Class eddc;
Eet_Data_Descriptor *ret;
DESC_NEW(Eet_Boolean_Item, ret);
EET_DATA_DESCRIPTOR_ADD_BASIC(ret, Eet_Boolean_Item, "b", b, EET_T_UCHAR);
return ret;
}
static Eet_Data_Descriptor *
_int_desc_new(void)
{
Eet_Data_Descriptor_Class eddc;
Eet_Data_Descriptor *ret;
DESC_NEW(Eet_Integer_Item, ret);
EET_DATA_DESCRIPTOR_ADD_BASIC(ret, Eet_Integer_Item, "i", i, EET_T_INT);
return ret;
}
static Eet_Data_Descriptor *
_float_desc_new(void)
{
Eet_Data_Descriptor_Class eddc;
Eet_Data_Descriptor *ret;
DESC_NEW(Eet_Float_Item, ret);
EET_DATA_DESCRIPTOR_ADD_BASIC(ret, Eet_Float_Item, "f", f, EET_T_FLOAT);
return ret;
}
static Eet_Data_Descriptor *
_str_desc_new(void)
{
Eet_Data_Descriptor_Class eddc;
Eet_Data_Descriptor *ret;
DESC_NEW(Eet_String_Item, ret);
EET_DATA_DESCRIPTOR_ADD_BASIC(ret, Eet_String_Item, "s", s, EET_T_STRING);
return ret;
}
static Eet_Data_Descriptor *
_date_desc_new(void)
{
Eet_Data_Descriptor_Class eddc;
Eet_Data_Descriptor *ret;
DESC_NEW(Eet_Date_Item, ret);
EET_DATA_DESCRIPTOR_ADD_BASIC(ret, Eet_Date_Item, "y", y, EET_T_UINT);
EET_DATA_DESCRIPTOR_ADD_BASIC(ret, Eet_Date_Item, "m", m, EET_T_UINT);
EET_DATA_DESCRIPTOR_ADD_BASIC(ret, Eet_Date_Item, "d", d, EET_T_UINT);
return ret;
}
static void
_elm_prefs_data_descriptors_init(void)
{
Eet_Data_Descriptor_Class eddc;
DESC_NEW(Eet_Data_Value, _values_edd);
EET_DATA_DESCRIPTOR_ADD_BASIC
(_values_edd, Eet_Data_Value, "version", version, EET_T_UINT);
_bool_value_edd = _bool_desc_new();
_int_value_edd = _int_desc_new();
_float_value_edd = _float_desc_new();
_str_value_edd = _str_desc_new();
_date_value_edd = _date_desc_new();
DESC_NEW(Eet_Data_Item, _item_edd);
EET_DATA_DESCRIPTOR_ADD_BASIC
(_item_edd, Eet_Data_Item, "name", name, EET_T_STRING);
eddc.version = EET_DATA_DESCRIPTOR_CLASS_VERSION;
eddc.func.type_get = _union_type_get;
eddc.func.type_set = _union_type_set;
_item_unified_edd = eet_data_descriptor_stream_new(&eddc);
EET_DATA_DESCRIPTOR_ADD_MAPPING
(_item_unified_edd, "boolean", _bool_value_edd);
EET_DATA_DESCRIPTOR_ADD_MAPPING
(_item_unified_edd, "integer", _int_value_edd);
EET_DATA_DESCRIPTOR_ADD_MAPPING
(_item_unified_edd, "float", _float_value_edd);
EET_DATA_DESCRIPTOR_ADD_MAPPING
(_item_unified_edd, "text", _str_value_edd);
EET_DATA_DESCRIPTOR_ADD_MAPPING
(_item_unified_edd, "date", _date_value_edd);
EET_DATA_DESCRIPTOR_ADD_MAPPING
(_item_unified_edd, "page", _str_value_edd);
EET_DATA_DESCRIPTOR_ADD_UNION
(_item_edd, Eet_Data_Item, "value", value, type, _item_unified_edd);
EET_DATA_DESCRIPTOR_ADD_LIST
(_values_edd, Eet_Data_Value, "values", values, _item_edd);
}
#undef DESC_NEW
static void
_elm_prefs_data_descriptors_shutdown(void)
{
eet_data_descriptor_free(_int_value_edd);
eet_data_descriptor_free(_float_value_edd);
eet_data_descriptor_free(_str_value_edd);
eet_data_descriptor_free(_date_value_edd);
eet_data_descriptor_free(_values_edd);
eet_data_descriptor_free(_item_edd);
eet_data_descriptor_free(_item_unified_edd);
}
void
_elm_prefs_data_init(void)
{
_elm_prefs_data_init_count++;
if (_elm_prefs_data_init_count > 1) return;
eina_magic_string_set(ELM_PREFS_DATA_MAGIC, "Elm_Prefs_Data");
_elm_prefs_data_descriptors_init();
}
void
_elm_prefs_data_shutdown(void)
{
_elm_prefs_data_init_count--;
if (_elm_prefs_data_init_count > 0) return;
_elm_prefs_data_descriptors_shutdown();
}