forked from enlightenment/efl
Evas_Smart_Interface support.
This gives Evas simple (smart object) interfaces, to extend the object behaviorextension beyond the limits of mere sub-classing. Patch by: Gustavo Lima Chaves <glima@profusion.mobi> SVN revision: 73302
This commit is contained in:
parent
3ef67a7c87
commit
b64fa6453a
|
@ -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 <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
|
||||
*
|
||||
|
@ -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 <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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue