efl: simplify logic for widget created by factory.
authorCedric Bail <cedric.bail@free.fr>
Mon, 16 Sep 2019 03:50:05 +0000 (20:50 -0700)
committerJongmin Lee <jm105.lee@samsung.com>
Tue, 24 Sep 2019 21:47:13 +0000 (06:47 +0900)
In an attempt to make things more complex than they should have been,
I tried to change the inheritance tree on the fly and assume widget would
rely on autodeleting its children. This is way more complex of a solution
than to let the View actually release all the child manually and just set
the window as the default parent.h

Co-authored-by: Marcel Hollerbach <mail@marcel-hollerbach.de>
Reviewed-by: Marcel Hollerbach <mail@marcel-hollerbach.de>
Differential Revision: https://phab.enlightenment.org/D9953

12 files changed:
src/examples/elementary/layout_property_bind.c
src/lib/efl/interfaces/efl_interfaces_main.c
src/lib/efl/interfaces/efl_ui_factory.eo
src/lib/efl/interfaces/efl_ui_view_factory.eo
src/lib/elementary/efl_ui_caching_factory.c
src/lib/elementary/efl_ui_caching_factory.eo
src/lib/elementary/efl_ui_image_factory.c
src/lib/elementary/efl_ui_layout.c
src/lib/elementary/efl_ui_list_view.c
src/lib/elementary/efl_ui_widget_factory.c
src/lib/elementary/efl_ui_widget_factory.eo
src/lib/elementary/elm_priv.h

index da4c5e6..f9c5cf9 100644 (file)
@@ -169,7 +169,7 @@ elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
    efl_ui_property_bind(img_factory, "", "path"); //connect to "path" property
    efl_ui_factory_bind(priv->bt, "icon", img_factory);
 
-   efl_future_then(win, efl_ui_view_factory_create_with_event(img_factory, NULL, bxr),
+   efl_future_then(win, efl_ui_view_factory_create_with_event(img_factory, NULL),
                    .success = _wait_for_image,
                    .data = priv);
 
index 4f144be..91b7ff1 100644 (file)
@@ -127,10 +127,11 @@ _efl_ui_view_factory_item_created(Eo *factory, void *data EINA_UNUSED, const Ein
    return v;
 }
 
-static Eina_Future *
-_efl_ui_view_factory_create_with_event(Efl_Ui_Factory *factory, Eina_Iterator *models, Efl_Gfx_Entity *parent)
+EOLIAN static Eina_Future *
+_efl_ui_view_factory_create_with_event(Efl_Ui_Factory *factory, Eina_Iterator *models)
 {
-   return efl_future_then(factory, efl_ui_factory_create(factory, models, parent),
+   EINA_SAFETY_ON_NULL_RETURN_VAL(factory, NULL);
+   return efl_future_then(factory, efl_ui_factory_create(factory, models),
                           .success_type = EINA_VALUE_TYPE_ARRAY,
                           .success = _efl_ui_view_factory_item_created);
 }
index bd3d84f..7eda0c6 100644 (file)
@@ -23,7 +23,6 @@ interface @beta Efl.Ui.Factory extends Efl.Ui.Property_Bind, Efl.Ui.Factory_Bind
          params {
             models: iterator<Efl.Model>; [[Efl iterator providing the model to be associated to the new item.
                                            It should remain valid until the end of the function call.]]
-            parent: Efl.Gfx.Entity; [[Efl canvas.]]
          }
          return: future<Efl.Gfx.Entity>; [[Created UI object.]]
       }
index bb1e4a4..728c259 100644 (file)
@@ -12,7 +12,6 @@ class @beta Efl.Ui.View_Factory
                                  event onto.]]
             models: iterator<Efl.Model>; [[Efl iterator providing the model to be associated to the new item. It should
                                      remain valid until the end of the function call.]]
-            parent: Efl.Gfx.Entity; [[Efl canvas]]
          }
          return: future<Efl.Gfx.Entity>; [[Created UI object]]
       }
