discomfitor pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=e7bcf0e690e75b13db022adaeeab1ab86c459540
commit e7bcf0e690e75b13db022adaeeab1ab86c459540 Author: Derek Foreman <derek.foreman.sams...@gmail.com> Date: Tue Jul 31 17:02:12 2018 -0400 evas: Defer render post callbacks added during async render Summary: To take screenshots, Enlightenment makes a new snapshot object, performs a manual render, and uses the snapshot results. Turns out if this happens while an async render is in progress, the async render's completion triggers a render post callback on the snapshot object even though it's never been involved in a render. We need to defer new render post callbacks until any currently running render completes, then add them during that render's post. Fix T7156 Reviewers: devilhorns, zmike Reviewed By: devilhorns, zmike Subscribers: devilhorns, cedric, #committers, zmike Tags: #efl Maniphest Tasks: T7156 Differential Revision: https://phab.enlightenment.org/D6711 --- src/lib/evas/canvas/evas_callbacks.c | 62 ++++++++++++++++++++++++++++++++++-- src/lib/evas/canvas/evas_render.c | 1 + src/lib/evas/include/evas_private.h | 3 ++ 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/lib/evas/canvas/evas_callbacks.c b/src/lib/evas/canvas/evas_callbacks.c index 0814b6fa5b..bb4face262 100644 --- a/src/lib/evas/canvas/evas_callbacks.c +++ b/src/lib/evas/canvas/evas_callbacks.c @@ -107,6 +107,7 @@ typedef struct void *data; Evas_Callback_Type type; Efl_Event_Info_Type efl_event_type; + Evas_Callback_Priority priority; } Evas_Event_Cb_Wrapper_Info; static int @@ -563,6 +564,24 @@ evas_event_callback_add(Evas *eo_e, Evas_Callback_Type type, Evas_Event_Cb func, func, data); } +void +_deferred_callbacks_process(Evas *eo_e, Evas_Public_Data *e) +{ + Evas_Event_Cb_Wrapper_Info *cb_info; + const Efl_Event_Description *desc; + + while (e->deferred_callbacks) + { + cb_info = EINA_INLIST_CONTAINER_GET(e->deferred_callbacks, + Evas_Event_Cb_Wrapper_Info); + e->deferred_callbacks = eina_inlist_remove(e->deferred_callbacks, + e->deferred_callbacks); + desc = _legacy_evas_callback_table(cb_info->type); + efl_event_callback_priority_add(eo_e, desc, cb_info->priority, _eo_evas_cb, cb_info); + e->callbacks = eina_inlist_append(e->callbacks, EINA_INLIST_GET(cb_info)); + } +} + EAPI void evas_event_callback_priority_add(Evas *eo_e, Evas_Callback_Type type, Evas_Callback_Priority priority, Evas_Event_Cb func, const void *data) { @@ -581,13 +600,22 @@ evas_event_callback_priority_add(Evas *eo_e, Evas_Callback_Type type, Evas_Callb cb_info = calloc(1, sizeof(*cb_info)); cb_info->func.evas_cb = func; cb_info->data = (void *)data; + cb_info->priority = priority; cb_info->type = type; cb_info->efl_event_type = _evas_event_efl_event_info_type(type); - desc = _legacy_evas_callback_table(type); - efl_event_callback_priority_add(eo_e, desc, priority, _eo_evas_cb, cb_info); + if ((e->rendering || e->inside_post_render) && type == EVAS_CALLBACK_RENDER_POST) + { + e->deferred_callbacks = eina_inlist_append(e->deferred_callbacks, + EINA_INLIST_GET(cb_info)); + } + else + { + desc = _legacy_evas_callback_table(type); + efl_event_callback_priority_add(eo_e, desc, priority, _eo_evas_cb, cb_info); - e->callbacks = eina_inlist_append(e->callbacks, EINA_INLIST_GET(cb_info)); + e->callbacks = eina_inlist_append(e->callbacks, EINA_INLIST_GET(cb_info)); + } } EAPI void * @@ -604,6 +632,20 @@ evas_event_callback_del(Evas *eo_e, Evas_Callback_Type type, Evas_Event_Cb func) if (!e->callbacks) return NULL; + if (type == EVAS_CALLBACK_RENDER_POST) + EINA_INLIST_REVERSE_FOREACH(e->deferred_callbacks, info) + { + if (info->func.evas_cb == func) + { + void *tmp = info->data; + + e->deferred_callbacks = + eina_inlist_remove(e->deferred_callbacks, EINA_INLIST_GET(info)); + free(info); + return tmp; + } + } + EINA_INLIST_REVERSE_FOREACH(e->callbacks, info) { if ((info->func.evas_cb == func) && (info->type == type)) @@ -634,6 +676,20 @@ evas_event_callback_del_full(Evas *eo_e, Evas_Callback_Type type, Evas_Event_Cb if (!e->callbacks) return NULL; + if (type == EVAS_CALLBACK_RENDER_POST) + EINA_INLIST_REVERSE_FOREACH(e->deferred_callbacks, info) + { + if ((info->func.evas_cb == func) && (info->data == data)) + { + void *tmp = info->data; + + e->deferred_callbacks = + eina_inlist_remove(e->deferred_callbacks, EINA_INLIST_GET(info)); + free(info); + return tmp; + } + } + EINA_INLIST_FOREACH(e->callbacks, info) { if ((info->func.evas_cb == func) && (info->type == type) && (info->data == data)) diff --git a/src/lib/evas/canvas/evas_render.c b/src/lib/evas/canvas/evas_render.c index f03a6a5cab..0a915a19df 100644 --- a/src/lib/evas/canvas/evas_render.c +++ b/src/lib/evas/canvas/evas_render.c @@ -3838,6 +3838,7 @@ evas_render_wakeup(Evas *eo_e) post.updated_area = ret_updates; _cb_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, &post); evas->inside_post_render = EINA_FALSE; + _deferred_callbacks_process(eo_e, evas); evas_render_updates_free(ret_updates); diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index bded8892b6..a63194df3f 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -860,6 +860,7 @@ struct _Evas_Public_Data Eina_List *post_events; // free me on evas_free Eina_Inlist *callbacks; + Eina_Inlist *deferred_callbacks; int delete_grabs; int walking_grabs; @@ -1914,6 +1915,8 @@ void _efl_canvas_gesture_manager_callback_add_hook(Eo *gesture_manager, Eo *targ void evas_focus_init(void); void evas_focus_shutdown(void); +void _deferred_callbacks_process(Evas *eo_e, Evas_Public_Data *e); + extern Eina_Cow *evas_object_proxy_cow; extern Eina_Cow *evas_object_map_cow; extern Eina_Cow *evas_object_state_cow; --