cedric pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=5c9815676b023b9707ee12c117335fb147d47c27

commit 5c9815676b023b9707ee12c117335fb147d47c27
Author: Cedric Bail <[email protected]>
Date:   Wed May 9 20:01:17 2018 -0700

    evas: move the del event to match invalidate and free event to the end of 
the destructor.
---
 src/lib/evas/canvas/efl_canvas_object.eo |   2 +-
 src/lib/evas/canvas/evas_main.c          | 169 ++++++++++++++++++-------------
 src/lib/evas/canvas/evas_object_main.c   | 129 ++++++++++++-----------
 src/lib/evas/canvas/evas_object_smart.c  |   9 +-
 src/lib/evas/include/evas_inline.x       |   9 ++
 5 files changed, 182 insertions(+), 136 deletions(-)

diff --git a/src/lib/evas/canvas/efl_canvas_object.eo 
b/src/lib/evas/canvas/efl_canvas_object.eo
index 1b82911d89..f9b31a1bab 100644
--- a/src/lib/evas/canvas/efl_canvas_object.eo
+++ b/src/lib/evas/canvas/efl_canvas_object.eo
@@ -593,9 +593,9 @@ abstract Efl.Canvas.Object (Efl.Object, Efl.Gfx.Entity, 
Efl.Gfx.Color, Efl.Gfx.S
    }
    implements {
       Efl.Object.constructor;
-      Efl.Object.destructor;
       Efl.Object.finalize;
       Efl.Object.invalidate;
+      Efl.Object.destructor;
       Efl.Object.parent { set; }
       Efl.Object.provider_find;
       Efl.Object.debug_name_override;
diff --git a/src/lib/evas/canvas/evas_main.c b/src/lib/evas/canvas/evas_main.c
index 95aaec1cf2..9cf2dddaa5 100644
--- a/src/lib/evas/canvas/evas_main.c
+++ b/src/lib/evas/canvas/evas_main.c
@@ -283,28 +283,16 @@ evas_free(Evas *eo_e)
 }
 
 EOLIAN static void
