elm_win: Forward events between window and evas

This does:
1. Forward keyboard events from evas to win
2. Allow feeding external input events

Input events can be faked by apps by simply forging
eo objects of the proper type (key or pointer evt) and
calling eo_event_callback_call().

Such events will be forwarded to the internal Evas, and
some bool flags prevent infinite refeeding loops.

efl_event_dup() returns fake events for this to work.

@feature
This commit is contained in:
Jean-Philippe Andre 2016-06-02 14:36:55 +09:00
parent a4701ea969
commit b147911bad
11 changed files with 229 additions and 44 deletions

View File

@ -3,6 +3,7 @@
#endif
#define ECORE_EVAS_INTERNAL
#define EFL_EVENT_PROTECTED
#include <stdlib.h>
#include <string.h>
@ -4358,7 +4359,7 @@ _direct_mouse_updown(Ecore_Evas *ee, const Ecore_Event_Mouse_Button *info, Efl_P
* modifiers (already passed to evas, no need to do anything)
*/
evt = efl_event_pointer_instance_get(EFL_EVENT_POINTER_CLASS, e, (void **) &ev);
evt = efl_event_instance_get(EFL_EVENT_POINTER_CLASS, e, (void **) &ev);
if (!evt) return EINA_FALSE;
ev->action = action;
@ -4418,7 +4419,7 @@ _direct_mouse_move_cb(Ecore_Evas *ee, const Ecore_Event_Mouse_Move *info)
* modifiers (already passed to evas, no need to do anything)
*/
evt = efl_event_pointer_instance_get(EFL_EVENT_POINTER_CLASS, e, (void **) &ev);
evt = efl_event_instance_get(EFL_EVENT_POINTER_CLASS, e, (void **) &ev);
if (!evt) return EINA_FALSE;
ev->action = EFL_POINTER_ACTION_MOVE;
@ -4455,7 +4456,7 @@ _direct_mouse_wheel_cb(Ecore_Evas *ee, const Ecore_Event_Mouse_Wheel *info)
* modifiers (already passed to evas, no need to do anything)
*/
evt = efl_event_pointer_instance_get(EFL_EVENT_POINTER_CLASS, e, (void **) &ev);
evt = efl_event_instance_get(EFL_EVENT_POINTER_CLASS, e, (void **) &ev);
if (!evt) return EINA_FALSE;
ev->action = EFL_POINTER_ACTION_WHEEL;
@ -4484,7 +4485,7 @@ _direct_mouse_inout(Ecore_Evas *ee, const Ecore_Event_Mouse_IO *info, Efl_Pointe
* modifiers (already passed to evas, no need to do anything)
*/
evt = efl_event_pointer_instance_get(EFL_EVENT_POINTER_CLASS, e, (void **) &ev);
evt = efl_event_instance_get(EFL_EVENT_POINTER_CLASS, e, (void **) &ev);
if (!evt) return EINA_FALSE;
ev->action = action;
@ -4526,9 +4527,8 @@ _direct_key_updown_cb(Ecore_Evas *ee, const Ecore_Event_Key *info, Eina_Bool dow
* modifiers (already passed to evas, no need to do anything)
*/
evt = eo_add(EFL_EVENT_KEY_CLASS, e);
ev = eo_data_scope_get(evt, EFL_EVENT_KEY_CLASS);
if (!ev) return EINA_FALSE;
evt = efl_event_instance_get(EFL_EVENT_KEY_CLASS, e, (void **) &ev);
if (!evt || !ev) return EINA_FALSE;
ev->timestamp = info->timestamp;
ev->pressed = down;

View File

@ -38,6 +38,7 @@ extern "C" {
/* Add here all the required ifdef for any @protected method */
#ifdef EFL_EFL_BUILD
# define EFL_PACK_LAYOUT_PROTECTED
# define EFL_EVENT_PROTECTED
#endif
/**

View File

@ -50,7 +50,9 @@ struct _Efl_Event_Pointer_Data
(see input vs. feed: this is "input") */
Evas_Modifier *modifiers;
Evas_Lock *locks;
Eina_Bool evas_done; /* set by evas */
Eina_Bool evas_done : 1; /* set by evas */
Eina_Bool fake : 1;
Eina_Bool win_fed : 1;
};
struct _Efl_Event_Key_Data
@ -70,7 +72,9 @@ struct _Efl_Event_Key_Data
Evas_Lock *locks;
Efl_Event_Flags event_flags;
Efl_Input_Device *device;
Eina_Bool evas_done; /* set by evas */
Eina_Bool evas_done : 1; /* set by evas */
Eina_Bool fake : 1;
Eina_Bool win_fed : 1;
};
struct _Efl_Input_Device_Data

View File

@ -33,5 +33,12 @@ interface Efl.Event
[[Creates a copy of this event.]]
return: own(Efl.Event);
}
instance_get @class @protected {
params {
@in owner: Eo.Base;
@out priv: void*;
}
return: Efl.Event;
}
}
}

View File

@ -17,6 +17,9 @@
#include "../evas/canvas/evas_box.eo.h"
#define EFL_INTERNAL_UNSTABLE
#include "interfaces/efl_common_internal.h"
#define MY_CLASS ELM_WIN_CLASS
#define MY_CLASS_NAME "Elm_Win"
@ -1629,11 +1632,36 @@ _elm_win_elm_widget_event(Eo *obj, Elm_Win_Data *_pd EINA_UNUSED, Evas_Object *s
return EINA_TRUE;
}
/* forward events sent to evas to the window */
static Eina_Bool
_evas_event_key_cb(void *data, const Eo_Event *ev)
{
Eo *win = data;
Eo *evt = ev->info;
Efl_Event_Key_Data *evdata;
evdata = eo_data_scope_get(evt, EFL_EVENT_KEY_CLASS);
if (!evdata || evdata->win_fed)
return EO_CALLBACK_CONTINUE;
// evas_callbacks will send the event to the focussed object (ie. this win)
if (evas_focus_get(evas_object_evas_get(win)) == win)
return EO_CALLBACK_CONTINUE;
eo_event_callback_call(win, ev->desc, evt);
return EO_CALLBACK_CONTINUE;
}
static Eina_Bool
_evas_event_pointer_cb(void *data, const Eo_Event *ev)
{
Eo *win = data;
Eo *evt = ev->info;
Efl_Event_Pointer_Data *evdata;
evdata = eo_data_scope_get(evt, EFL_EVENT_POINTER_CLASS);
if (!evdata || evdata->win_fed)
return EO_CALLBACK_CONTINUE;
eo_event_callback_call(win, ev->desc, evt);
return EO_CALLBACK_CONTINUE;
@ -1646,7 +1674,63 @@ EO_CALLBACKS_ARRAY_DEFINE(_elm_win_evas_forward_callbacks,
{ EFL_EVENT_POINTER_IN, _evas_event_pointer_cb },
{ EFL_EVENT_POINTER_OUT, _evas_event_pointer_cb },
{ EFL_EVENT_POINTER_CANCEL, _evas_event_pointer_cb },
{ EFL_EVENT_POINTER_WHEEL, _evas_event_pointer_cb })
{ EFL_EVENT_POINTER_WHEEL, _evas_event_pointer_cb },
{ EFL_EVENT_KEY_DOWN, _evas_event_key_cb },
{ EFL_EVENT_KEY_UP, _evas_event_key_cb })
/* feed events from the window to evas - for fake inputs */
static Eina_Bool
_evas_event_key_feed_fake_cb(void *data, const Eo_Event *ev)
{
Eo *evas = data;
Efl_Event *evt = ev->info;
Efl_Event_Key_Data *evdata;
if (!efl_event_fake_get(evt))
return EO_CALLBACK_CONTINUE;
evdata = eo_data_scope_get(evt, EFL_EVENT_KEY_CLASS);
if (!evdata || evdata->win_fed)
return EO_CALLBACK_CONTINUE;
evdata->win_fed = EINA_TRUE;
eo_event_callback_call(evas, ev->desc, evt);
evdata->win_fed = EINA_FALSE;
evdata->evas_done = EINA_FALSE;
return EO_CALLBACK_CONTINUE;
}
static Eina_Bool
_evas_event_pointer_feed_fake_cb(void *data, const Eo_Event *ev)
{
Eo *evas = data;
Efl_Event *evt = ev->info;
Efl_Event_Pointer_Data *evdata;
if (!efl_event_fake_get(evt))
return EO_CALLBACK_CONTINUE;
evdata = eo_data_scope_get(evt, EFL_EVENT_POINTER_CLASS);
if (!evdata || evdata->win_fed)
return EO_CALLBACK_CONTINUE;
evdata->win_fed = EINA_TRUE;
eo_event_callback_call(evas, ev->desc, evt);
evdata->win_fed = EINA_FALSE;
evdata->evas_done = EINA_FALSE;
return EO_CALLBACK_CONTINUE;
}
EO_CALLBACKS_ARRAY_DEFINE(_elm_win_evas_feed_fake_callbacks,
{ EFL_EVENT_POINTER_MOVE, _evas_event_pointer_feed_fake_cb },
{ EFL_EVENT_POINTER_DOWN, _evas_event_pointer_feed_fake_cb },
{ EFL_EVENT_POINTER_UP, _evas_event_pointer_feed_fake_cb },
{ EFL_EVENT_POINTER_IN, _evas_event_pointer_feed_fake_cb },
{ EFL_EVENT_POINTER_OUT, _evas_event_pointer_feed_fake_cb },
{ EFL_EVENT_POINTER_CANCEL, _evas_event_pointer_feed_fake_cb },
{ EFL_EVENT_POINTER_WHEEL, _evas_event_pointer_feed_fake_cb },
{ EFL_EVENT_KEY_DOWN, _evas_event_key_feed_fake_cb },
{ EFL_EVENT_KEY_UP, _evas_event_key_feed_fake_cb })
static void
_deferred_ecore_evas_free(void *data)
@ -1996,6 +2080,7 @@ _elm_win_evas_object_smart_del(Eo *obj, Elm_Win_Data *sd)
_elm_win_on_resize_obj_changed_size_hints,
obj);
eo_event_callback_array_del(sd->evas, _elm_win_evas_forward_callbacks(), obj);
eo_event_callback_array_del(obj, _elm_win_evas_feed_fake_callbacks(), sd->evas);
evas_object_del(sd->box);
evas_object_del(sd->edje);
@ -4054,6 +4139,7 @@ _elm_win_finalize_internal(Eo *obj, Elm_Win_Data *sd, const char *name, Elm_Win_
elm_interface_atspi_window_created_signal_emit(obj);
eo_event_callback_array_add(sd->evas, _elm_win_evas_forward_callbacks(), obj);
eo_event_callback_array_add(obj, _elm_win_evas_feed_fake_callbacks(), sd->evas);
evas_object_show(sd->edje);

View File

@ -28,5 +28,12 @@ interface Efl.Event.Input (Efl.Event)
val: bool;
}
}
@property fake {
[[$true if the event was fake, not triggered by real hardware.]]
get {}
values {
val: bool;
}
}
}
}

