From 115a9a22b1d25d8d3b2d433994cc6756174b11b9 Mon Sep 17 00:00:00 2001 From: Cedric BAIL Date: Thu, 5 Dec 2019 13:57:52 -0800 Subject: [PATCH] eo: only forward event if someone is listening. This limit long chain of useless event forwarding when nobody is listening at the end of the pipe. Differential Revision: https://phab.enlightenment.org/D10813 --- src/lib/eo/eo_base_class.c | 137 ++++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 3 deletions(-) diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c index 66e6032830..9fd4d2b08b 100644 --- a/src/lib/eo/eo_base_class.c +++ b/src/lib/eo/eo_base_class.c @@ -23,6 +23,18 @@ static int event_freeze_count = 0; typedef struct _Eo_Callback_Description Eo_Callback_Description; typedef struct _Efl_Event_Callback_Frame Efl_Event_Callback_Frame; +typedef struct _Efl_Event_Forwarder Efl_Event_Forwarder; + +struct _Efl_Event_Forwarder +{ + const Efl_Event_Description *desc; + Eo *source; + Eo *new_obj; + + short priority; + + Eina_Bool inserted : 1; +}; struct _Efl_Event_Callback_Frame { @@ -41,6 +53,7 @@ typedef struct Eo ***wrefs; Eina_Hash *providers; Eina_Hash *schedulers; + Eina_Hash *forwarders; } Efl_Object_Extension; #define EFL_OBJECT_EVENT_CALLBACK(Event) Eina_Bool event_cb_##Event : 1; @@ -124,6 +137,8 @@ typedef struct if ((pd)->event_frame) (pd)->event_frame = (pd)->event_frame->next; \ } while (0) +static void _efl_event_forwarder_callback(void *data, const Efl_Event *event); + static int _eo_nostep_alloc = -1; static void @@ -162,7 +177,8 @@ _efl_object_extension_noneed(Efl_Object_Data *pd) (ext->wrefs) || (ext->composite_parent) || (ext->providers) || - (ext->schedulers)) return; + (ext->schedulers) || + (ext->forwarders)) return; _efl_object_extension_free(pd->ext); pd->ext = NULL; } @@ -172,6 +188,13 @@ _efl_object_invalidate(Eo *obj_id, Efl_Object_Data *pd) { _efl_pending_futures_clear(pd); + if (pd->ext && pd->ext->forwarders) + { + eina_hash_free(pd->ext->forwarders); + pd->ext->forwarders = NULL; + _efl_object_extension_noneed(pd); + } + if (pd->ext && pd->ext->providers) { eina_hash_free(pd->ext->providers); @@ -1282,6 +1305,24 @@ _special_event_count_inc(Eo *obj_id, Efl_Object_Data *pd, const Efl_Callback_Arr EO_OBJ_DONE(obj_id); } + if (pd->ext && pd->ext->forwarders) + { + Efl_Event_Forwarder *forwarder; + Eina_List *l; + + // Check if some event need to be forwarded now + EINA_LIST_FOREACH(eina_hash_find(pd->ext->forwarders, it->desc), l, forwarder) + { + if (!forwarder->source) continue; + if (forwarder->inserted) continue; + efl_event_callback_priority_add(forwarder->source, + forwarder->desc, + forwarder->priority, + _efl_event_forwarder_callback, obj_id); + forwarder->inserted = EINA_TRUE; + } + } + if (update_hash) { unsigned char event_hash; @@ -2193,6 +2234,27 @@ _efl_event_forwarder_callback(void *data, const Efl_Event *event) } } +static void +_forwarders_list_clean(void *data) +{ + Efl_Event_Forwarder *forwarder; + Eina_List *l = data; + + EINA_LIST_FREE(l, forwarder) + { + if (forwarder->source) + { + if (forwarder->inserted) + efl_event_callback_del(forwarder->source, + forwarder->desc, + _efl_event_forwarder_callback, + forwarder->new_obj); + efl_wref_del(forwarder->source, &forwarder->source); + } + free(forwarder); + } +} + EOLIAN static void _efl_object_event_callback_forwarder_priority_add(Eo *obj, Efl_Object_Data *pd EINA_UNUSED, const Efl_Event_Description *desc, @@ -2201,8 +2263,50 @@ _efl_object_event_callback_forwarder_priority_add(Eo *obj, Efl_Object_Data *pd E { EO_OBJ_POINTER_RETURN(new_obj, new_data); EO_OBJ_DONE(new_obj); + Efl_Event_Forwarder *forwarder; + Efl_Object_Extension *ext; + Efl_Object_Data *dpd; + Eina_List *l; - efl_event_callback_priority_add(obj, desc, priority, _efl_event_forwarder_callback, new_obj); + dpd = efl_data_scope_safe_get(new_obj, EFL_OBJECT_CLASS); + EINA_SAFETY_ON_NULL_RETURN(dpd); + + ext = _efl_object_extension_need(dpd); + EINA_SAFETY_ON_NULL_RETURN(ext); + + // Prevent double insertion for the same object source and event description + EINA_LIST_FOREACH(eina_hash_find(ext->forwarders, desc), l, forwarder) + { + if (forwarder->desc == desc && + forwarder->new_obj == new_obj && + forwarder->source == obj) + { + ERR("Forwarder added on '%s' for event '%s' toward '%s' has already been set.\n", + efl_debug_name_get(obj), desc->name, efl_debug_name_get(new_obj)); + return; + } + } + + forwarder = malloc(sizeof (Efl_Event_Forwarder)); + EINA_SAFETY_ON_NULL_RETURN(forwarder); + forwarder->desc = desc; + forwarder->priority = priority; + forwarder->new_obj = new_obj; + efl_wref_add(obj, &forwarder->source); + + if (efl_event_callback_count(new_obj, desc) > 0) + { + efl_event_callback_priority_add(obj, desc, priority, _efl_event_forwarder_callback, new_obj); + forwarder->inserted = EINA_TRUE; + } + else + { + forwarder->inserted = EINA_FALSE; + } + + if (!ext->forwarders) + ext->forwarders = eina_hash_pointer_new(_forwarders_list_clean); + eina_hash_list_direct_append(ext->forwarders, forwarder->desc, forwarder); } EOLIAN static void @@ -2212,8 +2316,35 @@ _efl_object_event_callback_forwarder_del(Eo *obj, Efl_Object_Data *pd EINA_UNUSE { EO_OBJ_POINTER_RETURN(new_obj, new_data); EO_OBJ_DONE(new_obj); + Efl_Event_Forwarder *forwarder; + Efl_Object_Extension *ext; + Efl_Object_Data *dpd; + Eina_List *l, *tofree = NULL; - efl_event_callback_del(obj, desc, _efl_event_forwarder_callback, new_obj); + dpd = efl_data_scope_safe_get(new_obj, EFL_OBJECT_CLASS); + if (!dpd) return ; + + ext = _efl_object_extension_need(dpd); + if (!ext) return ; + + EINA_LIST_FOREACH(eina_hash_find(ext->forwarders, desc), l, forwarder) + { + // Remove dead source at the same time we remove any forwader + if (forwarder->source == obj || forwarder->source == NULL) + tofree = eina_list_append(tofree, forwarder); + } + + EINA_LIST_FREE(tofree, forwarder) + { + if (forwarder->source) + { + if (forwarder->inserted) + efl_event_callback_del(obj, desc, _efl_event_forwarder_callback, new_obj); + efl_wref_del(obj, &forwarder->source); + } + eina_hash_list_remove(ext->forwarders, desc, forwarder); + free(forwarder); + } } EOLIAN static void