diff --git a/legacy/evas/src/lib/Evas.h b/legacy/evas/src/lib/Evas.h index f4b0c4dec6..9f15764793 100644 --- a/legacy/evas/src/lib/Evas.h +++ b/legacy/evas/src/lib/Evas.h @@ -573,6 +573,22 @@ typedef struct _Evas_Precision_Position Evas_Precision_Position; /**< assoc */ typedef struct _Evas_Smart_Class Evas_Smart_Class; +/** + * @typedef Evas_Smart_Interface + * + * A smart object's @b base interface definition + * + * An Evas interface is exactly like the OO-concept: an 'contract' or + * API a given object is declared to support. A smart object may have + * more than one interface, thus extending the behavior it gets from + * sub-classing. + * + * @since 1.3 + * + * @ingroup Evas_Smart_Group + */ +typedef struct _Evas_Smart_Interface Evas_Smart_Interface; + /** * @typedef Evas_Smart_Cb_Description * @@ -9633,10 +9649,33 @@ struct _Evas_Smart_Class const Evas_Smart_Class *parent; /**< this class inherits from this parent */ const Evas_Smart_Cb_Description *callbacks; /**< callbacks at this level, @c NULL terminated */ - void *interfaces; /**< to be used in a future near you */ + const Evas_Smart_Interface **interfaces; /**< #Evas_Smart_Interface pointers array, @c NULL terminated. These will be the interfaces supported at this level for an object (parents may have others) @since 1.3 */ const void *data; }; +/** + * @struct _Evas_Smart_Interface + * + * A smart object's @b base interface definition + * + * Every Evas interface must have a name field, pointing to a global, + * constant string variable. This string pointer will be the only way + * of retrieving back a given interface from a smart object. Two + * function pointers must be defined, too, which will be called at + * object creation and deletion times. + * + * @since 1.3 + * + * @ingroup Evas_Smart_Group + */ +struct _Evas_Smart_Interface +{ + const char *name; /**< Name of the given interface */ + unsigned private_size; /**< Size, in bytes, of the interface's private dada blob. This will be allocated and freed automatically for you. Get it with evas_object_smart_interface_data_get(). */ + Eina_Bool (*add)(Evas_Object *obj); /**< Function to be called at object creation time */ + void (*del)(Evas_Object *obj); /**< Function to be called at object deletion time */ +}; + /** * @struct _Evas_Smart_Cb_Description * @@ -9846,6 +9885,96 @@ struct _Evas_Smart_Cb_Description return smart; \ } +/** + * @def EVAS_SMART_SUBCLASS_IFACE_NEW + * + * @since 1.3 + * + * Convenience macro to subclass a given Evas smart class. This is the + * same as #EVAS_SMART_SUBCLASS_NEW, but now declaring smart + * interfaces besides the smart callbacks. + * + * @param smart_name The name used for the smart class. e.g: + * @c "Evas_Object_Box". + * @param prefix Prefix used for all variables and functions defined + * and referenced by this macro. + * @param api_type Type of the structure used as API for the smart + * class. Either #Evas_Smart_Class or something + * derived from it. + * @param parent_type Type of the parent class API. + * @param parent_func Function that gets the parent class. e.g: + * evas_object_box_smart_class_get(). + * @param cb_desc Array of smart callback descriptions for this smart + * class. + * @param ifaces Array of Evas smart interafaces for this smart + * class. + * + * This macro saves some typing when writing a smart class derived + * from another one. In order to work, the user @b must provide some + * functions adhering to the following guidelines: + * - @_smart_set_user(): the @b internal @c _smart_set + * function (defined by this macro) will call this one, provided by + * the user, after inheriting everything from the parent, which + * should take care of setting the right member functions for + * the class, both overrides and extensions, if any. + * - If this new class should be subclassable as well, a @b public + * @c _smart_set() function is desirable to fill in the class used as + * parent by the children. It's up to the user to provide this + * interface, which will most likely call @_smart_set() to + * get the job done. + * + * After the macro's usage, the following will be defined for use: + * - @_parent_sc: A pointer to the @b parent smart + * class. When calling parent functions from overloaded ones, use + * this global variable. + * - @_smart_class_new(): this function returns the + * #Evas_Smart needed to create smart objects with this class, + * which should be passed to evas_object_smart_add(). + * + * @warning @p smart_name has to be a pointer to a globally available + * string! The smart class created here will just have a pointer set + * to that, and all object instances will depend on it for smart class + * name lookup. + * + * @ingroup Evas_Smart_Group + */ +#define EVAS_SMART_SUBCLASS_IFACE_NEW(smart_name, \ + prefix, \ + api_type, \ + parent_type, \ + parent_func, \ + cb_desc, \ + ifaces) \ + static const parent_type * prefix##_parent_sc = NULL; \ + static void prefix##_smart_set_user(api_type * api); \ + static void prefix##_smart_set(api_type * api) \ + { \ + Evas_Smart_Class *sc; \ + if (!(sc = (Evas_Smart_Class *)api)) \ + return; \ + if (!prefix##_parent_sc) \ + prefix##_parent_sc = parent_func(); \ + evas_smart_class_inherit(sc, prefix##_parent_sc); \ + prefix##_smart_set_user(api); \ + } \ + static Evas_Smart *prefix##_smart_class_new(void) \ + { \ + static Evas_Smart *smart = NULL; \ + static api_type api; \ + if (!smart) \ + { \ + Evas_Smart_Class *sc = (Evas_Smart_Class *)&api; \ + memset(&api, 0, sizeof(api_type)); \ + sc->version = EVAS_SMART_CLASS_VERSION; \ + sc->name = smart_name; \ + sc->callbacks = cb_desc; \ + sc->interfaces = ifaces; \ + prefix##_smart_set(&api); \ + smart = evas_smart_class_new(sc); \ + } \ + return smart; \ + } + /** * @def EVAS_SMART_DATA_ALLOC * @@ -10461,6 +10590,34 @@ EAPI void evas_object_smart_callbacks_descriptions_get(const Evas_Object */ EAPI void evas_object_smart_callback_description_find(const Evas_Object *obj, const char *name, const Evas_Smart_Cb_Description **class_description, const Evas_Smart_Cb_Description **instance_description) EINA_ARG_NONNULL(1, 2); +/** + * Retrieve an Evas smart object's interface, by name string pointer. + * + * @param obj An Evas smart object. + * @param name Name string of the desired interface, which must be the + * same pointer used at the interface's declarion, when + * creating the smart object @a obj. + * + * @since 1.3 + * + * @return The interface's handle pointer, if found, @c NULL + * otherwise. + */ +const void *evas_object_smart_interface_get(const Evas_Object *obj, const char *name); + +/** + * Retrieve an Evas smart object interface's private data. + * + * @param obj An Evas smart object. + * @param iface The given object's interface handle. + * + * @since 1.3 + * + * @return The object interface's private data blob pointer, if found, + * @c NULL otherwise. + */ +void *evas_object_smart_interface_data_get(const Evas_Object *obj, const Evas_Smart_Interface *iface); + /** * Mark smart object as changed, dirty. * diff --git a/legacy/evas/src/lib/canvas/evas_object_smart.c b/legacy/evas/src/lib/canvas/evas_object_smart.c index 3d9c89dd35..28ed4cbf5b 100644 --- a/legacy/evas/src/lib/canvas/evas_object_smart.c +++ b/legacy/evas/src/lib/canvas/evas_object_smart.c @@ -100,6 +100,54 @@ evas_object_smart_data_get(const Evas_Object *obj) return o->data; } +EAPI const void * +evas_object_smart_interface_get(const Evas_Object *obj, + const char *name) +{ + unsigned int i; + Evas_Smart *s; + + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + return NULL; + MAGIC_CHECK_END(); + + s = evas_object_smart_smart_get(obj); + + for (i = 0; i < s->interfaces.size; i++) + { + const Evas_Smart_Interface *iface; + + iface = s->interfaces.array[i]; + + if (iface->name == name) + return iface; + } + + return NULL; +} + +EAPI void * +evas_object_smart_interface_data_get(const Evas_Object *obj, + const Evas_Smart_Interface *iface) +{ + unsigned int i; + Evas_Smart *s; + + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + return NULL; + MAGIC_CHECK_END(); + + s = evas_object_smart_smart_get(obj); + + for (i = 0; i < s->interfaces.size; i++) + { + if (iface == s->interfaces.array[i]) + return obj->interface_privates[i]; + } + + return NULL; +} + EAPI Evas_Smart * evas_object_smart_smart_get(const Evas_Object *obj) { @@ -311,10 +359,76 @@ _evas_object_smart_members_all_del(Evas_Object *obj) } } +static void +_evas_smart_class_ifaces_private_data_alloc(Evas_Object *obj, + Evas_Smart *s) +{ + unsigned int i, total_priv_sz = 0; + const Evas_Smart_Class *sc; + unsigned char *ptr; + + /* get total size of interfaces private data */ + for (sc = s->smart_class; sc; sc = sc->parent) + { + const Evas_Smart_Interface **ifaces_array = sc->interfaces; + if (!ifaces_array) continue; + + while (*ifaces_array) + { + const Evas_Smart_Interface *iface = *ifaces_array; + + if (!iface->name) break; + + if (iface->private_size > 0) + { + unsigned int size = iface->private_size; + + if (size % sizeof(void *) != 0) + size += sizeof(void *) - (size % sizeof(void *)); + total_priv_sz += size; + } + + ifaces_array++; + } + } + + obj->interface_privates = malloc + (s->interfaces.size * sizeof(void *) + total_priv_sz); + if (!obj->interface_privates) + { + ERR("malloc failed!"); + return; + } + + /* make private data array ptrs point to right places, WHICH LIE ON + * THE SAME STRUCT, AFTER THE # OF INTERFACES COUNT */ + ptr = (unsigned char *)(obj->interface_privates + s->interfaces.size); + for (i = 0; i < s->interfaces.size; i++) + { + unsigned int size; + + size = s->interfaces.array[i]->private_size; + + if (size == 0) + { + obj->interface_privates[i] = NULL; + continue; + } + + obj->interface_privates[i] = ptr; + memset(ptr, 0, size); + + if (size % sizeof(void *) != 0) + size += sizeof(void *) - (size % sizeof(void *)); + ptr += size; + } +} + EAPI Evas_Object * evas_object_smart_add(Evas *e, Evas_Smart *s) { Evas_Object *obj; + unsigned int i; MAGIC_CHECK(e, Evas, MAGIC_EVAS); return NULL; @@ -332,8 +446,26 @@ evas_object_smart_add(Evas *e, Evas_Smart *s) evas_object_smart_use(s); + _evas_smart_class_ifaces_private_data_alloc(obj, s); + if (s->smart_class->add) s->smart_class->add(obj); + for (i = 0; i < s->interfaces.size; i++) + { + const Evas_Smart_Interface *iface; + + iface = s->interfaces.array[i]; + if (iface->add) + { + if (!iface->add(obj)) + { + ERR("failed to create interface %s\n", iface->name); + evas_object_del(obj); + return NULL; + } + } + } + return obj; } @@ -753,11 +885,25 @@ void evas_object_smart_del(Evas_Object *obj) { Evas_Smart *s; + unsigned int i; if (obj->delete_me) return; s = obj->smart.smart; + if ((s) && (s->smart_class->del)) s->smart_class->del(obj); if (obj->smart.parent) evas_object_smart_member_del(obj); + + for (i = 0; i < s->interfaces.size; i++) + { + const Evas_Smart_Interface *iface; + + iface = s->interfaces.array[i]; + if (iface->del) iface->del(obj); + } + + free(obj->interface_privates); + obj->interface_privates = NULL; + if (s) evas_object_smart_unuse(s); } diff --git a/legacy/evas/src/lib/canvas/evas_smart.c b/legacy/evas/src/lib/canvas/evas_smart.c index 0cfba054b6..f39721dd07 100644 --- a/legacy/evas/src/lib/canvas/evas_smart.c +++ b/legacy/evas/src/lib/canvas/evas_smart.c @@ -3,6 +3,7 @@ static void _evas_smart_class_callbacks_create(Evas_Smart *s); +static void _evas_smart_class_interfaces_create(Evas_Smart *s); /* all public */ @@ -16,6 +17,8 @@ evas_smart_free(Evas_Smart *s) if (s->usage > 0) return; if (s->class_allocated) free((void *)s->smart_class); free(s->callbacks.array); + free(s->interfaces.array); + free(s); } @@ -36,6 +39,7 @@ evas_smart_class_new(const Evas_Smart_Class *sc) s->smart_class = sc; _evas_smart_class_callbacks_create(s); + _evas_smart_class_interfaces_create(s); return s; } @@ -238,6 +242,7 @@ _evas_smart_class_callbacks_create(Evas_Smart *s) if (n == 0) return; if (!evas_smart_cb_descriptions_resize(&s->callbacks, n)) return; + s->callbacks.size = n; for (n = 0, sc = s->smart_class; sc; sc = sc->parent) { const Evas_Smart_Cb_Description *d; @@ -247,6 +252,67 @@ _evas_smart_class_callbacks_create(Evas_Smart *s) evas_smart_cb_descriptions_fix(&s->callbacks); } +static void +_evas_smart_class_interfaces_create(Evas_Smart *s) +{ + unsigned int i, total_priv_sz; + const Evas_Smart_Class *sc; + + /* get number of interfaces on the smart */ + for (i = 0, sc = s->smart_class; sc; sc = sc->parent) + { + const Evas_Smart_Interface **ifaces_array = sc->interfaces; + if (!ifaces_array) continue; + + while (*ifaces_array) + { + const Evas_Smart_Interface *iface = *ifaces_array; + + if (!iface->name) break; + + i++; + + if (iface->private_size > 0) + { + unsigned int size = iface->private_size; + + if (size % sizeof(void *) != 0) + size += sizeof(void *) - (size % sizeof(void *)); + total_priv_sz += size; + } + + ifaces_array++; + } + } + + if (!i) return; + + s->interfaces.array = malloc(i * sizeof(Evas_Smart_Interface *)); + if (!s->interfaces.array) + { + ERR("malloc failed!"); + return; + } + + s->interfaces.size = i; + + for (i = 0, sc = s->smart_class; sc; sc = sc->parent) + { + const Evas_Smart_Interface **ifaces_array = sc->interfaces; + if (!ifaces_array) continue; + + while (*ifaces_array) + { + const Evas_Smart_Interface *iface = *ifaces_array; + + if (!iface->name) break; + + s->interfaces.array[i++] = iface; + ifaces_array++; + } + } +} + static int _evas_smart_cb_description_cmp_search(const void *p1, const void *p2) { diff --git a/legacy/evas/src/lib/include/evas_private.h b/legacy/evas/src/lib/include/evas_private.h index 86dab875d5..18d440af15 100644 --- a/legacy/evas/src/lib/include/evas_private.h +++ b/legacy/evas/src/lib/include/evas_private.h @@ -45,6 +45,7 @@ typedef struct _Evas_Callbacks Evas_Callbacks; typedef struct _Evas_Format Evas_Format; typedef struct _Evas_Map_Point Evas_Map_Point; typedef struct _Evas_Smart_Cb_Description_Array Evas_Smart_Cb_Description_Array; +typedef struct _Evas_Smart_Interfaces_Array Evas_Smart_Interfaces_Array; typedef struct _Evas_Post_Callback Evas_Post_Callback; typedef struct _Evas_Coord_Touch_Point Evas_Coord_Touch_Point; @@ -245,6 +246,12 @@ struct _Evas_Smart_Cb_Description_Array const Evas_Smart_Cb_Description **array; }; +struct _Evas_Smart_Interfaces_Array +{ + unsigned int size; + const Evas_Smart_Interface **array; +}; + struct _Evas_Smart { DATA32 magic; @@ -254,6 +261,7 @@ struct _Evas_Smart const Evas_Smart_Class *smart_class; Evas_Smart_Cb_Description_Array callbacks; + Evas_Smart_Interfaces_Array interfaces; unsigned char delete_me : 1; unsigned char class_allocated : 1; @@ -587,6 +595,10 @@ struct _Evas_Object int in_move, in_resize; } doing; + /* ptr array + data blob holding all interfaces private data for + * this object */ + void **interface_privates; + unsigned int ref; unsigned char delete_me;