bu5hm4n pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=9e6d3b44e62c341bda6a7f226b589673fcc9cc98
commit 9e6d3b44e62c341bda6a7f226b589673fcc9cc98 Author: Cedric BAIL <cedric.b...@free.fr> Date: Thu Jul 11 14:53:19 2019 -0700 eo: add ability to register provider on the Eo object directly. This should reduce the need for custom implementation of efl_object_provider_bind. It also enable the ability to register provider from user code on any Efl_Object. Reviewed-by: Marcel Hollerbach <m...@marcel-hollerbach.de> Differential Revision: https://phab.enlightenment.org/D9292 --- src/lib/eo/efl_object.eo | 16 +++++++ src/lib/eo/eo_base_class.c | 104 +++++++++++++++++++++++++++++++++------------ 2 files changed, 93 insertions(+), 27 deletions(-) diff --git a/src/lib/eo/efl_object.eo b/src/lib/eo/efl_object.eo index 85cb664958..0b3c403a20 100644 --- a/src/lib/eo/efl_object.eo +++ b/src/lib/eo/efl_object.eo @@ -402,6 +402,22 @@ abstract Efl.Object even if @.parent is not $null.]] } } + provider_register { + [[Will register a manager of a specific class to be answered by eo.provider_find.]] + params { + @in klass: const(Efl.Class); [[The class provided by the registered provider.]] + @in provider: const(Efl.Object); [[The provider for the newly registered class that has to provide that said Efl.Class.]] + } + return: bool; [[$true if successfully register, $false otherwise.]] + } + provider_unregister { + [[Will unregister a manager of a specific class that was previously registered and answered by eo.provider_find.]] + params { + @in klass: const(Efl.Class); [[The class provided by the provider to unregister for.]] + @in provider: const(Efl.Object); [[The provider for the registered class to unregister.]] + } + return: bool; [[$true if successfully unregistered, $false otherwise.]] + } } implements { class.constructor; diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c index 62a1caf9a2..d9edf15a90 100644 --- a/src/lib/eo/eo_base_class.c +++ b/src/lib/eo/eo_base_class.c @@ -39,6 +39,7 @@ typedef struct Eo *composite_parent; Eina_Inlist *generic_data; Eo ***wrefs; + Eina_Hash *providers; } Efl_Object_Extension; struct _Efl_Object_Data @@ -125,11 +126,46 @@ _efl_pending_futures_clear(Efl_Object_Data *pd) } } +static inline void +_efl_object_extension_free(Efl_Object_Extension *ext) +{ + eina_freeq_ptr_main_add(ext, free, sizeof(*ext)); +} + +static inline Efl_Object_Extension * +_efl_object_extension_need(Efl_Object_Data *pd) +{ + if (!pd->ext) pd->ext = calloc(1, sizeof(Efl_Object_Extension)); + return pd->ext; +} + +static inline void +_efl_object_extension_noneed(Efl_Object_Data *pd) +{ + Efl_Object_Extension *ext = pd->ext; + if ((!ext) || + (ext->name) || + (ext->comment) || + (ext->generic_data) || + (ext->wrefs) || + (ext->composite_parent) || + (ext->providers)) return; + _efl_object_extension_free(pd->ext); + pd->ext = NULL; +} + static void _efl_object_invalidate(Eo *obj_id, Efl_Object_Data *pd) { _efl_pending_futures_clear(pd); + if (pd->ext && pd->ext->providers) + { + eina_hash_free(pd->ext->providers); + pd->ext->providers = NULL; + _efl_object_extension_noneed(pd); + } + EO_OBJ_POINTER_RETURN(obj_id, obj); // Finally invalidate itself if it wasn't done already @@ -185,33 +221,6 @@ _efl_invalidate(_Eo_Object *obj) obj->invalidate = EINA_TRUE; } -static inline void -_efl_object_extension_free(Efl_Object_Extension *ext) -{ - eina_freeq_ptr_main_add(ext, free, sizeof(*ext)); -} - -static inline Efl_Object_Extension * -_efl_object_extension_need(Efl_Object_Data *pd) -{ - if (!pd->ext) pd->ext = calloc(1, sizeof(Efl_Object_Extension)); - return pd->ext; -} - -static inline void -_efl_object_extension_noneed(Efl_Object_Data *pd) -{ - Efl_Object_Extension *ext = pd->ext; - if ((!ext) || - (ext->name) || - (ext->comment) || - (ext->generic_data) || - (ext->wrefs) || - (ext->composite_parent)) return; - _efl_object_extension_free(pd->ext); - pd->ext = NULL; -} - static void _key_generic_cb_del(void *data, const Efl_Event *event); static void @@ -832,6 +841,7 @@ EOLIAN static Efl_Object * _efl_object_provider_find(const Eo *obj, Efl_Object_Data *pd, const Efl_Object *klass) { Eina_Bool invalidate; + Efl_Object *r = NULL; invalidate = _efl_object_invalidated_get((Eo*) obj, NULL); if (invalidate) @@ -839,10 +849,50 @@ _efl_object_provider_find(const Eo *obj, Efl_Object_Data *pd, const Efl_Object * ERR("Calling efl_provider_find(%p) after the object was invalidated.", obj); return NULL; } + + if (efl_isa(obj, klass)) return (Eo *) obj; + + if (pd->ext) r = eina_hash_find(pd->ext->providers, &klass); + if (r) return r; + if (pd->parent) return efl_provider_find(pd->parent, klass); return NULL; } +static Eina_Bool +_efl_object_provider_register(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const Efl_Class *klass, const Efl_Object *provider) +{ + // The passed object does not provide that said class. + if (!efl_isa(provider, klass)) return EINA_FALSE; + + _efl_object_extension_need(pd); + if (!pd->ext) return EINA_FALSE; + if (!pd->ext->providers) pd->ext->providers = eina_hash_pointer_new(EINA_FREE_CB(efl_unref)); + + // Prevent double insertion for the same class + if (eina_hash_find(pd->ext->providers, &klass)) return EINA_FALSE; + + // Note: I would prefer to use efl_xref here, but I can't figure a nice way to + // call efl_xunref on hash destruction. + return eina_hash_add(pd->ext->providers, &klass, efl_ref(provider)); +} + +static Eina_Bool +_efl_object_provider_unregister(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const Efl_Class *klass, const Efl_Object *provider) +{ + Eina_Bool r; + + if (!pd->ext) return EINA_FALSE; + r = eina_hash_del(pd->ext->providers, &klass, provider); + + if (eina_hash_population(pd->ext->providers) != 0) return r; + eina_hash_free(pd->ext->providers); + pd->ext->providers = NULL; + _efl_object_extension_noneed(pd); + + return r; +} + /* Children accessor */ typedef struct _Eo_Children_Iterator Eo_Children_Iterator; struct _Eo_Children_Iterator --