From e49de4c97b907945f2c7dc38920bed68ef966e8c Mon Sep 17 00:00:00 2001 From: Daniel Zaoui Date: Wed, 26 Jun 2013 09:35:05 +0300 Subject: [PATCH] Gesture Layer: support multiple callbacks per type/state. elm_gesture_layer_cb_add/del functions have been added to provide this functionality. elm_gesture_layer_cb_set provided only one callback and so was overriding the callback with the new one. For ABI compatibility, some rules were needed: - when set function is called with NULL, all the callbacks of the state will be removed (old behavior respect) - try to use set or add/del exclusively with a preference to the new APIs. This is because of the first rule and because it will be more correct. - if you remove a callback, only one instance of this callback of this type/state for this gesture will be removed, by comparing func and data. It means that if you register twice the same callback/data, it will be added twice and you will have to remove also twice too. --- legacy/elementary/ChangeLog | 5 + legacy/elementary/src/lib/elm_gesture_layer.c | 124 ++++++++++++++++-- .../elementary/src/lib/elm_gesture_layer_eo.h | 44 ++++++- .../src/lib/elm_gesture_layer_legacy.h | 37 ++++++ 4 files changed, 197 insertions(+), 13 deletions(-) diff --git a/legacy/elementary/ChangeLog b/legacy/elementary/ChangeLog index 7f43061ea0..29358d8bae 100644 --- a/legacy/elementary/ChangeLog +++ b/legacy/elementary/ChangeLog @@ -1458,3 +1458,8 @@ 2013-06-25 Ryuan Choi (ryuan) * Fix crash of elm_notify when timeout is zero. + +2013-06-26 Daniel Zaoui (JackDanielZ) + + * Gesture Layer: add APIs to add/del multiple callbacks for a same + gesture/type/state. diff --git a/legacy/elementary/src/lib/elm_gesture_layer.c b/legacy/elementary/src/lib/elm_gesture_layer.c index 5e6e9fae9f..dc121849fd 100644 --- a/legacy/elementary/src/lib/elm_gesture_layer.c +++ b/legacy/elementary/src/lib/elm_gesture_layer.c @@ -44,10 +44,10 @@ _glayer_buf_dup(void *buf, size_t size) #define SET_TEST_BIT(P) \ do { \ - P->test = P->fn[ELM_GESTURE_STATE_START].cb || \ - P->fn[ELM_GESTURE_STATE_MOVE].cb || \ - P->fn[ELM_GESTURE_STATE_END].cb || \ - P->fn[ELM_GESTURE_STATE_ABORT].cb; \ + P->test = P->cbs[ELM_GESTURE_STATE_START] || \ + P->cbs[ELM_GESTURE_STATE_MOVE] || \ + P->cbs[ELM_GESTURE_STATE_END] || \ + P->cbs[ELM_GESTURE_STATE_ABORT]; \ } while (0) #define IS_TESTED_GESTURE(gesture) \ @@ -118,6 +118,7 @@ typedef struct _Pointer_Event Pointer_Event; */ struct _Func_Data { + EINA_INLIST; void *user_data; /**< Holds user data to CB (like sd) */ Elm_Gesture_Event_Cb cb; }; @@ -144,7 +145,7 @@ struct _Gesture_Info { Evas_Object *obj; void *data; /**< Holds gesture intemidiate processing data */ - Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */ + Eina_Inlist *cbs[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info (Func_Data) for states */ Elm_Gesture_Type g_type; /**< gesture type */ Elm_Gesture_State state; /**< gesture state */ void *info; /**< Data for the state callback */ @@ -606,14 +607,16 @@ static Evas_Event_Flags _state_report(Gesture_Info *gesture, void *info) { + Evas_Event_Flags flags = EVAS_EVENT_FLAG_NONE; /* We report current state (START, MOVE, END, ABORT), once */ if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) && - (gesture->fn[gesture->state].cb)) /* Fill state-info struct and - * send ptr to user - * callback */ + (gesture->cbs[gesture->state])) /* Fill state-info struct and + * send ptr to user + * callback */ { - return gesture->fn[gesture->state].cb( - gesture->fn[gesture->state].user_data, info); + Func_Data *cb_info; + EINA_INLIST_FOREACH(gesture->cbs[gesture->state], cb_info) + flags |= cb_info->cb(cb_info->user_data, info); } return EVAS_EVENT_FLAG_NONE; @@ -3704,6 +3707,8 @@ _elm_gesture_layer_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED) memset(priv->gesture, 0, sizeof(priv->gesture)); } +static void _cbs_clean(Elm_Gesture_Layer_Smart_Data *sd, Elm_Gesture_Type idx, Elm_Gesture_State cb_type); + static void _elm_gesture_layer_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED) { @@ -3727,6 +3732,10 @@ _elm_gesture_layer_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED) if (sd->gesture[i]->data) free(sd->gesture[i]->data); + _cbs_clean(sd, i, ELM_GESTURE_STATE_START); + _cbs_clean(sd, i, ELM_GESTURE_STATE_MOVE); + _cbs_clean(sd, i, ELM_GESTURE_STATE_END); + _cbs_clean(sd, i, ELM_GESTURE_STATE_ABORT); free(sd->gesture[i]); } if (sd->gest_taps_timeout) ecore_timer_del(sd->gest_taps_timeout); @@ -3888,6 +3897,23 @@ _attach(Eo *obj, void *_pd, va_list *list) if (ret) *ret = EINA_TRUE; } +static void +_cbs_clean(Elm_Gesture_Layer_Smart_Data *sd, + Elm_Gesture_Type idx, + Elm_Gesture_State cb_type) +{ + if (!sd->gesture[idx]) return; + + Func_Data *cb_info; + EINA_INLIST_FREE(sd->gesture[idx]->cbs[cb_type], cb_info) + { + sd->gesture[idx]->cbs[cb_type] = eina_inlist_remove( + sd->gesture[idx]->cbs[cb_type], EINA_INLIST_GET(cb_info)); + free(cb_info); + } + SET_TEST_BIT(sd->gesture[idx]); +} + EAPI void elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Type idx, @@ -3907,6 +3933,33 @@ _cb_set(Eo *obj, void *_pd, va_list *list) Elm_Gesture_Event_Cb cb = va_arg(*list, Elm_Gesture_Event_Cb); void *data = va_arg(*list, void *); + Elm_Gesture_Layer_Smart_Data *sd = _pd; + + _cbs_clean(sd, idx, cb_type); // for ABI compat. + eo_do(obj, elm_obj_gesture_layer_cb_add(idx, cb_type, cb, data)); +} + +EAPI void +elm_gesture_layer_cb_add(Evas_Object *obj, + Elm_Gesture_Type idx, + Elm_Gesture_State cb_type, + Elm_Gesture_Event_Cb cb, + void *data) +{ + ELM_GESTURE_LAYER_CHECK(obj); + eo_do(obj, elm_obj_gesture_layer_cb_add(idx, cb_type, cb, data)); +} + +static void +_cb_add(Eo *obj, void *_pd, va_list *list) +{ + Elm_Gesture_Type idx = va_arg(*list, Elm_Gesture_Type); + Elm_Gesture_State cb_type = va_arg(*list, Elm_Gesture_State); + Elm_Gesture_Event_Cb cb = va_arg(*list, Elm_Gesture_Event_Cb); + void *data = va_arg(*list, void *); + + if (!cb) return; + Gesture_Info *p; Elm_Gesture_Layer_Smart_Data *sd = _pd; @@ -3914,15 +3967,58 @@ _cb_set(Eo *obj, void *_pd, va_list *list) sd->gesture[idx] = calloc(1, sizeof(Gesture_Info)); if (!sd->gesture[idx]) return; + Func_Data *cb_info = calloc(1, sizeof(*cb_info)); + if (!cb_info) return; + cb_info->cb = cb; + cb_info->user_data = data; + p = sd->gesture[idx]; p->obj = obj; p->g_type = idx; - p->fn[cb_type].cb = cb; - p->fn[cb_type].user_data = data; + p->cbs[cb_type] = eina_inlist_append(p->cbs[cb_type], + EINA_INLIST_GET(cb_info)); p->state = ELM_GESTURE_STATE_UNDEFINED; SET_TEST_BIT(p); } +EAPI void +elm_gesture_layer_cb_del(Evas_Object *obj, + Elm_Gesture_Type idx, + Elm_Gesture_State cb_type, + Elm_Gesture_Event_Cb cb, + void *data) +{ + ELM_GESTURE_LAYER_CHECK(obj); + eo_do(obj, elm_obj_gesture_layer_cb_del(idx, cb_type, cb, data)); +} + +static void +_cb_del(Eo *obj EINA_UNUSED, void *_pd, va_list *list) +{ + Elm_Gesture_Type idx = va_arg(*list, Elm_Gesture_Type); + Elm_Gesture_State cb_type = va_arg(*list, Elm_Gesture_State); + Elm_Gesture_Event_Cb cb = va_arg(*list, Elm_Gesture_Event_Cb); + void *data = va_arg(*list, void *); + + Elm_Gesture_Layer_Smart_Data *sd = _pd; + + if (!sd->gesture[idx]) return; + + Eina_Inlist *itr; + Func_Data *cb_info; + EINA_INLIST_FOREACH_SAFE(sd->gesture[idx]->cbs[cb_type], itr, cb_info) + { + if (cb_info->cb == cb && cb_info->user_data == data) + { + sd->gesture[idx]->cbs[cb_type] = eina_inlist_remove( + sd->gesture[idx]->cbs[cb_type], EINA_INLIST_GET(cb_info)); + free(cb_info); + SET_TEST_BIT(sd->gesture[idx]); + return; + } + } +} + EAPI void elm_gesture_layer_line_min_length_set(Evas_Object *obj, int line_min_length) { @@ -4158,6 +4254,8 @@ _class_constructor(Eo_Class *klass) EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_SET), _cb_set), EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_SET), _tap_finger_size_set), EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_GET), _tap_finger_size_get), + EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_ADD), _cb_add), + EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_DEL), _cb_del), EO_OP_FUNC_SENTINEL }; eo_class_funcs_set(klass, func_desc); @@ -4176,6 +4274,8 @@ static const Eo_Op_Description op_desc[] = { EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_SET, "Use function to set callbacks to be notified about change of state of gesture."), EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_SET, "Use function to set valid touch-area size for finger."), EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_GET, "This function returns the valid touch-area size for finger."), + EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_ADD, "Use function to add callbacks to be notified about change of state of gesture."), + EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_DEL, "Use function to remove added callbacks."), EO_OP_DESCRIPTION_SENTINEL }; diff --git a/legacy/elementary/src/lib/elm_gesture_layer_eo.h b/legacy/elementary/src/lib/elm_gesture_layer_eo.h index a3b96039a4..d6014517d4 100644 --- a/legacy/elementary/src/lib/elm_gesture_layer_eo.h +++ b/legacy/elementary/src/lib/elm_gesture_layer_eo.h @@ -16,6 +16,8 @@ enum ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_SET, ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_SET, ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_GET, + ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_ADD, + ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_DEL, ELM_OBJ_GESTURE_LAYER_SUB_ID_LAST }; @@ -127,7 +129,10 @@ enum * @since 1.8 * * Use function to set callbacks to be notified about - * change of state of gesture. + * change of state of gesture. If a function was already + * set for this gesture/type/state, it will be replaced by the new one. + * For ABI compat, callbacks added by elm_obj_gesture_layer_cb_add will be removed. It is recommended + * to use only one of these functions for a gesture object. * * @param[in] idx * @param[in] cb_type @@ -135,11 +140,48 @@ enum * @param[in] data * * @see elm_gesture_layer_cb_set + * @see elm_gesture_layer_cb_add * * @ingroup Elm_Gesture_Layer */ #define elm_obj_gesture_layer_cb_set(idx, cb_type, cb, data) ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_SET), EO_TYPECHECK(Elm_Gesture_Type, idx), EO_TYPECHECK(Elm_Gesture_State, cb_type), EO_TYPECHECK(Elm_Gesture_Event_Cb, cb), EO_TYPECHECK(void *, data) +/** + * @def elm_obj_gesture_layer_cb_add + * @since 1.8 + * + * Use function to add a callback to be notified about + * change of state of gesture. + * + * @param[in] idx + * @param[in] cb_type + * @param[in] cb + * @param[in] data + * + * @see elm_gesture_layer_cb_add + * + * @ingroup Elm_Gesture_Layer + */ +#define elm_obj_gesture_layer_cb_add(idx, cb_type, cb, data) ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_ADD), EO_TYPECHECK(Elm_Gesture_Type, idx), EO_TYPECHECK(Elm_Gesture_State, cb_type), EO_TYPECHECK(Elm_Gesture_Event_Cb, cb), EO_TYPECHECK(void *, data) + +/** + * @def elm_obj_gesture_layer_cb_del + * @since 1.8 + * + * Use function to remove a callback that has been added + * to be notified about change of state of gesture. + * + * @param[in] idx + * @param[in] cb_type + * @param[in] cb + * @param[in] data + * + * @see elm_gesture_layer_cb_del + * + * @ingroup Elm_Gesture_Layer + */ +#define elm_obj_gesture_layer_cb_del(idx, cb_type, cb, data) ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_DEL), EO_TYPECHECK(Elm_Gesture_Type, idx), EO_TYPECHECK(Elm_Gesture_State, cb_type), EO_TYPECHECK(Elm_Gesture_Event_Cb, cb), EO_TYPECHECK(void *, data) + /** * @def elm_obj_gesture_layer_tap_finger_size_set * @since 1.8 diff --git a/legacy/elementary/src/lib/elm_gesture_layer_legacy.h b/legacy/elementary/src/lib/elm_gesture_layer_legacy.h index be0cd8caf0..b3005ded58 100644 --- a/legacy/elementary/src/lib/elm_gesture_layer_legacy.h +++ b/legacy/elementary/src/lib/elm_gesture_layer_legacy.h @@ -110,6 +110,43 @@ EAPI Eina_Bool elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *target */ EAPI void elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Type idx, Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data); +/** + * Use function to add callbacks to be notified about + * change of state of gesture. + * When a user registers a callback with this function + * this means this gesture has to be tested. + * + * When ALL callbacks for a gesture are set to NULL + * it means user isn't interested in gesture-state + * and it will not be tested. + * + * If a function was already set for this gesture/type/state, it will be + * replaced by the new one. For ABI compat, callbacks added by + * elm_gesture_layer_cb_add will be removed. It is recommended to + * use only one of these functions for a gesture object. + * + * @param obj gesture-layer. + * @param idx The gesture you would like to track its state. + * @param cb callback function pointer. + * @param cb_type what event this callback tracks: START, MOVE, END, ABORT. + * @param data user info to be sent to callback (usually, Smart Data) + * + */ +EAPI void elm_gesture_layer_cb_add(Evas_Object *obj, Elm_Gesture_Type idx, Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data); + +/** + * Use this function to remove a callback that has been added + * to be notified about change of state of gesture. + * + * @param obj gesture-layer. + * @param idx The gesture you would like to track its state. + * @param cb callback function pointer. + * @param cb_type what event this callback tracks: START, MOVE, END, ABORT. + * @param data user info for the callback (usually, Smart Data) + * + */ +EAPI void elm_gesture_layer_cb_del(Evas_Object *obj, Elm_Gesture_Type idx, Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data); + /** * @since 1.8 * This function sets the gesture layer finger-size for taps