From 58a49c2f6967deb83b441373bc26b8e3c003635e Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Sun, 7 Sep 2008 01:25:49 +0000 Subject: [PATCH] Add calculate callback to Evas_Smart_Class. Some people is using it for some time now without problems, so I'm adding it to SVN to get some broader use. Remember to recompile ALL libraries that depend on Evas as it will change the EVAS_SMART_CLASS_VERSION and old classes will fail to load. This will also change Edje so it will postpone _edje_recalc() to render time, calculate() callback, however some methods will force early recalculation. SVN revision: 35860 --- legacy/edje/src/lib/edje_calc.c | 12 +- legacy/edje/src/lib/edje_private.h | 2 + legacy/edje/src/lib/edje_smart.c | 12 ++ legacy/edje/src/lib/edje_util.c | 56 ++++++- legacy/emotion/src/lib/emotion_smart.c | 1 + legacy/evas/src/lib/Evas.h | 8 +- legacy/evas/src/lib/canvas/evas_main.c | 1 + .../evas/src/lib/canvas/evas_object_smart.c | 158 ++++++++++++++++++ legacy/evas/src/lib/canvas/evas_render.c | 2 + legacy/evas/src/lib/include/evas_private.h | 2 + 10 files changed, 248 insertions(+), 6 deletions(-) diff --git a/legacy/edje/src/lib/edje_calc.c b/legacy/edje/src/lib/edje_calc.c index f62f26ab9d..37a41edd77 100644 --- a/legacy/edje/src/lib/edje_calc.c +++ b/legacy/edje/src/lib/edje_calc.c @@ -135,6 +135,14 @@ _edje_part_description_apply(Edje *ed, Edje_Real_Part *ep, const char *d1, doubl void _edje_recalc(Edje *ed) +{ + if (ed->postponed) return ; + evas_object_smart_changed(ed->obj); + ed->postponed = 1; +} + +void +_edje_recalc_do(Edje *ed) { int i; @@ -142,7 +150,8 @@ _edje_recalc(Edje *ed) if (ed->freeze) { ed->recalc = 1; - if (!ed->calc_only) return; + if (!ed->calc_only && + !ed->postponed) return; } for (i = 0; i < ed->table_parts_size; i++) { @@ -161,6 +170,7 @@ _edje_recalc(Edje *ed) _edje_part_recalc(ed, ep, (~ep->calculated) & FLAG_XY); } ed->dirty = 0; + ed->postponed = 0; if (!ed->calc_only) ed->recalc = 0; } diff --git a/legacy/edje/src/lib/edje_private.h b/legacy/edje/src/lib/edje_private.h index 4bc95ccfea..603ab3ef5e 100644 --- a/legacy/edje/src/lib/edje_private.h +++ b/legacy/edje/src/lib/edje_private.h @@ -681,6 +681,7 @@ struct _Edje unsigned short walking_actions : 1; unsigned short block_break : 1; unsigned short delete_me : 1; + unsigned short postponed : 1; }; struct _Edje_Real_Part @@ -1007,6 +1008,7 @@ void _edje_part_pos_set(Edje *ed, Edje_Real_Part *ep, int mode, double pos); Edje_Part_Description *_edje_part_description_find(Edje *ed, Edje_Real_Part *rp, const char *name, double val); void _edje_part_description_apply(Edje *ed, Edje_Real_Part *ep, const char *d1, double v1, const char *d2, double v2); void _edje_recalc(Edje *ed); +void _edje_recalc_do(Edje *ed); int _edje_part_dragable_calc(Edje *ed, Edje_Real_Part *ep, double *x, double *y); void _edje_dragable_pos_set(Edje *ed, Edje_Real_Part *ep, double x, double y); diff --git a/legacy/edje/src/lib/edje_smart.c b/legacy/edje/src/lib/edje_smart.c index b4f027ff5e..a3b23abc53 100644 --- a/legacy/edje/src/lib/edje_smart.c +++ b/legacy/edje/src/lib/edje_smart.c @@ -13,6 +13,7 @@ static void _edje_smart_hide(Evas_Object * obj); static void _edje_smart_color_set(Evas_Object * obj, int r, int g, int b, int a); static void _edje_smart_clip_set(Evas_Object * obj, Evas_Object * clip); static void _edje_smart_clip_unset(Evas_Object * obj); +static void _edje_smart_calculate(Evas_Object * obj); static Evas_Smart *_edje_smart = NULL; @@ -45,6 +46,7 @@ edje_object_add(Evas *evas) _edje_smart_color_set, _edje_smart_clip_set, _edje_smart_clip_unset, + _edje_smart_calculate, NULL }; _edje_smart = evas_smart_class_new(&sc); @@ -237,3 +239,13 @@ _edje_smart_clip_unset(Evas_Object * obj) evas_object_clip_unset(ed->clipper); // _edje_emit(ed, "clip_unset", NULL); } + +static void +_edje_smart_calculate(Evas_Object *obj) +{ + Edje *ed; + + ed = evas_object_smart_data_get(obj); + if (!ed) return; + _edje_recalc_do(ed); +} diff --git a/legacy/edje/src/lib/edje_util.c b/legacy/edje/src/lib/edje_util.c index 4d91bd62ee..ec3eb3f924 100644 --- a/legacy/edje/src/lib/edje_util.c +++ b/legacy/edje/src/lib/edje_util.c @@ -715,6 +715,10 @@ edje_object_part_object_get(const Evas_Object *obj, const char *part) ed = _edje_fetch(obj); if ((!ed) || (!part)) return NULL; + + /* Need to recalc before providing the object. */ + _edje_recalc_do(ed); + rp = _edje_real_part_recursive_get(ed, (char *)part); if (!rp) return NULL; return rp->object; @@ -748,6 +752,10 @@ edje_object_part_geometry_get(const Evas_Object *obj, const char *part, Evas_Coo if (h) *h = 0; return; } + + /* Need to recalc before providing the object. */ + _edje_recalc_do(ed); + rp = _edje_real_part_recursive_get(ed, (char *)part); if (!rp) { @@ -828,6 +836,10 @@ edje_object_part_text_get(const Evas_Object *obj, const char *part) ed = _edje_fetch(obj); if ((!ed) || (!part)) return NULL; + + /* Need to recalc before providing the object. */ + _edje_recalc_do(ed); + rp = _edje_real_part_recursive_get(ed, (char *)part); if (!rp) return NULL; if (rp->part->type == EDJE_PART_TYPE_TEXT) @@ -855,6 +867,10 @@ edje_object_part_swallow(Evas_Object *obj, const char *part, Evas_Object *obj_sw ed = _edje_fetch(obj); if ((!ed) || (!part)) return; + + /* Need to recalc before providing the object. */ + _edje_recalc_do(ed); + rp = _edje_real_part_recursive_get(ed, (char *)part); if (!rp) return; if (rp->part->type != EDJE_PART_TYPE_SWALLOW) return; @@ -1021,7 +1037,7 @@ edje_object_part_unswallow(Evas_Object *obj, Evas_Object *obj_swallow) rp->swallow_params.max.w = 0; rp->swallow_params.max.h = 0; rp->edje->dirty = 1; - _edje_recalc(rp->edje); + _edje_recalc_do(rp->edje); return; } } @@ -1039,6 +1055,10 @@ edje_object_part_swallow_get(const Evas_Object *obj, const char *part) ed = _edje_fetch(obj); if ((!ed) || (!part)) return NULL; + + /* Need to recalc before providing the object. */ + _edje_recalc_do(ed); + rp = _edje_real_part_recursive_get(ed, (char *)part); if (!rp) return NULL; return rp->swallowed_object; @@ -1088,6 +1108,10 @@ edje_object_size_max_get(const Evas_Object *obj, Evas_Coord *maxw, Evas_Coord *m if (maxh) *maxh = 0; return; } + + /* Need to recalc before providing the object. */ + _edje_recalc_do(ed); + if (ed->collection->prop.max.w == 0) { /* XXX TODO: convert maxw to 0, fix things that break. */ @@ -1125,7 +1149,7 @@ edje_object_calc_force(Evas_Object *obj) ed->dirty = 1; pf = ed->freeze; ed->freeze = 0; - _edje_recalc(ed); + _edje_recalc_do(ed); ed->freeze = pf; } @@ -1187,7 +1211,7 @@ edje_object_size_min_restricted_calc(Evas_Object *obj, Evas_Coord *minw, Evas_Co ok = 0; ed->dirty = 1; - _edje_recalc(ed); + _edje_recalc_do(ed); if (reset_maxwh) { maxw = 0; @@ -1291,6 +1315,10 @@ edje_object_part_state_get(const Evas_Object *obj, const char *part, double *val if (val_ret) *val_ret = 0; return ""; } + + /* Need to recalc before providing the object. */ + _edje_recalc_do(ed); + rp = _edje_real_part_recursive_get(ed, (char *)part); if (!rp) { @@ -1335,6 +1363,10 @@ edje_object_part_drag_dir_get(const Evas_Object *obj, const char *part) ed = _edje_fetch(obj); if ((!ed) || (!part)) return EDJE_DRAG_DIR_NONE; + + /* Need to recalc before providing the object. */ + _edje_recalc_do(ed); + rp = _edje_real_part_recursive_get(ed, (char *)part); if (!rp) return EDJE_DRAG_DIR_NONE; if ((rp->part->dragable.x) && (rp->part->dragable.y)) return EDJE_DRAG_DIR_XY; @@ -1399,6 +1431,10 @@ edje_object_part_drag_value_get(const Evas_Object *obj, const char *part, double if (dy) *dy = 0; return; } + + /* Need to recalc before providing the object. */ + _edje_recalc_do(ed); + rp = _edje_real_part_recursive_get(ed, (char *)part); if (!rp) { @@ -1464,6 +1500,10 @@ edje_object_part_drag_size_get(const Evas_Object *obj, const char *part, double if (dh) *dh = 0; return; } + + /* Need to recalc before providing the object. */ + _edje_recalc_do(ed); + rp = _edje_real_part_recursive_get(ed, (char *)part); if (!rp) { @@ -1522,6 +1562,10 @@ edje_object_part_drag_step_get(const Evas_Object *obj, const char *part, double if (dy) *dy = 0; return; } + + /* Need to recalc before providing the object. */ + _edje_recalc_do(ed); + rp = _edje_real_part_recursive_get(ed, (char *)part); if (!rp) { @@ -1580,6 +1624,10 @@ edje_object_part_drag_page_get(const Evas_Object *obj, const char *part, double if (dy) *dy = 0; return; } + + /* Need to recalc before providing the object. */ + _edje_recalc_do(ed); + rp = _edje_real_part_recursive_get(ed, (char *)part); if (!rp) { @@ -2097,5 +2145,5 @@ _edje_real_part_swallow(Edje_Real_Part *rp, Evas_Object *obj_swallow) evas_object_precise_is_inside_set(obj_swallow, 1); rp->edje->dirty = 1; - _edje_recalc(rp->edje); + _edje_recalc_do(rp->edje); } diff --git a/legacy/emotion/src/lib/emotion_smart.c b/legacy/emotion/src/lib/emotion_smart.c index 5943820564..848bc2ea29 100644 --- a/legacy/emotion/src/lib/emotion_smart.c +++ b/legacy/emotion/src/lib/emotion_smart.c @@ -1164,6 +1164,7 @@ _smart_init(void) _smart_color_set, _smart_clip_set, _smart_clip_unset, + NULL, NULL }; smart = evas_smart_class_new(&sc); diff --git a/legacy/evas/src/lib/Evas.h b/legacy/evas/src/lib/Evas.h index 73156d6cf9..e5c1e44428 100644 --- a/legacy/evas/src/lib/Evas.h +++ b/legacy/evas/src/lib/Evas.h @@ -137,7 +137,7 @@ typedef enum _Evas_Aspect_Control } Evas_Aspect_Control; -#define EVAS_SMART_CLASS_VERSION 1 /** the version you have to put into the version field in the smart class struct */ +#define EVAS_SMART_CLASS_VERSION 2 /** 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 */ @@ -153,6 +153,7 @@ struct _Evas_Smart_Class /** a smart object class */ void (*color_set) (Evas_Object *o, int r, int g, int b, int a); // FIXME: DELETE ME void (*clip_set) (Evas_Object *o, Evas_Object *clip); // FIXME: DELETE ME void (*clip_unset) (Evas_Object *o); // FIXME: DELETE ME + void (*calculate) (Evas_Object *o); const void *data; }; @@ -767,6 +768,11 @@ extern "C" { EAPI void evas_object_smart_callback_add (Evas_Object *obj, const char *event, void (*func) (void *data, Evas_Object *obj, void *event_info), const void *data); EAPI void *evas_object_smart_callback_del (Evas_Object *obj, const char *event, void (*func) (void *data, Evas_Object *obj, void *event_info)); EAPI void evas_object_smart_callback_call (Evas_Object *obj, const char *event, void *event_info); + EAPI void evas_object_smart_changed (Evas_Object *obj); + EAPI void evas_object_smart_need_recalculate_set(Evas_Object *obj, Evas_Bool value); + EAPI Evas_Bool evas_object_smart_need_recalculate_get(Evas_Object *obj); + EAPI void evas_object_smart_calculate (Evas_Object *obj); + /* events */ EAPI void evas_event_freeze (Evas *e); diff --git a/legacy/evas/src/lib/canvas/evas_main.c b/legacy/evas/src/lib/canvas/evas_main.c index 27b3ce6ed8..1a9b34c8bb 100644 --- a/legacy/evas/src/lib/canvas/evas_main.c +++ b/legacy/evas/src/lib/canvas/evas_main.c @@ -70,6 +70,7 @@ evas_new(void) evas_array_setup(&e->pending_objects, 16); evas_array_setup(&e->obscuring_objects, 16); evas_array_setup(&e->temporary_objects, 16); + evas_array_setup(&e->calculate_objects, 16); return e; } diff --git a/legacy/evas/src/lib/canvas/evas_object_smart.c b/legacy/evas/src/lib/canvas/evas_object_smart.c index 811cb813a7..608a8282c7 100644 --- a/legacy/evas/src/lib/canvas/evas_object_smart.c +++ b/legacy/evas/src/lib/canvas/evas_object_smart.c @@ -13,6 +13,7 @@ struct _Evas_Object_Smart Evas_Object_List *contained; int walking_list; Evas_Bool deletions_waiting : 1; + Evas_Bool need_recalculate : 1; }; struct _Evas_Smart_Callback @@ -436,6 +437,163 @@ evas_object_smart_callback_call(Evas_Object *obj, const char *event, void *event evas_object_smart_callbacks_clear(obj); } +/** + * Set the need_recalculate flag of given smart object. + * + * If this flag is set then calculate() callback (method) of the given + * smart object will be called, if one is provided, during render phase + * usually evas_render(). After this step, this flag will be automatically + * unset. + * + * If no calculate() is provided, this flag will be left unchanged. + * + * @note just setting this flag will not make scene dirty and evas_render() + * will have no effect. To do that, use evas_object_smart_changed(), + * that will automatically call this function with 1 as parameter. + * + * @param obj the smart object + * @param value if one want to set or unset the need_recalculate flag. + * + * @ingroup Evas_Smart_Object_Group + */ +EAPI void +evas_object_smart_need_recalculate_set(Evas_Object *obj, Evas_Bool value) +{ + Evas_Object_Smart *o; + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + return; + MAGIC_CHECK_END(); + o = obj->object_data; + MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); + return; + MAGIC_CHECK_END(); + + value = !!value; + if (o->need_recalculate == value) + return; + o->need_recalculate = value; + + if (!obj->smart.smart->smart_class->calculate) + return; + + /* XXX: objects can be present multiple times in calculate_objects() + * XXX: after a set-unset-set cycle, but it's not a problem since + * XXX: on _evas_render_call_smart_calculate() will check for the flag + * XXX: and it will be unset after the first. + */ + if (o->need_recalculate) + { + Evas *e; + e = obj->layer->evas; + _evas_array_append(&e->calculate_objects, obj); + } + /* TODO: else, remove from array */ +} + +/** + * Get the current value of need_recalculate flag. + * + * @note this flag will be unset during the render phase, after calculate() + * is called if one is provided. If no calculate() is provided, then + * the flag will be left unchanged after render phase. + * + * @param obj the smart object + * @return if flag is set or not. + * + * @ingroup Evas_Smart_Object_Group + */ +EAPI Evas_Bool +evas_object_smart_need_recalculate_get(Evas_Object *obj) +{ + Evas_Object_Smart *o; + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + return; + MAGIC_CHECK_END(); + o = obj->object_data; + MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); + return; + MAGIC_CHECK_END(); + + return o->need_recalculate; +} + +/** + * Call user provided calculate() and unset need_calculate. + * + * @param obj the smart object + * @return if flag is set or not. + * + * @ingroup Evas_Smart_Object_Group + */ +EAPI void +evas_object_smart_calculate(Evas_Object *obj) +{ + Evas_Object_Smart *o; + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + return; + MAGIC_CHECK_END(); + o = obj->object_data; + MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); + return; + MAGIC_CHECK_END(); + + if (obj->smart.smart->smart_class->calculate) + obj->smart.smart->smart_class->calculate(obj); + o->need_recalculate = 0; +} + +/** + * Call calculate() on all smart objects that need_recalculate. + * + * @internal + */ +void +evas_call_smarts_calculate(Evas *e) +{ + Evas_Array *calculate; + unsigned int i; + + calculate = &e->calculate_objects; + for (i = 0; i < calculate->count; ++i) + { + Evas_Object *obj; + Evas_Object_Smart *o; + + obj = _evas_array_get(calculate, i); + if (obj->delete_me) + continue; + + o = obj->object_data; + if (o->need_recalculate) + { + obj->smart.smart->smart_class->calculate(obj); + o->need_recalculate = 0; + } + } + + evas_array_flush(calculate); +} + +/** + * Mark smart object as changed, dirty. + * + * This will inform the scene that it changed and needs to be redraw, also + * setting need_recalculate on the given object. + * + * @see evas_object_smart_need_recalculate_set(). + * + * @ingroup Evas_Smart_Object_Group + */ +EAPI void +evas_object_smart_changed(Evas_Object *obj) +{ + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + return; + MAGIC_CHECK_END(); + evas_object_change(obj); + evas_object_smart_need_recalculate_set(obj, 1); +} + /* internal calls */ static void evas_object_smart_callbacks_clear(Evas_Object *obj) diff --git a/legacy/evas/src/lib/canvas/evas_render.c b/legacy/evas/src/lib/canvas/evas_render.c index 8eb6a9670c..c36d4389b4 100644 --- a/legacy/evas/src/lib/canvas/evas_render.c +++ b/legacy/evas/src/lib/canvas/evas_render.c @@ -341,6 +341,8 @@ evas_render_updates_internal(Evas *e, unsigned char make_updates, unsigned char MAGIC_CHECK_END(); if (!e->changed) return NULL; + evas_call_smarts_calculate(e); + /* Check if the modified object mean recalculating every thing */ if (!e->invalidate) _evas_render_check_pending_objects(&e->pending_objects, e); diff --git a/legacy/evas/src/lib/include/evas_private.h b/legacy/evas/src/lib/include/evas_private.h index d2d56710ba..2f6a790a1b 100644 --- a/legacy/evas/src/lib/include/evas_private.h +++ b/legacy/evas/src/lib/include/evas_private.h @@ -288,6 +288,7 @@ struct _Evas Evas_Array pending_objects; Evas_Array obscuring_objects; Evas_Array temporary_objects; + Evas_Array calculate_objects; int delete_grabs; int walking_grabs; @@ -713,6 +714,7 @@ void evas_object_smart_member_lower(Evas_Object *member); void evas_object_smart_member_stack_above(Evas_Object *member, Evas_Object *other); void evas_object_smart_member_stack_below(Evas_Object *member, Evas_Object *other); const Evas_Object_List *evas_object_smart_members_get_direct(const Evas_Object *obj); +void evas_call_smarts_calculate(Evas *e); void *evas_mem_calloc(int size); void evas_object_event_callback_all_del(Evas_Object *obj); void evas_object_event_callback_cleanup(Evas_Object *obj);