diff --git a/legacy/evas/ChangeLog b/legacy/evas/ChangeLog index 7384d7caa3..bb57011be3 100644 --- a/legacy/evas/ChangeLog +++ b/legacy/evas/ChangeLog @@ -461,3 +461,7 @@ * Textblock: Added evas_textblock_cursor_visible_range_get which updates the cursors to the ends of the area currently visible on screen. + +2011-08-17 Tom Hacohen (TAsn) + + * Callbacks: Added priority support to callbacks. diff --git a/legacy/evas/src/lib/Evas.h b/legacy/evas/src/lib/Evas.h index 5b9a58fa7e..b779408803 100644 --- a/legacy/evas/src/lib/Evas.h +++ b/legacy/evas/src/lib/Evas.h @@ -432,6 +432,39 @@ typedef enum _Evas_Callback_Type EVAS_CALLBACK_LAST /**< kept as last element/sentinel -- not really an event */ } Evas_Callback_Type; /**< The types of events triggering a callback */ +/** + * @def EVAS_CALLBACK_PRIORITY_BEFORE + * Slightly more prioritized than default. + * @since 1.1.0 + */ +#define EVAS_CALLBACK_PRIORITY_BEFORE -100 +/** + * @def EVAS_CALLBACK_PRIORITY_DEFAULT + * Default callback priority level + * @since 1.1.0 + */ +#define EVAS_CALLBACK_PRIORITY_DEFAULT 0 +/** + * @def EVAS_CALLBACK_PRIORITY_AFTER + * Slightly less prioritized than default. + * @since 1.1.0 + */ +#define EVAS_CALLBACK_PRIORITY_AFTER 100 + +/** + * @typedef Evas_Callback_Priority + * + * Callback priority value. Range is -32k - 32k. The lower the number, the + * bigger the priority. + * + * @see EVAS_CALLBACK_PRIORITY_AFTER + * @see EVAS_CALLBACK_PRIORITY_BEFORE + * @see EVAS_CALLBACK_PRIORITY_DEFAULT + * + * @since 1.1.0 + */ +typedef short Evas_Callback_Priority; + /** * Flags for Mouse Button events */ @@ -2103,6 +2136,23 @@ EAPI Eina_Bool evas_pointer_inside_get (const Evas *e) EINA_WA */ EAPI void evas_event_callback_add (Evas *e, Evas_Callback_Type type, Evas_Event_Cb func, const void *data) EINA_ARG_NONNULL(1, 3); +/** + * Add (register) a callback function to a given canvas event with a + * non-default priority set. Except for the priority field, it's exactly the + * same as @ref evas_event_callback_add + * + * @param e Canvas to attach a callback to + * @param type The type of event that will trigger the callback + * @param priority The priority of the callback, lower values called first. + * @param func The (callback) function to be called when the event is + * triggered + * @param data The data pointer to be passed to @p func + * + * @see evas_event_callback_add + * @since 1.1.0 + */ +EAPI void evas_event_callback_priority_add(Evas *e, Evas_Callback_Type type, Evas_Callback_Priority priority, Evas_Event_Cb func, const void *data) EINA_ARG_NONNULL(1, 4); + /** * Delete a callback function from the canvas. * @@ -3708,6 +3758,22 @@ EAPI Evas_Object *evas_object_below_get (const Evas_Object *obj */ EAPI void evas_object_event_callback_add (Evas_Object *obj, Evas_Callback_Type type, Evas_Object_Event_Cb func, const void *data) EINA_ARG_NONNULL(1, 3); +/** + * Add (register) a callback function to a given Evas object event with a + * non-default priority set. Except for the priority field, it's exactly the + * same as @ref evas_object_event_callback_add + * + * @param obj Object to attach a callback to + * @param type The type of event that will trigger the callback + * @param priority The priority of the callback, lower values called first. + * @param func The function to be called when the event is triggered + * @param data The data pointer to be passed to @p func + * + * @see evas_object_event_callback_add + * @since 1.1.0 + */ +EAPI void evas_object_event_callback_priority_add(Evas_Object *obj, Evas_Callback_Type type, Evas_Callback_Priority priority, Evas_Object_Event_Cb func, const void *data) EINA_ARG_NONNULL(1, 4); + /** * Delete a callback function from an object * @@ -9439,6 +9505,23 @@ EAPI void evas_object_smart_data_set (Evas_Object *obj, void */ 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); +/** + * Add (register) a callback function to the smart event specified by + * @p event on the smart object @p obj. Except for the priority field, + * it's exactly the same as @ref evas_object_smart_callback_add + * + * @param obj a smart object + * @param event the event's name string + * @param priority The priority of the callback, lower values called first. + * @param func the callback function + * @param data user data to be passed to the callback function + * + * @see evas_object_smart_callback_add + * @since 1.1.0 + * @ingroup Evas_Smart_Object_Group + */ +EAPI void evas_object_smart_callback_priority_add(Evas_Object *obj, const char *event, Evas_Callback_Priority priority, Evas_Smart_Cb func, const void *data); + /** * Delete (unregister) a callback function from the smart event * specified by @p event on the smart object @p obj. diff --git a/legacy/evas/src/lib/canvas/evas_callbacks.c b/legacy/evas/src/lib/canvas/evas_callbacks.c index b87b3d8b6c..a2fd7719b1 100644 --- a/legacy/evas/src/lib/canvas/evas_callbacks.c +++ b/legacy/evas/src/lib/canvas/evas_callbacks.c @@ -256,10 +256,29 @@ evas_object_event_callback_call(Evas_Object *obj, Evas_Callback_Type type, void _evas_unwalk(e); } - +static int +_callback_priority_cmp(const void *_a, const void *_b) +{ + const Evas_Func_Node *a, *b; + a = EINA_INLIST_CONTAINER_GET(_a, Evas_Func_Node); + b = EINA_INLIST_CONTAINER_GET(_b, Evas_Func_Node); + if (a->priority < b->priority) + return -1; + else if (a->priority == b->priority) + return 0; + else + return 1; +} EAPI void evas_object_event_callback_add(Evas_Object *obj, Evas_Callback_Type type, Evas_Object_Event_Cb func, const void *data) +{ + evas_object_event_callback_priority_add(obj, type, + EVAS_CALLBACK_PRIORITY_DEFAULT, func, data); +} + +EAPI void +evas_object_event_callback_priority_add(Evas_Object *obj, Evas_Callback_Type type, Evas_Callback_Priority priority, Evas_Object_Event_Cb func, const void *data) { /* MEM OK */ Evas_Func_Node *fn; @@ -285,9 +304,11 @@ evas_object_event_callback_add(Evas_Object *obj, Evas_Callback_Type type, Evas_O fn->func = func; fn->data = (void *)data; fn->type = type; + fn->priority = priority; obj->callbacks->callbacks = - eina_inlist_prepend(obj->callbacks->callbacks, EINA_INLIST_GET(fn)); + eina_inlist_sorted_insert(obj->callbacks->callbacks, EINA_INLIST_GET(fn), + _callback_priority_cmp); } EAPI void * @@ -352,10 +373,15 @@ evas_object_event_callback_del_full(Evas_Object *obj, Evas_Callback_Type type, E return NULL; } - - EAPI void evas_event_callback_add(Evas *e, Evas_Callback_Type type, Evas_Event_Cb func, const void *data) +{ + evas_event_callback_priority_add(e, type, EVAS_CALLBACK_PRIORITY_DEFAULT, + func, data); +} + +EAPI void +evas_event_callback_priority_add(Evas *e, Evas_Callback_Type type, Evas_Callback_Priority priority, Evas_Event_Cb func, const void *data) { /* MEM OK */ Evas_Func_Node *fn; @@ -381,9 +407,10 @@ evas_event_callback_add(Evas *e, Evas_Callback_Type type, Evas_Event_Cb func, co fn->func = func; fn->data = (void *)data; fn->type = type; + fn->priority = priority; - e->callbacks->callbacks = - eina_inlist_prepend(e->callbacks->callbacks, EINA_INLIST_GET(fn)); + e->callbacks->callbacks = eina_inlist_sorted_insert(e->callbacks->callbacks, + EINA_INLIST_GET(fn), _callback_priority_cmp); } EAPI void * diff --git a/legacy/evas/src/lib/canvas/evas_object_smart.c b/legacy/evas/src/lib/canvas/evas_object_smart.c index 2cd9fb19cd..e8c351f7ee 100644 --- a/legacy/evas/src/lib/canvas/evas_object_smart.c +++ b/legacy/evas/src/lib/canvas/evas_object_smart.c @@ -22,6 +22,7 @@ struct _Evas_Smart_Callback const char *event; Evas_Smart_Cb func; void *func_data; + Evas_Callback_Priority priority; char delete_me : 1; }; @@ -324,8 +325,29 @@ evas_object_smart_add(Evas *e, Evas_Smart *s) return obj; } +static int +_callback_priority_cmp(const void *_a, const void *_b) +{ + const Evas_Smart_Callback *a, *b; + a = (const Evas_Smart_Callback *) _a; + b = (const Evas_Smart_Callback *) _b; + if (a->priority < b->priority) + return -1; + else if (a->priority == b->priority) + return 0; + else + return 1; +} + EAPI void evas_object_smart_callback_add(Evas_Object *obj, const char *event, Evas_Smart_Cb func, const void *data) +{ + evas_object_smart_callback_priority_add(obj, event, + EVAS_CALLBACK_PRIORITY_DEFAULT, func, data); +} + +EAPI void +evas_object_smart_callback_priority_add(Evas_Object *obj, const char *event, Evas_Callback_Priority priority, Evas_Smart_Cb func, const void *data) { Evas_Object_Smart *o; Evas_Smart_Callback *cb; @@ -346,7 +368,9 @@ evas_object_smart_callback_add(Evas_Object *obj, const char *event, Evas_Smart_C cb->event = eina_stringshare_add(event); cb->func = func; cb->func_data = (void *)data; - o->callbacks = eina_list_prepend(o->callbacks, cb); + cb->priority = priority; + o->callbacks = eina_list_sorted_insert(o->callbacks, _callback_priority_cmp, + cb); } EAPI void * diff --git a/legacy/evas/src/lib/include/evas_private.h b/legacy/evas/src/lib/include/evas_private.h index 4a628a7179..afaa05e059 100644 --- a/legacy/evas/src/lib/include/evas_private.h +++ b/legacy/evas/src/lib/include/evas_private.h @@ -553,6 +553,7 @@ struct _Evas_Func_Node void (*func) (); void *data; Evas_Callback_Type type; + Evas_Callback_Priority priority; unsigned char delete_me : 1; }; diff --git a/legacy/evas/src/tests/Makefile.am b/legacy/evas/src/tests/Makefile.am index 92a3401677..c659106e24 100644 --- a/legacy/evas/src/tests/Makefile.am +++ b/legacy/evas/src/tests/Makefile.am @@ -20,6 +20,7 @@ evas_suite.c \ evas_test_init.c \ evas_test_textblock.c \ evas_test_text.c \ +evas_test_callbacks.c \ evas_tests_helpers.h \ evas_suite.h diff --git a/legacy/evas/src/tests/evas_suite.c b/legacy/evas/src/tests/evas_suite.c index d2c8504659..55f4123289 100644 --- a/legacy/evas/src/tests/evas_suite.c +++ b/legacy/evas/src/tests/evas_suite.c @@ -21,6 +21,7 @@ static const Evas_Test_Case etc[] = { { "Evas", evas_test_init }, { "Object Textblock", evas_test_textblock }, { "Object Text", evas_test_text }, + { "Callbacks", evas_test_callbacks }, { NULL, NULL } }; diff --git a/legacy/evas/src/tests/evas_suite.h b/legacy/evas/src/tests/evas_suite.h index 27cdf0ff83..31d6d18ac1 100644 --- a/legacy/evas/src/tests/evas_suite.h +++ b/legacy/evas/src/tests/evas_suite.h @@ -6,6 +6,7 @@ void evas_test_init(TCase *tc); void evas_test_textblock(TCase *tc); void evas_test_text(TCase *tc); +void evas_test_callbacks(TCase *tc); #endif /* _EVAS_SUITE_H */ diff --git a/legacy/evas/src/tests/evas_test_callbacks.c b/legacy/evas/src/tests/evas_test_callbacks.c new file mode 100644 index 0000000000..675ee1ce8c --- /dev/null +++ b/legacy/evas/src/tests/evas_test_callbacks.c @@ -0,0 +1,135 @@ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "evas_suite.h" +#include "Evas.h" +#include "evas_tests_helpers.h" + +#define START_CALLBACK_TEST() \ + Evas *evas; \ + Evas_Object *rect; \ + evas = EVAS_TEST_INIT_EVAS(); \ + rect = evas_object_rectangle_add(evas); \ +do \ +{ \ +} \ +while (0) + +#define END_CALLBACK_TEST() \ +do \ +{ \ + evas_object_del(rect); \ + evas_free(evas); \ + evas_shutdown(); \ +} \ +while (0) + +static int counter = 1; + +static void +_obj_event_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + (void) e; + (void) obj; + (void) event_info; + + fail_if(((int) data) != counter); + + counter++; +} + +START_TEST(evas_object_event_callbacks_priority) +{ + START_CALLBACK_TEST(); + counter = 1; + evas_object_event_callback_priority_add(rect, EVAS_CALLBACK_MOVE, -10, + _obj_event_cb, (void *) 1); + evas_object_event_callback_priority_add(rect, EVAS_CALLBACK_MOVE, 0, + _obj_event_cb, (void *) 2); + evas_object_event_callback_priority_add(rect, EVAS_CALLBACK_MOVE, 10, + _obj_event_cb, (void *) 3); + evas_object_move(rect, 2, 2); + + /* Make sure we got through all the callbacks */ + fail_if(counter != 4); + + /* Delete _obj_event_cb 3 times */ + evas_object_event_callback_del(rect, EVAS_CALLBACK_MOVE, _obj_event_cb); + evas_object_event_callback_del(rect, EVAS_CALLBACK_MOVE, _obj_event_cb); + evas_object_event_callback_del(rect, EVAS_CALLBACK_MOVE, _obj_event_cb); + counter = 1; + evas_object_event_callback_priority_add(rect, EVAS_CALLBACK_MOVE, 0, + _obj_event_cb, (void *) 2); + evas_object_event_callback_priority_add(rect, EVAS_CALLBACK_MOVE, -10, + _obj_event_cb, (void *) 1); + evas_object_event_callback_priority_add(rect, EVAS_CALLBACK_MOVE, 10, + _obj_event_cb, (void *) 3); + evas_object_move(rect, 3, 3); + + /* Make sure we got through all the callbacks */ + fail_if(counter != 4); + + END_CALLBACK_TEST(); +} +END_TEST + +static void +_event_cb(void *data, Evas *e, void *event_info) +{ + (void) e; + (void) event_info; + + fail_if(((int) data) != counter); + + counter++; +} + +START_TEST(evas_event_callbacks_priority) +{ + START_CALLBACK_TEST(); + evas_object_focus_set(rect, EINA_FALSE); + counter = 1; + evas_event_callback_priority_add(evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, + -10, _event_cb, (void *) 1); + evas_event_callback_priority_add(evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, + 0, _event_cb, (void *) 2); + evas_event_callback_priority_add(evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, + 10, _event_cb, (void *) 3); + evas_object_focus_set(rect, EINA_TRUE); + + /* Make sure we got through all the callbacks */ + fail_if(counter != 4); + + /* Delete _event_cb 3 times */ + evas_event_callback_del(evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, + _event_cb); + evas_event_callback_del(evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, + _event_cb); + evas_event_callback_del(evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, + _event_cb); + evas_object_focus_set(rect, EINA_FALSE); + counter = 1; + evas_event_callback_priority_add(evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, + 0, _event_cb, (void *) 2); + evas_event_callback_priority_add(evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, + -10, _event_cb, (void *) 1); + evas_event_callback_priority_add(evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, + 10, _event_cb, (void *) 3); + evas_object_focus_set(rect, EINA_TRUE); + + /* Make sure we got through all the callbacks */ + fail_if(counter != 4); + + END_CALLBACK_TEST(); +} +END_TEST + +void evas_test_callbacks(TCase *tc) +{ + tcase_add_test(tc, evas_object_event_callbacks_priority); + tcase_add_test(tc, evas_event_callbacks_priority); +}