View File

@ -2,6 +2,8 @@
# include <config.h>
#endif
#define EFL_EVENT_PROTECTED
#include <Evas.h>
#define EFL_INTERNAL_UNSTABLE
@ -9,6 +11,62 @@
#define MY_CLASS EFL_EVENT_KEY_CLASS
static Efl_Event_Key *s_cached_event = NULL;
static void
_del_hook(Eo *evt)
{
if (!s_cached_event)
{
if (eo_parent_get(evt))
{
eo_ref(evt);
eo_parent_set(evt, NULL);
}
s_cached_event = evt;
}
else
{
eo_del_intercept_set(evt, NULL);
eo_del(evt);
}
}
EOLIAN static Efl_Event_Key *
_efl_event_key_efl_event_instance_get(Eo *klass EINA_UNUSED, void *_pd EINA_UNUSED,
Eo *owner, void **priv)
{
Efl_Event_Key_Data *ev;
Efl_Event_Key *evt;
if (s_cached_event)
{
evt = s_cached_event;
s_cached_event = NULL;
efl_event_reset(evt);
eo_parent_set(evt, owner);
}
else
{
evt = eo_add(EFL_EVENT_KEY_CLASS, owner);
eo_del_intercept_set(evt, _del_hook);
}
ev = eo_data_scope_get(evt, EFL_EVENT_KEY_CLASS);
ev->fake = EINA_FALSE;
if (priv) *priv = ev;
return evt;
}
EOLIAN static void
_efl_event_key_class_destructor(Eo_Class *klass EINA_UNUSED)
{
// this is a strange situation...
eo_del(s_cached_event);
s_cached_event = NULL;
}
EOLIAN static Eo_Base *
_efl_event_key_eo_base_constructor(Eo *obj, Efl_Event_Key_Data *pd EINA_UNUSED)
{
@ -98,28 +156,30 @@ _efl_event_key_efl_event_reset(Eo *obj EINA_UNUSED, Efl_Event_Key_Data *pd)
eina_stringshare_del(pd->compose);
memset(pd, 0, sizeof(*pd));
pd->eo = obj;
pd->fake = EINA_TRUE;
}
EOLIAN static Efl_Event *
_efl_event_key_efl_event_dup(Eo *obj EINA_UNUSED, Efl_Event_Key_Data *pd)
{
Efl_Event_Key_Data *pd2;
Efl_Event *ev;
Efl_Event_Key_Data *ev;
Efl_Event_Key *evt;
ev = eo_add(MY_CLASS, NULL); // no parent
pd2 = eo_data_scope_get(ev, MY_CLASS);
if (pd2)
{
memcpy(pd2, pd, sizeof(*pd));
pd2->eo = ev;
pd2->key = eina_stringshare_add(pd->key);
pd2->keyname = eina_stringshare_add(pd->keyname);
pd2->string = eina_stringshare_add(pd->string);
pd2->compose = eina_stringshare_add(pd->compose);
pd2->evas_done = 0;
}
// no parent
evt = efl_event_instance_get(EFL_EVENT_KEY_CLASS, NULL, (void **) &ev);
if (!evt || !ev) return NULL;
return ev;
memcpy(ev, pd, sizeof(*ev));
ev->eo = evt;
ev->key = eina_stringshare_add(pd->key);
ev->keyname = eina_stringshare_add(pd->keyname);
ev->string = eina_stringshare_add(pd->string);
ev->compose = eina_stringshare_add(pd->compose);
ev->evas_done = 0;
ev->win_fed = 0;
ev->fake = 1;
return evt;
}
EOLIAN static void
@ -202,4 +262,10 @@ _efl_event_key_efl_input_state_lock_enabled_get(Eo *obj EINA_UNUSED, Efl_Event_K
return evas_key_lock_is_set(pd->locks, name);
}
EOLIAN static Eina_Bool
_efl_event_key_efl_event_input_fake_get(Eo *obj EINA_UNUSED, Efl_Event_Key_Data *pd)
{
return pd->fake;
}
#include "efl_event_key.eo.c"

