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
This commit is contained in:
Derek Foreman 2018-07-31 17:02:12 -04:00 committed by Mike Blumenkrantz
parent 3524d48719
commit e7bcf0e690
3 changed files with 63 additions and 3 deletions

View File

@ -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))

View File

@ -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);

View File

@ -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;