diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h index de71a698b3..b86a556fe9 100644 --- a/src/lib/eo/Eo.h +++ b/src/lib/eo/Eo.h @@ -1516,6 +1516,33 @@ EAPI Eo * _efl_add_internal_start(const char *file, int line, const Efl_Class *k */ EAPI void efl_del(const Eo *obj); +/** + * @brief Set an override for a class + * + * This can be used to override a class with another class such that when @p klass is added + * with efl_add(), an object of type @p override is returned. + * + * @param[in] klass The class to be overridden + * @param[in] override The class to override with; must inherit from or implement @p klass + * @return Return @c true if the override was successfully set + * + * @ingroup Efl_Object + */ +EAPI Eina_Bool efl_class_override_register(const Efl_Class *klass, const Efl_Class *override); + +/** + * @brief Unset an override for a class + * + * This is used to unset a previously-set override on a given class. It will only succeed if + * @p override is the currently-set override for @p klass. + * + * @param[in] klass The class to unset the override from + * @param[in] override The class override to be removed + * @return Return @c true if the override was successfully unset + * + * @ingroup Efl_Object + */ +EAPI Eina_Bool efl_class_override_unregister(const Efl_Class *klass, const Efl_Class *override); /** * @brief Get a pointer to the data of an object for a specific class. * diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c index 8f711d8e4a..c39777b14c 100644 --- a/src/lib/eo/eo.c +++ b/src/lib/eo/eo.c @@ -44,6 +44,7 @@ int _eo_log_dom = -1; Eina_Thread _efl_object_main_thread; static unsigned int efl_del_api_generation = 0; static Efl_Object_Op _efl_del_api_op_id = 0; +static Eina_Hash *class_overrides; typedef enum _Eo_Ref_Op { EO_REF_OP_NONE, @@ -868,6 +869,12 @@ _efl_add_internal_start(const char *file, int line, const Efl_Class *klass_id, E if (is_fallback) fptr = _efl_add_fallback_stack_push(NULL); + if (class_overrides) + { + const Efl_Class *override = eina_hash_find(class_overrides, &klass_id); + if (override) klass_id = override; + } + EO_CLASS_POINTER_GOTO_PROXY(klass_id, klass, err_klass); // Check that in the case of efl_add we do pass a parent. @@ -2596,6 +2603,33 @@ efl_compatible(const Eo *obj, const Eo *obj_target) return EINA_FALSE; } +EAPI Eina_Bool +efl_class_override_register(const Efl_Class *klass, const Efl_Class *override) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(klass, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(override, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(!efl_isa(override, klass), EINA_FALSE); + if (!class_overrides) + class_overrides = eina_hash_pointer_new(NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(class_overrides, EINA_FALSE); + + eina_hash_set(class_overrides, &klass, override); + return EINA_TRUE; +} + +EAPI Eina_Bool +efl_class_override_unregister(const Efl_Class *klass, const Efl_Class *override) +{ + const Efl_Class *set; + EINA_SAFETY_ON_NULL_RETURN_VAL(klass, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(override, EINA_FALSE); + if (!class_overrides) return EINA_TRUE; + + set = eina_hash_find(class_overrides, &klass); + if (set != override) return EINA_FALSE; + return eina_hash_del_by_key(class_overrides, &klass); +} + EAPI Eina_Bool efl_destructed_is(const Eo *obj_id) { diff --git a/src/tests/eo/suite/eo_test_general.c b/src/tests/eo/suite/eo_test_general.c index a8e6391b2e..fac8c70bb5 100644 --- a/src/tests/eo/suite/eo_test_general.c +++ b/src/tests/eo/suite/eo_test_general.c @@ -1798,11 +1798,38 @@ EFL_START_TEST(efl_object_size) } EFL_END_TEST +EFL_START_TEST(eo_test_class_replacement) +{ + Eo *obj; + + /* test basic override */ + ck_assert(efl_class_override_register(SIMPLE_CLASS, SIMPLE3_CLASS)); + obj = efl_add_ref(SIMPLE_CLASS, NULL); + fail_if(!obj); + ck_assert_ptr_eq(efl_class_get(obj), SIMPLE3_CLASS); + efl_unref(obj); + + /* test overriding with non-inheriting class */ + ck_assert(!efl_class_override_register(SIMPLE_CLASS, SIMPLE2_CLASS)); + + /* test removing an invalid override */ + ck_assert(!efl_class_override_unregister(SIMPLE_CLASS, SIMPLE2_CLASS)); + + /* test removing an override */ + ck_assert(efl_class_override_unregister(SIMPLE_CLASS, SIMPLE3_CLASS)); + obj = efl_add_ref(SIMPLE_CLASS, NULL); + fail_if(!obj); + ck_assert_ptr_eq(efl_class_get(obj), SIMPLE_CLASS); + efl_unref(obj); +} +EFL_END_TEST + void eo_test_general(TCase *tc) { tcase_add_test(tc, eo_simple); tcase_add_test(tc, eo_singleton); tcase_add_test(tc, efl_object_override_tests); + tcase_add_test(tc, eo_test_class_replacement); tcase_add_test(tc, eo_signals); tcase_add_test(tc, efl_data_fetch); tcase_add_test(tc, efl_data_safe_fetch);