evas: add new event_grabber smart-ish object
authorMike Blumenkrantz <zmike@osg.samsung.com>
Sat, 10 Jun 2017 00:16:08 +0000 (20:16 -0400)
committerMike Blumenkrantz <zmike@osg.samsung.com>
Sat, 10 Jun 2017 00:06:19 +0000 (20:06 -0400)
adding an "event rect" is a common use case for rectangles, but I needed
a smarter event rect so I sent one off to school and it came back like this.

an event_grabber is a smart object which functions like a normal event rect
which has color(0,0,0,0), but with an important difference: it can have smart
members. event propagation works differently for an event_grabber:

normal:
event -> layer -> smart(obj1,obj2,obj3) ->(?) other objects
in this case, obj1,obj2,obj3 are all "inside" the smart object and their stacking
will always be considered as being inside the smart object. rendering is also
tied to the smart object in this case, as is clipping.
an event which reaches a smart object will be sent to the objects inside,
and then may continue through the smart object if there are no objects which
block repeating.

event_grabber:
event -> layer -> event_grabber -> obj1,obj2,obj3 -> STOP
in this case, obj1,obj2,obj3 are unmodified after being added to the event_grabber
and can be stacked, rendered, and clipped completely independently of the
event_grabber.
the event_grabber is considered an "event_parent" for this case. member objects
are not "inside" the event_grabber, and they are unable to receive events on
their own. instead, the event_grabber, which must be stacked above all its
members, receives events and propagates them top->down through its member objects.
if none of the member objects block the repeat of an event then the event will
still be blocked from further propagation past the event_grabber.

object lifetimes are independent of the event_grabber; deleting the event_grabber
has no effect on its members.

@feature

src/Makefile_Evas.am
src/lib/evas/Evas_Eo.h
src/lib/evas/Evas_Legacy.h
src/lib/evas/canvas/efl_canvas_object_event_grabber.c [new file with mode: 0644]
src/lib/evas/canvas/efl_canvas_object_event_grabber.eo [new file with mode: 0644]
src/lib/evas/canvas/evas_callbacks.c
src/lib/evas/canvas/evas_events.c
src/lib/evas/include/evas_private.h

index baa767a..41c44e7 100644 (file)
@@ -3,6 +3,7 @@
 
 evas_eolian_pub_files = \
        lib/evas/canvas/efl_canvas_object.eo \
+       lib/evas/canvas/efl_canvas_object_event_grabber.eo \
        lib/evas/canvas/efl_canvas_polygon.eo \
        lib/evas/canvas/efl_canvas_rectangle.eo \
        lib/evas/canvas/efl_canvas_text.eo \
@@ -199,6 +200,7 @@ lib/evas/canvas/evas_map.h \
 lib/evas/canvas/evas_gl.c \
 lib/evas/canvas/evas_out.c \
 lib/evas/canvas/efl_canvas_image.c \
+lib/evas/canvas/efl_canvas_object_event_grabber.c \
 lib/evas/canvas/efl_canvas_proxy.c \
 lib/evas/canvas/efl_canvas_snapshot.c \
 lib/evas/canvas/efl_canvas_scene3d.c \
index 38d1e3a..8581042 100644 (file)
@@ -66,6 +66,9 @@
 #endif /* EFL_EO_API_SUPPORT */
 
 #if defined(EFL_BETA_API_SUPPORT) && defined(EFL_EO_API_SUPPORT)
+
+#include "canvas/efl_canvas_object_event_grabber.eo.h"
+
  /**
  * @defgroup Evas_3D Evas 3D Extensions
  *
index a98aae4..ac6c429 100644 (file)
@@ -7666,3 +7666,29 @@ EAPI void evas_object_text_filter_program_set(Evas_Object *obj, const char *code
  * @since 1.18
  */
 EAPI void evas_object_text_filter_source_set(Evas_Object *obj, const char *name, Evas_Object *source) EINA_DEPRECATED;