-_evas_canvas_efl_object_invalidate(Eo *eo_e, Evas_Public_Data *e EINA_UNUSED)
+_evas_canvas_efl_object_invalidate(Eo *eo_e, Evas_Public_Data *e)
 {
-   evas_sync(eo_e);
-
-   efl_invalidate(efl_super(eo_e, MY_CLASS));
-}
-
-EOLIAN static void
-_evas_canvas_efl_object_destructor(Eo *eo_e, Evas_Public_Data *e)
-{
-   Eina_Rectangle *r;
-   Evas_Coord_Touch_Point *touch_point;
-   Evas_Post_Render_Job *job;
+   Evas_Object_Protected_Data *o;
    Evas_Layer *lay;
-   Efl_Canvas_Output *evo;
-   unsigned int prev_zombie_count = UINT_MAX;
-   int i;
-   Eina_Bool del;
+   Eo *obj;
+   Eina_Array stash = { 0 };
 
-   evas_canvas_async_block(e);
-   evas_render_idle_flush(eo_e);
+   evas_sync(eo_e);
 
+   evas_canvas_async_block(e);
    evas_render_idle_flush(eo_e);
 
    efl_replace(&e->default_seat, NULL);
@@ -314,75 +302,110 @@ _evas_canvas_efl_object_destructor(Eo *eo_e, 
Evas_Public_Data *e)
    _evas_post_event_callback_free(eo_e);
    _evas_canvas_event_shutdown(eo_e, e);
 
-   del = EINA_TRUE;
    e->cleanup = 1;
-   while (del)
+
+   eina_array_step_set(&stash, sizeof (Eina_Array), 16);
+
+   // The first pass should destroy all object that are properly referenced
+   EINA_INLIST_FOREACH(e->layers, lay)
      {
-        Eina_Bool detach_zombies = EINA_FALSE;
-        Evas_Object_Protected_Data *o;
-        Eina_List *unrefs = NULL;
-        Eo *eo_obj;
+        evas_layer_pre_free(lay);
 
-        del = EINA_FALSE;
-        EINA_INLIST_FOREACH(e->layers, lay)
+        EINA_INLIST_FOREACH(lay->objects, o)
           {
-             evas_layer_pre_free(lay);
-
-             EINA_INLIST_FOREACH(lay->objects, o)
-               {
-                  if (!o->delete_me)
-                    {
-                       if ((o->ref > 0) || (efl_ref_count(o->object) > 0))
-                         {
-                            ERR("obj(%s) ref count(%d) is bigger than 0. This "
-                                "object couldn't be deleted",
-                                efl_debug_name_get(o->object),
-                                efl_ref_count(o->object));
-                            continue;
-                         }
-                       unrefs = eina_list_append(unrefs, o->object);
-                       del = EINA_TRUE;
-                    }
-               }
+             if (!o->delete_me)
+               eina_array_push(&stash, o->object);
           }
+     }
 
-        if (eina_list_count(unrefs) >= prev_zombie_count)
-          detach_zombies = EINA_TRUE;
-        prev_zombie_count = eina_list_count(unrefs);
+   while ((obj = eina_array_pop(&stash)))
+     {
+        Evas_Object_Protected_Data *pd = efl_data_scope_get(obj, 
EFL_CANVAS_OBJECT_CLASS);
+
+        // Properly destroy depending on the object being legacy or not
+        if (pd->legacy.ctor) evas_object_del(obj);
+        else efl_del(obj);
+     }
 
-        EINA_LIST_FREE(unrefs, eo_obj)
+   // We are now potentially only facing zombies
+   EINA_INLIST_FOREACH(e->layers, lay)
+     {
+        evas_layer_pre_free(lay);
+        EINA_INLIST_FOREACH(lay->objects, o)
           {
-             ERR("Killing Zombie Object [%s]. Refs: %i:%i",
-                 efl_debug_name_get(eo_obj), efl_ref_count(eo_obj), 
___efl_ref2_count(eo_obj));
-             ___efl_ref2_reset(eo_obj);
-             while (efl_ref_count(eo_obj) > 1) efl_unref(eo_obj);
-             while (efl_ref_count(eo_obj) < 1) efl_ref(eo_obj);
-             efl_del(eo_obj);
-
-             if (!detach_zombies) continue;
-
-             EINA_INLIST_FOREACH(e->layers, lay)
-               EINA_INLIST_FOREACH(lay->objects, o)
-                 if (o && (o->object == eo_obj))
-                   {
-                      ERR("Zombie Object [%s] could not be removed "
-                          "from the list of objects. Maybe this object "
-                          "was deleted but the call to efl_destructor() "
-                          "was not propagated to all the parent classes? "
-                          "Forcibly removing it. This may leak! Refs: %i:%i",
-                          efl_debug_name_get(eo_obj), efl_ref_count(eo_obj), 
___efl_ref2_count(eo_obj));
-                      lay->objects = (Evas_Object_Protected_Data *)
-                            eina_inlist_remove(EINA_INLIST_GET(lay->objects), 
EINA_INLIST_GET(o));
-                      goto next_zombie;
-                   }
-next_zombie:
-             continue;
+             if (!o->delete_me)
+               eina_array_push(&stash, o->object);
           }
      }
+
+   // Killing zombies now
+   while ((obj = eina_array_pop(&stash)))
+     {
+        ERR("Killing Zombie Object [%s]. Refs: %i:%i",
+            efl_debug_name_get(obj), efl_ref_count(obj), 
___efl_ref2_count(obj));
+        ___efl_ref2_reset(obj);
+        // This code explicitely bypass all refcounting to destroy them
+        while (efl_ref_count(obj) > 1) efl_unref(obj);
+        while (efl_ref_count(obj) < 1) efl_ref(obj);
+        efl_del(obj);
+
+        // Forcefully remove the object from layers
+        EINA_INLIST_FOREACH(e->layers, lay)
+          EINA_INLIST_FOREACH(lay->objects, o)
+            if (o && (o->object == obj))
+              {
+                 ERR("Zombie Object [%s] %s@%p could not be removed "
+                     "from the list of objects. Maybe this object "
+                     "was deleted but the call to efl_invalidated() "
+                     "was not propagated to all the parent classes? "
+                     "Forcibly removing it. This may leak! Refs: %i:%i",
+                     efl_debug_name_get(obj), efl_class_name_get(obj), obj,
+                     efl_ref_count(obj), ___efl_ref2_count(obj));
+                 lay->objects = (Evas_Object_Protected_Data *)
+                   eina_inlist_remove(EINA_INLIST_GET(lay->objects), 
EINA_INLIST_GET(o));
+                 goto next_zombie;
+              }
+
+     next_zombie:
+        continue;
+     }
+
+   eina_array_flush(&stash);
+
+   // Destroying layers and their associated objects completely
    EINA_INLIST_FOREACH(e->layers, lay)
      evas_layer_free_objects(lay);
    evas_layer_clean(eo_e);
 
+   efl_invalidate(efl_super(eo_e, MY_CLASS));
+}
+
+EOLIAN static void
+_evas_canvas_efl_object_destructor(Eo *eo_e, Evas_Public_Data *e)
+{
+   Eina_Rectangle *r;
+   Evas_Coord_Touch_Point *touch_point;
+   Evas_Post_Render_Job *job;
+   Evas_Layer *lay;
+   Efl_Canvas_Output *evo;
+   int i;
+
+   if (e->layers)
+     {
+        // This should never happen as during invalidate we explicitely
+        // destroy all layers. If they survive, we have a zombie appocallypse.
+        Evas_Object_Protected_Data *o;
+
+        CRI("The layers of %p are not empty !", eo_e);
+
+        EINA_INLIST_FOREACH(e->layers, lay)
+          EINA_INLIST_FOREACH(lay->objects, o)
+            {
+               CRI("Zombie object [%s] %s@%p still present.",
+                   efl_debug_name_get(o->object), 
efl_class_name_get(o->object), o->object);
+            }
+     }
+
    evas_font_path_clear(eo_e);
 
    if (e->name_hash) eina_hash_free(e->name_hash);
diff --git a/src/lib/evas/canvas/evas_object_main.c 
b/src/lib/evas/canvas/evas_object_main.c
index f63e93372a..cd749de044 100644
--- a/src/lib/evas/canvas/evas_object_main.c
+++ b/src/lib/evas/canvas/evas_object_main.c
@@ -539,7 +539,10 @@ evas_object_cur_prev(Evas_Object_Protected_Data *obj)
 void
 evas_object_free(Evas_Object *eo_obj, Eina_Bool clean_layer)
 {
-   Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, MY_CLASS);
+   Evas_Object_Protected_Data *obj;
+
+   if (!eo_obj) return ;
+   obj = efl_data_scope_get(eo_obj, MY_CLASS);
    if (!obj) return;
    obj->clean_layer = !!clean_layer;
 
@@ -1030,20 +1033,6 @@ _efl_canvas_object_efl_object_parent_set(Eo *obj, 
Evas_Object_Protected_Data *pd
    efl_parent_set(efl_super(obj, MY_CLASS), parent);
 }
 
-EOLIAN static void
-_efl_canvas_object_efl_object_invalidate(Eo *eo_obj, 
Evas_Object_Protected_Data *obj)
-{
-   evas_object_async_block(obj);
-
-   //Unset callbacks for Hide event before hiding
-   evas_object_intercept_hide_callback_del((Eo *)eo_obj,
-                                           _animation_intercept_hide);
-
-   efl_gfx_entity_visible_set((Eo *) eo_obj, EINA_FALSE);
-   obj->efl_del_called = EINA_TRUE;
-   efl_invalidate(efl_super(eo_obj, MY_CLASS));
-}
-
 EAPI void
 evas_object_del(Evas_Object *obj)
 {
@@ -1255,19 +1244,24 @@ 
_efl_canvas_object_efl_object_event_callback_legacy_call(Eo *eo_obj,
 }
 
 EOLIAN static void
-_efl_canvas_object_efl_object_destructor(Eo *eo_obj, 
Evas_Object_Protected_Data *obj)
+_efl_canvas_object_efl_object_invalidate(Eo *eo_obj, 
Evas_Object_Protected_Data *obj)
 {
-   MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ);
-   return;
-   MAGIC_CHECK_END();
-   Evas_Object *proxy;
-   Eina_List *l, *l2;
-   Evas_Canvas3D_Texture *texture;
    Efl_Input_Device *dev;
    Evas_Public_Data *edata;
    Evas_Object_Pointer_Data *pdata;
+   Evas_Object *proxy;
+   Eina_List *l, *l2;
    int event_id;
 
+   evas_object_async_block(obj);
+
+   // Unset callbacks for Hide event before hiding
+   evas_object_intercept_hide_callback_del((Eo *)eo_obj,
+                                           _animation_intercept_hide);
+
+   efl_gfx_entity_visible_set((Eo *) eo_obj, EINA_FALSE);
+   obj->efl_del_called = EINA_TRUE;
+
    edata = efl_data_scope_get(evas_object_evas_get(eo_obj), EVAS_CANVAS_CLASS);
 
    evas_object_hide(eo_obj);
@@ -1295,54 +1289,41 @@ _efl_canvas_object_efl_object_destructor(Eo *eo_obj, 
Evas_Object_Protected_Data
    evas_object_event_callback_call(eo_obj, obj, EVAS_CALLBACK_DEL, NULL, 
event_id, NULL);
    if ((obj->layer) && (obj->layer->evas))
      _evas_post_event_callback_call(obj->layer->evas->evas, obj->layer->evas, 
event_id);
-   if (obj->name) evas_object_name_set(eo_obj, NULL);
+
    if (obj->layer)
      {
         if (obj->layer->evas)
           if (obj->layer->evas->pending_default_focus_obj == eo_obj)
             obj->layer->evas->pending_default_focus_obj = NULL;
      }
-   else
-     {
-        efl_manual_free_set(eo_obj, EINA_FALSE);
-        obj->clean_layer = 1;
-        goto end;
-     }
+
    evas_object_grabs_cleanup(eo_obj, obj);
-   if (obj->clip.clipees)
-     {
-        ERR("object %p still has %d clippees after del callback",
-            eo_obj, eina_list_count(obj->clip.clipees));
-        /* "while" should be used for null check of obj->clip.clipees,
-           because evas_objct_clip_unset can set null to obj->clip.clipees */
-        while (obj->clip.clipees)
-          {
-             Evas_Object_Protected_Data *tmp;
-             tmp = eina_list_data_get(obj->clip.clipees);
-             evas_object_clip_unset(tmp->object);
-          }
-     }
 
    /* FIXME: Proxies should listen to source death */
-   EINA_LIST_FOREACH_SAFE(obj->proxy->proxies, l, l2, proxy)
+   if (obj->proxy)
      {
-        if (efl_isa(proxy, EFL_CANVAS_IMAGE_INTERNAL_CLASS))
-          evas_object_image_source_unset(proxy);
-        if (efl_isa(proxy, EFL_GFX_FILTER_INTERFACE))
-          efl_gfx_filter_source_set(proxy, NULL, eo_obj);
-     }
+        EINA_LIST_FOREACH_SAFE(obj->proxy->proxies, l, l2, proxy)
+          {
+             if (efl_isa(proxy, EFL_CANVAS_IMAGE_INTERNAL_CLASS))
+               evas_object_image_source_unset(proxy);
+             if (efl_isa(proxy, EFL_GFX_FILTER_INTERFACE))
+               efl_gfx_filter_source_set(proxy, NULL, eo_obj);
+          }
 
-   /* Eina_Cow has no way to know if we are going to really change something
-    or not. So before calling the cow, let's check if we want to do something 
*/
-   if (obj->proxy->proxy_textures)
-     {
-        EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, obj->proxy,
-                             Evas_Object_Proxy_Data, proxy_src)
+        /* Eina_Cow has no way to know if we are going to really change 
something
+           or not. So before calling the cow, let's check if we want to do 
something */
+        if (obj->proxy->proxy_textures)
           {
-             EINA_LIST_FREE(proxy_src->proxy_textures, texture)
-               evas_canvas3d_texture_source_set(texture, NULL);
+             EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, obj->proxy,
+                                  Evas_Object_Proxy_Data, proxy_src)
+               {
+                  Evas_Canvas3D_Texture *texture;
+
+                  EINA_LIST_FREE(proxy_src->proxy_textures, texture)
+                    evas_canvas3d_texture_source_set(texture, NULL);
+               }
+             EINA_COW_WRITE_END(evas_object_proxy_cow, obj->proxy, proxy_src);
           }
-        EINA_COW_WRITE_END(evas_object_proxy_cow, obj->proxy, proxy_src);
      }
 
    if (obj->cur->clipper) evas_object_clip_unset(eo_obj);
@@ -1361,7 +1342,40 @@ _efl_canvas_object_efl_object_destructor(Eo *eo_obj, 
Evas_Object_Protected_Data
      }
 
    evas_object_map_set(eo_obj, NULL);
+
    if (obj->is_smart) evas_object_smart_del(eo_obj);
+   evas_object_change(eo_obj, obj);
+
+   efl_invalidate(efl_super(eo_obj, MY_CLASS));
+}
+
+EOLIAN static void
+_efl_canvas_object_efl_object_destructor(Eo *eo_obj, 
Evas_Object_Protected_Data *obj)
+{
+   int event_id;
+
+   if (obj->clip.clipees)
+     {
+        ERR("object %p of type '%s' still has %d clippees after del callback",
+            eo_obj, efl_class_name_get(eo_obj), 
eina_list_count(obj->clip.clipees));
+        /* "while" should be used for null check of obj->clip.clipees,
+           because evas_objct_clip_unset can set null to obj->clip.clipees */
+        while (obj->clip.clipees)
+          {
+             Evas_Object_Protected_Data *tmp;
+             tmp = eina_list_data_get(obj->clip.clipees);
+             evas_object_clip_unset(tmp->object);
+          }
+     }
+
+   if (obj->name) evas_object_name_set(eo_obj, NULL);
+   if (!obj->layer)
+     {
+        efl_manual_free_set(eo_obj, EINA_FALSE);
+        obj->clean_layer = 1;
+        goto end;
+     }
+
    event_id = _evas_object_event_new();
    evas_object_event_callback_call(eo_obj, obj, EVAS_CALLBACK_FREE, NULL, 
event_id, NULL);
    if ((obj->layer) && (obj->layer->evas))
@@ -1376,6 +1390,7 @@ end:
    efl_destructor(efl_super(eo_obj, MY_CLASS));
 }
 
