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
*
* A smart object callback description, used to provide introspection
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
*
* Describes a callback issued by a smart object
}
/**
+ * @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 <b>declaring smart
+ * interfaces</b> 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:
+ * - @<prefix@>_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 <b>take care of setting the right member functions for
+ * the class</b>, 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 @<prefix@>_smart_set() to
+ * get the job done.
+ *
+ * After the macro's usage, the following will be defined for use:
+ * - @<prefix@>_parent_sc: A pointer to the @b parent smart
+ * class. When calling parent functions from overloaded ones, use
+ * this global variable.
+ * - @<prefix@>_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
*
* Convenience macro to allocate smart data only if needed.
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 <b>private data</b>.
+ *
+ * @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.
*
* @param obj The given Evas smart object
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)
{
}
}
+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;
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;
}
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);
}
static void _evas_smart_class_callbacks_create(Evas_Smart *s);
+static void _evas_smart_class_interfaces_create(Evas_Smart *s);
/* all public */
if (s->usage > 0) return;
if (s->class_allocated) free((void *)s->smart_class);
free(s->callbacks.array);
+ free(s->interfaces.array);
+
free(s);
}
s->smart_class = sc;
_evas_smart_class_callbacks_create(s);
+ _evas_smart_class_interfaces_create(s);
return 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;
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)
{