diff --git a/legacy/evas/src/lib/Evas.h b/legacy/evas/src/lib/Evas.h index 1ae8c5444f..703621d053 100644 --- a/legacy/evas/src/lib/Evas.h +++ b/legacy/evas/src/lib/Evas.h @@ -104,6 +104,7 @@ typedef enum _Evas_Object_Table_Homogeneous_Mode typedef struct _Evas_Transform Evas_Transform; /**< An Evas projective or affine transform */ typedef struct _Evas_Coord_Rectangle Evas_Coord_Rectangle; /**< A generic rectangle handle */ typedef struct _Evas_Smart_Class Evas_Smart_Class; /**< A smart object base class */ +typedef struct _Evas_Smart_Cb_Description Evas_Smart_Cb_Description; /**< A smart object callback description, used to provide introspection */ typedef struct _Evas_Map Evas_Map; /**< An array of map points */ typedef struct _Evas Evas; /**< An Evas canvas handle */ @@ -144,7 +145,7 @@ typedef enum _Evas_Aspect_Control } Evas_Aspect_Control; -#define EVAS_SMART_CLASS_VERSION 3 /** the version you have to put into the version field in the smart class struct */ +#define EVAS_SMART_CLASS_VERSION 4 /** the version you have to put into the version field in the smart class struct */ struct _Evas_Smart_Class /** a smart object class */ { const char *name; /** the string name of the class */ @@ -164,16 +165,55 @@ struct _Evas_Smart_Class /** a smart object class */ void (*member_add) (Evas_Object *o, Evas_Object *child); void (*member_del) (Evas_Object *o, Evas_Object *child); + const Evas_Smart_Class *parent; /**< this class inherits from this parent */ + const Evas_Smart_Cb_Description *callbacks; /**< callbacks at this level, NULL terminated */ + const void *data; }; +struct _Evas_Smart_Cb_Description +{ + const char *name; /**< callback name, ie: "changed" */ + + /** + * @brief Hint type of @c event_info parameter of Evas_Smart_Cb. + * + * The type string uses the pattern similar to + * + * http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-signatures + * + * but extended to optionally include variable names within + * brackets preceding types. Example: + * + * @li Structure with two integers: + * @c "(ii)" + * + * @li Structure called 'x' with two integers named 'a' and 'b': + * @c "[x]([a]i[b]i)" + * + * @li Array of integers: + * @c "ai" + * + * @li Array called 'x' of struct with two integers: + * @c "[x]a(ii)" + * + * @note This type string is used as a hint and is @b not validated + * or enforced anyhow. Implementors should make the best use + * of it to help bindings, documentation and other users of + * introspection features. + */ + const char *type; +}; + /** * Initializer to zero a whole Evas_Smart_Class structure. * * @see EVAS_SMART_CLASS_INIT_VERSION * @see EVAS_SMART_CLASS_INIT_NAME_VERSION + * @see EVAS_SMART_CLASS_INIT_NAME_VERSION_PARENT + * @see EVAS_SMART_CLASS_INIT_NAME_VERSION_PARENT_CALLBACKS */ -#define EVAS_SMART_CLASS_INIT_NULL {NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} +#define EVAS_SMART_CLASS_INIT_NULL {NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} /** * Initializer to zero a whole Evas_Smart_Class structure and set version. @@ -183,8 +223,10 @@ struct _Evas_Smart_Class /** a smart object class */ * * @see EVAS_SMART_CLASS_INIT_NULL * @see EVAS_SMART_CLASS_INIT_NAME_VERSION + * @see EVAS_SMART_CLASS_INIT_NAME_VERSION_PARENT + * @see EVAS_SMART_CLASS_INIT_NAME_VERSION_PARENT_CALLBACKS */ -#define EVAS_SMART_CLASS_INIT_VERSION {NULL, EVAS_SMART_CLASS_VERSION, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} +#define EVAS_SMART_CLASS_INIT_VERSION {NULL, EVAS_SMART_CLASS_VERSION, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} /** * Initializer to zero a whole Evas_Smart_Class structure and set name @@ -199,10 +241,133 @@ struct _Evas_Smart_Class /** a smart object class */ * * @see EVAS_SMART_CLASS_INIT_NULL * @see EVAS_SMART_CLASS_INIT_VERSION + * @see EVAS_SMART_CLASS_INIT_NAME_VERSION_PARENT + * @see EVAS_SMART_CLASS_INIT_NAME_VERSION_PARENT_CALLBACKS */ -#define EVAS_SMART_CLASS_INIT_NAME_VERSION(name) {name, EVAS_SMART_CLASS_VERSION, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} +#define EVAS_SMART_CLASS_INIT_NAME_VERSION(name) {name, EVAS_SMART_CLASS_VERSION, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} +/** + * Initializer to zero a whole Evas_Smart_Class structure and set name, + * version and parent class. + * + * Similar to EVAS_SMART_CLASS_INIT_NULL, but will set version field to + * latest EVAS_SMART_CLASS_VERSION, name to the specified value and + * parent class. + * + * It will keep a reference to name field as a "const char *", that is, + * name must be available while the structure is used (hint: static or global!) + * and will not be modified. Similarly, parent reference will be kept. + * + * @see EVAS_SMART_CLASS_INIT_NULL + * @see EVAS_SMART_CLASS_INIT_VERSION + * @see EVAS_SMART_CLASS_INIT_NAME_VERSION + * @see EVAS_SMART_CLASS_INIT_NAME_VERSION_PARENT_CALLBACKS + */ +#define EVAS_SMART_CLASS_INIT_NAME_VERSION_PARENT(name, parent) {name, EVAS_SMART_CLASS_VERSION, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, parent, NULL} +/** + * Initializer to zero a whole Evas_Smart_Class structure and set name, + * version, parent class and callbacks definition. + * + * Similar to EVAS_SMART_CLASS_INIT_NULL, but will set version field to + * latest EVAS_SMART_CLASS_VERSION, name to the specified value, parent + * class and callbacks at this level. + * + * It will keep a reference to name field as a "const char *", that is, + * name must be available while the structure is used (hint: static or global!) + * and will not be modified. Similarly, parent and callbacks reference + * will be kept. + * + * @see EVAS_SMART_CLASS_INIT_NULL + * @see EVAS_SMART_CLASS_INIT_VERSION + * @see EVAS_SMART_CLASS_INIT_NAME_VERSION + * @see EVAS_SMART_CLASS_INIT_NAME_VERSION_PARENT + */ +#define EVAS_SMART_CLASS_INIT_NAME_VERSION_PARENT_CALLBACKS(name, parent, callbacks) {name, EVAS_SMART_CLASS_VERSION, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, parent, callbacks} + +/** + * Convenience macro to subclass a Smart Class. + * + * This macro saves some typing when writing a Smart Class derived from + * another one. In order to work, the user needs to provide some functions + * adhering to the following guidelines. + * - _smart_set_user(): the internal _smart_set function 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. + * - _parent_sc: smart class of the parent. 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, should be called by the public + * _add() function. + * - If this new class should be subclassable as well, a public _smart_set() + * function is desirable to fill 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. + * + * @param smart_name The name used for the Smart Class. e.g: "Evas_Object_Box". + * @param prefix Prefix used for all variables and functions defined. + * @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 sets up the parent class. e.g: evas_object_box_smart_set(). + * @param cb_desc Array of callback descriptions for this Smart Class. + */ +#define EVAS_SMART_SUBCLASS_NEW(smart_name, prefix, api_type, parent_type, parent_func, cb_desc) \ +static parent_type prefix##_parent_sc; \ +static Eina_Bool prefix##_parent_init = 0; \ +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_init) \ + { \ + memset(&prefix##_parent_sc, 0, sizeof(parent_type)); \ + ((Evas_Smart_Class)prefix##_parent_sc).version = EVAS_SMART_CLASS_VERSION; \ + parent_func(&prefix##_parent_sc); \ + prefix##_parent_init = 1; \ + } \ + 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; \ + prefix##_smart_set(&api); \ + smart = evas_smart_class_new(sc); \ + } \ + return smart; \ +} + +/** + * Convenience macro to allocate smart data only if needed. + * + * When writing a subclassable smart object, the .add function will need + * to check if the smart private data was already allocated by some child + * object or not. This macro makes it easier to do it. + * + * @param o Evas object passed to the .add function + * @param priv_type The type of the data to allocate + */ +#define EVAS_SMART_DATA_ALLOC(o, priv_type) \ + priv_type *priv; \ + priv = evas_object_smart_data_get(o); \ + if (!priv) \ + { \ + priv = (priv_type *)calloc(1, sizeof(priv_type)); \ + if (!priv) \ + return; \ + evas_object_smart_data_set(o, priv); \ + } typedef struct _Evas_Pixel_Import_Source Evas_Pixel_Import_Source; /**< A source description of pixels for importing pixels */ typedef struct _Evas_Engine_Info Evas_Engine_Info; /**< A generic Evas Engine information structure */ @@ -898,6 +1063,20 @@ extern "C" { EAPI const Evas_Smart_Class *evas_smart_class_get (const Evas_Smart *s) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; EAPI void *evas_smart_data_get (const Evas_Smart *s) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; + EAPI const Evas_Smart_Cb_Description *evas_smart_callback_description_find(const Evas_Smart *s, const char *name) EINA_ARG_NONNULL(1, 2) EINA_PURE; + + EAPI Eina_Bool evas_smart_class_inherit_full (Evas_Smart_Class *sc, const Evas_Smart_Class *parent_sc, unsigned int parent_sc_size) EINA_ARG_NONNULL(1, 2); + /** + * Easy to use version of evas_smart_class_inherit_full(). + * + * This version will use sizeof(parent_sc), copying everything. + * + * @param sc child class, will have methods copied from @a parent_sc + * @param parent_sc parent class, will provide contents to be copied. + * @return 1 on success, 0 on failure. + */ +#define evas_smart_class_inherit(sc, parent_sc) evas_smart_class_inherit_full(sc, parent_sc, sizeof(*parent_sc)) + EAPI Evas_Object *evas_object_smart_add (Evas *e, Evas_Smart *s) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2) EINA_MALLOC; EAPI void evas_object_smart_member_add (Evas_Object *obj, Evas_Object *smart_obj) EINA_ARG_NONNULL(1, 2); @@ -910,6 +1089,11 @@ extern "C" { EAPI void evas_object_smart_callback_add (Evas_Object *obj, const char *event, Evas_Smart_Cb func, const void *data) EINA_ARG_NONNULL(1, 2, 3); EAPI void *evas_object_smart_callback_del (Evas_Object *obj, const char *event, Evas_Smart_Cb func) EINA_ARG_NONNULL(1, 2, 3); EAPI void evas_object_smart_callback_call (Evas_Object *obj, const char *event, void *event_info) EINA_ARG_NONNULL(1, 2); + + EAPI Eina_Bool evas_object_smart_callbacks_descriptions_set(Evas_Object *obj, const Evas_Smart_Cb_Description *descriptions) EINA_ARG_NONNULL(1); + EAPI void evas_object_smart_callbacks_descriptions_get(const Evas_Object *obj, const Evas_Smart_Cb_Description ***class_descriptions, unsigned int *class_count, const Evas_Smart_Cb_Description ***instance_descriptions, unsigned int *instance_count) EINA_ARG_NONNULL(1); + 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); + EAPI void evas_object_smart_changed (Evas_Object *obj) EINA_ARG_NONNULL(1); EAPI void evas_object_smart_need_recalculate_set(Evas_Object *obj, Eina_Bool value) EINA_ARG_NONNULL(1); EAPI Eina_Bool evas_object_smart_need_recalculate_get(const Evas_Object *obj) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; diff --git a/legacy/evas/src/lib/canvas/evas_object_box.c b/legacy/evas/src/lib/canvas/evas_object_box.c index b5ded0366f..0efd262139 100644 --- a/legacy/evas/src/lib/canvas/evas_object_box.c +++ b/legacy/evas/src/lib/canvas/evas_object_box.c @@ -50,7 +50,9 @@ struct _Evas_Object_Box_Accessor return val; \ } -static Evas_Smart_Class _parent_sc = EVAS_SMART_CLASS_INIT_NULL; +EVAS_SMART_SUBCLASS_NEW("Evas_Object_Box", _evas_object_box, + Evas_Object_Box_Api, Evas_Smart_Class, + evas_object_smart_clipped_smart_set, NULL) static Eina_Bool _evas_object_box_iterator_next(Evas_Object_Box_Iterator *it, void **data) @@ -420,7 +422,7 @@ _evas_object_box_smart_add(Evas_Object *o) evas_object_smart_data_set(o, priv); } - _parent_sc.add(o); + _evas_object_box_parent_sc.add(o); priv->children = NULL; priv->align.h = 0.5; @@ -461,7 +463,7 @@ _evas_object_box_smart_del(Evas_Object *o) if (priv->layout.data && priv->layout.free_data) priv->layout.free_data(priv->layout.data); - _parent_sc.del(o); + _evas_object_box_parent_sc.del(o); } static void @@ -487,15 +489,23 @@ _evas_object_box_smart_calculate(Evas_Object *o) ERR("No layout function set for %p box.", o); } -static Evas_Smart * -_evas_object_box_smart_class_new(void) +static void +_evas_object_box_smart_set_user(Evas_Object_Box_Api *api) { - static Evas_Object_Box_Api api = EVAS_OBJECT_BOX_API_INIT_NAME_VERSION("Evas_Object_Box"); + api->base.add = _evas_object_box_smart_add; + api->base.del = _evas_object_box_smart_del; + api->base.resize = _evas_object_box_smart_resize; + api->base.calculate = _evas_object_box_smart_calculate; - if (!_parent_sc.name) - evas_object_box_smart_set(&api); - - return evas_smart_class_new(&api.base); + api->append = _evas_object_box_append_default; + api->prepend = _evas_object_box_prepend_default; + api->insert_before = _evas_object_box_insert_before_default; + api->insert_after = _evas_object_box_insert_after_default; + api->insert_at = _evas_object_box_insert_at_default; + api->remove = _evas_object_box_remove_default; + api->remove_at = _evas_object_box_remove_at_default; + api->option_new = _evas_object_box_option_new_default; + api->option_free = _evas_object_box_option_free_default; } /** @@ -506,17 +516,10 @@ _evas_object_box_smart_class_new(void) * properties of the box must be set/retrieved via * evas_object_box_{h,v}_{align,padding}_{get,set)(). */ -Evas_Object * +EAPI Evas_Object * evas_object_box_add(Evas *evas) { - static Evas_Smart *smart = NULL; - Evas_Object *o; - - if (!smart) - smart = _evas_object_box_smart_class_new(); - - o = evas_object_smart_add(evas, smart); - return o; + return evas_object_smart_add(evas, _evas_object_box_smart_class_new()); } /** @@ -524,7 +527,7 @@ evas_object_box_add(Evas *evas) * * @see evas_object_box_add() */ -Evas_Object * +EAPI Evas_Object * evas_object_box_add_to(Evas_Object *parent) { Evas *evas; @@ -540,41 +543,12 @@ evas_object_box_add_to(Evas_Object *parent) * Set the default box @a api struct (Evas_Object_Box_Api) * with the default values. May be used to extend that API. */ -void +EAPI void evas_object_box_smart_set(Evas_Object_Box_Api *api) { if (!api) return; - - if (!_parent_sc.name) - evas_object_smart_clipped_smart_set(&_parent_sc); - - api->base.add = _evas_object_box_smart_add; - api->base.del = _evas_object_box_smart_del; - api->base.move = _parent_sc.move; - api->base.resize = _evas_object_box_smart_resize; - api->base.show = _parent_sc.show; - api->base.hide = _parent_sc.hide; - api->base.color_set = _parent_sc.color_set; - api->base.clip_set = _parent_sc.clip_set; - api->base.clip_unset = _parent_sc.clip_unset; - api->base.calculate = _evas_object_box_smart_calculate; - api->base.member_add = _parent_sc.member_add; - api->base.member_del = _parent_sc.member_del; - - api->append = _evas_object_box_append_default; - api->prepend = _evas_object_box_prepend_default; - api->insert_before = _evas_object_box_insert_before_default; - api->insert_after = _evas_object_box_insert_after_default; - api->insert_at = _evas_object_box_insert_at_default; - api->remove = _evas_object_box_remove_default; - api->remove_at = _evas_object_box_remove_at_default; - api->property_set = NULL; - api->property_get = NULL; - api->property_name_get = NULL; - api->property_id_get = NULL; - api->option_new = _evas_object_box_option_new_default; - api->option_free = _evas_object_box_option_free_default; + _evas_object_box_smart_set(api); } /** @@ -582,7 +556,7 @@ evas_object_box_smart_set(Evas_Object_Box_Api *api) * which here defines its genre (horizontal, vertical, homogeneous, * etc.). */ -void +EAPI void evas_object_box_layout_set(Evas_Object *o, Evas_Object_Box_Layout cb, const void *data, void (*free_data)(void *data)) { EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv); @@ -789,7 +763,7 @@ _evas_object_box_layout_horizontal_weight_apply(Evas_Object_Box_Data *priv, Evas * properties must be set (by the * evas_object_size_hint_{min,max}_set() functions. */ -void +EAPI void evas_object_box_layout_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) { int pad_inc = 0, sub_pixel = 0; @@ -955,7 +929,7 @@ _evas_object_box_layout_vertical_weight_apply(Evas_Object_Box_Data *priv, Evas_O * evas_object_box_layout_horizontal(). The description of its * behaviour can be derived from that function's documentation. */ -void +EAPI void evas_object_box_layout_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) { int pad_inc = 0, sub_pixel = 0; @@ -1092,7 +1066,7 @@ evas_object_box_layout_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, void * element to the exact height of its parent (respecting the max hint * on the child's height). */ -void +EAPI void evas_object_box_layout_homogeneous_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) { int cell_sz, share, inc; @@ -1161,7 +1135,7 @@ evas_object_box_layout_homogeneous_horizontal(Evas_Object *o, Evas_Object_Box_Da * evas_object_box_layout_homogeneous_horizontal(). The description * of its behaviour can be derived from that function's documentation. */ -void +EAPI void evas_object_box_layout_homogeneous_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) { int cell_sz, share, inc; @@ -1262,7 +1236,7 @@ evas_object_box_layout_homogeneous_vertical(Evas_Object *o, Evas_Object_Box_Data * element to the exact height of its parent (respecting the max hint * on the child's height). */ -void +EAPI void evas_object_box_layout_homogeneous_max_size_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) { int remaining, global_pad, pad_inc = 0, sub_pixel = 0; @@ -1355,7 +1329,7 @@ evas_object_box_layout_homogeneous_max_size_horizontal(Evas_Object *o, Evas_Obje * description of its behaviour can be derived from that function's * documentation. */ -void +EAPI void evas_object_box_layout_homogeneous_max_size_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) { int remaining, global_pad, pad_inc = 0, sub_pixel = 0; @@ -1538,7 +1512,7 @@ _evas_object_box_layout_flow_horizontal_row_info_collect(Evas_Object_Box_Data *p * @c align_y dictates positioning relative to the *largest height* * required by a child object in the actual row. */ -void +EAPI void evas_object_box_layout_flow_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) { int n_children, v_justify; @@ -1727,7 +1701,7 @@ _evas_object_box_layout_flow_vertical_col_info_collect(Evas_Object_Box_Data *pri * evas_object_box_layout_flow_horizontal(). The description of its * behaviour can be derived from that function's documentation. */ -void +EAPI void evas_object_box_layout_flow_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) { int n_children; @@ -1863,7 +1837,7 @@ evas_object_box_layout_flow_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, * accounting its horizontal padding properties). Same applies to * vertical axis. */ -void +EAPI void evas_object_box_layout_stack(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) { Eina_List *l; @@ -1914,7 +1888,7 @@ evas_object_box_layout_stack(Evas_Object *o, Evas_Object_Box_Data *priv, void *d /** * Set the alignment of the whole bounding box of contents. */ -void +EAPI void evas_object_box_align_set(Evas_Object *o, double horizontal, double vertical) { EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv); @@ -1928,7 +1902,7 @@ evas_object_box_align_set(Evas_Object *o, double horizontal, double vertical) /** * Get alignment of the whole bounding box of contents. */ -void +EAPI void evas_object_box_align_get(const Evas_Object *o, double *horizontal, double *vertical) { EVAS_OBJECT_BOX_DATA_GET(o, priv); @@ -1947,7 +1921,7 @@ evas_object_box_align_get(const Evas_Object *o, double *horizontal, double *vert /** * Set the space (padding) between cells. */ -void +EAPI void evas_object_box_padding_set(Evas_Object *o, Evas_Coord horizontal, Evas_Coord vertical) { EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv); @@ -1961,7 +1935,7 @@ evas_object_box_padding_set(Evas_Object *o, Evas_Coord horizontal, Evas_Coord ve /** * Get the (space) padding between cells. */ -void +EAPI void evas_object_box_padding_get(const Evas_Object *o, Evas_Coord *horizontal, Evas_Coord *vertical) { EVAS_OBJECT_BOX_DATA_GET(o, priv); @@ -1981,7 +1955,7 @@ evas_object_box_padding_get(const Evas_Object *o, Evas_Coord *horizontal, Evas_C * Append a new object @a child to the box @a o. On error, @c NULL is * returned. */ -Evas_Object_Box_Option * +EAPI Evas_Object_Box_Option * evas_object_box_append(Evas_Object *o, Evas_Object *child) { Evas_Object_Box_Option *opt; @@ -2011,7 +1985,7 @@ evas_object_box_append(Evas_Object *o, Evas_Object *child) * Prepend a new object @a child to the box @a o. On error, @c NULL is * returned. */ -Evas_Object_Box_Option * +EAPI Evas_Object_Box_Option * evas_object_box_prepend(Evas_Object *o, Evas_Object *child) { Evas_Object_Box_Option *opt; @@ -2042,7 +2016,7 @@ evas_object_box_prepend(Evas_Object *o, Evas_Object *child) * reference. If @a reference is not contained in the box or any other * error occurs, @c NULL is returned. */ -Evas_Object_Box_Option * +EAPI Evas_Object_Box_Option * evas_object_box_insert_before(Evas_Object *o, Evas_Object *child, const Evas_Object *reference) { Evas_Object_Box_Option *opt; @@ -2073,7 +2047,7 @@ evas_object_box_insert_before(Evas_Object *o, Evas_Object *child, const Evas_Obj * reference. If @a reference is not contained in the box or any other * error occurs, @c NULL is returend. */ -Evas_Object_Box_Option * +EAPI Evas_Object_Box_Option * evas_object_box_insert_after(Evas_Object *o, Evas_Object *child, const Evas_Object *reference) { Evas_Object_Box_Option *opt; @@ -2103,7 +2077,7 @@ evas_object_box_insert_after(Evas_Object *o, Evas_Object *child, const Evas_Obje * Insert a new object @a child to the box @a o at position @a pos. On * error, @c NULL is returned. */ -Evas_Object_Box_Option * +EAPI Evas_Object_Box_Option * evas_object_box_insert_at(Evas_Object *o, Evas_Object *child, unsigned int pos) { Evas_Object_Box_Option *opt; @@ -2133,7 +2107,7 @@ evas_object_box_insert_at(Evas_Object *o, Evas_Object *child, unsigned int pos) * Remove an object @a child from the box @a o. On error, @c 0 is * returned. */ -Eina_Bool +EAPI Eina_Bool evas_object_box_remove(Evas_Object *o, Evas_Object *child) { const Evas_Object_Box_Api *api; @@ -2163,7 +2137,7 @@ evas_object_box_remove(Evas_Object *o, Evas_Object *child) * Remove an object from the box @a o which occupies position @a * pos. On error, @c 0 is returned. */ -Eina_Bool +EAPI Eina_Bool evas_object_box_remove_at(Evas_Object *o, unsigned int pos) { const Evas_Object_Box_Api *api; @@ -2190,7 +2164,7 @@ evas_object_box_remove_at(Evas_Object *o, unsigned int pos) * Remove all child objects. * @return 0 on errors */ -Eina_Bool +EAPI Eina_Bool evas_object_box_remove_all(Evas_Object *o, Eina_Bool clear) { const Evas_Object_Box_Api *api; @@ -2226,7 +2200,7 @@ evas_object_box_remove_all(Evas_Object *o, Eina_Bool clear) * * @note Do not remove or delete objects while walking the list. */ -Eina_Iterator * +EAPI Eina_Iterator * evas_object_box_iterator_new(const Evas_Object *o) { Evas_Object_Box_Iterator *it; @@ -2255,7 +2229,7 @@ evas_object_box_iterator_new(const Evas_Object *o) * * @note Do not remove or delete objects while walking the list. */ -Eina_Accessor * +EAPI Eina_Accessor * evas_object_box_accessor_new(const Evas_Object *o) { Evas_Object_Box_Accessor *it; @@ -2287,7 +2261,7 @@ evas_object_box_accessor_new(const Evas_Object *o) * It's possible to remove objects from the box when walking this * list, but these removals won't be reflected on it. */ -Eina_List * +EAPI Eina_List * evas_object_box_children_get(const Evas_Object *o) { Eina_List *new_list = NULL, *l; @@ -2305,7 +2279,7 @@ evas_object_box_children_get(const Evas_Object *o) * Get the name of the property of the child elements of the box @a o * whose id is @a property. On error, @c NULL is returned. */ -const char * +EAPI const char * evas_object_box_option_property_name_get(Evas_Object *o, int property) { const Evas_Object_Box_Api *api; @@ -2326,7 +2300,7 @@ evas_object_box_option_property_name_get(Evas_Object *o, int property) * Get the id of the property of the child elements of the box @a o * whose name is @a name. On error, @c -1 is returned. */ -int +EAPI int evas_object_box_option_property_id_get(Evas_Object *o, const char *name) { const Evas_Object_Box_Api *api; @@ -2349,7 +2323,7 @@ evas_object_box_option_property_id_get(Evas_Object *o, const char *name) * must be the last arguments and their type *must* match that of the * property itself. On error, @c 0 is returned. */ -Eina_Bool +EAPI Eina_Bool evas_object_box_option_property_set(Evas_Object *o, Evas_Object_Box_Option *opt, int property, ...) { Eina_Bool ret; @@ -2370,7 +2344,7 @@ evas_object_box_option_property_set(Evas_Object *o, Evas_Object_Box_Option *opt, * is returned. */ -Eina_Bool +EAPI Eina_Bool evas_object_box_option_property_vset(Evas_Object *o, Evas_Object_Box_Option *opt, int property, va_list args) { const Evas_Object_Box_Api *api; @@ -2396,7 +2370,7 @@ evas_object_box_option_property_vset(Evas_Object *o, Evas_Object_Box_Option *opt * be addresses of variables with the same type of that property. On * error, @c 0 is returned. */ -Eina_Bool +EAPI Eina_Bool evas_object_box_option_property_get(Evas_Object *o, Evas_Object_Box_Option *opt, int property, ...) { Eina_Bool ret; @@ -2415,7 +2389,7 @@ evas_object_box_option_property_get(Evas_Object *o, Evas_Object_Box_Option *opt, * va_list @a args is initialized with must be addresses of variables * with the same type of that property. On error, @c 0 is returned. */ -Eina_Bool +EAPI Eina_Bool evas_object_box_option_property_vget(Evas_Object *o, Evas_Object_Box_Option *opt, int property, va_list args) { const Evas_Object_Box_Api *api; diff --git a/legacy/evas/src/lib/canvas/evas_object_smart.c b/legacy/evas/src/lib/canvas/evas_object_smart.c index 3308ae821a..b697298e7e 100644 --- a/legacy/evas/src/lib/canvas/evas_object_smart.c +++ b/legacy/evas/src/lib/canvas/evas_object_smart.c @@ -11,6 +11,7 @@ struct _Evas_Object_Smart void *data; Eina_List *callbacks; Eina_Inlist *contained; + Evas_Smart_Cb_Description_Array callbacks_descriptions; int walking_list; Eina_Bool deletions_waiting : 1; Eina_Bool need_recalculate : 1; @@ -467,6 +468,174 @@ evas_object_smart_callback_call(Evas_Object *obj, const char *event, void *event evas_object_smart_callbacks_clear(obj); } +/** + * Set smart object instance callbacks descriptions. + * + * These descriptions are hints to be used by introspection and are + * not enforced in any way. + * + * It will not be checked if instance callbacks descriptions have the + * same name as another in class. Both are kept in different arrays + * and users of evas_object_smart_callbacks_descriptions_get() should + * handle this case as they wish. + * + * @param obj The smart object + * @param descriptions NULL terminated (name != NULL) array with + * descriptions. Array elements will not be modified, but + * reference to them and their contents will be made, so this + * array should be kept alive during object lifetime. + * @return 1 on success, 0 on failure. + * @ingroup Evas_Smart_Object_Group + * + * @note while instance callbacks descriptions are possible, they are + * not recommended. Use class callbacks descriptions instead as they + * make user's life simpler and will use less memory as descriptions + * and arrays will be shared among all instances. + */ +EAPI Eina_Bool +evas_object_smart_callbacks_descriptions_set(Evas_Object *obj, const Evas_Smart_Cb_Description *descriptions) +{ + const Evas_Smart_Cb_Description *d; + const Evas_Smart_Cb_Description_Array *sa; + Evas_Object_Smart *o; + unsigned int i, count; + + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + return 0; + MAGIC_CHECK_END(); + o = (Evas_Object_Smart *)(obj->object_data); + MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); + return 0; + MAGIC_CHECK_END(); + + if ((!descriptions) || (!descriptions->name)) + { + evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, 0); + return 1; + } + + for (count = 0, d = descriptions; d->name != NULL; d++) + count++; + + evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, count); + for (i = 0, d = descriptions; i < count; d++, i++) + o->callbacks_descriptions.array[i] = d; + + evas_smart_cb_descriptions_fix(&o->callbacks_descriptions); + + return 1; +} + +/** + * Get the callbacks descriptions known by this smart object. + * + * This call retrieves processed callbacks descriptions for both + * instance and class. These arrays are sorted by description's name + * and are @c NULL terminated, so both @a class_count and + * @a instance_count can be ignored, the terminator @c NULL is not + * counted in these values. + * + * @param s the smart object. + * @param class_descriptions where to store class callbacks + * descriptions array, if any is known. If no descriptions are + * known, @c NULL is returned. This parameter may be @c NULL if + * it is not of interest. + * @param class_count returns how many class callbacks descriptions + * are known. + * @param instance_descriptions where to store instance callbacks + * descriptions array, if any is known. If no descriptions are + * known, @c NULL is returned. This parameter may be @c NULL if + * it is not of interest. + * @param instance_count returns how many instance callbacks + * descriptions are known. + * + * @note if just class descriptions are of interest, try + * evas_smart_callbacks_descriptions_get() instead. + * + * @see evas_smart_callbacks_descriptions_get() + * @ingroup Evas_Smart_Object_Group + */ +EAPI void +evas_object_smart_callbacks_descriptions_get(const Evas_Object *obj, const Evas_Smart_Cb_Description ***class_descriptions, unsigned int *class_count, const Evas_Smart_Cb_Description ***instance_descriptions, unsigned int *instance_count) +{ + Evas_Object_Smart *o; + + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + if (class_descriptions) *class_descriptions = NULL; + if (class_count) *class_count = 0; + if (instance_descriptions) *instance_descriptions = NULL; + if (instance_count) *instance_count = 0; + return; + MAGIC_CHECK_END(); + o = (Evas_Object_Smart *)(obj->object_data); + MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); + if (class_descriptions) *class_descriptions = NULL; + if (class_count) *class_count = 0; + if (instance_descriptions) *instance_descriptions = NULL; + if (instance_count) *instance_count = 0; + return; + MAGIC_CHECK_END(); + + if (class_descriptions) + *class_descriptions = obj->smart.smart->callbacks.array; + if (class_count) + *class_count = obj->smart.smart->callbacks.size; + + if (instance_descriptions) + *instance_descriptions = o->callbacks_descriptions.array; + if (instance_count) + *instance_count = o->callbacks_descriptions.size; +} + +/** + * Find callback description for callback called @a name. + * + * @param obj the smart object. + * @param name name of desired callback, must @b not be @c NULL. The + * search have a special case for @a name being the same + * pointer as registered with Evas_Smart_Cb_Description, one + * can use it to avoid excessive use of strcmp(). + * @param class_description pointer to return class description or @c + * NULL if not found. If parameter is @c NULL, no search will + * be done on class descriptions. + * @param instance_description pointer to return instance description + * or @c NULL if not found. If parameter is @c NULL, no search + * will be done on instance descriptions. + * @return reference to description if found, @c NULL if not found. + */ +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) +{ + Evas_Object_Smart *o; + + if (!name) + { + if (class_description) *class_description = NULL; + if (instance_description) *instance_description = NULL; + return; + } + + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + if (class_description) *class_description = NULL; + if (instance_description) *instance_description = NULL; + return; + MAGIC_CHECK_END(); + o = (Evas_Object_Smart *)(obj->object_data); + MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); + if (class_description) *class_description = NULL; + if (instance_description) *instance_description = NULL; + return; + MAGIC_CHECK_END(); + + if (class_description) + *class_description = evas_smart_cb_description_find + (&obj->smart.smart->callbacks, name); + + if (instance_description) + *instance_description = evas_smart_cb_description_find + (&o->callbacks_descriptions, name); +} + /** * Set the need_recalculate flag of given smart object. * diff --git a/legacy/evas/src/lib/canvas/evas_object_table.c b/legacy/evas/src/lib/canvas/evas_object_table.c index 41cee1c566..126acb8566 100644 --- a/legacy/evas/src/lib/canvas/evas_object_table.c +++ b/legacy/evas/src/lib/canvas/evas_object_table.c @@ -813,24 +813,15 @@ _evas_object_table_smart_calculate_regular(Evas_Object *o, Evas_Object_Table_Dat _evas_object_table_calculate_layout_regular(o, priv); } -static Evas_Smart_Class _parent_sc = EVAS_SMART_CLASS_INIT_NULL; +EVAS_SMART_SUBCLASS_NEW("Evas_Object_Table", _evas_object_table, + Evas_Smart_Class, Evas_Smart_Class, + evas_object_smart_clipped_smart_set, NULL) static void _evas_object_table_smart_add(Evas_Object *o) { - Evas_Object_Table_Data *priv; + EVAS_SMART_DATA_ALLOC(o, Evas_Object_Table_Data) - priv = evas_object_smart_data_get(o); - if (!priv) - { - priv = calloc(1, sizeof(*priv)); - if (!priv) - { - ERR("could not allocate object private data."); - return; - } - evas_object_smart_data_set(o, priv); - } priv->pad.h = 0; priv->pad.v = 0; priv->align.h = 0.5; @@ -843,7 +834,7 @@ _evas_object_table_smart_add(Evas_Object *o) priv->expand_h = 0; priv->expand_v = 0; - _parent_sc.add(o); + _evas_object_table_parent_sc.add(o); } static void @@ -865,7 +856,7 @@ _evas_object_table_smart_del(Evas_Object *o) if (priv->cache) _evas_object_table_cache_free(priv->cache); - _parent_sc.del(o); + _evas_object_table_parent_sc.del(o); } static void @@ -896,37 +887,12 @@ _evas_object_table_smart_calculate(Evas_Object *o) } static void -_evas_object_table_smart_set(Evas_Smart_Class *sc) +_evas_object_table_smart_set_user(Evas_Smart_Class *sc) { - if (!sc) - return; - - if (!_parent_sc.name) - evas_object_smart_clipped_smart_set(&_parent_sc); - sc->add = _evas_object_table_smart_add; sc->del = _evas_object_table_smart_del; - sc->move = _parent_sc.move; sc->resize = _evas_object_table_smart_resize; - sc->show = _parent_sc.show; - sc->hide = _parent_sc.hide; - sc->color_set = _parent_sc.color_set; - sc->clip_set = _parent_sc.clip_set; - sc->clip_unset = _parent_sc.clip_unset; sc->calculate = _evas_object_table_smart_calculate; - sc->member_add = _parent_sc.member_add; - sc->member_del = _parent_sc.member_del; -} - -static Evas_Smart * -_evas_object_table_smart_class_new(void) -{ - static Evas_Smart_Class sc = EVAS_SMART_CLASS_INIT_NAME_VERSION("Evas_Object_Table"); - - if (!_parent_sc.name) - _evas_object_table_smart_set(&sc); - - return evas_smart_class_new(&sc); } /** @@ -935,17 +901,10 @@ _evas_object_table_smart_class_new(void) * It's set to non-homogeneous by default, add children with * evas_object_table_pack(). */ -Evas_Object * +EAPI Evas_Object * evas_object_table_add(Evas *evas) { - static Evas_Smart *smart = NULL; - Evas_Object *o; - - if (!smart) - smart = _evas_object_table_smart_class_new(); - - o = evas_object_smart_add(evas, smart); - return o; + return evas_object_smart_add(evas, _evas_object_table_smart_class_new()); } /** @@ -953,7 +912,7 @@ evas_object_table_add(Evas *evas) * * @see evas_object_table_add() */ -Evas_Object * +EAPI Evas_Object * evas_object_table_add_to(Evas_Object *parent) { Evas *evas; @@ -1007,7 +966,7 @@ evas_object_table_add_to(Evas_Object *parent) * no minimum size is provided at all then the table will fallback to * expand mode as well. */ -void +EAPI void evas_object_table_homogeneous_set(Evas_Object *o, Evas_Object_Table_Homogeneous_Mode homogeneous) { EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv); @@ -1023,7 +982,7 @@ evas_object_table_homogeneous_set(Evas_Object *o, Evas_Object_Table_Homogeneous_ * * @see evas_object_table_homogeneous_set() */ -Evas_Object_Table_Homogeneous_Mode +EAPI Evas_Object_Table_Homogeneous_Mode evas_object_table_homogeneous_get(const Evas_Object *o) { EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0); @@ -1033,7 +992,7 @@ evas_object_table_homogeneous_get(const Evas_Object *o) /** * Set the alignment of the whole bounding box of contents. */ -void +EAPI void evas_object_table_align_set(Evas_Object *o, double horizontal, double vertical) { EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv); @@ -1047,7 +1006,7 @@ evas_object_table_align_set(Evas_Object *o, double horizontal, double vertical) /** * Get alignment of the whole bounding box of contents. */ -void +EAPI void evas_object_table_align_get(const Evas_Object *o, double *horizontal, double *vertical) { EVAS_OBJECT_TABLE_DATA_GET(o, priv); @@ -1066,7 +1025,7 @@ evas_object_table_align_get(const Evas_Object *o, double *horizontal, double *ve /** * Set padding between cells. */ -void +EAPI void evas_object_table_padding_set(Evas_Object *o, Evas_Coord horizontal, Evas_Coord vertical) { EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv); @@ -1081,7 +1040,7 @@ evas_object_table_padding_set(Evas_Object *o, Evas_Coord horizontal, Evas_Coord /** * Get padding between cells. */ -void +EAPI void evas_object_table_padding_get(const Evas_Object *o, Evas_Coord *horizontal, Evas_Coord *vertical) { EVAS_OBJECT_TABLE_DATA_GET(o, priv); @@ -1109,7 +1068,7 @@ evas_object_table_padding_get(const Evas_Object *o, Evas_Coord *horizontal, Evas * * @return 1 on success, 0 on failure. */ -Eina_Bool +EAPI Eina_Bool evas_object_table_pack(Evas_Object *o, Evas_Object *child, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan) { Evas_Object_Table_Option *opt; @@ -1232,7 +1191,7 @@ _evas_object_table_remove_opt(Evas_Object_Table_Data *priv, Evas_Object_Table_Op * * @return 1 on success, 0 on failure. */ -Eina_Bool +EAPI Eina_Bool evas_object_table_unpack(Evas_Object *o, Evas_Object *child) { Evas_Object_Table_Option *opt; @@ -1268,7 +1227,7 @@ evas_object_table_unpack(Evas_Object *o, Evas_Object *child) * @param o The given table object. * @param clear if true, it will delete just removed children. */ -void +EAPI void evas_object_table_clear(Evas_Object *o, Eina_Bool clear) { Evas_Object_Table_Option *opt; @@ -1298,7 +1257,7 @@ evas_object_table_clear(Evas_Object *o, Eina_Bool clear) * difference for a single cell table is that paddings will be * accounted proportionally. */ -void +EAPI void evas_object_table_col_row_size_get(const Evas_Object *o, int *cols, int *rows) { EVAS_OBJECT_TABLE_DATA_GET(o, priv); @@ -1319,7 +1278,7 @@ evas_object_table_col_row_size_get(const Evas_Object *o, int *cols, int *rows) * * @note Do not remove or delete objects while walking the list. */ -Eina_Iterator * +EAPI Eina_Iterator * evas_object_table_iterator_new(const Evas_Object *o) { Evas_Object_Table_Iterator *it; @@ -1348,7 +1307,7 @@ evas_object_table_iterator_new(const Evas_Object *o) * * @note Do not remove or delete objects while walking the list. */ -Eina_Accessor * +EAPI Eina_Accessor * evas_object_table_accessor_new(const Evas_Object *o) { Evas_Object_Table_Accessor *it; @@ -1380,7 +1339,7 @@ evas_object_table_accessor_new(const Evas_Object *o) * It's possible to remove objects from the table when walking this * list, but these removals won't be reflected on it. */ -Eina_List * +EAPI Eina_List * evas_object_table_children_get(const Evas_Object *o) { Eina_List *new_list = NULL, *l; diff --git a/legacy/evas/src/lib/canvas/evas_smart.c b/legacy/evas/src/lib/canvas/evas_smart.c index 83309dcb8b..861b00198d 100644 --- a/legacy/evas/src/lib/canvas/evas_smart.c +++ b/legacy/evas/src/lib/canvas/evas_smart.c @@ -1,6 +1,9 @@ #include "evas_common.h" #include "evas_private.h" + +static void _evas_smart_class_callbacks_create(Evas_Smart *s); + /* all public */ /** @@ -142,6 +145,7 @@ evas_smart_class_new(const Evas_Smart_Class *sc) s->magic = MAGIC_SMART; s->smart_class = sc; + _evas_smart_class_callbacks_create(s); return s; } @@ -179,6 +183,118 @@ evas_smart_data_get(const Evas_Smart *s) return (void *)s->smart_class->data; } +/** + * Get the callbacks known by this Evas_Smart. + * + * This is likely different from Evas_Smart_Class::callbacks as it + * will contain the callbacks of all class hierarchy sorted, while the + * direct smart class member refers only to that specific class and + * should not include parent's. + * + * If no callbacks are known, this function returns @c NULL. + * + * The array elements and thus their contents will be reference to + * original values given to evas_smart_new() as + * Evas_Smart_Class::callbacks. + * + * The array is sorted by name. The last array element is the @c NULL + * pointer and is not counted in @a count. Loop iterations can check + * any of these cases. + * + * @param s the Evas_Smart. + * @param count returns the number of elements in returned array. + * @return the array with callback descriptions known by this class, + * its size is returned in @a count parameter. It should not + * be modified anyhow. If no callbacks are known, @c NULL is + * returned. The array is sorted by name and elements refer to + * the original value given to evas_smart_new(). + * + * @note objects may provide per-instance callbacks, use + * evas_object_smart_callbacks_descriptions_get() to get those + * as well. + * @see evas_object_smart_callbacks_descriptions_get() + */ +EAPI const Evas_Smart_Cb_Description ** +evas_smart_callbacks_descriptions_get(const Evas_Smart *s, unsigned int *count) +{ + MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART); + if (count) *count = 0; + return NULL; + MAGIC_CHECK_END(); + + if (count) *count = s->callbacks.size; + return s->callbacks.array; +} + +/** + * Find callback description for callback called @a name. + * + * @param s the Evas_Smart. + * @param name name of desired callback, must @b not be @c NULL. The + * search have a special case for @a name being the same + * pointer as registered with Evas_Smart_Cb_Description, one + * can use it to avoid excessive use of strcmp(). + * @return reference to description if found, @c NULL if not found. + */ +EAPI const Evas_Smart_Cb_Description * +evas_smart_callback_description_find(const Evas_Smart *s, const char *name) +{ + if (!name) return NULL; + MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART); + return NULL; + MAGIC_CHECK_END(); + return evas_smart_cb_description_find(&s->callbacks, name); +} + +/** + * Sets one class to inherit from the other. + * + * Copy all function pointers, set @c parent to @a parent_sc and copy + * everything after sizeof(Evas_Smart_Class) present in @a parent_sc, + * using @a parent_sc_size as reference. + * + * This is recommended instead of a single memcpy() since it will take + * care to not modify @a sc name, version, callbacks and possible + * other members. + * + * @param sc child class. + * @param parent_sc parent class, will provide attributes. + * @param parent_sc_size size of parent_sc structure, child should be at least + * this size. Everything after @c Evas_Smart_Class size is copied + * using regular memcpy(). + */ +EAPI Eina_Bool +evas_smart_class_inherit_full(Evas_Smart_Class *sc, const Evas_Smart_Class *parent_sc, unsigned int parent_sc_size) +{ + unsigned int off; + + /* api does not match abi! for now refuse as we only have 1 version */ + if (parent_sc->version != EVAS_SMART_CLASS_VERSION) return 0; + +#define _CP(m) sc->m = parent_sc->m + _CP(add); + _CP(del); + _CP(move); + _CP(resize); + _CP(show); + _CP(hide); + _CP(color_set); + _CP(clip_set); + _CP(clip_unset); + _CP(calculate); + _CP(member_add); + _CP(member_del); +#undef _CP + + sc->parent = parent_sc; + + off = sizeof(Evas_Smart_Class); + if (parent_sc_size == off) return 1; + + memcpy(((char *)sc) + off, ((char *)parent_sc) + off, parent_sc_size - off); + return 1; +} + /** * @} */ @@ -196,3 +312,122 @@ evas_object_smart_unuse(Evas_Smart *s) s->usage--; if ((s->usage <= 0) && (s->delete_me)) evas_smart_free(s); } + +Eina_Bool +evas_smart_cb_descriptions_resize(Evas_Smart_Cb_Description_Array *a, unsigned int size) +{ + void *tmp; + + if (size == a->size) + return 1; + + if (size == 0) + { + free(a->array); + a->array = NULL; + a->size = 0; + return 1; + } + + tmp = realloc(a->array, (size + 1) * sizeof(Evas_Smart_Cb_Description *)); + if (tmp) + { + a->array = tmp; + a->size = size; + a->array[size] = NULL; + return 1; + } + else + { + fprintf(stderr, "ERROR: realloc failed!\n"); + return 0; + } +} + +static int +_evas_smart_cb_description_cmp_sort(const void *p1, const void *p2) +{ + const Evas_Smart_Cb_Description * const*a = p1, * const*b = p2; + return strcmp((*a)->name, (*b)->name); +} + +void +evas_smart_cb_descriptions_fix(Evas_Smart_Cb_Description_Array *a) +{ + unsigned int i, j; + + qsort(a->array, a->size, sizeof(Evas_Smart_Cb_Description *), + _evas_smart_cb_description_cmp_sort); + + fprintf(stderr, "\nDEBUG: %u callbacks\n", a->size); + if (a->size) + fprintf(stderr, "DEBUG: %20.20s [%s]\n", a->array[0]->name, a->array[1]->type); + + for (i = 0, j = 1; j < a->size; j++) + { + const Evas_Smart_Cb_Description *cur, *prev; + + cur = a->array[j]; + prev = a->array[i]; + + fprintf(stderr, "DEBUG: %20.20s [%s]\n", cur->name, cur->type); + + if (strcmp(cur->name, prev->name) != 0) + { + i++; + if (i != j) + a->array[i] = a->array[j]; + } + else + { + if (strcmp(cur->type, prev->type) == 0) + fprintf(stderr, "WARNING: duplicated smart callback description name '%s', type '%s'\n", cur->name, cur->type); + else + fprintf(stderr, "ERROR: callback description named '%s' differ, keep '%s', ignore '%s'\n", cur->name, prev->type, cur->type); + } + } + + evas_smart_cb_descriptions_resize(a, a->size - (j - i)); +} + +static void +_evas_smart_class_callbacks_create(Evas_Smart *s) +{ + const Evas_Smart_Class *sc; + unsigned int n = 0; + + for (sc = s->smart_class; sc != NULL; sc = sc->parent) + { + const Evas_Smart_Cb_Description *d; + for (d = sc->callbacks; d && d->name != NULL; d++) + n++; + } + + if (n == 0) return; + if (!evas_smart_cb_descriptions_resize(&s->callbacks, n)) return; + for (n = 0, sc = s->smart_class; sc != NULL; sc = sc->parent) + { + const Evas_Smart_Cb_Description *d; + for (d = sc->callbacks; d->name != NULL; d++) + s->callbacks.array[n++] = d; + } + evas_smart_cb_descriptions_fix(&s->callbacks); +} + +static int +_evas_smart_cb_description_cmp_search(const void *p1, const void *p2) +{ + const char *name = p1; + const Evas_Smart_Cb_Description * const*v = p2; + /* speed up string shares searches (same pointers) */ + if (name == (*v)->name) return 0; + return strcmp(name, (*v)->name); +} + +const Evas_Smart_Cb_Description * +evas_smart_cb_description_find(const Evas_Smart_Cb_Description_Array *a, const char *name) +{ + if (!a->array) return NULL; + return bsearch(name, a->array, a->size, sizeof(Evas_Smart_Cb_Description *), + _evas_smart_cb_description_cmp_search); +} diff --git a/legacy/evas/src/lib/include/evas_private.h b/legacy/evas/src/lib/include/evas_private.h index 8eda2f0716..2d88328e30 100644 --- a/legacy/evas/src/lib/include/evas_private.h +++ b/legacy/evas/src/lib/include/evas_private.h @@ -49,6 +49,7 @@ typedef struct _Evas_Key_Grab Evas_Key_Grab; 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; #define MAGIC_EVAS 0x70777770 #define MAGIC_OBJ 0x71777770 @@ -173,6 +174,12 @@ struct _Evas_Intercept_Func Evas_Intercept_Func_Basic clip_unset; }; +struct _Evas_Smart_Cb_Description_Array +{ + unsigned int size; + const Evas_Smart_Cb_Description **array; +}; + struct _Evas_Smart { DATA32 magic; @@ -181,6 +188,8 @@ struct _Evas_Smart const Evas_Smart_Class *smart_class; + Evas_Smart_Cb_Description_Array callbacks; + unsigned char delete_me : 1; unsigned char class_allocated : 1; @@ -761,6 +770,10 @@ void evas_debug_generic(const char *str); const char *evas_debug_magic_string_get(DATA32 magic); void evas_object_smart_use(Evas_Smart *s); void evas_object_smart_unuse(Evas_Smart *s); +void evas_smart_cb_descriptions_fix(Evas_Smart_Cb_Description_Array *a) EINA_ARG_NONNULL(1); +Eina_Bool evas_smart_cb_descriptions_resize(Evas_Smart_Cb_Description_Array *a, unsigned int size) EINA_ARG_NONNULL(1); +const Evas_Smart_Cb_Description *evas_smart_cb_description_find(const Evas_Smart_Cb_Description_Array *a, const char *name) EINA_ARG_NONNULL(1, 2) EINA_PURE; + void evas_object_smart_del(Evas_Object *obj); void evas_object_smart_cleanup(Evas_Object *obj); void evas_object_smart_member_raise(Evas_Object *member);