index 843871e..3035c30 100644 (file)
@@ -125,7 +125,7 @@ _efl_ui_caching_factory_create_then(Eo *model, void *data, const Eina_Value v)
         // This is not ideal, we would want to gather all the request in one swoop here,
         // left for later improvement.
         f = efl_ui_factory_create(efl_super(r->factory, EFL_UI_CACHING_FACTORY_CLASS),
-                                  EINA_C_ARRAY_ITERATOR_NEW(models), r->parent);
+                                  EINA_C_ARRAY_ITERATOR_NEW(models));
         f = efl_future_then(r->factory, f,
                             .success = _efl_ui_caching_factory_uncap_then,
                             .success_type = EINA_VALUE_TYPE_ARRAY);
@@ -135,7 +135,6 @@ _efl_ui_caching_factory_create_then(Eo *model, void *data, const Eina_Value v)
    eina_hash_del(r->pd->lookup, style, w);
    _efl_ui_caching_factory_remove(r->pd, eina_list_data_find(r->pd->cache, w), w);
 
-   efl_parent_set(w, r->parent);
    efl_ui_view_model_set(w, model);
 
    return eina_value_object_init(w);
@@ -178,7 +177,7 @@ _efl_ui_caching_factory_group_cleanup(Eo *o EINA_UNUSED, void *data, const Eina_
 static Eina_Future *
 _efl_ui_caching_factory_efl_ui_factory_create(Eo *obj,
                                               Efl_Ui_Caching_Factory_Data *pd,
-                                              Eina_Iterator *models, Efl_Gfx_Entity *parent)
+                                              Eina_Iterator *models)
 {
    Efl_Ui_Caching_Factory_Request *r;
    Efl_Ui_Caching_Factory_Group_Request *gr;
@@ -195,7 +194,6 @@ _efl_ui_caching_factory_efl_ui_factory_create(Eo *obj,
         if (!r) return efl_loop_future_rejected(obj, ENOMEM);
 
         r->pd = pd;
-        r->parent = efl_ref(parent);
         r->factory = efl_ref(obj);
 
         all = calloc(1, sizeof (Eina_Future *));
@@ -231,7 +229,6 @@ _efl_ui_caching_factory_efl_ui_factory_create(Eo *obj,
        {
           w = eina_list_data_get(pd->cache);
           _efl_ui_caching_factory_remove(pd, pd->cache, w);
-          efl_parent_set(w, parent);
 
           efl_ui_view_model_set(w, model);
 
@@ -243,9 +240,11 @@ _efl_ui_caching_factory_efl_ui_factory_create(Eo *obj,
    // Now create object on the fly that are missing from the cache
    if (pd->klass)
      {
+        Efl_Ui_Widget *widget = efl_ui_widget_factory_widget_get(obj);
+
         EINA_ITERATOR_FOREACH(models, model)
           {
-             w = efl_add(pd->klass, parent,
+             w = efl_add(pd->klass, widget,
                          efl_ui_view_model_set(efl_added, model),
                          efl_event_callback_call(obj, EFL_UI_FACTORY_EVENT_ITEM_CONSTRUCTING, efl_added));
              efl_event_callback_call(obj, EFL_UI_FACTORY_EVENT_ITEM_BUILDING, w);
@@ -260,8 +259,7 @@ _efl_ui_caching_factory_efl_ui_factory_create(Eo *obj,
         return f;
      }
 
-   f = efl_ui_factory_create(efl_super(obj, EFL_UI_CACHING_FACTORY_CLASS),
-                             models, parent);
+   f = efl_ui_factory_create(efl_super(obj, EFL_UI_CACHING_FACTORY_CLASS), models);
    return efl_future_then(obj, f,
                           .success = _efl_ui_caching_factory_group_create_then,
                           .success_type = EINA_VALUE_TYPE_ARRAY,
@@ -357,7 +355,6 @@ _efl_ui_caching_factory_efl_ui_factory_release(Eo *obj,
      }
 
    // Change parent, disconnect the object and make it invisible
-   efl_parent_set(ui_view, obj);
    efl_gfx_entity_visible_set(ui_view, EINA_FALSE);
    efl_ui_view_model_set(ui_view, NULL);
 
@@ -380,29 +377,6 @@ _efl_ui_caching_factory_efl_ui_factory_release(Eo *obj,
 }
 
 static void
-_efl_ui_caching_factory_efl_object_invalidate(Eo *obj EINA_UNUSED,
-                                              Efl_Ui_Caching_Factory_Data *pd)
-{
-   // 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);
-   eina_hash_free(pd->lookup);
-   pd->lookup = NULL;
-   pd->invalidated = EINA_TRUE;
-}
-
-static Efl_App *
-_efl_ui_caching_factory_app_get(Eo *obj)
-{
-   Efl_Object *p;
-
-   p = efl_parent_get(obj);
-   if (!p) return NULL;
-
-   // It is acceptable to just have a loop as parent and not an app
-   return efl_provider_find(obj, EFL_APP_CLASS);
-}
-
-static void
 _efl_ui_caching_factory_pause(void *data, const Efl_Event *event EINA_UNUSED)
 {
    Efl_Ui_Caching_Factory_Data *pd = data;
@@ -418,18 +392,42 @@ _efl_ui_caching_factory_pause(void *data, const Efl_Event *event EINA_UNUSED)
 }
 
 static void
-_efl_ui_caching_factory_efl_object_parent_set(Eo *obj, Efl_Ui_Caching_Factory_Data *pd, Efl_Object *parent)
+_invalidate(void *data, const Efl_Event *event EINA_UNUSED)
 {
-   Efl_App *a;
+   Efl_Ui_Caching_Factory_Data *pd = data;
 
-   a = _efl_ui_caching_factory_app_get(obj);
-   if (a) efl_event_callback_del(a, EFL_APP_EVENT_PAUSE, _efl_ui_caching_factory_pause, pd);
+   // 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);
+   eina_hash_free(pd->lookup);
+   pd->lookup = NULL;
+   pd->invalidated = EINA_TRUE;
+}
+
+static Efl_Object *
+_efl_ui_caching_factory_efl_object_finalize(Eo *obj, Efl_Ui_Caching_Factory_Data *pd)
+{
+   Efl_App *a;
 
-   efl_parent_set(efl_super(obj, EFL_UI_CACHING_FACTORY_CLASS), parent);
+   obj = efl_finalize(efl_super(obj, EFL_UI_CACHING_FACTORY_CLASS));
+   if (!obj) return NULL;
 
-   // We are fetching the parent again, just in case the update was denied
-   a = _efl_ui_caching_factory_app_get(obj);
+   a = efl_provider_find(obj, EFL_APP_CLASS);
    if (a) efl_event_callback_add(a, EFL_APP_EVENT_PAUSE, _efl_ui_caching_factory_pause, pd);
+
+   // The order of the invalidate event is guaranteed to happen before any children is invalidated
+   // this is not the case for the children invalidate function, which can happen in random order.
+   efl_event_callback_add(efl_ui_widget_factory_widget_get(obj), EFL_EVENT_INVALIDATE, _invalidate, pd);
+
+   return obj;
+}
+
+static void
+_efl_ui_caching_factory_efl_object_invalidate(Eo *obj,
+                                              Efl_Ui_Caching_Factory_Data *pd)
+{
+   efl_event_callback_del(efl_ui_widget_factory_widget_get(obj), EFL_EVENT_INVALIDATE, _invalidate, pd);
+
+   efl_invalidate(efl_super(obj, EFL_UI_CACHING_FACTORY_CLASS));
 }
 
 static Eina_Error
index f0a5aae..9907da7 100644 (file)
@@ -41,6 +41,6 @@ class @beta Efl.Ui.Caching_Factory extends Efl.Ui.Widget_Factory
       Efl.Ui.Property_Bind.property_bind;
       Efl.Ui.Widget_Factory.item_class { get; set; }
       Efl.Object.invalidate;
-      Efl.Object.parent { set; }
+      Efl.Object.finalize;
    }
 }
index 615f202..f803404 100644 (file)
@@ -47,13 +47,11 @@ _efl_ui_image_factory_efl_object_destructor(Eo *obj EINA_UNUSED, Efl_Ui_Image_Fa
 }
 
 EOLIAN static Eina_Future *
-_efl_ui_image_factory_efl_ui_factory_create(Eo *obj, Efl_Ui_Image_Factory_Data *pd,
-                                            Eina_Iterator *models, Efl_Gfx_Entity *parent)
+_efl_ui_image_factory_efl_ui_factory_create(Eo *obj, Efl_Ui_Image_Factory_Data *pd, Eina_Iterator *models)
 {
-   if (!parent) return efl_loop_future_rejected(obj, EFL_FACTORY_ERROR_NOT_SUPPORTED);
    if (!pd->property) return efl_loop_future_rejected(obj, EFL_FACTORY_ERROR_NOT_SUPPORTED);
 
-   return efl_ui_factory_create(efl_super(obj, EFL_UI_IMAGE_FACTORY_CLASS), models, parent);
+   return efl_ui_factory_create(efl_super(obj, EFL_UI_IMAGE_FACTORY_CLASS), models);
 }
 
 EOLIAN static Eina_Error
index e586ce6..ee31fed 100644 (file)
@@ -2447,9 +2447,7 @@ _efl_ui_layout_view_model_content_update(Efl_Ui_Layout_Data *pd, Efl_Ui_Layout_F
    request->tracking = tracking;
 
    models[0] = efl_ui_view_model_get(pd->obj);
-   f = efl_ui_view_factory_create_with_event(tracking->factory,
-                                             EINA_C_ARRAY_ITERATOR_NEW(models),
-                                             pd->obj);
+   f = efl_ui_view_factory_create_with_event(tracking->factory, EINA_C_ARRAY_ITERATOR_NEW(models));
    f = efl_future_then(pd->obj, f,
                        .success = _content_created,
                        .success_type = EINA_VALUE_TYPE_ARRAY,
index 399303c..a321ea4 100644 (file)
@@ -967,9 +967,7 @@ _efl_ui_list_view_efl_ui_list_view_model_realize(Eo *obj, Efl_Ui_List_View_Data
    tracking->pd = pd;
    childrens[0] = item->children;
 
-   item->layout_request = efl_ui_view_factory_create_with_event(pd->factory,
-                                                                EINA_C_ARRAY_ITERATOR_NEW(childrens),
-                                                                obj);
+   item->layout_request = efl_ui_view_factory_create_with_event(pd->factory, EINA_C_ARRAY_ITERATOR_NEW(childrens));
    item->layout_request = efl_future_then(obj, item->layout_request,
                                           .success = _content_created,
                                           .success_type = EINA_VALUE_TYPE_ARRAY,
index 0d6f641..a485edf 100644 (file)
@@ -32,6 +32,8 @@ struct _Efl_Ui_Widget_Factory_Data
 {
    const Efl_Class *klass;
 
+   Efl_Ui_Widget *parenting_widget;
+
    Eina_Hash *parts;
 
    Eina_Stringshare *style;
@@ -41,9 +43,25 @@ struct _Efl_Ui_Widget_Factory_Request
 {
    Efl_Ui_Widget_Factory_Data *pd;
    Efl_Ui_Factory *factory;
-   Eo *parent;
 };
 
+static Efl_Object *
+_efl_ui_widget_factory_efl_object_finalize(Eo *obj, Efl_Ui_Widget_Factory_Data *pd)
+{
+   pd->parenting_widget = efl_provider_find(obj, EFL_UI_WIDGET_CLASS);
+   if (!pd->parenting_widget) return NULL;
+
+   return efl_finalize(efl_super(obj, EFL_UI_WIDGET_FACTORY_CLASS));
+}
+
+Efl_Ui_Win *
+efl_ui_widget_factory_widget_get(Efl_Ui_Widget_Factory *factory)
+{
+   Efl_Ui_Widget_Factory_Data *pd = efl_data_scope_get(factory, EFL_UI_WIDGET_FACTORY_CLASS);
+
+   return pd->parenting_widget;
+}
+
 static void
 _efl_ui_widget_factory_item_class_set(Eo *obj, Efl_Ui_Widget_Factory_Data *pd,
                                       const Efl_Class *klass)
@@ -151,7 +169,8 @@ _efl_ui_widget_factory_efl_object_constructor(Efl_Ui_Widget_Factory *obj,
 
 static Efl_Ui_Widget *
 _efl_ui_widget_create(const Efl_Ui_Factory *factory,
-                      const Efl_Class *klass, Eo *parent,
+                      const Efl_Class *klass,
+                      Efl_Ui_Widget *parent,
                       Efl_Model *model)
 {
    Efl_Ui_Widget *w;
@@ -169,7 +188,7 @@ _efl_ui_widget_factory_create_then(Eo *model, void *data, const Eina_Value v EIN
    Efl_Ui_Widget_Factory_Request *r = data;
    Efl_Ui_Widget *w;
 
-   w = _efl_ui_widget_create(r->factory, r->pd->klass, r->parent, model);
+   w = _efl_ui_widget_create(r->factory, r->pd->klass, r->pd->parenting_widget, model);
    if (!w) return eina_value_error_init(ENOMEM);
    return eina_value_object_init(w);
 }
@@ -186,13 +205,12 @@ _efl_ui_widget_factory_create_cleanup(Eo *o EINA_UNUSED, void *data, const Eina_
    Efl_Ui_Widget_Factory_Request *r = data;
 
    efl_unref(r->factory);
-   efl_unref(r->parent);
    free(r);
 }
 
 static Eina_Future *
 _efl_ui_widget_factory_efl_ui_factory_create(Eo *obj, Efl_Ui_Widget_Factory_Data *pd,
-                                             Eina_Iterator *models, Efl_Gfx_Entity *parent)
+                                             Eina_Iterator *models)
 {
    Efl_Ui_Widget_Factory_Request *r;
    Eina_Future **f;
@@ -211,7 +229,7 @@ _efl_ui_widget_factory_efl_ui_factory_create(Eo *obj, Efl_Ui_Widget_Factory_Data
 
         EINA_ITERATOR_FOREACH(models, model)
           {
-             w = _efl_ui_widget_create(obj, pd->klass, parent, model);
+             w = _efl_ui_widget_create(obj, pd->klass, pd->parenting_widget, model);
 
              if (!w) return efl_loop_future_rejected(obj, ENOMEM);
              eina_value_array_append(&r, w);
@@ -225,7 +243,6 @@ _efl_ui_widget_factory_efl_ui_factory_create(Eo *obj, Efl_Ui_Widget_Factory_Data
    if (!r) return efl_loop_future_rejected(obj, ENOMEM);
 
    r->pd = pd;
-   r->parent = efl_ref(parent);
    r->factory = efl_ref(obj);
 
    f = calloc(count + 1, sizeof (Eina_Future *));
@@ -249,7 +266,6 @@ _efl_ui_widget_factory_efl_ui_factory_create(Eo *obj, Efl_Ui_Widget_Factory_Data
                           .free = _efl_ui_widget_factory_create_cleanup);
 
 alloc_array_error:
-   efl_unref(r->parent);
    efl_unref(r->factory);
    free(r);
    eina_iterator_free(models);
index c00775a..82ce729 100644 (file)
@@ -22,6 +22,7 @@ class @beta Efl.Ui.Widget_Factory extends Efl.Loop_Consumer implements Efl.Ui.Fa
       Efl.Ui.Factory.release;
       Efl.Ui.Property_Bind.property_bind;
       Efl.Part.part_get;
+      Efl.Object.finalize;
    }
    constructors {
       .item_class @optional;
index ff856d2..f6e84d0 100644 (file)
@@ -923,6 +923,8 @@ extern const char SIG_LAYOUT_UNFOCUSED[];
 
 extern Eina_Stringshare *_property_style_ss;
 
+Efl_Ui_Win *efl_ui_widget_factory_widget_get(Efl_Ui_Widget_Factory *factory);
+
 extern Eina_Bool _config_profile_lock;
 
 extern Eina_FreeQ *postponed_fq;