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;