Enlightenment CVS committal Author : raster Project : e17 Module : libs/evas
Dir : e17/libs/evas/src/lib/cache Modified Files: evas_cache_engine_image.c evas_cache_image.c Log Message: cedric's cache changes patch =================================================================== RCS file: /cvs/e/e17/libs/evas/src/lib/cache/evas_cache_engine_image.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -3 -r1.5 -r1.6 --- evas_cache_engine_image.c 14 Mar 2008 16:49:47 -0000 1.5 +++ evas_cache_engine_image.c 12 Apr 2008 00:32:25 -0000 1.6 @@ -3,6 +3,144 @@ #include "evas_common.h" #include "evas_private.h" +static void +_evas_cache_engine_image_make_dirty(Evas_Cache_Engine_Image *cache, + Engine_Image_Entry *eim) +{ + eim->flags.cached = 1; + eim->flags.dirty = 1; + eim->flags.loaded = 1; + eim->flags.activ = 0; + cache->dirty = evas_object_list_prepend(cache->dirty, eim); +} + +static void +_evas_cache_engine_image_make_active(Evas_Cache_Engine_Image *cache, + Engine_Image_Entry *eim, + const char *key) +{ + eim->flags.cached = 1; + eim->flags.activ = 1; + eim->flags.dirty = 0; + cache->activ = evas_hash_add(cache->activ, key, eim); +} + +static void +_evas_cache_engine_image_make_inactive(Evas_Cache_Engine_Image *cache, + Engine_Image_Entry *eim, + const char *key) +{ + eim->flags.cached = 1; + eim->flags.dirty = 0; + eim->flags.activ = 0; + cache->inactiv = evas_hash_add(cache->inactiv, key, eim); + cache->lru = evas_object_list_prepend(cache->lru, eim); + cache->usage += cache->func.mem_size_get(eim); +} + +static void +_evas_cache_engine_image_remove_activ(Evas_Cache_Engine_Image *cache, + Engine_Image_Entry *eim) +{ + if (eim->flags.cached) + { + if (eim->flags.dirty) + { + cache->dirty = evas_object_list_remove(cache->dirty, eim); + } + else + if (eim->flags.activ) + { + cache->activ = evas_hash_del(cache->activ, eim->cache_key, eim); + } + else + { + cache->usage -= cache->func.mem_size_get(eim); + cache->inactiv = evas_hash_del(cache->inactiv, eim->cache_key, eim); + cache->lru = evas_object_list_remove(cache->lru, eim); + } + eim->flags.cached = 0; + eim->flags.dirty = 0; + eim->flags.activ = 0; + } +} + +static Engine_Image_Entry * +_evas_cache_engine_image_alloc(Evas_Cache_Engine_Image *cache, + Image_Entry *ie, + const char *hkey) +{ + Engine_Image_Entry *eim; + + assert(cache); + + if (cache->func.alloc) + eim = cache->func.alloc(); + else + eim = malloc(sizeof (Engine_Image_Entry)); + + if (!eim) goto on_error; + memset(eim, 0, sizeof (Engine_Image_Entry)); + + eim->cache = cache; + if (ie) + { + eim->w = ie->w; + eim->h = ie->h; + eim->src = ie; + eim->flags.need_parent = 1; + } + else + { + eim->w = -1; + eim->h = -1; + eim->flags.need_parent = 0; + eim->src = NULL; + } + + eim->flags.cached = 0; + eim->references = 0; + eim->cache_key = hkey; + + if (hkey) + _evas_cache_engine_image_make_active(cache, eim, hkey); + else + _evas_cache_engine_image_make_dirty(cache, eim); + + return eim; + + on_error: + if (eim) + evas_cache_engine_image_drop(eim); + evas_stringshare_del(hkey); + evas_cache_image_drop(ie); + return NULL; +} + +static void +_evas_cache_engine_image_dealloc(Evas_Cache_Engine_Image *cache, Engine_Image_Entry *eim) +{ + Image_Entry *im; + + if (cache->func.debug) cache->func.debug("delete", eim); + + _evas_cache_engine_image_remove_activ(cache, eim); + + im = eim->src; + cache->func.destructor(eim); + if (im) evas_cache_image_drop(im); + + if (cache->func.delete) + { + cache->func.delete(eim); + } + else + { + memset(eim, 0, sizeof (Engine_Image_Entry)); + free(eim); + } +} + EAPI int evas_cache_engine_image_usage_get(Evas_Cache_Engine_Image *cache) { @@ -42,11 +180,57 @@ new->usage = 0; new->dirty = NULL; + new->lru = NULL; new->activ = NULL; + new->inactiv = NULL; new->parent = parent; parent->references++; + new->brother = NULL; + + return new; +} + +EAPI Evas_Cache_Engine_Image * +evas_cache_engine_image_dup(const Evas_Cache_Engine_Image_Func *cb, Evas_Cache_Engine_Image *brother) +{ + Evas_Cache_Engine_Image *new; + + new = malloc(sizeof (Evas_Cache_Engine_Image)); + if (!new) + return NULL; + + new->func = brother->func; + +#define ORD(Func) if (cb->Func) new->func.Func = cb->Func; + + ORD(key); + ORD(constructor); + ORD(destructor); + ORD(dirty_region); + ORD(dirty); + ORD(size_set); + ORD(update_data); + ORD(load); + ORD(mem_size_get); + ORD(debug); + +#undef ORD + + new->limit = -1; + new->usage = 0; + new->references = 1; + + new->dirty = NULL; + new->activ = NULL; + + new->parent = brother->parent; + new->parent->references++; + + new->brother = brother; + brother->references++; + return new; } @@ -54,130 +238,126 @@ _evas_cache_engine_image_free_cb(const Evas_Hash *hash, const char *key, void *data, void *fdata) { Evas_Cache_Engine_Image *cache = fdata; - RGBA_Engine_Image *eim = data; - RGBA_Image *im; + Engine_Image_Entry *eim = data; - if (cache->func.debug) - cache->func.debug("shutdown-engine-activ", eim); + _evas_cache_engine_image_dealloc(cache, eim); - evas_stringshare_del(eim->cache_key); - eim->cache_key = NULL; + return 1; +} - im = eim->src; - cache->func.destructor(eim); - if (im) evas_cache_image_drop(im); - free(eim); +EAPI void +evas_cache_engine_image_flush(Evas_Cache_Engine_Image *cache) +{ + assert(cache != NULL); - return 1; + while ((cache->lru) && (cache->limit < cache->usage)) + { + Engine_Image_Entry *eim; + + eim = (Engine_Image_Entry *) cache->lru->last; + _evas_cache_engine_image_dealloc(cache, eim); + } } EAPI void evas_cache_engine_image_shutdown(Evas_Cache_Engine_Image *cache) { - RGBA_Engine_Image *eim; - RGBA_Image *im; + Engine_Image_Entry *eim; assert(cache != NULL); + if (cache->func.debug) cache->func.debug("shutdown-engine", NULL); + + evas_hash_foreach(cache->inactiv, _evas_cache_engine_image_free_cb, cache); + evas_hash_free(cache->inactiv); + /* This is mad, I am about to destroy image still alive, but we need to prevent leak. */ while (cache->dirty) { - eim = (RGBA_Engine_Image *) cache->dirty; - im = eim->src; - - cache->dirty = evas_object_list_remove(cache->dirty, eim); - - if (cache->func.debug) - cache->func.debug("shutdown-engine-dirty", eim); - cache->func.destructor(eim); - if (im) evas_cache_image_drop(im); - free(eim); + eim = (Engine_Image_Entry *) cache->dirty; + _evas_cache_engine_image_dealloc(cache, eim); } evas_hash_foreach(cache->activ, _evas_cache_engine_image_free_cb, cache); evas_hash_free(cache->activ); + + evas_cache_image_shutdown(cache->parent); + if (cache->brother) + evas_cache_engine_image_shutdown(cache->brother); + free(cache); } -EAPI RGBA_Engine_Image * -evas_cache_engine_image_request(Evas_Cache_Engine_Image *cache, const char *file, const char *key, +EAPI Engine_Image_Entry * +evas_cache_engine_image_request(Evas_Cache_Engine_Image *cache, + const char *file, const char *key, RGBA_Image_Loadopts *lo, void *data, int *error) { - RGBA_Engine_Image *eim; - RGBA_Image *im; + Engine_Image_Entry *eim; + Image_Entry *im; const char *ekey; assert(cache != NULL); + *error = -1; + + ekey = NULL; + eim = NULL; + im = evas_cache_image_request(cache->parent, file, key, lo, error); if (!im) - { - *error = -1; - return NULL; - } + goto on_error; if (cache->func.key) ekey = cache->func.key(im, file, key, lo, data); else ekey = evas_stringshare_add(im->cache_key); if (!ekey) + goto on_error; + + eim = evas_hash_find(cache->activ, ekey); + if (eim) { - *error = -1; evas_cache_image_drop(im); - return NULL; + goto on_ok; } - eim = evas_hash_find(cache->activ, ekey); - if (eim) goto on_ok; - - eim = malloc(sizeof(RGBA_Engine_Image)); - if (!eim) goto on_error; + eim = evas_hash_find(cache->inactiv, ekey); + if (eim) + { + _evas_cache_engine_image_remove_activ(cache, eim); + _evas_cache_engine_image_make_active(cache, eim, ekey); + evas_cache_image_drop(im); + goto on_ok; + } - eim->src = im; - eim->engine_data = NULL; - eim->flags.dirty = 0; - eim->flags.loaded = 0; - eim->cache = cache; - eim->cache_key = ekey; - eim->references = 0; + eim = _evas_cache_engine_image_alloc(cache, im, ekey); + if (!eim) return NULL; *error = cache->func.constructor(eim, data); + if (*error != 0) goto on_error; if (cache->func.debug) cache->func.debug("constructor-engine", eim); - if (*error != 0) goto on_error; - - cache->activ = evas_hash_add(cache->activ, ekey, eim); - cache->usage += strlen(eim->cache_key) + 1 + cache->func.mem_size_get(eim); - on_ok: eim->references++; return eim; on_error: - evas_cache_image_drop(im); - evas_stringshare_del(ekey); - if (eim) free(eim); - return NULL; -} - -static void -_evas_cache_engine_image_free(Evas_Cache_Engine_Image *cache, RGBA_Engine_Image *eim) -{ - int size; - - size = cache->func.mem_size_get(eim); - cache->usage -= size; + if (!eim) + { + if (im) evas_cache_image_drop(im); + if (ekey) evas_stringshare_del(ekey); + } + else + { + _evas_cache_engine_image_dealloc(cache, eim); + } - if (cache->func.debug) - cache->func.debug("drop-engine", eim); - cache->func.destructor(eim); - if (eim->src) evas_cache_image_drop(eim->src); - if (eim->cache_key) evas_stringshare_del(eim->cache_key); - free(eim); + return NULL; } EAPI void -evas_cache_engine_image_drop(RGBA_Engine_Image *eim) +evas_cache_engine_image_drop(Engine_Image_Entry *eim) { Evas_Cache_Engine_Image *cache; @@ -189,28 +369,27 @@ if (eim->flags.dirty) { - cache->dirty = evas_object_list_remove(cache->dirty, eim); - - _evas_cache_engine_image_free(cache, eim); + _evas_cache_engine_image_dealloc(cache, eim); return ; } if (eim->references == 0) { - cache->activ = evas_hash_del(cache->activ, eim->cache_key, eim); - - _evas_cache_engine_image_free(cache, eim); + _evas_cache_engine_image_remove_activ(cache, eim); + _evas_cache_engine_image_make_inactive(cache, eim, eim->cache_key); + evas_cache_engine_image_flush(cache); return ; } } -EAPI RGBA_Engine_Image * -evas_cache_engine_image_dirty(RGBA_Engine_Image *eim, int x, int y, int w, int h) +EAPI Engine_Image_Entry * +evas_cache_engine_image_dirty(Engine_Image_Entry *eim, int x, int y, int w, int h) { - RGBA_Engine_Image *eim_dirty = eim; - RGBA_Image *im; - RGBA_Image *im_dirty; - Evas_Cache_Engine_Image *cache; + Engine_Image_Entry *eim_dirty = eim; + Image_Entry *im_dirty = NULL; + Image_Entry *im; + Evas_Cache_Engine_Image *cache; + unsigned char alloc_eim; assert(eim); assert(eim->cache); @@ -218,56 +397,56 @@ cache = eim->cache; if (!(eim->flags.dirty)) { - im = eim->src; - im_dirty = evas_cache_image_dirty(im, x, y, w, h); + alloc_eim = 0; - /* If im == im_dirty, this meens that we have only one reference to the eim. */ - if (im != im_dirty) + if (eim->flags.need_parent == 1) { - if (eim->references == 1) - { - const char *hkey; - - hkey = eim->cache_key; - cache->activ = evas_hash_del(cache->activ, hkey, eim); + im = eim->src; + im_dirty = evas_cache_image_dirty(im, x, y, w, h); - cache->usage -= strlen(hkey) + 1; - - evas_stringshare_del(hkey); - - eim_dirty = eim; - eim_dirty->src = im_dirty; - } - else + /* If im == im_dirty, this meens that we have only one reference to the eim. */ + if (im != im_dirty) { - int error; - - eim_dirty = malloc(sizeof(RGBA_Engine_Image)); - if (!eim_dirty) goto on_error; - - eim_dirty->src = im_dirty; - eim_dirty->engine_data = NULL; - eim_dirty->flags.dirty = 1; - eim_dirty->flags.loaded = 1; - eim_dirty->cache = cache; - eim_dirty->cache_key = NULL; - eim_dirty->references = 1; + if (eim->references == 1) + { + _evas_cache_engine_image_remove_activ(cache, eim); + _evas_cache_engine_image_make_dirty(cache, eim); + + eim->src = im_dirty; + } + else + alloc_eim = 1; + } + } + else + if (eim->references > 1) + { + alloc_eim = 1; + } + else + { + _evas_cache_engine_image_remove_activ(cache, eim_dirty); + _evas_cache_engine_image_make_dirty(cache, eim_dirty); + } - error = cache->func.dirty(eim_dirty, eim); - if (cache->func.debug) - cache->func.debug("dirty-engine", eim_dirty); + if (alloc_eim == 1) + { + int error; - if (error != 0) goto on_error; + eim_dirty = _evas_cache_engine_image_alloc(cache, im_dirty, NULL); + if (!eim_dirty) goto on_error; - cache->usage += cache->func.mem_size_get(eim_dirty); + eim_dirty->w = eim->w; + eim_dirty->h = eim->h; + eim_dirty->references = 1; - evas_cache_engine_image_drop(eim); - } + error = cache->func.dirty(eim_dirty, eim); + if (cache->func.debug) + cache->func.debug("dirty-engine", eim_dirty); - eim_dirty->cache_key = NULL; - eim_dirty->flags.dirty = 1; + if (error != 0) goto on_error; - cache->dirty = evas_object_list_prepend(cache->dirty, eim_dirty); + evas_cache_engine_image_drop(eim); } } @@ -280,7 +459,7 @@ on_error: if (eim) evas_cache_engine_image_drop(eim); - if (eim_dirty) + if (eim_dirty && eim_dirty != eim) evas_cache_engine_image_drop(eim_dirty); else if (im_dirty) evas_cache_image_drop(im_dirty); @@ -288,21 +467,43 @@ return NULL; } -static RGBA_Engine_Image * -_evas_cache_engine_image_push_dirty(Evas_Cache_Engine_Image *cache, RGBA_Image *im, void *engine_data) +EAPI Engine_Image_Entry * +evas_cache_engine_image_alone(Engine_Image_Entry *eim, void *data) +{ + Evas_Cache_Engine_Image *cache; + Image_Entry *im; + + + assert(eim); + assert(eim->cache); + + cache = eim->cache; + im = evas_cache_image_alone(eim->src); + if (im != eim->src) + { + eim = _evas_cache_engine_image_alloc(cache, im, NULL); + if (!eim) goto on_error; + + eim->references = 1; + + if (cache->func.constructor(eim, data)) goto on_error; + } + /* FIXME */ + return eim; + + on_error: + evas_cache_image_drop(im); + return NULL; +} + +static Engine_Image_Entry * +_evas_cache_engine_image_push_dirty(Evas_Cache_Engine_Image *cache, Image_Entry *im, void *engine_data) { - RGBA_Engine_Image *eim; + Engine_Image_Entry *eim; int error; - eim = malloc(sizeof(RGBA_Engine_Image)); + eim = _evas_cache_engine_image_alloc(cache, im, NULL); if (!eim) goto on_error; - - eim->src = im; - eim->engine_data = NULL; - eim->flags.dirty = 1; - eim->flags.loaded = 1; - eim->cache = cache; - eim->cache_key = NULL; eim->references = 1; error = cache->func.update_data(eim, engine_data); @@ -310,22 +511,18 @@ cache->func.debug("dirty-update_data-engine", eim); if (error != 0) goto on_error; - cache->dirty = evas_object_list_prepend(cache->dirty, eim); - return eim; on_error: if (eim) evas_cache_engine_image_drop(eim); - else - evas_cache_image_drop(im); return NULL; } -EAPI RGBA_Engine_Image * +EAPI Engine_Image_Entry * evas_cache_engine_image_copied_data(Evas_Cache_Engine_Image *cache, int w, int h, DATA32 *image_data, int alpha, int cspace, void *engine_data) { - RGBA_Image *im; + Image_Entry *im; assert(cache); @@ -334,10 +531,10 @@ return _evas_cache_engine_image_push_dirty(cache, im, engine_data); } -EAPI RGBA_Engine_Image * +EAPI Engine_Image_Entry * evas_cache_engine_image_data(Evas_Cache_Engine_Image *cache, int w, int h, DATA32 *image_data, int alpha, int cspace, void *engine_data) { - RGBA_Image *im; + Image_Entry *im; assert(cache); @@ -346,64 +543,48 @@ return _evas_cache_engine_image_push_dirty(cache, im, engine_data); } -EAPI RGBA_Engine_Image * -evas_cache_engine_image_size_set(RGBA_Engine_Image *eim, int w, int h) +EAPI Engine_Image_Entry * +evas_cache_engine_image_size_set(Engine_Image_Entry *eim, int w, int h) { - Evas_Cache_Engine_Image *cache; - RGBA_Engine_Image *new; - RGBA_Image *im; - int error; + Evas_Cache_Engine_Image *cache; + Engine_Image_Entry *new; + Image_Entry *im; + const char *hkey; + int error; assert(eim); - assert(eim->src); assert(eim->cache); assert(eim->references > 0); - if (eim->src->image->w == w - && eim->src->image->h == h) - return eim; - + im = NULL; cache = eim->cache; - im = evas_cache_image_size_set(eim->src, w, h); - /* Good idea to call update_data ? */ - if (im == eim->src) return eim; - eim->src = NULL; + if (eim->flags.need_parent == 1) + { + assert(eim->src); + + if (eim->src->w == w + && eim->src->h == h) + return eim; + + im = evas_cache_image_size_set(eim->src, w, h); + /* FIXME: Good idea to call update_data ? */ + if (im == eim->src) return eim; + eim->src = NULL; + } + + hkey = (eim->references > 1 ) ? evas_stringshare_add(eim->cache_key) : NULL; - new = malloc(sizeof(RGBA_Engine_Image)); + new = _evas_cache_engine_image_alloc(cache, im, hkey); if (!new) goto on_error; - new->src = im; - new->engine_data = NULL; - new->flags = eim->flags; - new->flags.loaded = 1; - new->cache = cache; - new->cache_key = NULL; + new->w = w; + new->h = h; new->references = 1; error = cache->func.size_set(new, eim); if (error) goto on_error; - assert(new->engine_data != eim->engine_data); - - cache->usage += cache->func.mem_size_get(new); - - if (new->flags.dirty || eim->references > 1) - { - new->flags.dirty = 1; - cache->dirty = evas_object_list_prepend(cache->dirty, new); - } - else - { - const char *cache_key = NULL; - - cache_key = eim->cache_key ? evas_stringshare_add(eim->cache_key) : NULL; - new->cache_key = cache_key; - - cache->activ = evas_hash_add(cache->activ, cache_key, new); - cache->usage += strlen(new->cache_key) + 1; - } - evas_cache_engine_image_drop(eim); return new; @@ -419,10 +600,10 @@ } EAPI void -evas_cache_engine_image_load_data(RGBA_Engine_Image *eim) +evas_cache_engine_image_load_data(Engine_Image_Entry *eim) { Evas_Cache_Engine_Image *cache; - int size; + int size = 0; assert(eim); assert(eim->src); @@ -430,37 +611,35 @@ if (eim->flags.loaded) return ; - evas_cache_image_load_data(eim->src); + if (eim->src) + evas_cache_image_load_data(eim->src); cache = eim->cache; if (cache->func.debug) cache->func.debug("load-engine", eim); - size = cache->func.mem_size_get(eim); + if (eim->flags.dirty) + size = cache->func.mem_size_get(eim); cache = eim->cache; cache->func.load(eim, eim->src); - cache->usage += cache->func.mem_size_get(eim) - size; + if (eim->flags.dirty) + cache->usage += cache->func.mem_size_get(eim) - size; eim->flags.loaded = 1; } -EAPI RGBA_Engine_Image * +EAPI Engine_Image_Entry * evas_cache_engine_image_engine(Evas_Cache_Engine_Image *cache, void *engine_data) { - RGBA_Engine_Image *eim; - int error; + Engine_Image_Entry *eim; + Image_Entry *ie; + int error; - eim = malloc(sizeof(RGBA_Engine_Image)); - if (!eim) goto on_error; - - eim->src = evas_cache_image_empty(cache->parent); - if (!eim->src) goto on_error; + ie = evas_cache_image_empty(cache->parent); + if (!ie) return NULL; - eim->engine_data = NULL; - eim->flags.dirty = 1; - eim->flags.loaded = 1; - eim->cache = cache; - eim->cache_key = NULL; + eim = _evas_cache_engine_image_alloc(cache, ie, NULL); + if (!eim) goto on_error; eim->references = 1; error = cache->func.update_data(eim, engine_data); @@ -469,18 +648,23 @@ if (error != 0) goto on_error; - cache->dirty = evas_object_list_prepend(cache->dirty, eim); - return eim; on_error: - if (eim) - evas_cache_engine_image_drop(eim); + if (!eim) + { + if (ie) + evas_cache_image_drop(ie); + } + else + { + evas_cache_engine_image_drop(eim); + } return NULL; } EAPI void -evas_cache_engine_image_colorspace(RGBA_Engine_Image *eim, int cspace, void *engine_data) +evas_cache_engine_image_colorspace(Engine_Image_Entry *eim, int cspace, void *engine_data) { Evas_Cache_Engine_Image *cache = eim->cache; @@ -493,3 +677,12 @@ cache->func.debug("cosntructor-colorspace-engine", eim); } +EAPI void +evas_cache_engine_parent_not_needed(Engine_Image_Entry *eim) +{ + assert(eim); + assert(eim->cache); + + eim->flags.need_parent = 0; + evas_cache_image_data_not_needed(eim->src); +} =================================================================== RCS file: /cvs/e/e17/libs/evas/src/lib/cache/evas_cache_image.c,v retrieving revision 1.13 retrieving revision 1.14 diff -u -3 -r1.13 -r1.14 --- evas_cache_image.c 14 Mar 2008 16:49:47 -0000 1.13 +++ evas_cache_image.c 12 Apr 2008 00:32:25 -0000 1.14 @@ -4,6 +4,221 @@ #include "evas_common.h" #include "evas_private.h" +#define FREESTRC(Var) \ + if (Var) \ + { \ + evas_stringshare_del(Var); \ + Var = NULL; \ + } + +static void +_evas_cache_image_make_dirty(Evas_Cache_Image *cache, + Image_Entry *im) +{ + im->flags.cached = 1; + im->flags.dirty = 1; + im->flags.activ = 0; + im->flags.lru_nodata = 0; + cache->dirty = evas_object_list_prepend(cache->dirty, im); + + if (im->cache_key) + { + evas_stringshare_del(im->cache_key); + im->cache_key = NULL; + } +} + +static void +_evas_cache_image_make_activ(Evas_Cache_Image *cache, + Image_Entry *im, + const char *key) +{ + im->cache_key = key; + if (key != NULL) + { + im->flags.cached = 1; + im->flags.activ = 1; + im->flags.lru_nodata = 0; + im->flags.dirty = 0; + cache->activ = evas_hash_direct_add(cache->activ, key, im); + } + else + { + _evas_cache_image_make_dirty(cache, im); + } +} + +static void +_evas_cache_image_make_inactiv(Evas_Cache_Image *cache, + Image_Entry *im, + const char *key) +{ + im->flags.activ = 0; + im->flags.dirty = 0; + im->flags.cached = 1; + cache->inactiv = evas_hash_direct_add(cache->inactiv, key, im); + cache->lru = evas_object_list_prepend(cache->lru, im); + cache->usage += cache->func.mem_size_get(im); +} + +static void +_evas_cache_image_remove_lru_nodata(Evas_Cache_Image *cache, + Image_Entry *im) +{ + if (im->flags.lru_nodata) + { + im->flags.lru_nodata = 0; + cache->lru_nodata = evas_object_list_remove(cache->lru_nodata, im); + cache->usage -= cache->func.mem_size_get(im); + } +} + +static void +_evas_cache_image_activ_lru_nodata(Evas_Cache_Image *cache, + Image_Entry *im) +{ + im->flags.need_data = 0; + im->flags.lru_nodata = 1; + cache->lru_nodata = evas_object_list_prepend(cache->lru_nodata, im); + cache->usage += cache->func.mem_size_get(im); +} + +static void +_evas_cache_image_remove_activ(Evas_Cache_Image *cache, + Image_Entry *ie) +{ + if (ie->flags.cached) + { + if (ie->flags.activ) + { + cache->activ = evas_hash_del(cache->activ, ie->cache_key, ie); + _evas_cache_image_remove_lru_nodata(cache, ie); + } + else + { + if (ie->flags.dirty) + { + cache->dirty = evas_object_list_remove(cache->dirty, ie); + } + else + { + cache->inactiv = evas_hash_del(cache->inactiv, ie->cache_key, ie); + cache->lru = evas_object_list_remove(cache->lru, ie); + cache->usage -= cache->func.mem_size_get(ie); + } + } + ie->flags.cached = 0; + ie->flags.dirty = 0; + ie->flags.activ = 0; + } +} + +static void +_evas_cache_image_entry_delete(Evas_Cache_Image *cache, Image_Entry *ie) +{ + if (!ie) return ; + + if (cache->func.debug) + cache->func.debug("deleting", ie); + + cache->func.destructor(ie); + + _evas_cache_image_remove_activ(cache, ie); + + if (ie->cache_key) + { + evas_stringshare_del(ie->cache_key); + ie->cache_key = NULL; + } + + FREESTRC(ie->file); + FREESTRC(ie->key); + + cache->func.surface_delete(ie); + cache->func.delete(ie); +} + +static Image_Entry * +_evas_cache_image_entry_new(Evas_Cache_Image *cache, + const char *hkey, + time_t timestamp, + const char *file, + const char *key, + RGBA_Image_Loadopts *lo, + int *error) +{ + Image_Entry *ie; + const char *cache_key; + + ie = cache->func.alloc(); + if (!ie) + return NULL; + + cache_key = hkey ? evas_stringshare_add(hkey) : NULL; + + ie->flags.loaded = 0; + ie->flags.need_data = 1; + + _evas_cache_image_make_activ(cache, ie, cache_key); + + ie->space = EVAS_COLORSPACE_ARGB8888; + ie->w = -1; + ie->h = -1; + + ie->references = 0; + ie->cache = cache; + + ie->file = file ? evas_stringshare_add(file) : NULL; + ie->key = key ? evas_stringshare_add(key) : NULL; + + ie->timestamp = timestamp; + ie->laststat = time(NULL); + + ie->load_opts.scale_down_by = 0; + ie->load_opts.dpi = 0; + ie->load_opts.w = 0; + ie->load_opts.h = 0; + ie->scale = 1; + + if (lo) + ie->load_opts = *lo; + + ie->references = 0; + if (file) + { + *error = cache->func.constructor(ie); + if (*error != 0) + { + _evas_cache_image_entry_delete(cache, ie); + return NULL; + } + } + if (cache->func.debug) + cache->func.debug("build", ie); + + return ie; +} + +static void +_evas_cache_image_entry_surface_alloc(Evas_Cache_Image *cache, + Image_Entry *ie, + int w, + int h) +{ + int wmin; + int hmin; + + wmin = w > 0 ? w : 1; + hmin = h > 0 ? h : 1; + if (cache->func.surface_alloc(ie, wmin, hmin)) + { + wmin = 0; + hmin = 0; + } + ie->w = wmin; + ie->h = hmin; +} + EAPI int evas_cache_image_usage_get(Evas_Cache_Image *cache) { @@ -45,6 +260,7 @@ new->dirty = NULL; new->lru = NULL; + new->lru_nodata = NULL; new->inactiv = NULL; new->activ = NULL; @@ -57,26 +273,17 @@ _evas_cache_image_free_cb(const Evas_Hash *hash, const char *key, void *data, void *fdata) { Evas_Cache_Image *cache = fdata; - RGBA_Image *im = data; - - if (cache->func.debug) - cache->func.debug("shutdown-activ", im); + Image_Entry *im = data; - if (im->cache_key) - { - evas_stringshare_del(im->cache_key); - im->cache_key = NULL; - } + _evas_cache_image_entry_delete(cache, im); - cache->func.destructor(im); - evas_common_image_delete(im); return 1; } EAPI void evas_cache_image_shutdown(Evas_Cache_Image *cache) { - RGBA_Image *im; + Image_Entry *im; assert(cache != NULL); cache->references--; @@ -86,31 +293,21 @@ while (cache->lru) { - im = (RGBA_Image *) cache->lru; - cache->lru = evas_object_list_remove(cache->lru, im); - - if (im->cache_key) - { - evas_stringshare_del(im->cache_key); - im->cache_key = NULL; - } + im = (Image_Entry *) cache->lru; + _evas_cache_image_entry_delete(cache, im); + } - if (cache->func.debug) - cache->func.debug("shutdown-lru", im); - cache->func.destructor(im); - evas_common_image_delete(im); + while (cache->lru_nodata) + { + im = (Image_Entry *) cache->lru_nodata; + _evas_cache_image_entry_delete(cache, im); } /* This is mad, I am about to destroy image still alive, but we need to prevent leak. */ while (cache->dirty) { - im = (RGBA_Image *) cache->dirty; - cache->dirty = evas_object_list_remove(cache->dirty, im); - - if (cache->func.debug) - cache->func.debug("shutdown-dirty", im); - cache->func.destructor(im); - evas_common_image_delete(im); + im = (Image_Entry *) cache->dirty; + _evas_cache_image_entry_delete(cache, im); } evas_hash_foreach(cache->activ, _evas_cache_image_free_cb, cache); @@ -120,14 +317,17 @@ free(cache); } -EAPI RGBA_Image * +#define STAT_GAP 2 + +EAPI Image_Entry * evas_cache_image_request(Evas_Cache_Image *cache, const char *file, const char *key, RGBA_Image_Loadopts *lo, int *error) { const char *format; char *hkey; - RGBA_Image *im; + Image_Entry *im; Evas_Image_Load_Opts prevent; int size; + int stat_done = 0; struct stat st; assert(cache != NULL); @@ -157,106 +357,86 @@ hkey = alloca(sizeof (char) * size); snprintf(hkey, size, format, file, key, lo->scale_down_by, lo->dpi, lo->w, lo->h); - if (stat(file, &st) < 0) - { - im = evas_hash_find(cache->inactiv, hkey); - if (im) - { - cache->lru = evas_object_list_remove(cache->lru, im); - cache->inactiv = evas_hash_del(cache->inactiv, im->cache_key, im); -// printf("IMG %p %ix%i %s SUB %i\n", -// im, im->image->w, im->image->h, im->cache_key, -// cache->func.mem_size_get(im)); - cache->usage -= cache->func.mem_size_get(im); - if (im->cache_key) - { - evas_stringshare_del(im->cache_key); - im->cache_key = NULL; - } - cache->func.destructor(im); - evas_common_image_delete(im); - } - return NULL; - } - im = evas_hash_find(cache->activ, hkey); if (im) { - if (st.st_mtime == im->timestamp) - goto on_ok; + time_t t; + int ok; + + ok = 1; + t = time(NULL); + + if ((t - im->laststat) > STAT_GAP) + { + stat_done = 1; + if (stat(file, &st) < 0) goto on_error; + + im->laststat = t; + if (st.st_mtime != im->timestamp) ok = 0; + } + if (ok) goto on_ok; } im = evas_hash_find(cache->inactiv, hkey); if (im) { - if (st.st_mtime == im->timestamp) - { - cache->lru = evas_object_list_remove(cache->lru, im); - cache->inactiv = evas_hash_del(cache->inactiv, im->cache_key, im); - cache->activ = evas_hash_direct_add(cache->activ, im->cache_key, im); -// printf("IMG %p %ix%i %s SUB %i\n", -// im, im->image->w, im->image->h, im->cache_key, -// cache->func.mem_size_get(im)); - cache->usage -= cache->func.mem_size_get(im); - goto on_ok; - } - else - { - cache->lru = evas_object_list_remove(cache->lru, im); - cache->inactiv = evas_hash_del(cache->inactiv, im->cache_key, im); -// printf("IMG %p %ix%i %s SUB %i\n", -// im, im->image->w, im->image->h, im->cache_key, -// cache->func.mem_size_get(im)); - cache->usage -= cache->func.mem_size_get(im); - if (im->cache_key) - { - evas_stringshare_del(im->cache_key); - im->cache_key = NULL; - } - cache->func.destructor(im); - evas_common_image_delete(im); - } - } + int ok; - im = evas_common_image_new(); - if (!im) - { - *error = -1; - return NULL; - } + ok = 1; + if (!stat_done) + { + time_t t; - im->timestamp = st.st_mtime; - im->laststat = time(NULL); + t = time(NULL); + if ((t - im->laststat) > STAT_GAP) + { + stat_done = 1; + if (stat(file, &st) < 0) goto on_error; + + im->laststat = t; + if (st.st_mtime != im->timestamp) ok = 0; + } + } + else + if (st.st_mtime != im->timestamp) ok = 0; - if (lo) im->load_opts = *lo; + if (ok) + { + _evas_cache_image_remove_activ(cache, im); + _evas_cache_image_make_activ(cache, im, im->cache_key); + goto on_ok; + } - im->info.file = (char *) evas_stringshare_add(file); - if (key) im->info.key = (char *) evas_stringshare_add(key); + _evas_cache_image_entry_delete(cache, im); + } - *error = cache->func.constructor(im); - if (*error != 0) + if (!stat_done) { - evas_common_image_delete(im); - return NULL; + if (stat(file, &st) < 0) return NULL; } + im = _evas_cache_image_entry_new(cache, hkey, st.st_mtime, file, key, lo, error); + if (!im) + return NULL; + if (cache->func.debug) cache->func.debug("request", im); - im->references = 0; - im->cache_key = evas_stringshare_add(hkey); - im->cache = cache; - - cache->activ = evas_hash_direct_add(cache->activ, im->cache_key, im); - - on_ok: + on_ok: *error = 0; im->references++; + if (im->references > 1 && im->flags.lru_nodata) + _evas_cache_image_remove_lru_nodata(cache, im); + return im; + + on_error: + _evas_cache_image_entry_delete(cache, im); + return NULL; } EAPI void -evas_cache_image_drop(RGBA_Image *im) +evas_cache_image_drop(Image_Entry *im) { Evas_Cache_Image *cache; @@ -266,72 +446,59 @@ im->references--; cache = im->cache; -// if (im->cache_key) printf("DROP %s -> ref = %i\n", im->cache_key, im->references); - if ((im->flags & RGBA_IMAGE_IS_DIRTY) == RGBA_IMAGE_IS_DIRTY) + if (im->flags.dirty) { -// printf("IMG %p %ix%i %s SUB %i\n", -// im, im->image->w, im->image->h, im->cache_key, -// cache->func.mem_size_get(im)); -//// don't decrement cache usage - unless we remove from the lru -// cache->usage -= cache->func.mem_size_get(im); -// if (im->cache_key) printf("IM-- %s, cache = %i\n", im->cache_key, cache->usage); - cache->dirty = evas_object_list_remove(cache->dirty, im); - if (cache->func.debug) - cache->func.debug("drop", im); - - cache->func.destructor(im); - evas_common_image_delete(im); - + _evas_cache_image_entry_delete(cache, im); return ; } if (im->references == 0) { - cache->activ = evas_hash_del(cache->activ, im->cache_key, im); - cache->inactiv = evas_hash_direct_add(cache->inactiv, im->cache_key, im); - cache->lru = evas_object_list_prepend(cache->lru, im); - -// printf("IMG %p %ix%i %s ADD %i\n", -// im, im->image->w, im->image->h, im->cache_key, -// cache->func.mem_size_get(im)); - cache->usage += cache->func.mem_size_get(im); -// printf("FLUSH!\n"); + _evas_cache_image_remove_activ(cache, im); + _evas_cache_image_make_inactiv(cache, im, im->cache_key); evas_cache_image_flush(cache); } } -EAPI RGBA_Image * -evas_cache_image_dirty(RGBA_Image *im, int x, int y, int w, int h) +EAPI void +evas_cache_image_data_not_needed(Image_Entry *im) { - RGBA_Image *im_dirty = im; Evas_Cache_Image *cache; assert(im); assert(im->cache); cache = im->cache; - if (!(im->flags & RGBA_IMAGE_IS_DIRTY)) + + if (im->references > 1) return ; + if (im->flags.dirty || !im->flags.need_data) return ; + + _evas_cache_image_activ_lru_nodata(cache, im); +} + +EAPI Image_Entry * +evas_cache_image_dirty(Image_Entry *im, int x, int y, int w, int h) +{ + Image_Entry *im_dirty = im; + Evas_Cache_Image *cache; + + assert(im); + assert(im->cache); + + cache = im->cache; + if (!(im->flags.dirty)) { if (im->references == 1) { - if (im->cache_key) - { - cache->activ = evas_hash_del(cache->activ, im->cache_key, im); - evas_stringshare_del(im->cache_key); - im->cache_key = NULL; - } + _evas_cache_image_remove_activ(cache, im); im_dirty = im; } else { int error; - im_dirty = evas_common_image_new(); + im_dirty = _evas_cache_image_entry_new(cache, NULL, im->timestamp, im->file, im->key, &im->load_opts, &error); if (!im_dirty) goto on_error; - im_dirty->image = evas_common_image_surface_new(im); - if (!im_dirty->image) goto on_error; - im_dirty->image->w = w; - im_dirty->image->h = h; if (cache->func.debug) cache->func.debug("dirty-src", im); @@ -341,34 +508,32 @@ if (error != 0) goto on_error; - im_dirty->cache = cache; im_dirty->references = 1; evas_cache_image_drop(im); } - im_dirty->flags |= RGBA_IMAGE_IS_DIRTY; - cache->dirty = evas_object_list_prepend(cache->dirty, im_dirty); + _evas_cache_image_make_dirty(cache, im_dirty); } - + if (cache->func.debug) cache->func.debug("dirty-region", im_dirty); if (cache->func.dirty_region) cache->func.dirty_region(im_dirty, x, y, w, h); - + return im_dirty; - - on_error: - if (im_dirty) evas_common_image_delete(im_dirty); + + on_error: + if (im_dirty) _evas_cache_image_entry_delete(cache, im_dirty); evas_cache_image_drop(im); return NULL; } -EAPI RGBA_Image * -evas_cache_image_alone(RGBA_Image *im) +EAPI Image_Entry * +evas_cache_image_alone(Image_Entry *im) { - RGBA_Image *im_dirty = im; - Evas_Cache_Image *cache; + Evas_Cache_Image *cache; + Image_Entry *im_dirty = im; assert(im); assert(im->cache); @@ -376,28 +541,18 @@ cache = im->cache; if (im->references == 1) { - if (!(im->flags & RGBA_IMAGE_IS_DIRTY)) + if (!(im->flags.dirty)) { - if (im->cache_key) - { - cache->activ = evas_hash_del(cache->activ, im->cache_key, im); - evas_stringshare_del(im->cache_key); - im->cache_key = NULL; - } - im->flags |= RGBA_IMAGE_IS_DIRTY; - cache->dirty = evas_object_list_prepend(cache->dirty, im); + _evas_cache_image_remove_activ(cache, im); + _evas_cache_image_make_dirty(cache, im); } } else { int error; - im_dirty = evas_common_image_new(); + im_dirty = _evas_cache_image_entry_new(cache, NULL, im->timestamp, im->file, im->key, &im->load_opts, &error); if (!im_dirty) goto on_error; - im_dirty->image = evas_common_image_surface_new(im); - if (!im_dirty->image) goto on_error; - im_dirty->image->w = im->image->w; - im_dirty->image->h = im->image->h; if (cache->func.debug) cache->func.debug("dirty-src", im); @@ -407,46 +562,23 @@ if (error != 0) goto on_error; - if (im_dirty->cache_key) - { - evas_stringshare_del(im_dirty->cache_key); - im_dirty->cache_key = NULL; - } - im_dirty->flags |= RGBA_IMAGE_IS_DIRTY; im_dirty->references = 1; - cache->dirty = evas_object_list_prepend(cache->dirty, im_dirty); - evas_cache_image_drop(im); } return im_dirty; on_error: - if (im_dirty) evas_common_image_delete(im_dirty); + if (im_dirty) _evas_cache_image_entry_delete(cache, im_dirty); evas_cache_image_drop(im); return NULL; } -static RGBA_Image * -_evas_cache_image_push_dirty(Evas_Cache_Image *cache, RGBA_Image *im) -{ - cache->dirty = evas_object_list_prepend(cache->dirty, im); - - im->flags |= RGBA_IMAGE_IS_DIRTY; - if (im->cache_key) - { - evas_stringshare_del(im->cache_key); - im->cache_key = NULL; - } - im->cache = cache; - return im; -} - -EAPI RGBA_Image * +EAPI Image_Entry * evas_cache_image_copied_data(Evas_Cache_Image *cache, int w, int h, DATA32 *image_data, int alpha, int cspace) { - RGBA_Image *im; + Image_Entry *im; assert(cache); @@ -454,122 +586,132 @@ (cspace == EVAS_COLORSPACE_YCBCR422P709_PL)) w &= ~0x1; - im = evas_common_image_create(w, h); + im = _evas_cache_image_entry_new(cache, NULL, 0, NULL, NULL, NULL, NULL); if (!im) return NULL; + im->space = cspace; + + _evas_cache_image_entry_surface_alloc(cache, im, w, h); if (cache->func.copied_data(im, w, h, image_data, alpha, cspace) != 0) { - evas_common_image_delete(im); + _evas_cache_image_entry_delete(cache, im); return NULL; } + im->references = 1; - return _evas_cache_image_push_dirty(cache, im); + if (cache->func.debug) + cache->func.debug("copied-data", im); + return im; } -EAPI RGBA_Image * +EAPI Image_Entry * evas_cache_image_data(Evas_Cache_Image *cache, int w, int h, DATA32 *image_data, int alpha, int cspace) { - RGBA_Image *im; + Image_Entry *im; assert(cache); - im = evas_common_image_new(); - if (!im) return NULL; - im->image = evas_common_image_surface_new(im); - if (!im->image) - { - evas_common_image_delete(im); - return NULL; - } + im = _evas_cache_image_entry_new(cache, NULL, 0, NULL, NULL, NULL, NULL); + im->w = w; + im->h = h; if (cache->func.data(im, w, h, image_data, alpha, cspace) != 0) { - evas_common_image_delete(im); + _evas_cache_image_entry_delete(cache, im); return NULL; } + im->references = 1; + + if (cache->func.debug) + cache->func.debug("data", im); + return im; +} + +EAPI void +evas_cache_image_surface_alloc(Image_Entry *im, int w, int h) +{ + Evas_Cache_Image *cache; - return _evas_cache_image_push_dirty(cache, im); + assert(im); + assert(im->cache); + + cache = im->cache; + + _evas_cache_image_entry_surface_alloc(cache, im, w, h); + + if (cache->func.debug) + cache->func.debug("surface-alloc", im); } -EAPI RGBA_Image * -evas_cache_image_size_set(RGBA_Image *im, int w, int h) +EAPI Image_Entry * +evas_cache_image_size_set(Image_Entry *im, int w, int h) { Evas_Cache_Image *cache; - RGBA_Image *new; + Image_Entry *new; int error; assert(im); - assert(im->image); assert(im->cache); assert(im->references > 0); - if ((im->image->w == w) && (im->image->h == h)) + if ((im->w == w) && (im->h == h)) return im; cache = im->cache; - new = evas_common_image_new(); + new = _evas_cache_image_entry_new(cache, NULL, 0, NULL, NULL, NULL, &error); if (!new) goto on_error; - new->image = evas_common_image_surface_new(im); - if (!new->image) goto on_error; - new->image->w = w; - new->image->h = h; - if (cache->func.debug) - cache->func.debug("size_set-in", im); - error = cache->func.size_set(new, im, w, h); - if (cache->func.debug) - cache->func.debug("size_set-out", new); + _evas_cache_image_entry_surface_alloc(cache, new, w, h); - if (error != 0) goto on_error; + new->space = im->space; + new->load_opts = im->load_opts; - new->cache = cache; - new->cache_key = NULL; + error = cache->func.size_set(new, im, w, h); + if (error != 0) goto on_error; new->references = 1; -// cache->usage += cache->func.mem_size_get(new); - - if (((im->flags & RGBA_IMAGE_IS_DIRTY) == RGBA_IMAGE_IS_DIRTY) - || (im->references > 1)) - { - new->flags |= RGBA_IMAGE_IS_DIRTY; - cache->dirty = evas_object_list_prepend(cache->dirty, new); - } - else - { - new->cache_key = im->cache_key ? evas_stringshare_add(im->cache_key) : NULL; - cache->activ = evas_hash_direct_add(cache->activ, new->cache_key, new); - } evas_cache_image_drop(im); - + + if (cache->func.debug) + cache->func.debug("size_set", new); + return new; - - on_error: - if (new) evas_common_image_delete(new); + + on_error: + if (new) _evas_cache_image_entry_delete(cache, new); evas_cache_image_drop(im); return NULL; } EAPI void -evas_cache_image_load_data(RGBA_Image *im) +evas_cache_image_load_data(Image_Entry *im) { Evas_Cache_Image *cache; + int error; assert(im); - assert(im->image); assert(im->cache); - if ((im->flags & RGBA_IMAGE_LOADED) == RGBA_IMAGE_LOADED) return ; - + if (im->flags.loaded) return ; + cache = im->cache; + + error = cache->func.load(im); + if (cache->func.debug) cache->func.debug("load", im); - cache->func.load(im); - im->flags |= RGBA_IMAGE_LOADED; + if (error) + { + _evas_cache_image_entry_surface_alloc(cache, im, im->w, im->h); + im->flags.loaded = 0; + + return ; + } - assert(im->image->data); + im->flags.loaded = 1; } EAPI int @@ -583,58 +725,53 @@ while ((cache->lru) && (cache->limit < cache->usage)) { - RGBA_Image *im; + Image_Entry *im; - im = (RGBA_Image *) cache->lru->last; - cache->lru = evas_object_list_remove(cache->lru, im); - cache->inactiv = evas_hash_del(cache->inactiv, im->cache_key, im); -// printf("IMG %p %ix%i %s SUB %i\n", -// im, im->image->w, im->image->h, im->cache_key, -// cache->func.mem_size_get(im)); - cache->usage -= cache->func.mem_size_get(im); + im = (Image_Entry *) cache->lru->last; + _evas_cache_image_entry_delete(cache, im); + } + + while ((cache->lru_nodata) && (cache->limit < cache->usage)) + { + Image_Entry *im; + + im = (Image_Entry *) cache->lru_nodata->last; + _evas_cache_image_remove_lru_nodata(cache, im); + + cache->func.surface_delete(im); - if (im->cache_key) - { - evas_stringshare_del(im->cache_key); - im->cache_key = NULL; - } -// printf("DEL IMG FROM CACHE\n"); - cache->func.destructor(im); - evas_common_image_delete(im); + im->flags.loaded = 0; } + return cache->usage; } -EAPI RGBA_Image * +EAPI Image_Entry * evas_cache_image_empty(Evas_Cache_Image *cache) { - RGBA_Image *new; + Image_Entry *new; - new = evas_common_image_new(); - if (!new) goto on_error; - new->image = evas_common_image_surface_new(new); - if (!new->image) goto on_error; + new = _evas_cache_image_entry_new(cache, NULL, 0, NULL, NULL, NULL, NULL); + if (!new) return NULL; - new->cache = cache; new->references = 1; - new->cache_key = NULL; - new->flags |= RGBA_IMAGE_IS_DIRTY; - - cache->dirty = evas_object_list_prepend(cache->dirty, new); - return new; - - on_error: - if (new) evas_common_image_delete(new); - return NULL; } EAPI void -evas_cache_image_colorspace(RGBA_Image *im, int cspace) +evas_cache_image_colorspace(Image_Entry *im, int cspace) { + Evas_Cache_Image *cache; + + assert(im); + assert(im->cache); + + cache = im->cache; + if (!im) return ; - if (im->cs.space == cspace) return ; + if (im->space == cspace) return ; - evas_common_image_colorspace_set(im, cspace); + im->space = cspace; + cache->func.color_space(im, cspace); } ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone _______________________________________________ enlightenment-cvs mailing list enlightenment-cvs@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-cvs