Discussion:
[EGIT] [core/efl] master 01/01: elementary: make Efl.Ui.Factory.create asynchronous.
Cedric BAIL
2018-12-07 10:47:22 UTC
Permalink
xartigas pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=4d6f20d714ea083471be163f67af518eced4028c

commit 4d6f20d714ea083471be163f67af518eced4028c
Author: Cedric BAIL <***@osg.samsung.com>
Date: Fri Dec 7 11:26:54 2018 +0100

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
---
src/lib/efl/interfaces/efl_ui_factory.eo | 2 +-
src/lib/elementary/efl_ui_image_factory.c | 9 +-
src/lib/elementary/efl_ui_layout.c | 146 ++++++++++++++++++++----
src/lib/elementary/efl_ui_layout_factory.c | 11 +-
src/lib/elementary/efl_ui_list_view.c | 68 +++++++++--
src/lib/elementary/efl_ui_list_view_seg_array.h | 2 -
src/lib/elementary/efl_ui_list_view_types.eot | 1 +
7 files changed, 198 insertions(+), 41 deletions(-)

diff --git a/src/lib/efl/interfaces/efl_ui_factory.eo b/src/lib/efl/interfaces/efl_ui_factory.eo
index 4765f3beca..adbd93bbd1 100644
--- a/src/lib/efl/interfaces/efl_ui_factory.eo
+++ b/src/lib/efl/interfaces/efl_ui_factory.eo
@@ -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.]]
diff --git a/src/lib/elementary/efl_ui_image_factory.c b/src/lib/elementary/efl_ui_image_factory.c
index 9607665e06..998c43f70d 100644
--- a/src/lib/elementary/efl_ui_image_factory.c
+++ b/src/lib/elementary/efl_ui_image_factory.c
@@ -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
diff --git a/src/lib/elementary/efl_ui_layout.c b/src/lib/elementary/efl_ui_layout.c
index c14bebac3d..5544e4e65e 100644
--- a/src/lib/elementary/efl_ui_layout.c
+++ b/src/lib/elementary/efl_ui_layout.c
@@ -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);
}

+typedef struct _Efl_Ui_Layout_Factory_Request Efl_Ui_Layout_Factory_Request;
+struct _Efl_Ui_Layout_Factory_Request
+{
+ Efl_Ui_Layout_Factory_Tracking *tracking;
+ Efl_Ui_Layout *obj;
+ Efl_Ui_Layout_Data *pd;
+ Efl_Ui_Factory *factory;
+ const char *name;
+};
+
+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
-_efl_ui_layout_view_model_content_update(Efl_Ui_Layout_Data *pd, Efl_Ui_Factory *factory, const char *name)
+_clean_request(void *data, const Eina_Future *dead_future EINA_UNUSED)
{
- Efl_Gfx_Entity *content;
+ 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);

- content = efl_ui_factory_create(factory, pd->connect.model, pd->obj);
- elm_layout_content_set(pd->obj, name, content);
+ 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));
+ // First undo the old one if there is one
+ tracking = eina_hash_find(pd->connect.factories, ss_name);
+ if (tracking)
+ {
+ 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);

- new_ev = efl_ui_factory_create(factory, pd->connect.model, obj);
- EINA_SAFETY_ON_NULL_RETURN(new_ev);
+ // Stop in flight request
+ if (tracking->in_flight) eina_future_cancel(tracking->in_flight);

- old_factory = eina_hash_set(pd->connect.factories, ss_name, efl_ref(factory));
- if (old_factory)
+ // Release previous factory
+ efl_replace(&tracking->factory, NULL);
+ }
+ else
{
- old_ev = elm_layout_content_get(obj, name);
- if (old_ev)
- efl_ui_factory_release(old_factory, old_ev);
- efl_unref(old_factory);
+ 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 *
diff --git a/src/lib/elementary/efl_ui_layout_factory.c b/src/lib/elementary/efl_ui_layout_factory.c
index cbd8139064..36bf8ddb5f 100644
--- a/src/lib/elementary/efl_ui_layout_factory.c
+++ b/src/lib/elementary/efl_ui_layout_factory.c
@@ -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
diff --git a/src/lib/elementary/efl_ui_list_view.c b/src/lib/elementary/efl_ui_list_view.c
index 5a9a764947..a4b74ab1c0 100644
--- a/src/lib/elementary/efl_ui_list_view.c
+++ b/src/lib/elementary/efl_ui_list_view.c
@@ -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))
{
diff --git a/src/lib/elementary/efl_ui_list_view_seg_array.h b/src/lib/elementary/efl_ui_list_view_seg_array.h
index 2461534cc5..485398d469 100644
--- a/src/lib/elementary/efl_ui_list_view_seg_array.h
+++ b/src/lib/elementary/efl_ui_list_view_seg_array.h
@@ -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;
diff --git a/src/lib/elementary/efl_ui_list_view_types.eot b/src/lib/elementary/efl_ui_list_view_types.eot
index f33bbf5b22..780dc202a6 100644
--- a/src/lib/elementary/efl_ui_list_view_types.eot
+++ b/src/lib/elementary/efl_ui_list_view_types.eot
@@ -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;

--

Loading...