+
 EOLIAN static void
 _efl_canvas_object_efl_gfx_entity_geometry_set(Eo *obj, 
Evas_Object_Protected_Data *pd EINA_UNUSED, Eina_Rect r)
 {
diff --git a/src/lib/evas/canvas/evas_object_smart.c 
b/src/lib/evas/canvas/evas_object_smart.c
index 8b1a5669f2..f76fb9d25c 100644
--- a/src/lib/evas/canvas/evas_object_smart.c
+++ b/src/lib/evas/canvas/evas_object_smart.c
@@ -579,17 +579,16 @@ evas_object_smart_members_get_direct(const Evas_Object 
*eo_obj)
 static void
 _efl_canvas_group_group_members_all_del_internal(Evas_Smart_Data *o)
 {
+   Evas_Object_Smart_Clipped_Data *cso = o->clipped ? o->data : NULL;
    Evas_Object_Protected_Data *memobj;
    Eina_Inlist *itrn;
-   Eo *eo_clipper;
 
-   eo_clipper = _smart_clipper_get(o);
    EINA_INLIST_FOREACH_SAFE(o->contained, itrn, memobj)
      {
-        if (memobj->object != eo_clipper)
-          efl_del(memobj->object);
+        if (memobj->object != cso->clipper)
+          _evas_wrap_del(&memobj->object, memobj);
      }
-   efl_del(eo_clipper);
+   _evas_wrap_del(&cso->clipper, efl_data_scope_get(cso->clipper, 
EFL_CANVAS_OBJECT_CLASS));
    o->group_del_called = EINA_TRUE;
 }
 
diff --git a/src/lib/evas/include/evas_inline.x 
b/src/lib/evas/include/evas_inline.x
index fd00dbe2aa..74ed8bbd01 100644
--- a/src/lib/evas/include/evas_inline.x
+++ b/src/lib/evas/include/evas_inline.x
@@ -355,6 +355,15 @@ _evas_engine_context(Evas_Public_Data *e)
    return e->backend;
 }
 
+static inline void
+_evas_wrap_del(Evas_Object **eo, Evas_Object_Protected_Data *pd)
+{
+   if (!*eo) return ;
+   if (pd->legacy.ctor) evas_object_del(*eo);
+   else efl_del(*eo);
+   *eo = NULL;
+}
+
 #define _EVAS_COLOR_CLAMP(x, y) do { \
    if (x > y) { x = y; bad = 1; } \
    if (x < 0) { x = 0; bad = 1; } } while (0)

-- 


Reply via email to