forked from enlightenment/efl
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
This commit is contained in:
commit
ddf3558628
|
@ -19,6 +19,7 @@
|
|||
/evas_aspect_hints
|
||||
/evas_box
|
||||
/evas_buffer_simple
|
||||
/evas_event_filter
|
||||
/evas_canvas3d_aabb
|
||||
/evas_canvas3d_blending
|
||||
/evas_canvas3d_colorpick
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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).]]
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue