Eo composite: change composite objects to not be tied to parent

This commit breaks behaviour!
Re-parenting no longer detaches composite objects, so watch out.

Now you can have an object be a composite object of an object although
it's not its child. This allows widgets to do things like having an
object as the child of a child object while still making it a composite
object to the main object.

With this change, composite objects don't keep a reference to the child,
but instead composite "bonds" are implicitly removed when either the
parent or the child are destructed.
This commit is contained in:
Tom Hacohen 2016-05-05 16:08:08 +01:00
parent 9d5caf00b6
commit 537b138a23
3 changed files with 59 additions and 22 deletions

View File

@ -19,6 +19,7 @@ typedef struct
{
const char *id;
const char *comment;
Eo *composite_parent;
Eina_Inlist *generic_data;
Eo ***wrefs;
} Eo_Base_Extension;
@ -82,7 +83,7 @@ _eo_base_extension_noneed(Eo_Base_Data *pd)
{
Eo_Base_Extension *ext = pd->ext;
if ((!ext) || (ext->id) || (ext->comment) || (ext->generic_data) ||
(ext->wrefs)) return;
(ext->wrefs) || (ext->composite_parent)) return;
_eo_base_extension_free(pd->ext);
pd->ext = NULL;
}
@ -478,11 +479,6 @@ _eo_base_parent_set(Eo *obj, Eo_Base_Data *pd, Eo *parent_id)
if (pd->parent == parent_id)
return;
if (eo_composite_part_is(obj) && pd->parent)
{
eo_composite_detach(pd->parent, obj);
}
if (pd->parent)
{
Eo_Base_Data *old_parent_pd;
@ -1236,23 +1232,34 @@ _eo_base_composite_attach(Eo *parent_id, Eo_Base_Data *pd EINA_UNUSED, Eo *comp_
EO_OBJ_POINTER_RETURN_VAL(comp_obj_id, comp_obj, EINA_FALSE);
EO_OBJ_POINTER_RETURN_VAL(parent_id, parent, EINA_FALSE);
if (!eo_isa(parent_id, _eo_class_id_get(comp_obj->klass))) return EINA_FALSE;
if (!eo_isa(parent_id, _eo_class_id_get(comp_obj->klass)))
{
return EINA_FALSE;
}
Eo_Base_Data *comp_pd = eo_data_scope_get(comp_obj_id, EO_BASE_CLASS);
/* Don't composite if we already have a composite object of this type */
{
Eina_List *itr;
Eo *emb_obj_id;
EINA_LIST_FOREACH(parent->composite_objects, itr, emb_obj_id)
{
EO_OBJ_POINTER_RETURN_VAL(emb_obj_id, emb_obj, EINA_FALSE);
if(emb_obj->klass == comp_obj->klass)
if (emb_obj->klass == comp_obj->klass)
return EINA_FALSE;
}
}
comp_obj->composite = EINA_TRUE;
parent->composite_objects = eina_list_prepend(parent->composite_objects, comp_obj_id);
if (eo_composite_part_is(comp_obj_id))
{
eo_composite_detach(comp_pd->ext->composite_parent, comp_obj_id);
}
eo_parent_set(comp_obj_id, parent_id);
/* Set the parent comp on the child. */
_eo_base_extension_need(comp_pd);
comp_pd->ext->composite_parent = parent_id;
parent->composite_objects = eina_list_prepend(parent->composite_objects, comp_obj_id);
return EINA_TRUE;
}
@ -1263,22 +1270,25 @@ _eo_base_composite_detach(Eo *parent_id, Eo_Base_Data *pd EINA_UNUSED, Eo *comp_
EO_OBJ_POINTER_RETURN_VAL(comp_obj_id, comp_obj, EINA_FALSE);
EO_OBJ_POINTER_RETURN_VAL(parent_id, parent, EINA_FALSE);
if (!comp_obj->composite)
if (!eo_composite_part_is(comp_obj_id))
return EINA_FALSE;
comp_obj->composite = EINA_FALSE;
parent->composite_objects = eina_list_remove(parent->composite_objects, comp_obj_id);
eo_parent_set(comp_obj_id, NULL);
/* Clear the comp parent on the child. */
{
Eo_Base_Data *comp_pd = eo_data_scope_get(comp_obj_id, EO_BASE_CLASS);
comp_pd->ext->composite_parent = NULL;
_eo_base_extension_noneed(comp_pd);
}
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_eo_base_composite_part_is(Eo *comp_obj_id, Eo_Base_Data *pd EINA_UNUSED)
_eo_base_composite_part_is(Eo *comp_obj_id EINA_UNUSED, Eo_Base_Data *pd)
{
EO_OBJ_POINTER_RETURN_VAL(comp_obj_id, comp_obj, EINA_FALSE);
return comp_obj->composite;
return pd->ext && pd->ext->composite_parent;
}
/* Eo_Dbg */
@ -1408,6 +1418,22 @@ _eo_base_destructor(Eo *obj, Eo_Base_Data *pd)
eo_parent_set(child, NULL);
}
/* If we are a composite object, detach children */
{
EO_OBJ_POINTER_RETURN(obj, obj_data);
Eina_List *itr;
Eo *emb_obj_id;
EINA_LIST_FOREACH(obj_data->composite_objects, itr, emb_obj_id)
{
eo_composite_detach(obj, emb_obj_id);
}
}
if (pd->ext && pd->ext->composite_parent)
{
eo_composite_detach(pd->ext->composite_parent, obj);
}
if (pd->parent)
{
ERR("Object '%p' still has a parent at the time of destruction.", obj);

View File

@ -103,7 +103,6 @@ struct _Eo_Object
Eina_Bool condtor_done:1;
Eina_Bool finalized:1;
Eina_Bool composite:1;
Eina_Bool del_triggered:1;
Eina_Bool destructed:1;
Eina_Bool manual_free:1;

View File

@ -299,12 +299,24 @@ START_TEST(eo_composite_tests)
fail_if(!obj);
Eo *obj2 = eo_add(SIMPLE_CLASS, NULL);
fail_if(!obj2);
Eo *obj3 = eo_add(SIMPLE_CLASS, NULL);
fail_if(!obj3);
eo_composite_attach(obj, obj2);
eo_parent_set(obj2, NULL);
fail_if(eo_composite_part_is(obj2));
fail_if(!eo_composite_part_is(obj2));
/* Check swapping attachments works. */
eo_composite_attach(obj3, obj2);
fail_if(!eo_composite_part_is(obj2));
/* Check that a deletion of a child detaches from the parent. */
eo_del(obj2);
fail_if(!eo_composite_attach(obj3, obj));
/* Check that a deletion of the parent detaches the child. */
eo_del(obj3);
fail_if(eo_composite_part_is(obj));
eo_unref(obj2);
eo_unref(obj);
eo_shutdown();