elementary: make Efl.Ui.Factory.create asynchronous.

Reviewers: felipealmeida, SanghyeonLee, vitor.sousa, bu5hm4n, segfaultxavi

Reviewed By: felipealmeida, vitor.sousa, segfaultxavi

Subscribers: segfaultxavi, #reviewers, #committers

Tags: #efl

Maniphest Tasks: T7472

Differential Revision: https://phab.enlightenment.org/D7332
This commit is contained in:
Cedric BAIL 2018-12-07 11:26:54 +01:00 committed by Xavi Artigas
parent 89683f49ca
commit 4d6f20d714
7 changed files with 201 additions and 44 deletions

View File

@ -8,7 +8,7 @@ interface Efl.Ui.Factory (Efl.Ui.Model.Connect)
model: Efl.Model; [[Efl model]]
parent: Efl.Gfx.Entity; [[Efl canvas]]
}
return: Efl.Gfx.Entity; [[Created UI object]]
return: future<Efl.Gfx.Entity>; [[Created UI object]]
}
release {
[[Release a UI object and disconnect from models.]]

View File

@ -32,10 +32,11 @@ _efl_ui_image_factory_efl_object_destructor(Eo *obj EINA_UNUSED, Efl_Ui_Image_Fa
efl_destructor(efl_super(obj, MY_CLASS));
}
EOLIAN static Efl_Gfx_Entity *
_efl_ui_image_factory_efl_ui_factory_create(Eo *obj EINA_UNUSED, Efl_Ui_Image_Factory_Data *pd, Efl_Model *model, Efl_Gfx_Entity *parent)
EOLIAN static Eina_Future *
_efl_ui_image_factory_efl_ui_factory_create(Eo *obj, Efl_Ui_Image_Factory_Data *pd, Efl_Model *model, Efl_Gfx_Entity *parent)
{
Efl_Gfx_Entity *ui_view;
Eina_Value r;
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->property, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
@ -43,7 +44,9 @@ _efl_ui_image_factory_efl_ui_factory_create(Eo *obj EINA_UNUSED, Efl_Ui_Image_Fa
efl_ui_view_model_set(ui_view, model);
efl_ui_model_connect(ui_view, "filename", pd->property);
return ui_view;
r = eina_value_object_init(ui_view);
return eina_future_resolved(efl_loop_future_scheduler_get(obj), r);
}
EOLIAN static void

View File

@ -69,6 +69,15 @@ static const char *_efl_ui_layout_swallow_parts[] = {
NULL
};
typedef struct _Efl_Ui_Layout_Factory_Tracking Efl_Ui_Layout_Factory_Tracking;
struct _Efl_Ui_Layout_Factory_Tracking
{
Efl_Ui_Factory *factory;
Eina_Future *in_flight;
Eina_Stringshare *name;
};
/* these are data operated by layout's class functions internally, and
* should not be messed up by inhering classes */
@ -2034,13 +2043,68 @@ on_error:
free(value);
}
static void
_efl_ui_layout_view_model_content_update(Efl_Ui_Layout_Data *pd, Efl_Ui_Factory *factory, const char *name)
typedef struct _Efl_Ui_Layout_Factory_Request Efl_Ui_Layout_Factory_Request;
struct _Efl_Ui_Layout_Factory_Request
{
Efl_Gfx_Entity *content;
Efl_Ui_Layout_Factory_Tracking *tracking;
Efl_Ui_Layout *obj;
Efl_Ui_Layout_Data *pd;
Efl_Ui_Factory *factory;
const char *name;
};
content = efl_ui_factory_create(factory, pd->connect.model, pd->obj);
elm_layout_content_set(pd->obj, name, content);
static Eina_Value
_content_created(void *data, const Eina_Value value)
{
Efl_Ui_Layout_Factory_Request *request = data;
Efl_Gfx_Entity *content = NULL;
Efl_Gfx_Entity *old_content;
eina_value_get(&value, &content);
// Recycle old content
old_content = elm_layout_content_get(request->obj, request->name);
if (old_content) efl_ui_factory_release(request->factory, old_content);
// Set new content
elm_layout_content_set(request->obj, request->name, content);
return value;
}
static void
_clean_request(void *data, const Eina_Future *dead_future EINA_UNUSED)
{
Efl_Ui_Layout_Factory_Request *request = data;
request->tracking->in_flight = NULL;
eina_stringshare_del(request->name);
efl_unref(request->factory);
free(request);
}
static void
_efl_ui_layout_view_model_content_update(Efl_Ui_Layout_Data *pd, Efl_Ui_Layout_Factory_Tracking *tracking, const char *name)
{
Efl_Ui_Layout_Factory_Request *request = calloc(1, sizeof (Efl_Ui_Layout_Factory_Request));
Eina_Future *f;
if (!request) return ;
if (tracking->in_flight) eina_future_cancel(tracking->in_flight);
request->name = eina_stringshare_ref(name);
request->pd = pd;
request->obj = pd->obj;
request->factory = efl_ref(tracking->factory);
request->tracking = tracking;
f = efl_ui_factory_create(tracking->factory, pd->connect.model, pd->obj);
f = eina_future_then_from_desc(efl_future_then(pd->obj, f),
eina_future_cb_easy(.success = _content_created,
.success_type = EINA_VALUE_TYPE_OBJECT,
.data = request,
.free = _clean_request));
}
static void
@ -2063,7 +2127,11 @@ _efl_ui_layout_view_model_update(Efl_Ui_Layout_Data *pd)
it = eina_hash_iterator_tuple_new(pd->connect.factories);
EINA_ITERATOR_FOREACH(it, tuple)
_efl_ui_layout_view_model_content_update(pd, tuple->data, tuple->key);
{
Efl_Ui_Layout_Factory_Tracking *factory = tuple->data;
_efl_ui_layout_view_model_content_update(pd, factory, tuple->key);
}
eina_iterator_free(it);
}
@ -2083,7 +2151,7 @@ _efl_model_properties_changed_cb(void *data, const Efl_Event *event)
Eina_Stringshare *sprop = eina_stringshare_add(prop);
const char *part;
const char *signal;
Efl_Ui_Factory *factory;
Efl_Ui_Layout_Factory_Tracking *factory;
part = eina_hash_find(pd->connect.properties, sprop);
if (part) _efl_ui_layout_view_model_property_update(pd, part, sprop);
@ -2098,6 +2166,15 @@ _efl_model_properties_changed_cb(void *data, const Efl_Event *event)
}
}
static void
_efl_ui_layout_factory_free(Efl_Ui_Layout_Factory_Tracking *tracking)
{
if (tracking->in_flight) eina_future_cancel(tracking->in_flight);
efl_unref(tracking->factory);
eina_stringshare_del(tracking->name);
free(tracking);
}
static void
_efl_ui_layout_connect_hash(Efl_Ui_Layout_Data *pd)
{
@ -2105,7 +2182,7 @@ _efl_ui_layout_connect_hash(Efl_Ui_Layout_Data *pd)
pd->connect.properties = eina_hash_stringshared_new(EINA_FREE_CB(free)); // Hash of property targeting a part
pd->connect.signals = eina_hash_stringshared_new(EINA_FREE_CB(free)); // Hash of property triggering a signal
pd->connect.factories = eina_hash_stringshared_new(EINA_FREE_CB(efl_unref)); // Hash of property triggering a content creation
pd->connect.factories = eina_hash_stringshared_new(EINA_FREE_CB(_efl_ui_layout_factory_free)); // Hash of property triggering a content creation
}
EOLIAN static void
@ -2139,15 +2216,21 @@ _efl_ui_layout_efl_ui_view_model_set(Eo *obj, Efl_Ui_Layout_Data *pd, Efl_Model
it = eina_hash_iterator_tuple_new(pd->connect.factories);
EINA_ITERATOR_FOREACH(it, tuple)
{
Efl_Ui_Factory *factory;
Efl_Ui_Layout_Factory_Tracking *factory;
Efl_Gfx_Entity *content;
name = tuple->key;
factory = tuple->data;
content = elm_layout_content_get(obj, name);
// Cancel in flight creation request
if (factory->in_flight) eina_future_cancel(factory->in_flight);
// Cleanup content
content = elm_layout_content_get(obj, name);
elm_layout_content_set(obj, name, NULL);
efl_ui_factory_release(factory, content);
// And recycle it
efl_ui_factory_release(factory->factory, content);
}
eina_iterator_free(it);
@ -2215,31 +2298,48 @@ _efl_ui_layout_efl_ui_factory_model_connect(Eo *obj EINA_UNUSED, Efl_Ui_Layout_D
const char *name, Efl_Ui_Factory *factory)
{
EINA_SAFETY_ON_NULL_RETURN(name);
Efl_Ui_Layout_Factory_Tracking *tracking;
Eina_Stringshare *ss_name;
Efl_Ui_Factory *old_factory;
Evas_Object *new_ev, *old_ev;
if (!_elm_layout_part_aliasing_eval(obj, &name, EINA_TRUE))
return;
if (!pd->connect.factories)
pd->connect.factories = eina_hash_stringshared_new(EINA_FREE_CB(_efl_ui_layout_factory_free));
ss_name = eina_stringshare_add(name);
if (!pd->connect.factories)
pd->connect.factories = eina_hash_stringshared_new(EINA_FREE_CB(efl_unref));
new_ev = efl_ui_factory_create(factory, pd->connect.model, obj);
EINA_SAFETY_ON_NULL_RETURN(new_ev);
old_factory = eina_hash_set(pd->connect.factories, ss_name, efl_ref(factory));
if (old_factory)
// First undo the old one if there is one
tracking = eina_hash_find(pd->connect.factories, ss_name);
if (tracking)
{
old_ev = elm_layout_content_get(obj, name);
if (old_ev)
efl_ui_factory_release(old_factory, old_ev);
efl_unref(old_factory);
Efl_Gfx_Entity *old;
// Unset and recycle
old = elm_layout_content_get(obj, ss_name);
elm_layout_content_set(obj, ss_name, NULL);
if (old) efl_ui_factory_release(tracking->factory, old);
// Stop in flight request
if (tracking->in_flight) eina_future_cancel(tracking->in_flight);
// Release previous factory
efl_replace(&tracking->factory, NULL);
}
else
{
tracking = calloc(1, sizeof (Efl_Ui_Layout_Factory_Tracking));
if (!tracking) return ;
tracking->name = ss_name;
eina_hash_add(pd->connect.factories, ss_name, tracking);
}
elm_layout_content_set(obj, name, new_ev);
// And update content with the new factory
tracking->factory = efl_ref(factory);
_efl_ui_layout_view_model_content_update(pd, tracking, ss_name);
}
EOLIAN static Eo *

View File

@ -64,10 +64,11 @@ _efl_ui_layout_factory_efl_object_destructor(Eo *obj, Efl_Ui_Layout_Factory_Data
efl_destructor(efl_super(obj, MY_CLASS));
}
EOLIAN static Efl_Gfx_Entity *
_efl_ui_layout_factory_efl_ui_factory_create(Eo *obj EINA_UNUSED, Efl_Ui_Layout_Factory_Data *pd
, Efl_Model *model, Efl_Gfx_Entity *parent)
EOLIAN static Eina_Future *
_efl_ui_layout_factory_efl_ui_factory_create(Eo *obj, Efl_Ui_Layout_Factory_Data *pd,
Efl_Model *model, Efl_Gfx_Entity *parent)
{
Eina_Value r;
Efl_Gfx_Entity *layout;
EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
@ -81,7 +82,9 @@ _efl_ui_layout_factory_efl_ui_factory_create(Eo *obj EINA_UNUSED, Efl_Ui_Layout_
evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, 0);
evas_object_size_hint_align_set(layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
return layout;
r = eina_value_object_init(layout);
return eina_future_resolved(efl_loop_future_scheduler_get(obj), r);
}
EOLIAN static void

View File

@ -902,18 +902,25 @@ _efl_ui_list_view_efl_ui_widget_focus_state_apply(Eo *obj, Efl_Ui_List_View_Data
return efl_ui_widget_focus_state_apply(efl_super(obj, MY_CLASS), current_state, configured_state, obj);
}
EOLIAN static Efl_Ui_List_View_Layout_Item *
_efl_ui_list_view_efl_ui_list_view_model_realize(Eo *obj, Efl_Ui_List_View_Data *pd, Efl_Ui_List_View_Layout_Item *item)
typedef struct _Efl_Ui_List_Vuew_Layout_Item_Tracking Efl_Ui_List_View_Layout_Item_Tracking;
struct _Efl_Ui_List_Vuew_Layout_Item_Tracking
{
Efl_Ui_List_View_Layout_Item *item;
Eo *obj;
Efl_Ui_List_View_Data *pd;
};
static Eina_Value
_content_created(void *data, const Eina_Value value)
{
Efl_Ui_List_View_Layout_Item_Tracking *tracking = data;
Efl_Ui_List_View_Layout_Item *item = tracking->item;
Eo *obj = tracking->obj;
Efl_Ui_List_View_Item_Event evt;
EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
if (!item->children)
return item;
eina_value_pget(&value, &item->layout);
item->layout = efl_ui_factory_create(pd->factory, item->children, obj);
EINA_SAFETY_ON_NULL_RETURN_VAL(item->layout, NULL);
evas_object_smart_member_add(item->layout, pd->pan_obj);
evas_object_smart_member_add(item->layout, tracking->pd->pan_obj);
evas_object_event_callback_add(item->layout, EVAS_CALLBACK_MOUSE_UP, _on_item_mouse_up, item);
if (_elm_config->atspi_mode)
@ -929,6 +936,44 @@ _efl_ui_list_view_efl_ui_list_view_model_realize(Eo *obj, Efl_Ui_List_View_Data
efl_ui_focus_composition_dirty(obj);
evas_object_show(item->layout);
return value;
}
static void
_clean_request(void *data, const Eina_Future *dead_future EINA_UNUSED)
{
Efl_Ui_List_View_Layout_Item_Tracking *tracking = data;
tracking->item->layout_request = NULL;
free(tracking);
}
EOLIAN static Efl_Ui_List_View_Layout_Item *
_efl_ui_list_view_efl_ui_list_view_model_realize(Eo *obj, Efl_Ui_List_View_Data *pd, Efl_Ui_List_View_Layout_Item *item)
{
Efl_Ui_List_View_Layout_Item_Tracking *tracking;
EINA_SAFETY_ON_NULL_RETURN_VAL(item->children, item);
if (!item->children) return item;
if (item->layout_request) eina_future_cancel(item->layout_request);
tracking = calloc(1, sizeof (Efl_Ui_List_View_Layout_Item_Tracking));
if (!tracking) return item;
tracking->item = item;
tracking->obj = obj;
tracking->pd = pd;
item->layout_request = efl_ui_factory_create(pd->factory, item->children, obj);
item->layout_request = efl_future_then(obj, item->layout_request);
item->layout_request = eina_future_then_from_desc(item->layout_request,
eina_future_cb_easy(.success = _content_created,
.success_type = EINA_VALUE_TYPE_OBJECT,
.data = tracking,
.free = _clean_request));
return item;
}
@ -941,6 +986,13 @@ _efl_ui_list_view_efl_ui_list_view_model_unrealize(Eo *obj, Efl_Ui_List_View_Dat
if (!item->layout)
return;
// First check if the item has been fully realized
if (item->layout_request)
{
eina_future_cancel(item->layout_request);
return ;
}
evas_object_event_callback_del_full(item->layout, EVAS_CALLBACK_MOUSE_UP, _on_item_mouse_up, item);
if (elm_object_focus_allow_get(item->layout))
{

View File

@ -1,8 +1,6 @@
#ifndef EFL_UI_LIST_VIEW_SEG_ARRAY_H
#define EFL_UI_LIST_VIEW_SEG_ARRAY_H
typedef struct _Efl_Ui_List_View_Item Efl_Ui_List_View_Item;
typedef struct _Efl_Ui_List_View_SegArray_Node
{
EINA_RBTREE;

View File

@ -1,5 +1,6 @@
struct Efl.Ui.List_View_Layout_Item {
layout: Efl.Ui.Layout;
layout_request: future<Efl.Ui.Layout>;
children: Efl.Model;
index_offset: int;
tree_node: void_ptr;