forked from enlightenment/efl
evas: Strengthen post-event callbacks
See T3144 that I marked as Wontfix. Bryce in E manually feeds events from a post-event callback resulting in Evas going insane and leading to frequent crashes. The ideal solution (for E) would be to ensure that everything works smoothly, the input event data is valid up until the post-event cb is called, etc... Unfortunately, with recursive events the exact order of operations may be messed up: the post-event I don't want to add yet more complexity to Evas events here (it's already spaghetti all over the place) so I'm simply blocking any new event feed when running the post-event callback list. It's not possible to just freeze the events (I tried, it failed). ********************** Some more explanation: post-event callbacks are used to implement reverse-order logic where the on-hold flag of an input event may be set by an event listener that does not come first. Here's a situation to illustrate: scroller A inside scroller B. As events are propagated from children to parents (assuming the propagate flag is set), we'd assume the events to go first to A and then to B, which means a mouse wheel event would make the inner-most scroller (A) scroll, and the outer-most scroller (B) wouldn't budge. But as things are designed, A and B are not simple evas objects, and the actual event-catching object is a top-most transparent rectangle (top-most in Z stack order). Since A is inside B, B's rectangle BR is over A's rectangle AR, thus catches the wheel event first. But in terms of UX we still want A to scroll, not B. The solution then is to reverse the event processing order and post-event callbacks are the way to do that. This comes with the consequence that the event_info needs to remain valid until the post-event is called, and stay the same (so that the on-hold flag set by A can be read by B). Recursive events (by explicit feed or modifying the canvas so that mouse,in or mouse,out are triggered) mess with this logic, and trigger the post-events too early (event is not fully processed) or too late (event_info is not valid anymore... and crash!). Thanks @raster for explaining the goal of post-event callbacks!
This commit is contained in:
parent
e434653fc2
commit
b184874fa5
|
@ -227,12 +227,12 @@ _evas_post_event_callback_call(Evas *eo_e, Evas_Public_Data *e)
|
|||
Evas_Post_Callback *pc;
|
||||
Eina_List *l, *l_next;
|
||||
int skip = 0;
|
||||
static int first_run = 1; // FIXME: This is a workaround to prevent this
|
||||
// function from being called recursively.
|
||||
|
||||
if (e->delete_me || (!first_run)) return;
|
||||
if (e->delete_me || e->running_post_events) return;
|
||||
if (!e->post_events) return;
|
||||
|
||||
_evas_walk(e);
|
||||
first_run = 0;
|
||||
e->running_post_events = EINA_TRUE;
|
||||
EINA_LIST_FOREACH_SAFE(e->post_events, l, l_next, pc)
|
||||
{
|
||||
e->post_events = eina_list_remove_list(e->post_events, l);
|
||||
|
@ -242,7 +242,7 @@ _evas_post_event_callback_call(Evas *eo_e, Evas_Public_Data *e)
|
|||
}
|
||||
EVAS_MEMPOOL_FREE(_mp_pc, pc);
|
||||
}
|
||||
first_run = 1;
|
||||
e->running_post_events = EINA_FALSE;
|
||||
_evas_unwalk(e);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,17 @@ static void
|
|||
_canvas_event_feed_mouse_move_legacy(Evas *eo_e, Evas_Public_Data *e, int x, int y,
|
||||
unsigned int timestamp, const void *data);
|
||||
|
||||
static inline Eina_Bool
|
||||
_evas_event_feed_allow(Evas_Public_Data *e)
|
||||
{
|
||||
if (EINA_LIKELY(!e->running_post_events)) return EINA_TRUE;
|
||||
ERR("Can not feed input events while running post-event callbacks!");
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
#define EVAS_EVENT_FEED_SAFETY_CHECK(evas, ...) do { \
|
||||
if (!_evas_event_feed_allow(evas)) return __VA_ARGS__; } while (0)
|
||||
|
||||
static void
|
||||
_evas_event_havemap_adjust_f(Evas_Object *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, Eina_Vector2 *point, Eina_Bool mouse_grabbed)
|
||||
{
|
||||
|
@ -1390,6 +1401,7 @@ _canvas_event_feed_mouse_down_internal(Evas_Public_Data *e, Efl_Input_Pointer_Da
|
|||
_efl_input_value_mask(EFL_INPUT_VALUE_BUTTON);
|
||||
|
||||
if (!e || !ev) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
pdata = _evas_pointer_data_by_device_get(e, ev->device);
|
||||
if (!pdata) return;
|
||||
|
@ -1509,13 +1521,13 @@ _post_up_handle(Evas_Public_Data *e, Efl_Input_Pointer *parent_ev,
|
|||
Evas_Object_Pointer_Data *obj_pdata;
|
||||
int event_id;
|
||||
|
||||
event_id = _evas_object_event_new();
|
||||
|
||||
/* Duplicating UP event */
|
||||
evt = efl_input_dup(parent_ev);
|
||||
ev = efl_data_scope_get(evt, EFL_INPUT_POINTER_CLASS);
|
||||
if (!ev) return 0;
|
||||
|
||||
event_id = _evas_object_event_new();
|
||||
|
||||
/* Actually we want an OUT */
|
||||
ev->action = EFL_POINTER_ACTION_OUT;
|
||||
|
||||
|
@ -1633,6 +1645,7 @@ _canvas_event_feed_mouse_up_internal(Evas_Public_Data *e, Efl_Input_Pointer_Data
|
|||
_efl_input_value_mask(EFL_INPUT_VALUE_BUTTON);
|
||||
|
||||
if (!e || !ev) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
pdata = _evas_pointer_data_by_device_get(e, ev->device);
|
||||
if (!pdata) return;
|
||||
|
@ -1736,6 +1749,7 @@ _canvas_event_feed_mouse_updown(Eo *eo_e, int b, Evas_Button_Flags flags,
|
|||
|
||||
e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
|
||||
if (!e) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
evt = efl_input_instance_get(EFL_INPUT_POINTER_CLASS, eo_e, (void **) &ev);
|
||||
if (!ev) return;
|
||||
|
@ -1803,6 +1817,7 @@ _canvas_event_feed_mouse_cancel_internal(Evas_Public_Data *e, Efl_Input_Pointer_
|
|||
|
||||
if (!e || !ev) return;
|
||||
if (e->is_frozen) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
pdata = _evas_pointer_data_by_device_get(e, ev->device);
|
||||
if (!pdata) return;
|
||||
|
@ -1851,6 +1866,7 @@ evas_event_feed_mouse_cancel(Eo *eo_e, unsigned int timestamp, const void *data)
|
|||
|
||||
evt = efl_input_instance_get(EFL_INPUT_POINTER_CLASS, eo_e, (void **) &ev);
|
||||
if (!ev) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
ev->timestamp = timestamp;
|
||||
ev->data = (void *) data;
|
||||
|
@ -1880,6 +1896,7 @@ _canvas_event_feed_mouse_wheel_internal(Eo *eo_e, Efl_Input_Pointer_Data *pe)
|
|||
_efl_input_value_mask(EFL_INPUT_VALUE_WHEEL_DIRECTION);
|
||||
|
||||
if (e->is_frozen) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
pdata = _evas_pointer_data_by_device_get(e, pe->device);
|
||||
if (!pdata) return;
|
||||
|
@ -1981,6 +1998,7 @@ _canvas_event_feed_mouse_move_internal(Evas_Public_Data *e, Efl_Input_Pointer_Da
|
|||
|
||||
if (!e || !ev) return;
|
||||
if (e->is_frozen) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
pdata = _evas_pointer_data_by_device_get(e, ev->device);
|
||||
if (!pdata) return;
|
||||
|
@ -2257,7 +2275,6 @@ nogrep:
|
|||
|
||||
// NOTE: was foreach + append without free (smelled bad)
|
||||
newin = eina_list_merge(newin, ins);
|
||||
|
||||
EINA_LIST_FOREACH(lst, l, eo_obj)
|
||||
{
|
||||
obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
|
||||
|
@ -2412,6 +2429,7 @@ _canvas_event_feed_mouse_in_internal(Evas *eo_e, Efl_Input_Pointer_Data *ev)
|
|||
_efl_input_value_mask(EFL_INPUT_VALUE_TOOL);
|
||||
|
||||
if (!e || !ev) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
pdata = _evas_pointer_data_by_device_get(e, ev->device);
|
||||
if (!pdata) return;
|
||||
|
@ -2492,6 +2510,7 @@ _canvas_event_feed_mouse_out_internal(Evas *eo_e, Efl_Input_Pointer_Data *ev)
|
|||
_efl_input_value_mask(EFL_INPUT_VALUE_TOOL);
|
||||
|
||||
if (!e || !ev) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
pdata = _evas_pointer_data_by_device_get(e, ev->device);
|
||||
if (!pdata) return;
|
||||
pdata->inside = 0;
|
||||
|
@ -2608,6 +2627,7 @@ _canvas_event_feed_multi_down_internal(Evas_Public_Data *e, Efl_Input_Pointer_Da
|
|||
_efl_input_value_mask(EFL_INPUT_VALUE_BUTTON);
|
||||
|
||||
if (!e || !ev) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
pdata = _evas_pointer_data_by_device_get(e, ev->device);
|
||||
if (!pdata) return;
|
||||
|
@ -2699,6 +2719,7 @@ _canvas_event_feed_multi_up_internal(Evas_Public_Data *e, Efl_Input_Pointer_Data
|
|||
_efl_input_value_mask(EFL_INPUT_VALUE_TOOL);
|
||||
|
||||
if (!e || !ev) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
pdata = _evas_pointer_data_by_device_get(e, ev->device);
|
||||
if (!pdata) return;
|
||||
|
@ -2776,6 +2797,7 @@ _canvas_event_feed_multi_internal(Evas *eo_e, Evas_Public_Data *e,
|
|||
|
||||
evt = efl_input_instance_get(EFL_INPUT_POINTER_CLASS, eo_e, (void **) &ev);
|
||||
if (!e || !ev) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
if (EINA_DBL_EQ(fx, 0.0)) fx = x;
|
||||
if (EINA_DBL_EQ(fy, 0.0)) fy = y;
|
||||
|
@ -2874,6 +2896,7 @@ _canvas_event_feed_multi_move_internal(Evas_Public_Data *e, Efl_Input_Pointer_Da
|
|||
_efl_input_value_mask(EFL_INPUT_VALUE_TOOL);
|
||||
|
||||
if (!e || !ev) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
pdata = _evas_pointer_data_by_device_get(e, ev->device);
|
||||
if (!pdata) return;
|
||||
|
@ -3069,6 +3092,7 @@ _canvas_event_feed_key_down_internal(Evas_Public_Data *e, Efl_Input_Key_Data *ev
|
|||
|
||||
if (!e || !ev) return;
|
||||
if (e->is_frozen) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
e->last_timestamp = ev->timestamp;
|
||||
_evas_walk(e);
|
||||
|
||||
|
@ -3155,6 +3179,7 @@ _canvas_event_feed_key_up_internal(Evas_Public_Data *e, Efl_Input_Key_Data *ev)
|
|||
|
||||
if (!e || !ev) return;
|
||||
if (e->is_frozen) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
e->last_timestamp = ev->timestamp;
|
||||
_evas_walk(e);
|
||||
|
||||
|
@ -3314,6 +3339,7 @@ evas_event_feed_hold(Eo *eo_e, int hold, unsigned int timestamp, const void *dat
|
|||
Evas_Pointer_Data *pdata;
|
||||
|
||||
if (e->is_frozen) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
e->last_timestamp = timestamp;
|
||||
|
||||
event_id = _evas_object_event_new();
|
||||
|
@ -3368,6 +3394,7 @@ _canvas_event_feed_axis_update_internal(Evas_Public_Data *e, Efl_Input_Pointer_D
|
|||
|
||||
if (!e || !ev) return;
|
||||
if (e->is_frozen) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
pdata = _evas_pointer_data_by_device_get(e, ev->device);
|
||||
if (!pdata) return;
|
||||
|
@ -3413,6 +3440,9 @@ evas_event_feed_axis_update(Evas *eo_e, unsigned int timestamp, int device, int
|
|||
double x = 0, y = 0;
|
||||
int n;
|
||||
|
||||
if (!e) return;
|
||||
EVAS_EVENT_FEED_SAFETY_CHECK(e);
|
||||
|
||||
evt = efl_input_instance_get(EFL_INPUT_POINTER_CLASS, eo_e, (void **) &ev);
|
||||
if (!ev) return;
|
||||
|
||||
|
|
|
@ -949,6 +949,7 @@ struct _Evas_Public_Data
|
|||
Eina_Bool rendering : 1;
|
||||
Eina_Bool render2 : 1;
|
||||
Eina_Bool common_init : 1;
|
||||
Eina_Bool running_post_events : 1;
|
||||
};
|
||||
|
||||
struct _Evas_Layer
|
||||
|
|
Loading…
Reference in New Issue