eo: Add API to allow deletion by unref
authorJean-Philippe Andre <jp.andre@samsung.com>
Thu, 28 Sep 2017 07:38:00 +0000 (16:38 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Thu, 28 Sep 2017 07:42:04 +0000 (16:42 +0900)
This allows deleting an object by simply calling efl_unref() on it, even
if there is a parent. Normally the parent is in charge, and you can
request deletion by calling efl_del() or efl_parent_set(NULL).

But in some rare cases, you want to give ownership of an object (@owned)
and still give a parent to that object. efl_unref() should be used (and
would be used by bindings when going out of scope or on garbage
collection), which would then print an error message. This API allows
the specific behaviour.

@feature

src/lib/eo/efl_object.eo
src/lib/eo/eo_base_class.c

index 68d0d197703228a257f39ead8f5ce111e2c8153e..db634ea7e6fed41e4c93b8a3324f316c6c64fd57 100644 (file)
@@ -262,6 +262,25 @@ abstract Efl.Object ()
            ]]
            return: bool; [[$true if it is. $false otherwise.]]
       }
+      @property allow_parent_unref {
+         [[Allow an object to be deleted by unref even if it has a parent.
+
+           This simply hides error messages warning that an object being
+           destructed still has a parent. This property is false by default.
+
+           In a normal object use case, when ownership of an object is given
+           to a caller, said ownership should be released with efl_unref(). But
+           if the object has a parent, this will print error messages, as
+           $efl_unref() is stealing the ref from the parent.
+
+           Warning: Use this function very carefully, if you are absolutely
+           sure of what you are doing.
+         ]]
+         values {
+            allow: bool(false); [[Whether to allow $efl_unref() to zero
+               even if @.parent is not $null.]]
+         }
+      }
    }
    implements {
         class.constructor;
index 60ceaf6c67f495e7ad241722c5ca35931dd81a38..72171fbf4b5fdefa0478af900d281dce40080fc0 100644 (file)
@@ -58,6 +58,7 @@ typedef struct
    Eina_Bool                  callback_stopped : 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                  allow_parent_unref : 1; // Allows unref to zero even with a parent
 } Efl_Object_Data;
 
 typedef enum
@@ -2088,11 +2089,24 @@ composite_obj:
    goto composite_obj_back;
 
 err_parent:
-   ERR("Object '%p' still has a parent at the time of destruction.", obj);
+   if (EINA_LIKELY(!pd->allow_parent_unref))
+     ERR("Object '%p' still has a parent at the time of destruction.", obj);
    efl_parent_set(obj, NULL);
    goto err_parent_back;
 }
 
+EOLIAN static void
+_efl_object_allow_parent_unref_set(Eo *obj_id EINA_UNUSED, Efl_Object_Data *pd, Eina_Bool allow)
+{
+   pd->allow_parent_unref = !!allow;
+}
+
+EOLIAN static Eina_Bool
+_efl_object_allow_parent_unref_get(Eo *obj_id EINA_UNUSED, Efl_Object_Data *pd)
+{
+   return pd->allow_parent_unref;
+}
+
 EOLIAN static Eo *
 _efl_object_finalize(Eo *obj, Efl_Object_Data *pd EINA_UNUSED)
 {