summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Dilly <bdilly@profusion.mobi>2016-12-12 16:04:58 -0200
committerBruno Dilly <bdilly@profusion.mobi>2016-12-12 16:04:58 -0200
commitddf3558628a7e6b6c5d48741f1ef9a8360d122ca (patch)
treefab1215b757f81b109c64c608a5ab8ba493fd77f
parenteef89ceb3a27088b22555a15ce5621eeb4ad5b02 (diff)
parent200ee1869bd4fed9b0b9a16640af4e9f256c37f7 (diff)
downloadefl-ddf3558628a7e6b6c5d48741f1ef9a8360d122ca.tar.gz
Merge branch 'devs/iscaro/event-filter'
Series of patches adding support to filter input and focus events per seat for any evas object. So it will make it possible to block or unblock keyboard, mouse and focus events that was originated by a specific seat. Requested on RFC regarding multiseaet support on Edje - such feature will be also supported on Edje later. Patches by Guilherme Iscaro <iscaro@profusion.mobi> Reviewed By: bdilly, cedric, jpeg Differential Revision: https://phab.enlightenment.org/D4468
-rw-r--r--src/examples/evas/.gitignore1
-rw-r--r--src/examples/evas/Makefile.am6
-rw-r--r--src/examples/evas/evas-event-filter.c277
-rw-r--r--src/lib/evas/canvas/efl_canvas_object.eo4
-rw-r--r--src/lib/evas/canvas/efl_input_interface.eo16
-rw-r--r--src/lib/evas/canvas/evas_focus.c3
-rw-r--r--src/lib/evas/canvas/evas_object_main.c97
-rw-r--r--src/lib/evas/include/evas_private.h6
8 files changed, 410 insertions, 0 deletions
diff --git a/src/examples/evas/.gitignore b/src/examples/evas/.gitignore
index ae8e78e9c5..df145d0821 100644
--- a/src/examples/evas/.gitignore
+++ b/src/examples/evas/.gitignore
@@ -19,6 +19,7 @@
/evas_aspect_hints
/evas_box
/evas_buffer_simple
+/evas_event_filter
/evas_canvas3d_aabb
/evas_canvas3d_blending
/evas_canvas3d_colorpick
diff --git a/src/examples/evas/Makefile.am b/src/examples/evas/Makefile.am
index c4d155d356..c4ed9dea01 100644
--- a/src/examples/evas/Makefile.am
+++ b/src/examples/evas/Makefile.am
@@ -119,6 +119,11 @@ evas_events_SOURCES = evas-events.c
evas_events_LDADD = $(ECORE_EVAS_COMMON_LDADD)
evas_events_CPPFLAGS = $(ECORE_EVAS_COMMON_CPPFLAGS)
+EXTRA_PROGRAMS += evas_event_filter
+evas_event_filter_SOURCES = evas-event-filter.c
+evas_event_filter_LDADD = $(ECORE_EVAS_COMMON_LDADD)
+evas_event_filter_CPPFLAGS = $(ECORE_EVAS_COMMON_CPPFLAGS)
+
EXTRA_PROGRAMS += evas_multiseat_events
evas_multiseat_events_SOURCES = evas-multiseat-events.c
evas_multiseat_events_LDADD = $(ECORE_EVAS_COMMON_LDADD)
@@ -369,6 +374,7 @@ evas-aspect-hints.c \
evas-box.c \
evas-buffer-simple.c \
evas-events.c \
+evas-event-filter.c \
evas-hints.c \
evas-images.c \
evas-images2.c \
diff --git a/src/examples/evas/evas-event-filter.c b/src/examples/evas/evas-event-filter.c
new file mode 100644
index 0000000000..aa41d8ec71
--- /dev/null
+++ b/src/examples/evas/evas-event-filter.c
@@ -0,0 +1,277 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <Evas.h>
+#include <Ecore_Evas.h>
+#include <stdio.h>
+
+#define W (300)
+#define H (300)
+#define RECT_W (50)
+#define RECT_H (50)
+
+typedef struct _Context {
+ Evas_Object *filtered_obj;
+ Efl_Input_Device *allowed_seat;
+} Context;
+
+static void
+_ee_del_request_cb(Ecore_Evas *ee EINA_UNUSED)
+{
+ ecore_main_loop_quit();
+}
+
+static void
+_ee_resize_cb(Ecore_Evas *ee)
+{
+ Evas_Object *bg;
+ int w, h;
+
+ ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
+ bg = ecore_evas_data_get(ee, "bg");
+ evas_object_resize(bg, w, h);
+}
+
+static Eina_Bool
+_allowed_seat_get(Evas_Object *filtered_obj,
+ Efl_Input_Device **allowed_seat)
+{
+ const Eina_List *devs, *l;
+ Efl_Input_Device *seat;
+ Eina_Bool allowed_seat_changed = EINA_FALSE;
+
+ if (!filtered_obj) return EINA_TRUE;
+
+ devs = evas_device_list(evas_object_evas_get(filtered_obj), NULL);
+ EINA_LIST_FOREACH(devs, l, seat)
+ {
+ if ((efl_input_device_type_get(seat) != EFL_INPUT_DEVICE_CLASS_SEAT) ||
+ (*allowed_seat == seat))
+ continue;
+ if (!allowed_seat_changed)
+ {
+ printf("The '%s' shall only receive events from seat '%s'\n",
+ evas_object_name_get(filtered_obj),
+ efl_input_device_name_get(seat));
+ allowed_seat_changed = EINA_TRUE;
+ *allowed_seat = seat;
+ efl_input_seat_event_filter_set(filtered_obj, seat, EINA_TRUE);
+ if (!efl_canvas_object_seat_focus_add(filtered_obj, seat))
+ {
+ fprintf(stderr, "ERROR: The '%s' could not be focused by the seat '%s'\n",
+ evas_object_name_get(filtered_obj),
+ efl_input_device_name_get(seat));
+ return EINA_FALSE;
+ }
+ }
+ else
+ {
+ if (efl_canvas_object_seat_focus_add(filtered_obj, seat))
+ {
+ fprintf(stderr, "ERROR: The '%s' should not be focused by the seat '%s'\n",
+ evas_object_name_get(filtered_obj),
+ efl_input_device_name_get(seat));
+ return EINA_FALSE;
+ }
+ }
+ }
+ if (!allowed_seat_changed)
+ *allowed_seat = NULL;
+ return EINA_TRUE;
+}
+
+static const char *
+_event_as_string(const void *desc)
+{
+ if (desc == EFL_EVENT_FOCUS_IN)
+ return "FOCUS_IN";
+ else if (desc == EFL_EVENT_FOCUS_OUT)
+ return "FOCUS_OUT";
+ else if (desc == EFL_EVENT_KEY_DOWN)
+ return "KEY_DOWN";
+ else if (desc == EFL_EVENT_KEY_UP)
+ return "KEY_UP";
+ else if (desc == EFL_EVENT_HOLD)
+ return "HOLD";
+ else if (desc == EFL_EVENT_POINTER_IN)
+ return "POINTER_IN";
+ else if (desc == EFL_EVENT_POINTER_OUT)
+ return "POINTER_OUT";
+ else if (desc == EFL_EVENT_POINTER_DOWN)
+ return "POINTER_DOWN";
+ else if (desc == EFL_EVENT_POINTER_UP)
+ return "POINTER_UP";
+ else if (desc == EFL_EVENT_POINTER_MOVE)
+ return "POINTER_MOVE";
+ else
+ return "MOUSE_WHEEL";
+}
+
+static void
+_obj_events_cb(void *data, const Efl_Event *event)
+{
+ Efl_Input_Device *seat = efl_input_device_seat_get(efl_input_device_get(event->info));
+ Context *ctx = data;
+ const char *event_name;
+
+ event_name = _event_as_string(event->desc);
+ if (seat != ctx->allowed_seat && event->object == ctx->filtered_obj)
+ {
+ fprintf(stderr, "ERROR: The object '%s' should not receive the event"
+ "'%s' from the seat '%s'\n",
+ evas_object_name_get(event->object), event_name,
+ efl_input_device_name_get(seat));
+ ecore_main_loop_quit();
+ }
+ else
+ printf("The object '%s' recevied a '%s' event from seat '%s'\n",
+ evas_object_name_get(event->object), event_name,
+ efl_input_device_name_get(seat));
+}
+
+static void
+_obj_del_event_cb(void *data, const Efl_Event *event)
+{
+ Context *ctx = data;
+
+ if (event->object == ctx->filtered_obj)
+ ctx->filtered_obj = NULL;
+}
+
+static void
+_device_added_removed_cb(void *data, const Efl_Event *event)
+{
+ Efl_Input_Device *dev = event->info;
+ Context *ctx = data;
+
+ if (efl_input_device_type_get(dev) != EFL_INPUT_DEVICE_CLASS_SEAT)
+ return;
+
+ if (event->desc == EFL_CANVAS_EVENT_DEVICE_ADDED)
+ {
+ if (ctx->allowed_seat)
+ efl_input_seat_event_filter_set(ctx->filtered_obj,
+ ctx->allowed_seat, EINA_FALSE);
+ ctx->allowed_seat = dev;
+ }
+ else
+ {
+ if (!_allowed_seat_get(ctx->filtered_obj, &ctx->allowed_seat))
+ ecore_main_loop_quit();
+ }
+}
+
+EFL_CALLBACKS_ARRAY_DEFINE(_device_callbacks,
+ { EFL_CANVAS_EVENT_DEVICE_ADDED, _device_added_removed_cb },
+ { EFL_CANVAS_EVENT_DEVICE_REMOVED, _device_added_removed_cb });
+
+EFL_CALLBACKS_ARRAY_DEFINE(_obj_callbacks,
+ { EFL_EVENT_FOCUS_IN, _obj_events_cb },
+ { EFL_EVENT_FOCUS_OUT, _obj_events_cb },
+ { EFL_EVENT_KEY_DOWN, _obj_events_cb },
+ { EFL_EVENT_KEY_UP, _obj_events_cb },
+ { EFL_EVENT_HOLD, _obj_events_cb },
+ { EFL_EVENT_POINTER_IN, _obj_events_cb },
+ { EFL_EVENT_POINTER_OUT,_obj_events_cb },
+ { EFL_EVENT_POINTER_DOWN, _obj_events_cb },
+ { EFL_EVENT_POINTER_UP, _obj_events_cb },
+ { EFL_EVENT_POINTER_MOVE, _obj_events_cb },
+ { EFL_EVENT_POINTER_WHEEL, _obj_events_cb },
+ { EFL_EVENT_DEL, _obj_del_event_cb });
+
+static Evas_Object *
+_rect_add(Evas *e, Context *ctx, const char *name,
+ int w, int h, int x, int y, int r, int g, int b,
+ Eina_Bool add_callbacks)
+{
+ Evas_Object *obj;
+
+ obj = evas_object_rectangle_add(e);
+ if (!obj)
+ {
+ fprintf(stderr, "Could not create the BG\n");
+ return NULL;
+ }
+
+ evas_object_color_set(obj, r, g, b, 255);
+ evas_object_resize(obj, w, h);
+ evas_object_move(obj, x, y);
+ evas_object_show(obj);
+ evas_object_name_set(obj, name);
+ if (add_callbacks)
+ efl_event_callback_array_add(obj, _obj_callbacks(), ctx);
+ return obj;
+}
+
+int
+main(int argc EINA_UNUSED, char *argv[] EINA_UNUSED)
+{
+ Context ctx = { 0 };
+ Ecore_Evas *ee;
+ Evas_Object *obj;
+ Evas *e;
+
+ if (!ecore_evas_init())
+ {
+ fprintf(stderr, "Could not init Ecore_Evas\n");
+ return EXIT_FAILURE;
+ }
+
+ ee = ecore_evas_new(NULL, 0, 0, W, H, NULL);
+ if (!ee)
+ {
+ fprintf(stderr, "Coult not create the Ecore_Evas\n");
+ goto err_ee;
+ }
+
+ e = ecore_evas_get(ee);
+
+ obj = _rect_add(e, &ctx, "bg", W, H, 0, 0, 255, 255, 255, EINA_FALSE);
+ if (!obj)
+ {
+ fprintf(stderr, "Could not create the BG\n");
+ goto err_obj;
+ }
+ ecore_evas_data_set(ee, "bg", obj);
+
+ obj = _rect_add(e, &ctx, "Red Rectangle", RECT_W, RECT_H, W/2 - RECT_W/2,
+ H/2 - RECT_H/2, 255, 0, 0, EINA_TRUE);
+ if (!obj)
+ {
+ fprintf(stderr, "Could not create the red rectangle\n");
+ goto err_obj;
+ }
+ ctx.filtered_obj = obj;
+
+ obj = _rect_add(e, &ctx, "Blue Rectangle", RECT_W, RECT_H,
+ 100, 100, 0, 0, 255, EINA_TRUE);
+ if (!obj)
+ {
+ fprintf(stderr, "Could not create the blue rectangle\n");
+ goto err_obj;
+ }
+
+ printf("The '%s' shall receive events from any seat\n",
+ evas_object_name_get(obj));
+
+ if (!_allowed_seat_get(ctx.filtered_obj, &ctx.allowed_seat))
+ goto err_obj;
+ efl_event_callback_array_add(e, _device_callbacks(), &ctx);
+ ecore_evas_callback_resize_set(ee, _ee_resize_cb);
+ ecore_evas_callback_delete_request_set(ee, _ee_del_request_cb);
+ ecore_evas_show(ee);
+ ecore_main_loop_begin();
+ ecore_evas_free(ee);
+ ecore_evas_shutdown();
+ return EXIT_SUCCESS;
+
+ err_obj:
+ ecore_evas_free(ee);
+ err_ee:
+ ecore_evas_shutdown();
+ return EXIT_FAILURE;
+}
+
diff --git a/src/lib/evas/canvas/efl_canvas_object.eo b/src/lib/evas/canvas/efl_canvas_object.eo
index 606dd45213..24a706bd04 100644
--- a/src/lib/evas/canvas/efl_canvas_object.eo
+++ b/src/lib/evas/canvas/efl_canvas_object.eo
@@ -624,6 +624,8 @@ abstract Efl.Canvas.Object (Efl.Object, Efl.Gfx, Efl.Gfx.Stack, Efl.Animator,
Efl.Object.constructor;
Efl.Object.destructor;
Efl.Object.dbg_info_get;
+ Efl.Object.event_callback_legacy_call;
+ Efl.Object.event_callback_call;
Efl.Object.provider_find;
Efl.Gfx.visible.set;
Efl.Gfx.visible.get;
@@ -666,5 +668,7 @@ abstract Efl.Canvas.Object (Efl.Object, Efl.Gfx, Efl.Gfx.Stack, Efl.Animator,
Efl.Gfx.Size.Hint.hint_weight.get;
Efl.Gfx.Map.map_enable.set;
Efl.Gfx.Map.map_enable.get;
+ Efl.Input.Interface.seat_event_filter.set;
+ Efl.Input.Interface.seat_event_filter.get;
}
}
diff --git a/src/lib/evas/canvas/efl_input_interface.eo b/src/lib/evas/canvas/efl_input_interface.eo
index 49a7f1ab00..5ee9782a77 100644
--- a/src/lib/evas/canvas/efl_input_interface.eo
+++ b/src/lib/evas/canvas/efl_input_interface.eo
@@ -79,6 +79,22 @@ interface Efl.Input.Interface ()
}
return: iterator<const(Efl.Input.Pointer)>; [[Iterator to pointer positions]]
}
+ @property seat_event_filter {
+ set {
+ [[Add or remove a given seat to the filter list. If the filter list is empty this object
+ will report mouse, keyboard and focus events from any seat, otherwise those events will
+ only be reported if the event comes from a seat that is in the list.]]
+ }
+ get {
+ [[Check if input events from a given seat is enabled.]]
+ }
+ keys {
+ seat: Efl.Input.Device; [[The seat to act on.]]
+ }
+ values {
+ enable: bool; [[$true to enable events for a seat or $false otherwise.]]
+ }
+ }
}
events {
pointer,move: Efl.Input.Pointer; [[Main pointer move (current and previous positions are known).]]
diff --git a/src/lib/evas/canvas/evas_focus.c b/src/lib/evas/canvas/evas_focus.c
index 9269985073..36f265c1b0 100644
--- a/src/lib/evas/canvas/evas_focus.c
+++ b/src/lib/evas/canvas/evas_focus.c
@@ -167,6 +167,9 @@ _efl_canvas_object_seat_focus_add(Eo *eo_obj,
if (efl_input_device_type_get(seat) != EFL_INPUT_DEVICE_CLASS_SEAT)
return EINA_FALSE;
+ if (!efl_input_seat_event_filter_get(eo_obj, seat))
+ return EINA_FALSE;
+
if (_already_focused(obj->focused_by_seats, seat))
goto end;
diff --git a/src/lib/evas/canvas/evas_object_main.c b/src/lib/evas/canvas/evas_object_main.c
index 00c4590657..07518b6901 100644
--- a/src/lib/evas/canvas/evas_object_main.c
+++ b/src/lib/evas/canvas/evas_object_main.c
@@ -887,6 +887,101 @@ evas_object_del(Evas_Object *eo_obj)
efl_del(eo_obj);
}
+EOLIAN static Eina_Bool
+_efl_canvas_object_efl_input_interface_seat_event_filter_get(Eo *eo_obj EINA_UNUSED,
+ Evas_Object_Protected_Data *obj,
+ Efl_Input_Device *seat)
+{
+ //If the list is empty this object accept events from any seat.
+ if (!obj->events_whitelist)
+ return EINA_TRUE;
+ return eina_list_data_find(obj->events_whitelist, seat) ?
+ EINA_TRUE : EINA_FALSE;
+}
+
+static void
+_whitelist_events_device_remove_cb(void *data, const Efl_Event *event)
+{
+ Evas_Object_Protected_Data *obj = data;
+ obj->events_whitelist = eina_list_remove(obj->events_whitelist,
+ event->object);
+}
+
+EOLIAN static void
+_efl_canvas_object_efl_input_interface_seat_event_filter_set(Eo *eo_obj,
+ Evas_Object_Protected_Data *obj,
+ Efl_Input_Device *seat,
+ Eina_Bool add)
+{
+ EINA_SAFETY_ON_NULL_RETURN(seat);
+
+ if (efl_input_device_type_get(seat) != EFL_INPUT_DEVICE_CLASS_SEAT) return;
+ if (add)
+ {
+ if (eina_list_data_find(obj->events_whitelist, seat)) return;
+ if (efl_canvas_object_seat_focus_check(eo_obj, seat))
+ efl_canvas_object_seat_focus_del(eo_obj, seat);
+ obj->events_whitelist = eina_list_append(obj->events_whitelist, seat);
+ efl_event_callback_add(seat, EFL_EVENT_DEL,
+ _whitelist_events_device_remove_cb, obj);
+ }
+ else
+ {
+ obj->events_whitelist = eina_list_remove(obj->events_whitelist, seat);
+ efl_event_callback_del(seat, EFL_EVENT_DEL,
+ _whitelist_events_device_remove_cb, obj);
+ }
+}
+
+static Eina_Bool
+_is_event_blocked(Eo *eo_obj, const Efl_Event_Description *desc,
+ void *event_info)
+{
+ if ((desc == EFL_EVENT_FOCUS_IN) ||
+ (desc == EFL_EVENT_FOCUS_OUT) ||
+ (desc == EFL_EVENT_KEY_DOWN) ||
+ (desc == EFL_EVENT_KEY_UP) ||
+ (desc == EFL_EVENT_HOLD) ||
+ (desc == EFL_EVENT_POINTER_IN) ||
+ (desc == EFL_EVENT_POINTER_OUT) ||
+ (desc == EFL_EVENT_POINTER_DOWN) ||
+ (desc == EFL_EVENT_POINTER_UP) ||
+ (desc == EFL_EVENT_POINTER_MOVE) ||
+ (desc == EFL_EVENT_POINTER_WHEEL) ||
+ (desc == EFL_EVENT_POINTER_CANCEL) ||
+ (desc == EFL_EVENT_POINTER_AXIS) ||
+ (desc == EFL_EVENT_FINGER_MOVE) ||
+ (desc == EFL_EVENT_FINGER_DOWN) ||
+ (desc == EFL_EVENT_FINGER_UP))
+ {
+ Efl_Input_Device *seat = efl_input_device_seat_get(efl_input_device_get(event_info));
+ return !efl_input_seat_event_filter_get(eo_obj, seat);
+ }
+ return EINA_FALSE;
+}
+
+EOLIAN static Eina_Bool
+_efl_canvas_object_efl_object_event_callback_call(Eo *eo_obj,
+ Evas_Object_Protected_Data *obj EINA_UNUSED,
+ const Efl_Event_Description *desc,
+ void *event_info)
+{
+ if (_is_event_blocked(eo_obj, desc, event_info)) return EINA_FALSE;
+ return efl_event_callback_call(efl_super(eo_obj, MY_CLASS),
+ desc, event_info);
+}
+
+EOLIAN static Eina_Bool
+_efl_canvas_object_efl_object_event_callback_legacy_call(Eo *eo_obj,
+ Evas_Object_Protected_Data *obj EINA_UNUSED,
+ const Efl_Event_Description *desc,
+ void *event_info)
+{
+ if (_is_event_blocked(eo_obj, desc, event_info)) return EINA_FALSE;
+ return efl_event_callback_legacy_call(efl_super(eo_obj, MY_CLASS),
+ desc, event_info);
+}
+
EOLIAN static void
_efl_canvas_object_efl_object_destructor(Eo *eo_obj, Evas_Object_Protected_Data *obj)
{
@@ -914,6 +1009,8 @@ _efl_canvas_object_efl_object_destructor(Eo *eo_obj, Evas_Object_Protected_Data
evas_object_event_callback_call(eo_obj, obj, EVAS_CALLBACK_DEL, NULL, _evas_object_event_new(), NULL);
if ((obj->layer) && (obj->layer->evas))
_evas_post_event_callback_call(obj->layer->evas->evas, obj->layer->evas);
+ EINA_LIST_FREE(obj->events_whitelist, dev)
+ efl_event_callback_del(dev, EFL_EVENT_DEL, _whitelist_events_device_remove_cb, obj);
if (obj->name) evas_object_name_set(eo_obj, NULL);
if (!obj->layer)
{
diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h
index d5645fc668..77e393dd30 100644
--- a/src/lib/evas/include/evas_private.h
+++ b/src/lib/evas/include/evas_private.h
@@ -1116,6 +1116,12 @@ struct _Evas_Object_Protected_Data
Eina_List *grabs;
Eina_Inlist *callbacks;
+ /*
+ The list below contain the seats (Efl.Input.Devices) which this
+ object allows events to be reported (Mouse, Keybord and focus events).
+ If this list is empty, this object will allow events from any seat.
+ */
+ Eina_List *events_whitelist;
struct {
Eina_List *clipees;