eo: trigger invalidate and noref event before any modification is commited on the...
authorCedric Bail <cedric@osg.samsung.com>
Tue, 3 Apr 2018 00:18:46 +0000 (17:18 -0700)
committerWonki Kim <wonki_.kim@samsung.com>
Tue, 10 Apr 2018 13:22:45 +0000 (22:22 +0900)
src/lib/eo/eo.c
src/lib/eo/eo_base_class.c

index 0fb5891..479938a 100644 (file)
@@ -1882,6 +1882,14 @@ efl_unref(const Eo *obj_id)
 {
    EO_OBJ_POINTER_RETURN(obj_id, obj);
 
+   if (EINA_UNLIKELY(obj->user_refcount == 1))
+     {
+        // The noref event should happen before any object in the
+        // tree get affected by the change in refcount.
+        efl_event_callback_call((Eo *) obj_id, EFL_EVENT_NOREF, NULL);
+        efl_noref((Eo *) obj_id);
+     }
+
    --(obj->user_refcount);
 #ifdef EO_DEBUG
    _eo_log_obj_ref_op(obj, EO_REF_OP_UNREF);
@@ -1896,7 +1904,6 @@ efl_unref(const Eo *obj_id)
              EO_OBJ_DONE(obj_id);
              return;
           }
-        efl_noref((Eo *) obj_id);
         _efl_unref(obj);
      }
    EO_OBJ_DONE(obj_id);
index 4dfde15..fefc106 100644 (file)
@@ -110,6 +110,43 @@ typedef struct
 
 static int _eo_nostep_alloc = -1;
 
+static void
+_efl_pending_futures_clear(Efl_Object_Data *pd)
+{
+   while (pd->pending_futures)
+     {
+        Efl_Future_Pending *pending = EINA_INLIST_CONTAINER_GET(pd->pending_futures, Efl_Future_Pending);
+        Eina_Future *future = *pending->desc.storage;
+        assert(future);
+        eina_future_cancel(future);
+     }
+}
+
+// Generate the invalidate event in all case and make sure it happens
+// before any user code can change the children invalidate state. This
+// make sure that the entire tree of object is valid at the time of
+// the invalidate event.
+static void
+_efl_invalidate(Eo *obj)
+{
+   efl_event_callback_call(obj, EFL_EVENT_INVALIDATE, NULL);
+
+   efl_invalidate(obj);
+}
+
+static void
+_efl_object_invalidate(Eo *obj, Efl_Object_Data *pd)
+{
+   _efl_pending_futures_clear(pd);
+   efl_parent_set(obj, NULL);
+   pd->invalidate = EINA_TRUE;
+}
+
+static void
+_efl_object_noref(Eo *obj EINA_UNUSED, Efl_Object_Data *pd EINA_UNUSED)
+{
+}
+
 static inline void
 _efl_object_extension_free(Efl_Object_Extension *ext)
 {
@@ -676,7 +713,7 @@ _efl_object_parent_set(Eo *obj, Efl_Object_Data *pd, Eo *parent_id)
    else
      {
         pd->parent = NULL;
-        if (prev_parent) efl_invalidate(obj);
+        if (prev_parent) _efl_invalidate(obj);
         if (prev_parent && !eo_obj->del_triggered) efl_unref(obj);
      }
 
@@ -1934,18 +1971,6 @@ EAPI const Eina_Value_Type *EFL_DBG_INFO_TYPE = &_EFL_DBG_INFO_TYPE;
 /* EFL_OBJECT_CLASS stuff */
 #define MY_CLASS EFL_OBJECT_CLASS
 
-static void
-_efl_pending_futures_clear(Efl_Object_Data *pd)
-{
-   while (pd->pending_futures)
-     {
-        Efl_Future_Pending *pending = EINA_INLIST_CONTAINER_GET(pd->pending_futures, Efl_Future_Pending);
-        Eina_Future *future = *pending->desc.storage;
-        assert(future);
-        eina_future_cancel(future);
-     }
-}
-
 static Eina_Value
 _efl_future_cb(void *data, const Eina_Value value, const Eina_Future *dead_future)
 {
@@ -2056,7 +2081,8 @@ _efl_object_destructor(Eo *obj, Efl_Object_Data *pd)
    // This can happen when the object has no parent and get
    // deleted by efl_unref.
    if (!pd->invalidate)
-     efl_invalidate(obj);
+     _efl_invalidate(obj);
+
 
    // special removal - remove from children list by hand after getting
    // child handle in case unparent method is overridden and does
@@ -2170,22 +2196,6 @@ _efl_object_finalize(Eo *obj, Efl_Object_Data *pd EINA_UNUSED)
    return obj;
 }
 
-static void
-_efl_object_invalidate(Eo *obj, Efl_Object_Data *pd)
-{
-   efl_event_callback_call(obj, EFL_EVENT_INVALIDATE, NULL);
-
-   _efl_pending_futures_clear(pd);
-   efl_parent_set(obj, NULL);
-   pd->invalidate = EINA_TRUE;
-}
-
-static void
-_efl_object_noref(Eo *obj, Efl_Object_Data *pd EINA_UNUSED)
-{
-   efl_event_callback_call(obj, EFL_EVENT_NOREF, NULL);
-}
-
 EOLIAN static void
 _efl_object_class_constructor(Efl_Class *klass EINA_UNUSED)
 {