View File

@ -52,11 +52,14 @@ class Efl.Event.Key (Eo.Base, Efl.Event, Efl.Input.State, Efl.Event.Input)
}
}
implements {
class.destructor;
Eo.Base.constructor;
Efl.Event.instance_get;
Efl.Event.reset;
Efl.Event.dup;
Efl.Event.timestamp.set;
Efl.Event.timestamp.get;
Efl.Event.Input.fake.get;
Efl.Event.Input.event_flags.set;
Efl.Event.Input.event_flags.get;
Efl.Event.Input.on_hold.set;

View File

@ -2,6 +2,8 @@
# include <config.h>
#endif
#define EFL_EVENT_PROTECTED
#include <Evas.h>
#define EFL_INTERNAL_UNSTABLE
@ -42,9 +44,10 @@ _del_hook(Eo *evt)
}
EOLIAN static Efl_Event_Pointer *
_efl_event_pointer_instance_get(Eo_Class *klass EINA_UNUSED, void *pd EINA_UNUSED,
Eo *owner, void **priv)
_efl_event_pointer_efl_event_instance_get(Eo *klass EINA_UNUSED, void *_pd EINA_UNUSED,
Eo *owner, void **priv)
{
Efl_Event_Pointer_Data *ev;
Efl_Event_Pointer *evt;
if (s_cached_event)
@ -60,8 +63,9 @@ _efl_event_pointer_instance_get(Eo_Class *klass EINA_UNUSED, void *pd EINA_UNUSE
eo_del_intercept_set(evt, _del_hook);
}
if (priv)
*priv = eo_data_scope_get(evt, EFL_EVENT_POINTER_CLASS);
ev = eo_data_scope_get(evt, EFL_EVENT_POINTER_CLASS);
ev->fake = EINA_FALSE;
if (priv) *priv = ev;
return evt;
}
@ -70,7 +74,7 @@ EOLIAN static void
_efl_event_pointer_class_destructor(Eo_Class *klass EINA_UNUSED)
{
// this is a strange situation...
eo_unref(s_cached_event);
eo_del(s_cached_event);
s_cached_event = NULL;
}
@ -85,23 +89,28 @@ _efl_event_pointer_eo_base_constructor(Eo *obj, Efl_Event_Pointer_Data *pd EINA_
EOLIAN static void
_efl_event_pointer_efl_event_reset(Eo *obj, Efl_Event_Pointer_Data *pd)
{
Eina_Bool fake = pd->fake;
memset(pd, 0, sizeof(*pd));
pd->eo = obj;
pd->wheel.dir = EFL_ORIENT_VERTICAL;
pd->fake = fake;
}
EOLIAN static Efl_Event *
_efl_event_pointer_efl_event_dup(Eo *obj, Efl_Event_Pointer_Data *pd)
_efl_event_pointer_efl_event_dup(Eo *obj EINA_UNUSED, Efl_Event_Pointer_Data *pd)
{
Efl_Event_Pointer_Data *ev;
Efl_Event_Pointer *evt;
evt = _efl_event_pointer_instance_get((Eo_Class *) EFL_EVENT_POINTER_CLASS,
NULL, obj, (void **) &ev);
// no parent
evt = efl_event_instance_get(EFL_EVENT_POINTER_CLASS, NULL, (void **) &ev);
if (!evt) return NULL;
memcpy(ev, pd, sizeof(*ev));
ev->eo = evt;
ev->evas_done = 0;
ev->win_fed = 0;
ev->fake = 1;
return evt;
}
@ -397,4 +406,11 @@ _efl_event_pointer_efl_event_input_on_scroll_get(Eo *obj EINA_UNUSED, Efl_Event_
return !!(pd->event_flags & EFL_EVENT_FLAGS_ON_SCROLL);
}
EOLIAN static Eina_Bool
_efl_event_pointer_efl_event_input_fake_get(Eo *obj EINA_UNUSED, Efl_Event_Pointer_Data *pd)
{
// read-only
return pd->fake;
}
#include "efl_event_pointer.eo.c"

View File

@ -125,24 +125,16 @@ class Efl.Event.Pointer (Eo.Base, Efl.Event, Efl.Input.State, Efl.Event.Input)
dist: int;
}
}
instance_get @class {
[[Creates an instance of this events or returns a fresh one from
a memory pool.
]]
params {
@in owner: Eo.Base; [[The parent object.]]
@out priv: void_ptr; [[Pointer to the internal data of the object.]]
}
return: own(Efl.Event.Pointer);
}
}
implements {
Eo.Base.constructor;
class.destructor;
Efl.Event.instance_get;
Efl.Event.reset;
Efl.Event.dup;
Efl.Event.timestamp.set;
Efl.Event.timestamp.get;
Efl.Event.Input.fake.get;
Efl.Event.Input.event_flags.set;
Efl.Event.Input.event_flags.get;
Efl.Event.Input.on_hold.set;

View File

@ -1,3 +1,5 @@
#define EFL_EVENT_PROTECTED
#include "evas_common_private.h"
#include "evas_private.h"
@ -104,7 +106,7 @@ _efl_event_create(Efl_Event *evt, Evas_Callback_Type type, void *ev,
#define EV_CASE(TYPE, Type, OBJTYP, objtyp) \
case EVAS_CALLBACK_ ## TYPE: \
if (!evt) evt = eo_add(EFL_EVENT_ ## OBJTYP ## _CLASS, parentev); \
if (!evt) evt = efl_event_instance_get(EFL_EVENT_ ## OBJTYP ## _CLASS, parentev, NULL); \
efl_event_ ## objtyp ## _legacy_info_set(evt, ev, type); \
if (pflags) *pflags = &(((Evas_Event_ ## Type *) ev)->event_flags); \
break;
@ -122,6 +124,7 @@ _efl_event_create(Efl_Event *evt, Evas_Callback_Type type, void *ev,
EV_CASE(MOUSE_WHEEL, Mouse_Wheel, POINTER, pointer);
EV_CASE(KEY_DOWN, Key_Down, KEY, key);
EV_CASE(KEY_UP, Key_Up, KEY, key);
default:
DBG("Support for event type %d not implemented yet.", type);
break;