+
+#ifdef EFL_BETA_API_SUPPORT
+/**
+ * Creates a new smart rectangle object on the given Evas @p e canvas.
+ *
+ * @param e The given canvas.
+ * @return The created object handle.
+ *
+ * This provides a smart version of the typical "event rectangle",
+ * which allows objects to set this as their parent and route events
+ * to a group of objects. Events will not propagate to non-member objects
+ * below this object.
+ *
+ * Adding members is done just like a normal smart object, using
+ * efl_canvas_group_member_add (Eo API) or evas_object_smart_member_add (legacy).
+ *
+ * Child objects are not modified in any way, unlike other types of smart objects.
+ *
+ * It is a user error for any child objects to be stacked above the event
+ * grabber parent while the event grabber is visible.
+ * A critical error will be raised if this is detected at any point.
+ *
+ * @since 1.20
+ */
+EAPI Evas_Object *evas_object_event_grabber_add(Evas *e);
+#endif
diff --git a/src/lib/evas/canvas/efl_canvas_object_event_grabber.c b/src/lib/evas/canvas/efl_canvas_object_event_grabber.c
new file mode 100644 (file)
index 0000000..12d882d
--- /dev/null
@@ -0,0 +1,350 @@
+#include "evas_common_private.h"
+#include "evas_private.h"
+#include "efl_canvas_object_event_grabber.eo.h"
+
+#define MY_CLASS EFL_CANVAS_OBJECT_EVENT_GRABBER_CLASS
+#define MY_CLASS_NAME "Efl_Object_Event_Grabber"
+#define MY_CLASS_NAME_LEGACY "evas_object_event_grabber"
+
+
+struct _Efl_Object_Event_Grabber_Data
+{
+   Eo *rect;
+   Eina_Clist contained;
+   Eina_Bool vis : 1;
+};
+
+typedef struct Efl_Object_Event_Grabber_Iterator
+{
+   Eina_Iterator iterator;
+
+   Eina_Clist *head;
+   Eina_Clist *current;
+   Eo *parent;
+} Efl_Object_Event_Grabber_Iterator;
+
+
+static Eina_Bool
+_efl_canvas_object_event_grabber_efl_canvas_group_group_iterator_next(Efl_Object_Event_Grabber_Iterator *it, void **data)
+{
+   Evas_Object_Protected_Data *obj;
+
+   if (!eina_clist_next(it->head, it->current)) return EINA_FALSE;
+
+   obj = EINA_CLIST_ENTRY(eina_clist_head(it->current), Evas_Object_Protected_Data, event.member);
+   if (data) *data = obj->object;
+
+   it->current = eina_clist_next(it->head, it->current);
+
+   return EINA_TRUE;
+}
+
+static Evas_Object *
+_efl_canvas_object_event_grabber_efl_canvas_group_group_iterator_get_container(Efl_Object_Event_Grabber_Iterator *it)
+{
+   return it->parent;
+}
+
+static void
+_efl_canvas_object_event_grabber_efl_canvas_group_group_iterator_free(Efl_Object_Event_Grabber_Iterator *it)
+{
+   efl_unref(it->parent);
+   free(it);
+}
+
+EOLIAN static Eina_Iterator*
+_efl_canvas_object_event_grabber_efl_canvas_group_group_children_iterate(const Eo *eo_obj, Efl_Object_Event_Grabber_Data *pd)
+{
+   Efl_Object_Event_Grabber_Iterator *it;
+
+   if (eina_clist_empty(&pd->contained)) return NULL;
+
+   it = calloc(1, sizeof(Efl_Object_Event_Grabber_Iterator));
+   if (!it) return NULL;
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+   it->parent = efl_ref(eo_obj);
+   it->head = it->current = &pd->contained;
+
+   it->iterator.next = FUNC_ITERATOR_NEXT(_efl_canvas_object_event_grabber_efl_canvas_group_group_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_efl_canvas_object_event_grabber_efl_canvas_group_group_iterator_get_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(_efl_canvas_object_event_grabber_efl_canvas_group_group_iterator_free);
+
+   return &it->iterator;
+}
+
+static void
+_stacking_verify(Efl_Object_Event_Grabber_Data *pd, Evas_Object_Protected_Data *obj)
+{
+   Eo *grabber;
+   Evas_Object_Protected_Data *gobj, *i;
+
+   grabber = efl_parent_get(pd->rect);
+   gobj = efl_data_scope_get(grabber, EFL_CANVAS_OBJECT_CLASS);
+   if (obj->layer->layer > gobj->layer->layer)
+     {
+        CRI("Cannot stack child object above event grabber object!");
+        return;
+     }
+   if (obj->layer != gobj->layer) return;
+
+   EINA_INLIST_REVERSE_FOREACH(EINA_INLIST_GET(gobj->layer->objects), i)
+     {
+        if (i == gobj) break;
+        if (i == obj)
+          {
+             CRI("Cannot stack child object above event grabber object!");
+             return;
+          }
+     }
+}
+
+static void
+_child_insert(Efl_Object_Event_Grabber_Data *pd, Evas_Object_Protected_Data *obj)
+{
+   Evas_Object_Protected_Data *a, *i;
+
+   if (eina_clist_empty(&pd->contained))
+     {
+        /* pd->rect case */
+        eina_clist_add_head(&pd->contained, &obj->event.member);
+        return;
+     }
+
+   if (pd->vis) _stacking_verify(pd, obj);
+   EINA_CLIST_FOR_EACH_ENTRY_REV(a, &pd->contained, Evas_Object_Protected_Data, event.member)
+     {
+        if (a->object == pd->rect)
+          {
+             eina_clist_add_after(&a->event.member, &obj->event.member);
+             return;
+          }
+        if (a->layer->layer > obj->layer->layer) continue;
+        if (a->layer->layer < obj->layer->layer)
+          {
+             eina_clist_add_after(&a->event.member, &obj->event.member);
+             return;
+          }
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(a->layer->objects), i)
+          {
+             if (a == i)
+               {
+                  eina_clist_add_after(&a->event.member, &obj->event.member);
+                  return;
+               }
+             if (obj == i)
+               {
+                  eina_clist_add_before(&a->event.member, &obj->event.member);
+                  return;
+               }
+          }
+     }
+}
+
+static void
+_efl_canvas_object_event_grabber_child_restack(void *data, const Efl_Event *event)
+{
+   Efl_Object_Event_Grabber_Data *pd = data;
+   Evas_Object_Protected_Data *obj = efl_data_scope_get(event->object, EFL_CANVAS_OBJECT_CLASS);
+
+   eina_clist_remove(&obj->event.member);
+   _child_insert(pd, obj);
+}
+
+static void
+_efl_canvas_object_event_grabber_child_del(void *data, const Efl_Event *event)
+{
+   Efl_Object_Event_Grabber_Data *pd = data;
+
+   efl_canvas_group_member_del(efl_parent_get(pd->rect), event->object);
+}
+
+EOLIAN static void
+_efl_canvas_object_event_grabber_efl_canvas_group_group_member_add(Eo *eo_obj, Efl_Object_Event_Grabber_Data *pd, Eo *member)
+{
+   Evas_Object_Protected_Data *obj = efl_data_scope_get(member, EFL_CANVAS_OBJECT_CLASS);
+   Evas_Object_Protected_Data *smart = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
+
+   EINA_SAFETY_ON_NULL_RETURN(obj);
+   EINA_SAFETY_ON_NULL_RETURN(smart);
+
+   if (member != pd->rect)
+     {
+        if (obj->delete_me)
+          {
+             CRI("Adding deleted object %p to smart obj %p", member, eo_obj);
+             return;
+          }
+        if (smart->delete_me)
+          {
+             CRI("Adding object %p to deleted smart obj %p", member, eo_obj);
+             return;
+          }
+        if (!smart->layer)
+          {
+             CRI("No evas surface associated with smart object (%p)", eo_obj);
+             return;
+          }
+        if (!obj->layer)
+          {
+             CRI("No evas surface associated with member object (%p)", member);
+             return;
+          }
+        if ((obj->layer && smart->layer) &&
+            (obj->layer->evas != smart->layer->evas))
+          {
+             CRI("Adding object %p from Evas (%p) from another Evas (%p)", member, obj->layer->evas, smart->layer->evas);
+             return;
+          }
+     }
+   if (obj->event.parent == eo_obj) return;
+
+   if (obj->smart.parent || obj->event.parent) evas_object_smart_member_del(member);
+   obj->event.parent = eo_obj;
+   _child_insert(pd, obj);
+   efl_event_callback_add(member, EFL_EVENT_DEL, _efl_canvas_object_event_grabber_child_del, pd);
+   if (member != pd->rect)
+     efl_event_callback_add(member, EFL_GFX_EVENT_RESTACK, _efl_canvas_object_event_grabber_child_restack, pd);
+}
+
+EOLIAN static void
+_efl_canvas_object_event_grabber_efl_canvas_group_group_member_del(Eo *eo_obj EINA_UNUSED, Efl_Object_Event_Grabber_Data *pd EINA_UNUSED, Eo *member)
+{
+   Evas_Object_Protected_Data *obj = efl_data_scope_get(member, EFL_CANVAS_OBJECT_CLASS);
+
+   efl_event_callback_del(member, EFL_EVENT_DEL, _efl_canvas_object_event_grabber_child_del, pd);
+   efl_event_callback_del(member, EFL_GFX_EVENT_RESTACK, _efl_canvas_object_event_grabber_child_restack, pd);
+   eina_clist_remove(&obj->event.member);
+   obj->event.parent = NULL;
+}
+
+EOLIAN static void
+_efl_canvas_object_event_grabber_efl_canvas_group_group_change(Eo *eo_obj EINA_UNUSED, Efl_Object_Event_Grabber_Data *pd EINA_UNUSED)
+{}
+
+EOLIAN static void
+_efl_canvas_object_event_grabber_efl_canvas_group_group_calculate(Eo *eo_obj EINA_UNUSED, Efl_Object_Event_Grabber_Data *pd EINA_UNUSED)
+{}
+
+EOLIAN static void
+_efl_canvas_object_event_grabber_efl_canvas_group_group_need_recalculate_set(Eo *eo_obj EINA_UNUSED, Efl_Object_Event_Grabber_Data *pd EINA_UNUSED, Eina_Bool set EINA_UNUSED)
+{}
+
+EOLIAN static Eina_Bool
+_efl_canvas_object_event_grabber_efl_canvas_group_group_need_recalculate_get(Eo *eo_obj EINA_UNUSED, Efl_Object_Event_Grabber_Data *pd EINA_UNUSED)
+{
+   return EINA_FALSE;
+}
+
+EOLIAN static void
+_efl_canvas_object_event_grabber_efl_gfx_position_set(Eo *eo_obj, Efl_Object_Event_Grabber_Data *pd, int x, int y)
+{
+   efl_gfx_position_set(efl_super(eo_obj, MY_CLASS), x, y);
+   efl_gfx_position_set(pd->rect, x, y);
+}
+
+EOLIAN static void
+_efl_canvas_object_event_grabber_efl_gfx_size_set(Eo *eo_obj, Efl_Object_Event_Grabber_Data *pd, int w, int h)
+{
+   efl_gfx_size_set(efl_super(eo_obj, MY_CLASS), w, h);
+   efl_gfx_size_set(pd->rect, w, h);
+}
+
+EOLIAN static Eina_Bool
+_efl_canvas_object_event_grabber_efl_gfx_visible_get(Eo *eo_obj EINA_UNUSED, Efl_Object_Event_Grabber_Data *pd)
+{
+   return pd->vis;
+}
+
+EOLIAN static void
+_efl_canvas_object_event_grabber_efl_gfx_visible_set(Eo *eo_obj EINA_UNUSED, Efl_Object_Event_Grabber_Data *pd, Eina_Bool set)
+{
+   if (set)
+     {
+        Evas_Object_Protected_Data *obj;
+
+        EINA_CLIST_FOR_EACH_ENTRY(obj, &pd->contained, Evas_Object_Protected_Data, event.member)
+          if (obj->object != pd->rect) _stacking_verify(pd, obj);
+     }
+   pd->vis = !!set;
+   efl_gfx_visible_set(pd->rect, set);
+}
+
+EOLIAN static void
+_efl_canvas_object_event_grabber_efl_gfx_stack_layer_set(Eo *eo_obj, Efl_Object_Event_Grabber_Data *pd, short l)
+{
+   efl_gfx_stack_layer_set(efl_super(eo_obj, MY_CLASS), l);
+   efl_gfx_stack_layer_set(pd->rect, l);
+}
+
+static void
+_efl_canvas_object_event_grabber_restack(void *data, const Efl_Event *event)
+{
+   Efl_Object_Event_Grabber_Data *pd = data;
+   Eina_List *list = NULL;
+   Evas_Object_Protected_Data *obj, *nobj;
+
+   evas_object_layer_set(pd->rect, evas_object_layer_get(event->object));
+   evas_object_stack_below(pd->rect, event->object);
+
+   EINA_CLIST_FOR_EACH_ENTRY_SAFE(obj, nobj, &pd->contained, Evas_Object_Protected_Data, event.member)
+     {
+        if (obj->object == pd->rect) continue;
+        list = eina_list_append(list, obj);
+        eina_clist_remove(&obj->event.member);
+     }
+   EINA_LIST_FREE(list, obj)
+     _child_insert(pd, obj);
+}
+
+EOLIAN static Eo *
+_efl_canvas_object_event_grabber_efl_object_constructor(Eo *eo_obj, Efl_Object_Event_Grabber_Data *pd)
+{
+   Evas_Object_Protected_Data *obj;
+   
+   eo_obj = efl_constructor(efl_super(eo_obj, MY_CLASS));
+   efl_canvas_object_type_set(eo_obj, MY_CLASS_NAME_LEGACY);
+   obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
+   obj->is_event_parent = 1;
+   obj->is_smart = 0;
+   eina_clist_init(&pd->contained);
+   efl_event_callback_add(eo_obj, EFL_GFX_EVENT_RESTACK, _efl_canvas_object_event_grabber_restack, pd);
+   pd->rect = evas_object_rectangle_add(efl_parent_get(eo_obj));
+   evas_object_pointer_mode_set(pd->rect, EVAS_OBJECT_POINTER_MODE_NOGRAB);
+   efl_parent_set(pd->rect, eo_obj);
+   efl_canvas_group_member_add(eo_obj, pd->rect);
+   evas_object_color_set(pd->rect, 0, 0, 0, 0);
+   return eo_obj;
+}
+
+EOLIAN static void
+_efl_canvas_object_event_grabber_efl_object_destructor(Eo *eo_obj, Efl_Object_Event_Grabber_Data *pd)
+{
+   Evas_Object_Protected_Data *obj, *nobj;
+   EINA_CLIST_FOR_EACH_ENTRY_SAFE(obj, nobj, &pd->contained, Evas_Object_Protected_Data, event.member)
+     efl_canvas_group_member_del(eo_obj, obj->object);
+   efl_canvas_group_del(eo_obj);
+   efl_destructor(efl_super(eo_obj, MY_CLASS));
+}
+
+static void
+_efl_canvas_object_event_grabber_class_constructor(Efl_Class *klass)
+{
+   evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
+}
+
+const Eina_Clist *
+evas_object_event_grabber_members_list(const Eo *eo_obj)
+{
+   Efl_Object_Event_Grabber_Data *pd = efl_data_scope_get(eo_obj, MY_CLASS);
+   return &pd->contained;
+}
+
+EAPI Evas_Object *
+evas_object_event_grabber_add(Evas *eo_e)
+{
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(eo_e, EVAS_CANVAS_CLASS), NULL);
+   return efl_add(MY_CLASS, eo_e, efl_canvas_object_legacy_ctor(efl_added));
+}
+
+#include "efl_canvas_object_event_grabber.eo.c"
diff --git a/src/lib/evas/canvas/efl_canvas_object_event_grabber.eo b/src/lib/evas/canvas/efl_canvas_object_event_grabber.eo
new file mode 100644 (file)
index 0000000..9389c87
--- /dev/null
@@ -0,0 +1,38 @@
+class Efl.Canvas.Object.Event.Grabber (Efl.Canvas.Group)
+{
+   [[Low-level rectangle object.
+
+     This provides a smart version of the typical "event rectangle",
+     which allows objects to set this as their parent and route events
+     to a group of objects. Events will not propagate to non-member objects
+     below this object.
+
+     Adding members is done just like a normal smart object, using
+     efl_canvas_group_member_add (Eo API) or evas_object_smart_member_add (legacy).
+
+     Child objects are not modified in any way, unlike other types of smart objects.
+
+     It is a user error for any child objects to be stacked above the event
+     grabber parent while the event grabber is visible.
+     A critical error will be raised if this is detected at any point.
+
+     @since 1.20
+   ]]
+   data: Efl_Object_Event_Grabber_Data;
+   legacy_prefix: evas_object_event_grabber;
+   implements {
+      class.constructor;
+      Efl.Object.constructor;
+      Efl.Object.destructor;
+      Efl.Canvas.Group.group_member_add;
+      Efl.Canvas.Group.group_member_del;
+      Efl.Canvas.Group.group_children_iterate;
+      Efl.Canvas.Group.group_calculate;
+      Efl.Canvas.Group.group_change;
+      Efl.Canvas.Group.group_need_recalculate { get; set; }
+      Efl.Gfx.position { set; }
+      Efl.Gfx.size { set; }
+      Efl.Gfx.visible { get; set; }
+      Efl.Gfx.Stack.layer { set; }
+   }
+}
index e3d2643..822baa2 100644 (file)
@@ -436,11 +436,15 @@ evas_object_event_callback_call(Evas_Object *eo_obj, Evas_Object_Protected_Data
 nothing_here:
    if (!obj->no_propagate)
      {
-        if ((obj->smart.parent) && (type != EVAS_CALLBACK_FREE) &&
+        if ((obj->smart.parent || obj->event.parent) && (type != EVAS_CALLBACK_FREE) &&
               (type <= EVAS_CALLBACK_KEY_UP))
           {
-             Evas_Object_Protected_Data *smart_parent = efl_data_scope_get(obj->smart.parent, EFL_CANVAS_OBJECT_CLASS);
-             evas_object_event_callback_call(obj->smart.parent, smart_parent, type, event_info, event_id, efl_event_desc);
+             Evas_Object_Protected_Data *parent_obj;
+             Eo *parent;
+
+             parent = obj->event.parent ?: obj->smart.parent;
+             parent_obj = efl_data_scope_get(parent, EFL_CANVAS_OBJECT_CLASS);
+             evas_object_event_callback_call(parent, parent_obj, type, event_info, event_id, efl_event_desc);
           }
      }
    _evas_unwalk(e);
index 0fc4850..d4b728d 100644 (file)
@@ -10,7 +10,7 @@ int _evas_event_counter = 0;
 
 static Eina_List *
 _evas_event_object_list_in_get(Evas *eo_e, Eina_List *in,
-                               const Eina_Inlist *list, Evas_Object *stop,
+                               const Eina_Inlist *list, const Eina_Clist *clist, Evas_Object *stop,
                                int x, int y, int *no_rep, Eina_Bool source);
 
 /* FIXME: use eina_list_clone */
@@ -118,7 +118,7 @@ _evas_event_object_list_raw_in_get_single(Evas *eo_e, Evas_Object_Protected_Data
 #endif
         return in;
      }
-   if (!obj->cur->visible) return in;
+   if ((!obj->cur->visible) && (!obj->is_event_parent)) return in;
    // XXX: this below DYNAMICALLY calculates the current clip rect
    // by walking clippers to each parent clipper until there are
    // no more of them. this is a necessary hack because cache.clip
@@ -229,8 +229,8 @@ _evas_event_object_list_raw_in_get_single(Evas *eo_e, Evas_Object_Protected_Data
         if (evas_object_is_source_invisible(eo_obj, obj)) return in;
      }
    if ((obj->delete_me == 0) &&
-       ((source) || ((obj->cur->visible) && (!obj->clip.clipees) &&
-        (evas_object_clippers_is_visible(eo_obj, obj)))))
+       ((source) || ((obj->cur->visible || obj->is_event_parent) && (!obj->clip.clipees) &&
+        (obj->is_event_parent || evas_object_clippers_is_visible(eo_obj, obj)))))
      {
         if (obj->is_smart)
           {
@@ -259,6 +259,7 @@ _evas_event_object_list_raw_in_get_single(Evas *eo_e, Evas_Object_Protected_Data
                             in = _evas_event_object_list_in_get
                                (eo_e, in,
                                 evas_object_smart_members_get_direct(eo_obj),
+                                NULL,
                                 stop,
                                 obj->cur->geometry.x + obj->map->cur.map->mx,
                                 obj->cur->geometry.y + obj->map->cur.map->my,
@@ -285,7 +286,7 @@ _evas_event_object_list_raw_in_get_single(Evas *eo_e, Evas_Object_Protected_Data
                        obj->cur->geometry.y <= y &&
                        obj->cur->geometry.y + obj->cur->geometry.h >= y))
                     in = _evas_event_object_list_in_get
-                       (eo_e, in, evas_object_smart_members_get_direct(eo_obj),
+                       (eo_e, in, evas_object_smart_members_get_direct(eo_obj), NULL,
                        stop, x, y, &norep, source);
                }
              if (norep)
@@ -301,6 +302,25 @@ _evas_event_object_list_raw_in_get_single(Evas *eo_e, Evas_Object_Protected_Data
                     }
                }
           }
+        else if (obj->is_event_parent)
+          {
+             int norep = 0;
+             in = _evas_event_object_list_in_get(eo_e, in,
+               NULL, evas_object_event_grabber_members_list(eo_obj),
+               stop, x, y, &norep, source);
+             if (norep)
+               {
+                  if (!obj->repeat_events)
+                    {
+                       *no_rep = 1;
+#ifdef DDD_DO
+                       (*spaces)--;
+                       DDD("***** NO REP1 *****\n");
+#endif
+                       return in;
+                    }
+               }
+          }
         else
           {
              Evas_Object_Protected_Data *clip = obj->cur->clipper;
@@ -347,23 +367,27 @@ _evas_event_object_list_raw_in_get_single(Evas *eo_e, Evas_Object_Protected_Data
 
 static Eina_List *
 _evas_event_object_list_raw_in_get(Evas *eo_e, Eina_List *in,
-                                   const Eina_Inlist *list, Evas_Object *stop,
+                                   const Eina_Inlist *list, const Eina_Clist *clist, Evas_Object *stop,
                                    int x, int y, int *no_rep, Eina_Bool source)
 {
    Evas_Object_Protected_Data *obj = NULL;
+   Evas_Object_Protected_Data *nobj;
 
 #ifdef DDD_DO
    static int spaces = 0;
 #endif
 
-   if (!list) return in;
+   if ((!list) && (!clist)) return in;
 #ifdef DDD_DO
    spaces++;
 #endif
+   if (list)
+     {
         for (obj = _EINA_INLIST_CONTAINER(obj, eina_inlist_last(list));
              obj;
              obj = _EINA_INLIST_CONTAINER(obj, EINA_INLIST_GET(obj)->prev))
           {
+             if (obj->event.parent) continue;
              in = _evas_event_object_list_raw_in_get_single(eo_e, obj, in, stop, x, y, no_rep, source
 #ifdef DDD_DO
                ,&spaces
@@ -371,6 +395,19 @@ _evas_event_object_list_raw_in_get(Evas *eo_e, Eina_List *in,
              );
              if (*no_rep) return in;
           }
+     }
+   else
+     {
+        EINA_CLIST_FOR_EACH_ENTRY_SAFE_REV(obj, nobj, clist, Evas_Object_Protected_Data, event.member)
+          {
+             in = _evas_event_object_list_raw_in_get_single(eo_e, obj, in, stop, x, y, no_rep, source
+#ifdef DDD_DO
+               ,&spaces
+#endif
+             );
+             if (*no_rep) return in;
+          }
+     }
    *no_rep = 0;
 #ifdef DDD_DO
    spaces--;
@@ -454,7 +491,14 @@ _evas_event_source_mouse_down_events(Evas_Object *eo_obj, Evas *eo_e,
           {
              proxy_write->src_event_in = _evas_event_object_list_raw_in_get
                (eo_e, proxy_write->src_event_in,
-                evas_object_smart_members_get_direct(eo_src),
+                evas_object_smart_members_get_direct(eo_src), NULL,
+                NULL, ev->cur.x, ev->cur.y, &no_rep, EINA_TRUE);
+         }
+       else if (src->is_event_parent)
+         {
+            proxy_write->src_event_in = _evas_event_object_list_raw_in_get
+               (eo_e, proxy_write->src_event_in,
+                NULL, evas_object_event_grabber_members_list(eo_src),
                 NULL, ev->cur.x, ev->cur.y, &no_rep, EINA_TRUE);
          }
        else
@@ -571,7 +615,8 @@ _evas_event_source_mouse_move_events(Evas_Object *eo_obj, Evas *eo_e,
                   continue;
                }
 
-             if ((evas_object_clippers_is_visible(eo_child, child) ||
+             if ((child->is_event_parent ||
+                 evas_object_clippers_is_visible(eo_child, child) ||
                  obj_pdata->mouse_grabbed) &&
                (!evas_event_passes_through(eo_child, child)) &&
                (!evas_event_freezes_through(eo_child, child)) &&
@@ -630,6 +675,12 @@ _evas_event_source_mouse_move_events(Evas_Object *eo_obj, Evas *eo_e,
           {
              int no_rep = 0;
              ins = _evas_event_object_list_raw_in_get(eo_e, ins, evas_object_smart_members_get_direct(eo_src),
+                                                      NULL, NULL, ev->cur.x, ev->cur.y, &no_rep, EINA_TRUE);
+          }
+        else if (src->is_event_parent)
+          {
+             int no_rep = 0;
+             ins = _evas_event_object_list_raw_in_get(eo_e, ins, NULL, evas_object_event_grabber_members_list(eo_src),
                                                       NULL, ev->cur.x, ev->cur.y, &no_rep, EINA_TRUE);
           }
         else
@@ -653,7 +704,8 @@ _evas_event_source_mouse_move_events(Evas_Object *eo_obj, Evas *eo_e,
              ev->cur = curpt;
              if (evas_object_is_in_output_rect(eo_child, child,
                                                ev->cur.x, ev->cur.y, 1, 1) &&
-                (evas_object_clippers_is_visible(eo_child, child) ||
+                (child->is_event_parent ||
+                 evas_object_clippers_is_visible(eo_child, child) ||
                  obj_pdata->mouse_grabbed) &&
                 eina_list_data_find(ins, eo_child) &&
                (!evas_event_passes_through(eo_child, child)) &&
@@ -1047,7 +1099,7 @@ _evas_event_source_multi_move_events(Evas_Object_Protected_Data *obj, Evas_Publi
                       ev->device);
                   continue;
                }
-             if (((evas_object_clippers_is_visible(eo_child, child)) ||
+             if (((child->is_event_parent || evas_object_clippers_is_visible(eo_child, child)) ||
                   ((obj_pdata->mouse_grabbed) &&
                   (!evas_event_passes_through(eo_child, child)) &&
                   (!evas_event_freezes_through(eo_child, child)) &&
@@ -1070,7 +1122,14 @@ _evas_event_source_multi_move_events(Evas_Object_Protected_Data *obj, Evas_Publi
           {
              int no_rep = 0;
              ins = _evas_event_object_list_raw_in_get
-                   (eo_e, ins, evas_object_smart_members_get_direct(eo_src), NULL,
+                   (eo_e, ins, evas_object_smart_members_get_direct(eo_src), NULL, NULL,
+                    ev->cur.x, ev->cur.y, &no_rep, EINA_TRUE);
+          }
+        if (src->is_event_parent)
+          {
+             int no_rep = 0;
+             ins = _evas_event_object_list_raw_in_get
+                   (eo_e, ins, NULL, evas_object_event_grabber_members_list(eo_src), NULL,
                     ev->cur.x, ev->cur.y, &no_rep, EINA_TRUE);
           }
         else
@@ -1090,7 +1149,7 @@ _evas_event_source_multi_move_events(Evas_Object_Protected_Data *obj, Evas_Publi
                }
 
              if (evas_object_is_in_output_rect(eo_child, child, ev->cur.x, ev->cur.y, 1, 1) &&
-                (evas_object_clippers_is_visible(eo_child, child) ||
+                (child->is_event_parent || evas_object_clippers_is_visible(eo_child, child) ||
                  obj_pdata->mouse_grabbed) &&
                 eina_list_data_find(ins, eo_child) &&
                (!evas_event_passes_through(eo_child, child)) &&
@@ -1156,6 +1215,13 @@ _evas_event_source_mouse_in_events(Evas_Object *eo_obj, Evas *eo_e,
      {
         int no_rep = 0;
         ins = _evas_event_object_list_raw_in_get(eo_e, ins, evas_object_smart_members_get_direct(eo_src),
+                                                 NULL, NULL, ev->cur.x, ev->cur.y, &no_rep, EINA_TRUE);
+
+     }
+   else if (src->is_event_parent)
+     {
+        int no_rep = 0;
+        ins = _evas_event_object_list_raw_in_get(eo_e, ins, NULL, evas_object_event_grabber_members_list(eo_src),
                                                  NULL, ev->cur.x, ev->cur.y, &no_rep, EINA_TRUE);
 
      }
@@ -1260,10 +1326,10 @@ _evas_event_source_mouse_out_events(Evas_Object *eo_obj, Evas *eo_e,
 
 static Eina_List *
 _evas_event_object_list_in_get(Evas *eo_e, Eina_List *in,
-                               const Eina_Inlist *list, Evas_Object *stop,
+                               const Eina_Inlist *list, const Eina_Clist *clist, Evas_Object *stop,
                                int x, int y, int *no_rep, Eina_Bool source)
 {
-   return _evas_event_object_list_raw_in_get(eo_e, in, list, stop, x, y,
+   return _evas_event_object_list_raw_in_get(eo_e, in, list, clist, stop, x, y,
                                              no_rep, source);
 }
 
@@ -1282,7 +1348,7 @@ _evas_event_objects_event_list_no_frozen_check(Evas *eo_e, Evas_Object *stop, in
         int no_rep = 0;
         D("############################# check layer %i\n", lay->layer);
         in = _evas_event_object_list_in_get(eo_e, in,
-                                            EINA_INLIST_GET(lay->objects),
+                                            EINA_INLIST_GET(lay->objects), NULL,
                                             stop, x, y, &no_rep, EINA_FALSE);
         if (no_rep) return in;
      }
@@ -2070,7 +2136,7 @@ _canvas_event_feed_mouse_move_internal(Evas_Public_Data *e, Efl_Input_Pointer_Da
                   continue;
                }
              if ((!e->is_frozen) &&
-                 (evas_object_clippers_is_visible(eo_obj, obj) ||
+                 (obj->is_event_parent || evas_object_clippers_is_visible(eo_obj, obj) ||
                   obj_pdata->mouse_grabbed) &&
                  (!evas_event_passes_through(eo_obj, obj)) &&
                  (!evas_event_freezes_through(eo_obj, obj)) &&
@@ -2163,7 +2229,7 @@ _canvas_event_feed_mouse_move_internal(Evas_Public_Data *e, Efl_Input_Pointer_Da
              //             evas_object_clip_recalc(eo_obj);
              if ((!e->is_frozen) &&
                  evas_object_is_in_output_rect(eo_obj, obj, x, y, 1, 1) &&
-                 (evas_object_clippers_is_visible(eo_obj, obj) ||
+                 (obj->is_event_parent || evas_object_clippers_is_visible(eo_obj, obj) ||
                   obj_pdata->mouse_grabbed) &&
                  eina_list_data_find(ins, eo_obj) &&
                  (!evas_event_passes_through(eo_obj, obj)) &&
@@ -2277,7 +2343,7 @@ nogrep:
              Evas_Object_Protected_Data *below_obj = efl_data_scope_get(eo_below_obj, EFL_CANVAS_OBJECT_CLASS);
              int norep = 0;
              ins = _evas_event_object_list_raw_in_get(eo_e, NULL,
-                                                   EINA_INLIST_GET(below_obj), NULL,
+                                                   EINA_INLIST_GET(below_obj), NULL, NULL,
                                                    pdata->seat->x, pdata->seat->y,
                                                    &norep, EINA_FALSE);
           }
@@ -2306,7 +2372,7 @@ nogrep:
              //             evas_object_clip_recalc(eo_obj);
              if ((!e->is_frozen) &&
                  evas_object_is_in_output_rect(eo_obj, obj, x, y, 1, 1) &&
-                 (evas_object_clippers_is_visible(eo_obj, obj) ||
+                 (obj->is_event_parent || evas_object_clippers_is_visible(eo_obj, obj) ||
                   obj_pdata->mouse_grabbed) &&
                  eina_list_data_find(newin, eo_obj) &&
                  (!evas_event_passes_through(eo_obj, obj)) &&
@@ -2955,7 +3021,7 @@ _canvas_event_feed_multi_move_internal(Evas_Public_Data *e, Efl_Input_Pointer_Da
                       ev->device);
                   continue;
                }
-             if ((evas_object_clippers_is_visible(eo_obj, obj) ||
+             if ((obj->is_event_parent || evas_object_clippers_is_visible(eo_obj, obj) ||
                   obj_pdata->mouse_grabbed) &&
                  (!evas_event_passes_through(eo_obj, obj)) &&
                  (!evas_event_freezes_through(eo_obj, obj)) &&
@@ -2999,7 +3065,7 @@ _canvas_event_feed_multi_move_internal(Evas_Public_Data *e, Efl_Input_Pointer_Da
              // FIXME: i don't think we need this
              //             evas_object_clip_recalc(eo_obj);
              if (evas_object_is_in_output_rect(eo_obj, obj, ev->cur.x, ev->cur.y, 1, 1) &&
-                 (evas_object_clippers_is_visible(eo_obj, obj) ||
+                 (obj->is_event_parent || evas_object_clippers_is_visible(eo_obj, obj) ||
                   obj_pdata->mouse_grabbed) &&
                  eina_list_data_find(ins, eo_obj) &&
                  (!evas_event_passes_through(eo_obj, obj)) &&
index 6189390..fea6c3a 100644 (file)
@@ -92,6 +92,8 @@ typedef struct _Evas_Object_Mask_Data       Evas_Object_Mask_Data;
 typedef struct _Evas_Object_Pointer_Data            Evas_Object_Pointer_Data;
 
 typedef struct _Evas_Smart_Data             Evas_Smart_Data;
+typedef struct _Efl_Object_Event_Grabber_Data  Efl_Object_Event_Grabber_Data;
+
 
 typedef struct _Evas_Object_Protected_State Evas_Object_Protected_State;
 typedef struct _Evas_Object_Protected_Data  Evas_Object_Protected_Data;
@@ -1169,6 +1171,11 @@ struct _Evas_Object_Protected_Data
       Evas_Object_Protected_Data *parent_object_data;
    } smart;
 
+   struct {
+      Evas_Object *parent;
+      Eina_Clist   member;
+   } event;
+
    // Eina_Cow pointer be careful when writing to it
    const Evas_Object_Proxy_Data *proxy;
    const Evas_Object_Map_Data *map;
@@ -1206,6 +1213,7 @@ struct _Evas_Object_Protected_Data
    Eina_Bool                   changed : 1;
    Eina_Bool                   restack : 1;
    Eina_Bool                   is_smart : 1;
+   Eina_Bool                   is_event_parent : 1;
    Eina_Bool                   pass_events : 1;
    Eina_Bool                   store : 1;
 
@@ -1689,6 +1697,8 @@ void evas_object_smart_render_cache_clear(Evas_Object *eo_obj);
 void *evas_object_smart_render_cache_get(const Evas_Object *eo_obj);
 void evas_object_smart_render_cache_set(Evas_Object *eo_obj, void *data);
 
+const Eina_Clist *evas_object_event_grabber_members_list(const Eo *eo_obj);
+
 const Eina_Inlist *evas_object_smart_members_get_direct(const Evas_Object *obj);
 void _efl_canvas_group_group_members_all_del(Evas_Object *eo_obj);
 void _evas_object_smart_clipped_smart_move_internal(Evas_Object *eo_obj, Evas_Coord x, Evas_Coord y);