summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCedric BAIL <cedric@osg.samsung.com>2016-04-20 15:50:46 -0700
committerCedric BAIL <cedric@osg.samsung.com>2016-04-20 15:50:46 -0700
commit1fd049510fac6d277f04f6262d4be88f07bcf3ba (patch)
tree16e6dbe82b066548d04fb2fafe425d6764310b62
parent13b4a56ddc185a7c62bb0137a159ad57efb7b06d (diff)
downloadefl-1fd049510fac6d277f04f6262d4be88f07bcf3ba.tar.gz
eo: add support for restartable event inside nested call.
The idea is that when you are processing those events from within they won't call twice any of the event until all of them are processed at least once (Or one of them did return EINA_FALSE).
-rw-r--r--src/lib/eo/Eo.h22
-rw-r--r--src/lib/eo/eo_base.eo1
-rw-r--r--src/lib/eo/eo_base_class.c62
3 files changed, 81 insertions, 4 deletions
diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h
index 456410076f..1d492b1f18 100644
--- a/src/lib/eo/Eo.h
+++ b/src/lib/eo/Eo.h
@@ -259,7 +259,7 @@ typedef unsigned int Eo_Op;
* @param name The name of the event.
* @see Eo_Event_Description
*/
-#define EO_EVENT_DESCRIPTION(name) { name, EINA_FALSE, EINA_FALSE }
+#define EO_EVENT_DESCRIPTION(name) { name, EINA_FALSE, EINA_FALSE, EINA_FALSE }
/**
* @def EO_EVENT_DESCRIPTION_HOT(name)
@@ -269,7 +269,25 @@ typedef unsigned int Eo_Op;
* @see Eo_Event_Description
* @see EO_EVENT_DESCRIPTION
*/
-#define EO_EVENT_DESCRIPTION_HOT(name) { name, EINA_TRUE, EINA_FALSE }
+#define EO_EVENT_DESCRIPTION_HOT(name) { name, EINA_TRUE, EINA_FALSE, EINA_FALSE }
+
+/**
+ * @def EO_EVENT_DESCRIPTION(name)
+ * An helper macro to help populating #Eo_Event_Description
+ * @param name The name of the event.
+ * @see Eo_Event_Description
+ */
+#define EO_EVENT_DESCRIPTION_RESTART(name) { name, EINA_FALSE, EINA_FALSE, EINA_TRUE }
+
+/**
+ * @def EO_EVENT_DESCRIPTION_HOT(name)
+ * An helper macro to help populating #Eo_Event_Description and make
+ * the event impossible to freeze.
+ * @param name The name of the event.
+ * @see Eo_Event_Description
+ * @see EO_EVENT_DESCRIPTION
+ */
+#define EO_EVENT_DESCRIPTION_HOT_RESTART(name) { name, EINA_TRUE, EINA_FALSE, EINA_TRUE }
diff --git a/src/lib/eo/eo_base.eo b/src/lib/eo/eo_base.eo
index 8ac0573780..a804e1b828 100644
--- a/src/lib/eo/eo_base.eo
+++ b/src/lib/eo/eo_base.eo
@@ -5,6 +5,7 @@ struct Eo.Event_Description {
name: const(char) *; [[name of the event.]]
unfreezable: bool; [[Eina_True if the event cannot be frozen.]]
legacy_is: bool; [[Internal use: if is a legacy event.]]
+ restart: bool; [[Eina_True if when the event is triggered again from a callback, it should start from where it was]]
}
struct Eo.Event {
diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c
index 07038e69f1..16c0d4f77c 100644
--- a/src/lib/eo/eo_base_class.c
+++ b/src/lib/eo/eo_base_class.c
@@ -32,6 +32,9 @@ typedef struct
Eo_Base_Extension *extension;
Eo_Callback_Description *callbacks;
+
+ Eina_Inlist *current;
+
unsigned short walking_list;
unsigned short event_freeze_count;
Eina_Bool deletions_waiting : 1;
@@ -46,7 +49,12 @@ typedef struct
Eina_Bool data_is_value : 1;
} Eo_Generic_Data_Node;
-
+typedef struct
+{
+ EINA_INLIST;
+ const Eo_Event_Description *desc;
+ Eo_Callback_Description *current;
+} Eo_Current_Callback_Description;
static Eo_Base_Extension *
_eo_base_extension_new(void)
@@ -1157,14 +1165,45 @@ _eo_base_event_callback_call(Eo *obj_id, Eo_Base_Data *pd,
{
Eina_Bool ret = EINA_TRUE;
Eo_Callback_Description *cb;
+ Eo_Current_Callback_Description *lookup = NULL;
+ Eo_Current_Callback_Description saved;
Eo_Event ev;
+
ev.obj = obj_id;
ev.desc = desc;
ev.info = event_info;
pd->walking_list++;
- for (cb = pd->callbacks; cb; cb = cb->next)
+ // Handle event that require to restart where we were in the nested list walking
+ if (desc->restart)
+ {
+ EINA_INLIST_FOREACH(pd->current, lookup)
+ if (lookup->desc == desc)
+ break;
+
+ // This is the first event to trigger it, so register it here
+ if (!lookup)
+ {
+ // This following trick get us a zero allocation list
+ saved.desc = desc;
+ saved.current = NULL;
+ lookup = &saved;
+ // Ideally there will most of the time be only one item in this list
+ // But just to speed up things, prepend so we find it fast at the end
+ // of this function
+ pd->current = eina_inlist_prepend(pd->current, EINA_INLIST_GET(lookup));
+ }
+
+ if (!lookup->current) lookup->current = pd->callbacks;
+ cb = lookup->current;
+ }
+ else
+ {
+ cb = pd->callbacks;
+ }
+
+ for (; cb; cb = cb->next)
{
if (!cb->delete_me)
{
@@ -1180,12 +1219,18 @@ _eo_base_event_callback_call(Eo *obj_id, Eo_Base_Data *pd,
(event_freeze_count || pd->event_freeze_count))
continue;
+ // Handle nested restart of walking list
+ if (lookup) lookup->current = cb->next;
/* Abort callback calling if the func says so. */
if (!it->func((void *) cb->func_data, &ev))
{
ret = EINA_FALSE;
goto end;
}
+ // We have actually walked this list during a nested call
+ if (lookup &&
+ lookup->current == NULL)
+ goto end;
}
}
else
@@ -1196,17 +1241,30 @@ _eo_base_event_callback_call(Eo *obj_id, Eo_Base_Data *pd,
(event_freeze_count || pd->event_freeze_count))
continue;
+ // Handle nested restart of walking list
+ if (lookup) lookup->current = cb->next;
/* Abort callback calling if the func says so. */
if (!cb->items.item.func((void *) cb->func_data, &ev))
{
ret = EINA_FALSE;
goto end;
}
+ // We have actually walked this list during a nested call
+ if (lookup &&
+ lookup->current == NULL)
+ goto end;
}
}
}
end:
+ // Handling restarting list walking complete exit.
+ if (lookup) lookup->current = NULL;
+ if (lookup == &saved)
+ {
+ pd->current = eina_inlist_remove(pd->current, EINA_INLIST_GET(lookup));
+ }
+
pd->walking_list--;
_eo_callbacks_clear(pd);