forked from enlightenment/efl
elementary: update Efl.Ui.Caching_Factory to rely on Efl.Ui.Widget_Factory for Efl.Ui.Widget.
I am not sure we really need Efl.Ui.Caching_Factory after this, but in case we want a Caching_Factory for non Efl.Ui.Widget, this is supported by this patch (And is the reason why most of the complexity). The benefit from inheriting from Efl.Ui.Widget_Factory allow to get the style of an Efl.Ui.Widget defined by an Efl.Model properly done at creation time. Reviewed-by: SangHyeon Jade Lee <sh10233.lee@samsung.com> Reviewed-by: Larry Lira <larry@expertisesolutions.com.br> Differential Revision: https://phab.enlightenment.org/D7705
This commit is contained in:
parent
aa0e89a590
commit
c910679917
|
@ -6,18 +6,33 @@
|
||||||
#include "elm_priv.h"
|
#include "elm_priv.h"
|
||||||
|
|
||||||
typedef struct _Efl_Ui_Caching_Factory_Data Efl_Ui_Caching_Factory_Data;
|
typedef struct _Efl_Ui_Caching_Factory_Data Efl_Ui_Caching_Factory_Data;
|
||||||
|
typedef struct _Efl_Ui_Caching_Factory_Request Efl_Ui_Caching_Factory_Request;
|
||||||
|
|
||||||
struct _Efl_Ui_Caching_Factory_Data
|
struct _Efl_Ui_Caching_Factory_Data
|
||||||
{
|
{
|
||||||
const Efl_Class *klass;
|
const Efl_Class *klass;
|
||||||
|
|
||||||
|
Eina_Stringshare *style;
|
||||||
|
|
||||||
// Simple list of ready-to-use objects. They are all equal so it does not matter from which
|
// Simple list of ready-to-use objects. They are all equal so it does not matter from which
|
||||||
// end of the list objects are added and removed.
|
// end of the list objects are added and removed.
|
||||||
Eina_List *cache;
|
Eina_List *cache;
|
||||||
|
Eina_Hash *lookup;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
unsigned int memory;
|
unsigned int memory;
|
||||||
unsigned int items;
|
unsigned int items;
|
||||||
} limit, current;
|
} limit, current;
|
||||||
|
|
||||||
|
Eina_Bool invalidated : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Efl_Ui_Caching_Factory_Request
|
||||||
|
{
|
||||||
|
Efl_Ui_Caching_Factory_Data *pd;
|
||||||
|
|
||||||
|
Eo *parent;
|
||||||
|
Efl_Model *model;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Clear the cache until it meet the constraint
|
// Clear the cache until it meet the constraint
|
||||||
|
@ -33,7 +48,15 @@ _efl_ui_caching_factory_remove(Efl_Ui_Caching_Factory_Data *pd, Eina_List *l, Ef
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_efl_ui_caching_factory_flush(Efl_Ui_Caching_Factory_Data *pd)
|
_efl_ui_caching_factory_item_del(Eo *obj, Efl_Ui_Caching_Factory_Data *pd,
|
||||||
|
Efl_Gfx_Entity *entity)
|
||||||
|
{
|
||||||
|
if (pd->klass) efl_del(entity);
|
||||||
|
else efl_ui_factory_release(efl_super(obj, EFL_UI_CACHING_FACTORY_CLASS), entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_ui_caching_factory_flush(Eo *obj, Efl_Ui_Caching_Factory_Data *pd)
|
||||||
{
|
{
|
||||||
while (pd->limit.items != 0 &&
|
while (pd->limit.items != 0 &&
|
||||||
pd->current.items > pd->limit.items)
|
pd->current.items > pd->limit.items)
|
||||||
|
@ -43,8 +66,8 @@ _efl_ui_caching_factory_flush(Efl_Ui_Caching_Factory_Data *pd)
|
||||||
entity = eina_list_data_get(eina_list_last(pd->cache));
|
entity = eina_list_data_get(eina_list_last(pd->cache));
|
||||||
|
|
||||||
_efl_ui_caching_factory_remove(pd, eina_list_last(pd->cache), entity);
|
_efl_ui_caching_factory_remove(pd, eina_list_last(pd->cache), entity);
|
||||||
|
if (pd->lookup) eina_hash_del(pd->lookup, efl_ui_widget_style_get(entity), entity);
|
||||||
efl_del(entity);
|
_efl_ui_caching_factory_item_del(obj, pd, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (pd->limit.memory != 0 &&
|
while (pd->limit.memory != 0 &&
|
||||||
|
@ -55,69 +78,138 @@ _efl_ui_caching_factory_flush(Efl_Ui_Caching_Factory_Data *pd)
|
||||||
entity = eina_list_data_get(eina_list_last(pd->cache));
|
entity = eina_list_data_get(eina_list_last(pd->cache));
|
||||||
|
|
||||||
_efl_ui_caching_factory_remove(pd, eina_list_last(pd->cache), entity);
|
_efl_ui_caching_factory_remove(pd, eina_list_last(pd->cache), entity);
|
||||||
|
if (pd->lookup) eina_hash_del(pd->lookup, efl_ui_widget_style_get(entity), entity);
|
||||||
efl_del(entity);
|
_efl_ui_caching_factory_item_del(obj, pd, entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Eina_Value
|
||||||
|
_efl_ui_caching_factory_create_then(Eo *obj EINA_UNUSED, void *data, const Eina_Value v)
|
||||||
|
{
|
||||||
|
Efl_Ui_Caching_Factory_Request *r = data;
|
||||||
|
Efl_Ui_Widget *w;
|
||||||
|
const char *string = NULL;
|
||||||
|
|
||||||
|
if (!eina_value_string_get(&v, &string))
|
||||||
|
return eina_value_error_init(EFL_MODEL_ERROR_NOT_SUPPORTED);
|
||||||
|
|
||||||
|
w = eina_hash_find(r->pd->lookup, string);
|
||||||
|
if (!w)
|
||||||
|
{
|
||||||
|
Eina_Future *f;
|
||||||
|
|
||||||
|
// No object of that style in the cache, need to create a new one
|
||||||
|
f = efl_ui_factory_create(efl_super(obj, EFL_UI_CACHING_FACTORY_CLASS),
|
||||||
|
r->model, r->parent);
|
||||||
|
return eina_future_as_value(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
eina_hash_del(r->pd->lookup, string, w);
|
||||||
|
_efl_ui_caching_factory_remove(r->pd, r->pd->cache, w);
|
||||||
|
|
||||||
|
efl_parent_set(w, r->parent);
|
||||||
|
efl_ui_view_model_set(w, r->model);
|
||||||
|
|
||||||
|
return eina_value_object_init(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_ui_caching_factory_create_cleanup(Eo *o EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED)
|
||||||
|
{
|
||||||
|
Efl_Ui_Caching_Factory_Request *r = data;
|
||||||
|
|
||||||
|
efl_unref(r->model);
|
||||||
|
efl_unref(r->parent);
|
||||||
|
free(r);
|
||||||
|
}
|
||||||
|
|
||||||
static Eina_Future *
|
static Eina_Future *
|
||||||
_efl_ui_caching_factory_efl_ui_factory_create(Eo *obj,
|
_efl_ui_caching_factory_efl_ui_factory_create(Eo *obj,
|
||||||
Efl_Ui_Caching_Factory_Data *pd,
|
Efl_Ui_Caching_Factory_Data *pd,
|
||||||
Efl_Model *model, Efl_Gfx_Entity *parent)
|
Efl_Model *model, Efl_Gfx_Entity *parent)
|
||||||
{
|
{
|
||||||
Efl_Gfx_Entity *r;
|
Efl_Gfx_Entity *w = NULL;
|
||||||
|
|
||||||
if (pd->cache)
|
if (pd->cache)
|
||||||
{
|
{
|
||||||
r = eina_list_data_get(pd->cache);
|
if (pd->style && !pd->klass)
|
||||||
|
|
||||||
_efl_ui_caching_factory_remove(pd, pd->cache, r);
|
|
||||||
|
|
||||||
efl_parent_set(r, parent);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
r = efl_add(pd->klass, parent);
|
Efl_Ui_Caching_Factory_Request *r;
|
||||||
|
|
||||||
|
r = calloc(1, sizeof (Efl_Ui_Caching_Factory_Request));
|
||||||
|
if (!r) return efl_loop_future_rejected(obj, ENOMEM);
|
||||||
|
|
||||||
|
r->pd = pd;
|
||||||
|
r->parent = efl_ref(parent);
|
||||||
|
r->model = efl_ref(model);
|
||||||
|
|
||||||
|
return efl_future_then(obj, efl_model_property_ready_get(obj, pd->style),
|
||||||
|
.success = _efl_ui_caching_factory_create_then,
|
||||||
|
.data = r,
|
||||||
|
.free = _efl_ui_caching_factory_create_cleanup);
|
||||||
}
|
}
|
||||||
|
|
||||||
efl_ui_view_model_set(r, model);
|
w = eina_list_data_get(pd->cache);
|
||||||
|
|
||||||
return efl_loop_future_resolved(obj, eina_value_object_init(r));
|
_efl_ui_caching_factory_remove(pd, pd->cache, w);
|
||||||
|
|
||||||
|
efl_parent_set(w, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!w)
|
||||||
|
{
|
||||||
|
if (pd->klass) w = efl_add(pd->klass, parent);
|
||||||
|
else return efl_ui_factory_create(efl_super(obj, EFL_UI_CACHING_FACTORY_CLASS),
|
||||||
|
model, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
efl_ui_view_model_set(w, model);
|
||||||
|
|
||||||
|
return efl_loop_future_resolved(obj, eina_value_object_init(w));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_efl_ui_caching_factory_item_class_set(Eo *obj,
|
_efl_ui_caching_factory_efl_ui_widget_factory_item_class_set(Eo *obj,
|
||||||
Efl_Ui_Caching_Factory_Data *pd,
|
Efl_Ui_Caching_Factory_Data *pd,
|
||||||
const Efl_Object *klass)
|
const Efl_Object *klass)
|
||||||
{
|
{
|
||||||
|
if (efl_isa(klass, EFL_UI_VIEW_INTERFACE) &&
|
||||||
|
!efl_isa(klass, EFL_UI_WIDGET_CLASS))
|
||||||
|
{
|
||||||
if (!efl_isa(klass, EFL_GFX_ENTITY_INTERFACE) ||
|
if (!efl_isa(klass, EFL_GFX_ENTITY_INTERFACE) ||
|
||||||
!efl_isa(klass, EFL_UI_VIEW_INTERFACE))
|
!efl_isa(klass, EFL_UI_VIEW_INTERFACE))
|
||||||
{
|
{
|
||||||
ERR("Provided class '%s' for factory '%s' doesn't implement '%s' and '%s' interfaces.",
|
ERR("Provided class '%s' for factory '%s' doesn't implement '%s' and '%s' interfaces nor '%s' and '%s' interfaces.",
|
||||||
efl_class_name_get(klass),
|
efl_class_name_get(klass),
|
||||||
efl_class_name_get(obj),
|
efl_class_name_get(obj),
|
||||||
efl_class_name_get(EFL_GFX_ENTITY_INTERFACE),
|
efl_class_name_get(EFL_GFX_ENTITY_INTERFACE),
|
||||||
|
efl_class_name_get(EFL_UI_VIEW_INTERFACE),
|
||||||
|
efl_class_name_get(EFL_UI_WIDGET_CLASS),
|
||||||
efl_class_name_get(EFL_UI_VIEW_INTERFACE));
|
efl_class_name_get(EFL_UI_VIEW_INTERFACE));
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
pd->klass = klass;
|
pd->klass = klass;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
efl_ui_widget_factory_item_class_set(efl_super(obj, EFL_UI_CACHING_FACTORY_CLASS), klass);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Efl_Object *
|
static const Efl_Object *
|
||||||
_efl_ui_caching_factory_item_class_get(const Eo *obj EINA_UNUSED,
|
_efl_ui_caching_factory_efl_ui_widget_factory_item_class_get(const Eo *obj,
|
||||||
Efl_Ui_Caching_Factory_Data *pd)
|
Efl_Ui_Caching_Factory_Data *pd)
|
||||||
{
|
{
|
||||||
return pd->klass;
|
if (pd->klass) return pd->klass;
|
||||||
|
return efl_ui_widget_factory_item_class_get(efl_super(obj, EFL_UI_CACHING_FACTORY_CLASS));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_efl_ui_caching_factory_memory_limit_set(Eo *obj EINA_UNUSED,
|
_efl_ui_caching_factory_memory_limit_set(Eo *obj,
|
||||||
Efl_Ui_Caching_Factory_Data *pd,
|
Efl_Ui_Caching_Factory_Data *pd,
|
||||||
unsigned int limit)
|
unsigned int limit)
|
||||||
{
|
{
|
||||||
pd->limit.memory = limit;
|
pd->limit.memory = limit;
|
||||||
|
|
||||||
_efl_ui_caching_factory_flush(pd);
|
_efl_ui_caching_factory_flush(obj, pd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
|
@ -128,13 +220,13 @@ _efl_ui_caching_factory_memory_limit_get(const Eo *obj EINA_UNUSED,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_efl_ui_caching_factory_items_limit_set(Eo *obj EINA_UNUSED,
|
_efl_ui_caching_factory_items_limit_set(Eo *obj,
|
||||||
Efl_Ui_Caching_Factory_Data *pd,
|
Efl_Ui_Caching_Factory_Data *pd,
|
||||||
unsigned int limit)
|
unsigned int limit)
|
||||||
{
|
{
|
||||||
pd->limit.items = limit;
|
pd->limit.items = limit;
|
||||||
|
|
||||||
_efl_ui_caching_factory_flush(pd);
|
_efl_ui_caching_factory_flush(obj, pd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
|
@ -149,6 +241,13 @@ _efl_ui_caching_factory_efl_ui_factory_release(Eo *obj,
|
||||||
Efl_Ui_Caching_Factory_Data *pd,
|
Efl_Ui_Caching_Factory_Data *pd,
|
||||||
Efl_Gfx_Entity *ui_view)
|
Efl_Gfx_Entity *ui_view)
|
||||||
{
|
{
|
||||||
|
// Are we invalidated ?
|
||||||
|
if (pd->invalidated)
|
||||||
|
{
|
||||||
|
_efl_ui_caching_factory_item_del(obj, pd, ui_view);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Change parent, disconnect the object and make it invisible
|
// Change parent, disconnect the object and make it invisible
|
||||||
efl_parent_set(ui_view, obj);
|
efl_parent_set(ui_view, obj);
|
||||||
efl_gfx_entity_visible_set(ui_view, EINA_FALSE);
|
efl_gfx_entity_visible_set(ui_view, EINA_FALSE);
|
||||||
|
@ -161,8 +260,15 @@ _efl_ui_caching_factory_efl_ui_factory_release(Eo *obj,
|
||||||
if (efl_isa(ui_view, EFL_CACHED_ITEM_INTERFACE))
|
if (efl_isa(ui_view, EFL_CACHED_ITEM_INTERFACE))
|
||||||
pd->current.memory += efl_cached_item_memory_size_get(ui_view);
|
pd->current.memory += efl_cached_item_memory_size_get(ui_view);
|
||||||
|
|
||||||
|
// Fill lookup
|
||||||
|
if (!pd->klass && efl_ui_widget_style_get(ui_view))
|
||||||
|
{
|
||||||
|
if (!pd->lookup) pd->lookup = eina_hash_string_djb2_new(NULL);
|
||||||
|
eina_hash_direct_add(pd->lookup, efl_ui_widget_style_get(ui_view), ui_view);
|
||||||
|
}
|
||||||
|
|
||||||
// And check if the cache need some triming
|
// And check if the cache need some triming
|
||||||
_efl_ui_caching_factory_flush(pd);
|
_efl_ui_caching_factory_flush(obj, pd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -171,6 +277,9 @@ _efl_ui_caching_factory_efl_object_invalidate(Eo *obj EINA_UNUSED,
|
||||||
{
|
{
|
||||||
// As all the objects in the cache have the factory as parent, there's no need to unparent them
|
// As all the objects in the cache have the factory as parent, there's no need to unparent them
|
||||||
pd->cache = eina_list_free(pd->cache);
|
pd->cache = eina_list_free(pd->cache);
|
||||||
|
eina_hash_free(pd->lookup);
|
||||||
|
pd->lookup = NULL;
|
||||||
|
pd->invalidated = EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Efl_App *
|
static Efl_App *
|
||||||
|
@ -215,4 +324,13 @@ _efl_ui_caching_factory_efl_object_parent_set(Eo *obj, Efl_Ui_Caching_Factory_Da
|
||||||
if (a) efl_event_callback_add(a, EFL_APP_EVENT_PAUSE, _efl_ui_caching_factory_pause, pd);
|
if (a) efl_event_callback_add(a, EFL_APP_EVENT_PAUSE, _efl_ui_caching_factory_pause, pd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_ui_caching_factory_efl_ui_model_connect_connect(Eo *obj, Efl_Ui_Caching_Factory_Data *pd,
|
||||||
|
const char *name, const char *property)
|
||||||
|
{
|
||||||
|
if (!strcmp(name, "style"))
|
||||||
|
eina_stringshare_replace(&pd->style, property);
|
||||||
|
efl_ui_model_connect(efl_super(obj, EFL_UI_CACHING_FACTORY_CLASS), name, property);
|
||||||
|
}
|
||||||
|
|
||||||
#include "efl_ui_caching_factory.eo.c"
|
#include "efl_ui_caching_factory.eo.c"
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
class Efl.Ui.Caching_Factory extends Efl.Loop_Consumer implements Efl.Ui.Factory
|
class Efl.Ui.Caching_Factory extends Efl.Ui.Widget_Factory
|
||||||
{
|
{
|
||||||
[[Efl Ui Factory that provides object caching.
|
[[Efl Ui Factory that provides object caching.
|
||||||
|
|
||||||
This factory handles caching of one type of object and automatically empties the cache
|
This factory handles caching of one type of object that must be an @Efl.Gfx.Entity with an @Efl.Ui.View interface defined.
|
||||||
when the application goes into pause.
|
This factory will rely on its parent class @Efl.Ui.Widget_Factory for creating the subset of class that match @Efl.Ui.Widget
|
||||||
|
interface.
|
||||||
|
The factory will automatically empties the cache when the application goes into pause.
|
||||||
|
|
||||||
Creating objects is costly and time consuming, keeping a few on hand for when you next will need them helps a lot.
|
Creating objects is costly and time consuming, keeping a few on hand for when you next will need them helps a lot.
|
||||||
This is what this factory caching infrastructure provides. It will create the object from the class defined on it and
|
This is what this factory caching infrastructure provides. It will create the object from the class defined on it and
|
||||||
|
@ -13,14 +15,6 @@ class Efl.Ui.Caching_Factory extends Efl.Loop_Consumer implements Efl.Ui.Factory
|
||||||
The cache might decide to flush itself when the application event pause is triggered.
|
The cache might decide to flush itself when the application event pause is triggered.
|
||||||
]]
|
]]
|
||||||
methods {
|
methods {
|
||||||
@property item_class {
|
|
||||||
[[Define the class of the item returned by this factory.]]
|
|
||||||
get {}
|
|
||||||
set {}
|
|
||||||
values {
|
|
||||||
klass: const(Efl.Class); [[The class identifier to create item from.]]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@property memory_limit {
|
@property memory_limit {
|
||||||
[[Define the maxium size in Bytes that all the object waiting on standby in the cache take. They must provide the @Efl.Cached.Item interface for an accurate accounting.]]
|
[[Define the maxium size in Bytes that all the object waiting on standby in the cache take. They must provide the @Efl.Cached.Item interface for an accurate accounting.]]
|
||||||
get {}
|
get {}
|
||||||
|
@ -42,6 +36,8 @@ class Efl.Ui.Caching_Factory extends Efl.Loop_Consumer implements Efl.Ui.Factory
|
||||||
implements {
|
implements {
|
||||||
Efl.Ui.Factory.create;
|
Efl.Ui.Factory.create;
|
||||||
Efl.Ui.Factory.release;
|
Efl.Ui.Factory.release;
|
||||||
|
Efl.Ui.Model.Connect.connect;
|
||||||
|
Efl.Ui.Widget_Factory.item_class { get; set; }
|
||||||
Efl.Object.invalidate;
|
Efl.Object.invalidate;
|
||||||
Efl.Object.parent { set; }
|
Efl.Object.parent { set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ EOLIAN static Eo *
|
||||||
_efl_ui_image_factory_efl_object_constructor(Eo *obj, Efl_Ui_Image_Factory_Data *pd)
|
_efl_ui_image_factory_efl_object_constructor(Eo *obj, Efl_Ui_Image_Factory_Data *pd)
|
||||||
{
|
{
|
||||||
obj = efl_constructor(efl_super(obj, MY_CLASS));
|
obj = efl_constructor(efl_super(obj, MY_CLASS));
|
||||||
efl_ui_caching_factory_item_class_set(obj, EFL_UI_IMAGE_CLASS);
|
efl_ui_widget_factory_item_class_set(obj, EFL_UI_IMAGE_CLASS);
|
||||||
|
|
||||||
pd->property = NULL;
|
pd->property = NULL;
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ _efl_ui_layout_factory_efl_object_constructor(Eo *obj, Efl_Ui_Layout_Factory_Dat
|
||||||
{
|
{
|
||||||
obj = efl_constructor(efl_super(obj, MY_CLASS));
|
obj = efl_constructor(efl_super(obj, MY_CLASS));
|
||||||
|
|
||||||
efl_ui_caching_factory_item_class_set(obj, EFL_UI_LAYOUT_CLASS);
|
efl_ui_widget_factory_item_class_set(obj, EFL_UI_LAYOUT_CLASS);
|
||||||
|
|
||||||
pd->connects = eina_hash_stringshared_new(EINA_FREE_CB(eina_stringshare_del));
|
pd->connects = eina_hash_stringshared_new(EINA_FREE_CB(eina_stringshare_del));
|
||||||
pd->factory_connects = eina_hash_stringshared_new(EINA_FREE_CB(efl_unref));
|
pd->factory_connects = eina_hash_stringshared_new(EINA_FREE_CB(efl_unref));
|
||||||
|
|
Loading…
Reference in New Issue