jpeg pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=b184874fa5a0c3177c24a1989d24dcfb650af052

commit b184874fa5a0c3177c24a1989d24dcfb650af052
Author: Jean-Philippe Andre <jp.an...@samsung.com>
Date:   Thu Feb 16 16:47:57 2017 +0900

    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!
---
 src/lib/evas/canvas/evas_callbacks.c | 10 +++++-----
 src/lib/evas/canvas/evas_events.c    | 36 +++++++++++++++++++++++++++++++++---
 src/lib/evas/include/evas_private.h  |  1 +
 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 da5bb48..42dd851 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 ff20292..69a1586 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 ff28339..2495dca 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

-- 


Reply via email to