summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2017-02-16 16:47:57 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2017-02-16 18:10:18 +0900
commitb184874fa5a0c3177c24a1989d24dcfb650af052 (patch)
treef175a25241fc395db81472351b3fab56067ba80f
parente434653fc2a23b1841ebbe243f5169813939b178 (diff)
downloadefl-b184874fa5a0c3177c24a1989d24dcfb650af052.tar.gz
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!
-rw-r--r--src/lib/evas/canvas/evas_callbacks.c10
-rw-r--r--src/lib/evas/canvas/evas_events.c36
-rw-r--r--src/lib/evas/include/evas_private.h1
3 files changed, 39 insertions, 8 deletions
diff --git a/src/lib/evas/canvas/evas_callbacks.c b/src/lib/evas/canvas/evas_callbacks.c
index da5bb48b96..42dd8515f0 100644
--- a/src/lib/evas/canvas/evas_callbacks.c
+++ b/src/lib/evas/canvas/evas_callbacks.c
@@ -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);
}
diff --git a/src/lib/evas/canvas/evas_events.c b/src/lib/evas/canvas/evas_events.c
index ff202928a2..69a1586fe6 100644
--- a/src/lib/evas/canvas/evas_events.c
+++ b/src/lib/evas/canvas/evas_events.c
@@ -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;
diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h
index ff28339f32..2495dca758 100644
--- a/src/lib/evas/include/evas_private.h
+++ b/src/lib/evas/include/evas_private.h
@@ -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