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) --
