These functions let you pass an array of callbacks instead of just one.
It's more memory efficient to use this if you just add a bulk of events
on the same object.
This commits breaks ABI, and breaks API of the EO_EV_CALLBACK_ADD/DEL
signals (the event info passed).
EO_BASE_SUB_ID_WREF_DEL,
EO_BASE_SUB_ID_EVENT_CALLBACK_PRIORITY_ADD,
EO_BASE_SUB_ID_EVENT_CALLBACK_DEL,
+ EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_PRIORITY_ADD,
+ EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_DEL,
EO_BASE_SUB_ID_EVENT_CALLBACK_CALL,
EO_BASE_SUB_ID_EVENT_CALLBACK_FORWARDER_ADD,
EO_BASE_SUB_ID_EVENT_CALLBACK_FORWARDER_DEL,
typedef Eina_Bool (*Eo_Event_Cb)(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info);
/**
+ * @typedef Eo_Callback_Array_Item
+ * A convenience typedef for #_Eo_Callback_Array_Item
+ */
+typedef struct _Eo_Callback_Array_Item Eo_Callback_Array_Item;
+
+/**
+ * @struct _Eo_Callback_Array_Item
+ * An item in an array of callback desc/func.
+ * @see eo_event_callback_array_add()
+ */
+struct _Eo_Callback_Array_Item
+{
+ const Eo_Event_Description *desc; /**< The event description. */
+ Eo_Event_Cb func; /**< The callback function. */
+};
+
+/**
* @def eo_event_callback_forwarder_add
* @brief Add an event callback forwarder for an event and an object.
* @param[in] desc The description of the event to listen to.
*/
#define eo_event_callback_priority_add(desc, priority, cb, data) EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_PRIORITY_ADD), EO_TYPECHECK(const Eo_Event_Description *, desc), EO_TYPECHECK(Eo_Callback_Priority, priority), EO_TYPECHECK(Eo_Event_Cb, cb), EO_TYPECHECK(const void *, data)
-
/**
* @def eo_event_callback_del
* @brief Del a callback with a specific data associated to it for an event.
#define eo_event_callback_del(desc, func, user_data) EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_DEL), EO_TYPECHECK(const Eo_Event_Description *, desc), EO_TYPECHECK(Eo_Event_Cb, func), EO_TYPECHECK(const void *, user_data)
/**
+ * @def eo_event_callback_array_add(obj, desc, cb, data)
+ * Add a callback array for an event.
+ * @param[in] array an #Eo_Callback_Array_Item of events to listen to.
+ * @param[in] data additional data to pass to the callback.
+ *
+ * callbacks of the same priority are called in reverse order of creation.
+ *
+ * @see eo_event_callback_array_priority_add()
+ */
+#define eo_event_callback_array_add(array, data) \
+ eo_event_callback_array_priority_add(array, \
+ EO_CALLBACK_PRIORITY_DEFAULT, data)
+
+/**
+ * @def eo_event_callback_priority_add
+ * @brief Add a callback array for an event with a specific priority.
+ * @param[in] array an #Eo_Callback_Array_Item of events to listen to.
+ * @param[in] priority The priority of the callback.
+ * @param[in] data additional data to pass to the callback.
+ *
+ * callbacks of the same priority are called in reverse order of creation.
+ *
+ * @see #eo_event_callback_add
+ */
+#define eo_event_callback_array_priority_add(array, priority, data) EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_PRIORITY_ADD), EO_TYPECHECK(const Eo_Callback_Array_Item *, array), EO_TYPECHECK(Eo_Callback_Priority, priority), EO_TYPECHECK(const void *, data)
+
+/**
+ * @def eo_event_callback_del
+ * @brief Del a callback array with a specific data associated to it for an event.
+ * @param[in] array an #Eo_Callback_Array_Item of events to listen to.
+ * @param[in] user_data The data to compare.
+ *
+ */
+#define eo_event_callback_array_del(array, user_data) EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_DEL), EO_TYPECHECK(const Eo_Callback_Array_Item *, array), EO_TYPECHECK(const void *, user_data)
+
+/**
* @def eo_event_callback_call
* @brief Call the callbacks for an event of an object.
* @param[in] desc The description of the event to call.
struct _Eo_Callback_Description
{
Eo_Callback_Description *next;
- const Eo_Event_Description *event;
- Eo_Event_Cb func;
+ union
+ {
+ Eo_Callback_Array_Item item;
+ const Eo_Callback_Array_Item *item_array;
+ } items;
void *func_data;
Eo_Callback_Priority priority;
Eina_Bool delete_me : 1;
+ Eina_Bool func_array : 1;
};
/* Actually remove, doesn't care about walking list, or delete_me */
const void *data = va_arg(*list, const void *);
Eo_Callback_Description *cb = calloc(1, sizeof(*cb));
- cb->event = desc;
- cb->func = func;
+ cb->items.item.desc = desc;
+ cb->items.item.func = func;
cb->func_data = (void *) data;
cb->priority = priority;
_eo_callbacks_sorted_insert(pd, cb);
- eo_do(obj, eo_event_callback_call(EO_EV_CALLBACK_ADD, desc, NULL));
+ {
+ const Eo_Callback_Array_Item arr[] = { {desc, func}, {NULL, NULL}};
+ eo_do(obj, eo_event_callback_call(EO_EV_CALLBACK_ADD, arr, NULL));
+ }
}
static void
Eo_Callback_Description *cb;
for (cb = pd->callbacks ; cb ; cb = cb->next)
{
- if ((cb->event == desc) && (cb->func == func) &&
+ if ((cb->items.item.desc == desc) && (cb->items.item.func == func) &&
(cb->func_data == user_data))
{
+ const Eo_Callback_Array_Item arr[] = { {desc, func}, {NULL, NULL}};
+
cb->delete_me = EINA_TRUE;
pd->deletions_waiting = EINA_TRUE;
_eo_callbacks_clear(pd);
- eo_do(obj, eo_event_callback_call(EO_EV_CALLBACK_DEL, desc, NULL));
+ eo_do(obj, eo_event_callback_call(EO_EV_CALLBACK_DEL, arr, NULL));
return;
}
}
}
static void
+_ev_cb_array_priority_add(Eo *obj, void *class_data, va_list *list)
+{
+ Private_Data *pd = (Private_Data *) class_data;
+ const Eo_Callback_Array_Item *array = va_arg(*list, const Eo_Callback_Array_Item *);
+ Eo_Callback_Priority priority = va_arg(*list, int);
+ const void *data = va_arg(*list, const void *);
+
+ Eo_Callback_Description *cb = calloc(1, sizeof(*cb));
+ cb->func_data = (void *) data;
+ cb->priority = priority;
+ cb->items.item_array = array;
+ cb->func_array = EINA_TRUE;
+ _eo_callbacks_sorted_insert(pd, cb);
+
+ {
+ eo_do(obj, eo_event_callback_call(EO_EV_CALLBACK_ADD, array, NULL));
+ }
+}
+
+static void
+_ev_cb_array_del(Eo *obj, void *class_data, va_list *list)
+{
+ Private_Data *pd = (Private_Data *) class_data;
+ const Eo_Callback_Array_Item *array = va_arg(*list, const Eo_Callback_Array_Item *);
+ void *user_data = va_arg(*list, void *);
+
+ Eo_Callback_Description *cb;
+ for (cb = pd->callbacks ; cb ; cb = cb->next)
+ {
+ if ((cb->items.item_array == array) && (cb->func_data == user_data))
+ {
+ cb->delete_me = EINA_TRUE;
+ pd->deletions_waiting = EINA_TRUE;
+ _eo_callbacks_clear(pd);
+
+ eo_do(obj, eo_event_callback_call(EO_EV_CALLBACK_DEL, array, NULL));
+ return;
+ }
+ }
+
+ ERR("Callback of object %p with function array %p and data %p not found.", obj, array, user_data);
+}
+
+static void
_ev_cb_call(Eo *obj, void *class_data, va_list *list)
{
Private_Data *pd = (Private_Data *) class_data;
Eo_Callback_Description *cb;
for (cb = pd->callbacks ; cb ; cb = cb->next)
{
- if (!cb->delete_me && (cb->event == desc))
+ if (!cb->delete_me)
{
- /* Abort callback calling if the func says so. */
- if (!cb->func((void *) cb->func_data, obj, desc,
- (void *) event_info))
+ if (cb->func_array)
{
- if (ret) *ret = EINA_FALSE;
- break;
+ const Eo_Callback_Array_Item *it;
+ for (it = cb->items.item_array ; it->func ; it++)
+ {
+ if (it->desc != desc)
+ continue;
+ /* Abort callback calling if the func says so. */
+ if (!it->func((void *) cb->func_data, obj, desc,
+ (void *) event_info))
+ {
+ if (ret) *ret = EINA_FALSE;
+ goto end;
+ }
+ }
+ }
+ else
+ {
+ if (cb->items.item.desc == desc)
+ {
+ /* Abort callback calling if the func says so. */
+ if (!cb->items.item.func((void *) cb->func_data, obj, desc,
+ (void *) event_info))
+ {
+ if (ret) *ret = EINA_FALSE;
+ goto end;
+ }
+ }
}
}
}
+
+end:
pd->walking_list--;
_eo_callbacks_clear(pd);
eo_unref(obj);
EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_WREF_DEL), _wref_del),
EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_PRIORITY_ADD), _ev_cb_priority_add),
EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_DEL), _ev_cb_del),
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_PRIORITY_ADD), _ev_cb_array_priority_add),
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_DEL), _ev_cb_array_del),
EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_CALL), _ev_cb_call),
EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_FORWARDER_ADD), _ev_cb_forwarder_add),
EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_FORWARDER_DEL), _ev_cb_forwarder_del),
EO_OP_DESCRIPTION(EO_BASE_SUB_ID_WREF_DEL, "Delete the weak ref."),
EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_PRIORITY_ADD, "Add an event callback with a priority."),
EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_DEL, "Delete an event callback"),
+ EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_PRIORITY_ADD, "Add an event callback array with a priority."),
+ EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_DEL, "Delete an event callback array"),
EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_CALL, "Call the event callbacks for an event."),
EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_FORWARDER_ADD, "Add an event forwarder."),
EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_FORWARDER_DEL, "Delete an event forwarder."),
_cb_added(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info)
{
Simple_Public_Data *pd = eo_data_get(obj, MY_CLASS);
- const Eo_Event_Description *cb_desc = event_info;
+ const Eo_Callback_Array_Item *callback_array = event_info;
(void) data;
(void) desc;
- if (cb_desc != EV_A_CHANGED)
+ if (callback_array->desc != EV_A_CHANGED)
return EINA_TRUE;
pd->cb_count++;
_cb_deled(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info)
{
Simple_Public_Data *pd = eo_data_get(obj, MY_CLASS);
- const Eo_Event_Description *cb_desc = event_info;
+ const Eo_Callback_Array_Item *callback_array = event_info;
(void) data;
(void) desc;
- if (cb_desc != EV_A_CHANGED)
+ if (callback_array->desc != EV_A_CHANGED)
return EINA_TRUE;
pd->cb_count--;
EAPI Eo_Op SIMPLE_BASE_ID = 0;
+EAPI const Eo_Event_Description _EV_A_CHANGED =
+ EO_EVENT_DESCRIPTION("a,changed", "Called when a has changed.");
+
static void
_a_set(Eo *obj EINA_UNUSED, void *class_data, va_list *list)
{
a = va_arg(*list, int);
printf("%s %d\n", eo_class_name_get(MY_CLASS), a);
pd->a = a;
+
+ eo_do(obj, eo_event_callback_call(EV_A_CHANGED, &pd->a, NULL));
}
static void
#define simple_a_print() SIMPLE_ID(SIMPLE_SUB_ID_A_PRINT)
#define simple_class_hi_print() SIMPLE_ID(SIMPLE_SUB_ID_CLASS_HI_PRINT)
-extern const Eo_Event_Description _SIG_A_CHANGED;
-#define SIG_A_CHANGED (&(_SIG_A_CHANGED))
+extern const Eo_Event_Description _EV_A_CHANGED;
+#define EV_A_CHANGED (&(_EV_A_CHANGED))
#define SIMPLE_CLASS simple_class_get()
const Eo_Class *simple_class_get(void);
}
END_TEST
+static int _eo_signals_cb_curent = 0;
+static int _eo_signals_cb_flag = 0;
+
+static Eina_Bool
+_eo_signals_a_changed_cb(void *_data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ int data = (intptr_t) _data;
+ _eo_signals_cb_curent++;
+ ck_assert_int_eq(data, _eo_signals_cb_curent);
+ _eo_signals_cb_flag |= 0x1;
+ return EO_CALLBACK_CONTINUE;
+}
+
+static Eina_Bool
+_eo_signals_a_changed_cb2(void *_data EINA_UNUSED, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ _eo_signals_cb_flag |= 0x2;
+ return EO_CALLBACK_CONTINUE;
+}
+
+static Eina_Bool
+_eo_signals_eo_del_cb(void *_data EINA_UNUSED, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ _eo_signals_cb_flag |= 0x4;
+ return EO_CALLBACK_CONTINUE;
+}
+
+Eina_Bool
+_eo_signals_cb_added_deled(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info)
+{
+ const Eo_Callback_Array_Item *callback_array = event_info;
+
+ fail_if((callback_array != data) &&
+ (callback_array->func != _eo_signals_cb_added_deled));
+
+ return EO_CALLBACK_CONTINUE;
+}
+
+START_TEST(eo_signals)
+{
+ eo_init();
+ static const Eo_Callback_Array_Item callbacks[] = {
+ { EV_A_CHANGED, _eo_signals_a_changed_cb },
+ { EV_A_CHANGED, _eo_signals_a_changed_cb2 },
+ { EO_EV_DEL, _eo_signals_eo_del_cb },
+ { NULL, NULL }
+ };
+ Eo *obj = eo_add(SIMPLE_CLASS, NULL);
+
+ eo_do(obj, eo_event_callback_add(EO_EV_CALLBACK_ADD, _eo_signals_cb_added_deled, callbacks));
+ eo_do(obj, eo_event_callback_add(EO_EV_CALLBACK_DEL, _eo_signals_cb_added_deled, callbacks));
+ eo_do(obj, eo_event_callback_array_priority_add(callbacks, -100, (void *) 1));
+ eo_do(obj, eo_event_callback_array_add(callbacks, (void *) 3));
+ eo_do(obj, eo_event_callback_array_priority_add(callbacks, -50, (void *) 2));
+ fail_if(!eo_do(obj, simple_a_set(1)));
+ ck_assert_int_eq(_eo_signals_cb_flag, 0x3);
+
+ eo_do(obj, eo_event_callback_array_del(callbacks, (void *) 1));
+ eo_do(obj, eo_event_callback_array_del(callbacks, (void *) 2));
+ eo_do(obj, eo_event_callback_array_del(callbacks, (void *) 3));
+ _eo_signals_cb_flag = 0;
+ fail_if(!eo_do(obj, simple_a_set(1)));
+ ck_assert_int_eq(_eo_signals_cb_flag, 0x0);
+
+ eo_unref(obj);
+
+ eo_shutdown();
+}
+END_TEST
+
START_TEST(eo_data_fetch)
{
eo_init();
tcase_add_test(tc, eo_isa_tests);
tcase_add_test(tc, eo_multiple_do);
tcase_add_test(tc, eo_add_do_and_custom);
+ tcase_add_test(tc, eo_signals);
}