forked from enlightenment/efl
eo: Add "destruct" event
Triggered after (almost) complete destruction of the object. Not called "deleted" because the other event is already "del". I don't like "destruct" much but this follows the terminology of "constructor" / "destructor". @feature
This commit is contained in:
parent
63bbf0f3e5
commit
f285fd5925
|
@ -288,6 +288,9 @@ abstract Efl.Object ()
|
||||||
callback,add @hot; [[A callback was added.]]
|
callback,add @hot; [[A callback was added.]]
|
||||||
callback,del @hot; [[A callback was deleted.]]
|
callback,del @hot; [[A callback was deleted.]]
|
||||||
del @hot; [[Object is being deleted.]]
|
del @hot; [[Object is being deleted.]]
|
||||||
|
destruct @hot; [[Object has been fully destroyed. It can not be used
|
||||||
|
beyond this point. This event should only serve to clean up any
|
||||||
|
dangling pointer.]]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ typedef struct
|
||||||
Eina_Bool need_cleaning : 1;
|
Eina_Bool need_cleaning : 1;
|
||||||
Eina_Bool parent_sunk : 1; // If parent ref has already been settled (parent has been set, or we are in add_ref mode
|
Eina_Bool parent_sunk : 1; // If parent ref has already been settled (parent has been set, or we are in add_ref mode
|
||||||
Eina_Bool allow_parent_unref : 1; // Allows unref to zero even with a parent
|
Eina_Bool allow_parent_unref : 1; // Allows unref to zero even with a parent
|
||||||
|
Eina_Bool has_destroyed_event_cb : 1; // No proper count: minor optimization triggered at destruction only
|
||||||
} Efl_Object_Data;
|
} Efl_Object_Data;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
@ -146,10 +147,12 @@ _eo_generic_data_node_free(Eo_Generic_Data_Node *node)
|
||||||
case DATA_PTR:
|
case DATA_PTR:
|
||||||
break;
|
break;
|
||||||
case DATA_OBJ:
|
case DATA_OBJ:
|
||||||
|
// FIXME: should this use "destruct" event instead?
|
||||||
efl_event_callback_del(node->d.obj, EFL_EVENT_DEL, _key_generic_cb_del, node);
|
efl_event_callback_del(node->d.obj, EFL_EVENT_DEL, _key_generic_cb_del, node);
|
||||||
efl_unref(node->d.obj);
|
efl_unref(node->d.obj);
|
||||||
break;
|
break;
|
||||||
case DATA_OBJ_WEAK:
|
case DATA_OBJ_WEAK:
|
||||||
|
// FIXME: should this use "destruct" event instead?
|
||||||
efl_event_callback_del(node->d.obj, EFL_EVENT_DEL, _key_generic_cb_del, node);
|
efl_event_callback_del(node->d.obj, EFL_EVENT_DEL, _key_generic_cb_del, node);
|
||||||
break;
|
break;
|
||||||
case DATA_VAL:
|
case DATA_VAL:
|
||||||
|
@ -1068,6 +1071,8 @@ _special_event_count_inc(Efl_Object_Data *pd, const Efl_Callback_Array_Item *it)
|
||||||
CB_COUNT_INC(pd->event_cb_efl_event_callback_del_count);
|
CB_COUNT_INC(pd->event_cb_efl_event_callback_del_count);
|
||||||
else if (it->desc == EFL_EVENT_DEL)
|
else if (it->desc == EFL_EVENT_DEL)
|
||||||
CB_COUNT_INC(pd->event_cb_efl_event_del_count);
|
CB_COUNT_INC(pd->event_cb_efl_event_del_count);
|
||||||
|
else if (it->desc == EFL_EVENT_DESTRUCT)
|
||||||
|
pd->has_destroyed_event_cb = EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -1126,6 +1131,7 @@ _eo_callback_remove_all(Efl_Object_Data *pd)
|
||||||
eina_freeq_ptr_main_add(pd->callbacks, free, 0);
|
eina_freeq_ptr_main_add(pd->callbacks, free, 0);
|
||||||
pd->callbacks = NULL;
|
pd->callbacks = NULL;
|
||||||
pd->callbacks_count = 0;
|
pd->callbacks_count = 0;
|
||||||
|
pd->has_destroyed_event_cb = EINA_FALSE;
|
||||||
#ifdef EFL_EVENT_SPECIAL_SKIP
|
#ifdef EFL_EVENT_SPECIAL_SKIP
|
||||||
pd->event_cb_efl_event_callback_add_count = 0;
|
pd->event_cb_efl_event_callback_add_count = 0;
|
||||||
pd->event_cb_efl_event_callback_del_count = 0;
|
pd->event_cb_efl_event_callback_del_count = 0;
|
||||||
|
@ -1284,6 +1290,8 @@ _efl_object_event_callback_priority_add(Eo *obj, Efl_Object_Data *pd,
|
||||||
#ifdef EFL_EVENT_SPECIAL_SKIP
|
#ifdef EFL_EVENT_SPECIAL_SKIP
|
||||||
_special_event_count_inc(pd, &(cb->items.item));
|
_special_event_count_inc(pd, &(cb->items.item));
|
||||||
#endif
|
#endif
|
||||||
|
if (EINA_UNLIKELY(desc == EFL_EVENT_DESTRUCT))
|
||||||
|
pd->has_destroyed_event_cb = EINA_TRUE;
|
||||||
|
|
||||||
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, (void *)arr);
|
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, (void *)arr);
|
||||||
|
|
||||||
|
@ -1389,6 +1397,16 @@ _efl_object_event_callback_array_priority_add(Eo *obj, Efl_Object_Data *pd,
|
||||||
#ifdef EFL_EVENT_SPECIAL_SKIP
|
#ifdef EFL_EVENT_SPECIAL_SKIP
|
||||||
for (it = cb->items.item_array; it->func; it++)
|
for (it = cb->items.item_array; it->func; it++)
|
||||||
_special_event_count_inc(pd, it);
|
_special_event_count_inc(pd, it);
|
||||||
|
#else
|
||||||
|
if (!pd->has_destroyed_event_cb)
|
||||||
|
{
|
||||||
|
for (it = cb->items.item_array; it->func; it++)
|
||||||
|
if (it->desc == EFL_EVENT_DESTRUCT)
|
||||||
|
{
|
||||||
|
pd->has_destroyed_event_cb = EINA_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, (void *)array);
|
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, (void *)array);
|
||||||
|
@ -2044,8 +2062,16 @@ composite_obj_back:
|
||||||
err_parent_back:
|
err_parent_back:
|
||||||
|
|
||||||
_efl_pending_futures_clear(pd);
|
_efl_pending_futures_clear(pd);
|
||||||
_eo_generic_data_del_all(obj, pd);
|
|
||||||
_wref_destruct(pd);
|
_wref_destruct(pd);
|
||||||
|
|
||||||
|
// this isn't 100% correct, as the object is still "slightly" alive at this
|
||||||
|
// point (so efl_destructed_is() returns false), but triggering the
|
||||||
|
// "destruct" event here is the simplest, safest solution.
|
||||||
|
if (EINA_UNLIKELY(pd->has_destroyed_event_cb))
|
||||||
|
_event_callback_call(obj, pd, EFL_EVENT_DESTRUCT, NULL, EINA_FALSE);
|
||||||
|
|
||||||
|
// remove generic data after this final event, in case they are used in a cb
|
||||||
|
_eo_generic_data_del_all(obj, pd);
|
||||||
_eo_callback_remove_all(pd);
|
_eo_callback_remove_all(pd);
|
||||||
|
|
||||||
ext = pd->ext;
|
ext = pd->ext;
|
||||||
|
|
|
@ -1719,6 +1719,44 @@ START_TEST(efl_cast_test)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
static void _destruct_test_del_cb(void *data, const Efl_Event *ev EINA_UNUSED)
|
||||||
|
{
|
||||||
|
int *var = data;
|
||||||
|
*var = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destruct_test_destruct_cb(void *data, const Efl_Event *ev)
|
||||||
|
{
|
||||||
|
int *var = data;
|
||||||
|
*var *= 2;
|
||||||
|
|
||||||
|
ck_assert_int_eq(efl_ref_count(ev->object), 0);
|
||||||
|
|
||||||
|
// test disabled: object isn't yet marked as destructed (we're inside the
|
||||||
|
// base class destructor here).
|
||||||
|
//ck_assert_int_ne(efl_destructed_is(ev->object), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST(efl_object_destruct_test)
|
||||||
|
{
|
||||||
|
int var = 0;
|
||||||
|
Eo *obj;
|
||||||
|
|
||||||
|
efl_object_init();
|
||||||
|
|
||||||
|
obj = efl_add(SIMPLE_CLASS, NULL);
|
||||||
|
fail_if(efl_ref_count(obj) != 1);
|
||||||
|
efl_event_callback_add(obj, EFL_EVENT_DEL, _destruct_test_del_cb, &var);
|
||||||
|
efl_event_callback_add(obj, EFL_EVENT_DESTRUCT, _destruct_test_destruct_cb, &var);
|
||||||
|
efl_del(obj);
|
||||||
|
|
||||||
|
// var should be 2 if del then destruct, 0 otherwise
|
||||||
|
ck_assert_int_eq(var, 2);
|
||||||
|
|
||||||
|
efl_object_shutdown();
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_auto_unref_del_cb(void *data, const Efl_Event *ev EINA_UNUSED)
|
_auto_unref_del_cb(void *data, const Efl_Event *ev EINA_UNUSED)
|
||||||
{
|
{
|
||||||
|
@ -1797,5 +1835,6 @@ void eo_test_general(TCase *tc)
|
||||||
tcase_add_test(tc, eo_rec_interface);
|
tcase_add_test(tc, eo_rec_interface);
|
||||||
tcase_add_test(tc, eo_domain);
|
tcase_add_test(tc, eo_domain);
|
||||||
tcase_add_test(tc, efl_cast_test);
|
tcase_add_test(tc, efl_cast_test);
|
||||||
|
tcase_add_test(tc, efl_object_destruct_test);
|
||||||
tcase_add_test(tc, efl_object_auto_unref_test);
|
tcase_add_test(tc, efl_object_auto_unref_test);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue