jackdanielz pushed a commit to branch master.

commit c5ef1cbf87bfcf7eec26b12a480cc3efb79bdc2e
Author: Daniel Zaoui <[email protected]>
Date:   Wed Jun 26 09:35:05 2013 +0300

    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.
---
 ChangeLog                          |   5 ++
 src/lib/elm_gesture_layer.c        | 124 +++++++++++++++++++++++++++++++++----
 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/ChangeLog b/ChangeLog
index 7f43061..29358d8 100644
--- a/ChangeLog
+++ b/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/src/lib/elm_gesture_layer.c b/src/lib/elm_gesture_layer.c
index 5e6e9fa..dc12184 100644
--- a/src/lib/elm_gesture_layer.c
+++ b/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,16 +3967,59 @@ _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)
 {
    ELM_GESTURE_LAYER_CHECK(obj);
@@ -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/src/lib/elm_gesture_layer_eo.h b/src/lib/elm_gesture_layer_eo.h
index a3b9603..d601451 100644
--- a/src/lib/elm_gesture_layer_eo.h
+++ b/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,12 +140,49 @@ 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/src/lib/elm_gesture_layer_legacy.h 
b/src/lib/elm_gesture_layer_legacy.h
index be0cd8c..b3005de 100644
--- a/src/lib/elm_gesture_layer_legacy.h
+++ b/src/lib/elm_gesture_layer_legacy.h
@@ -111,6 +111,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
  * If not set, this size taken from elm_config.

-- 

------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:

Build for Windows Store.

http://p.sf.net/sfu/windows-dev2dev

Reply via email to