efl/src/lib/evas/canvas/evas_callbacks.c

885 lines
28 KiB
C
Raw Normal View History

#include "evas_common_private.h"
2002-11-08 00:02:15 -08:00
#include "evas_private.h"
EVAS_MEMPOOL(_mp_pc);
extern Eina_Hash* signals_hash_table;
/* Legacy events, do not use anywhere */
void _evas_object_smart_callback_call_internal(Evas_Object *eo_obj, const Efl_Event_Description *efl_event_desc);
static const Efl_Event_Description _EVAS_OBJECT_EVENT_FREE = EFL_EVENT_DESCRIPTION("free");
static const Efl_Event_Description _EVAS_OBJECT_EVENT_DEL = EFL_EVENT_DESCRIPTION("del");
#define EVAS_OBJECT_EVENT_FREE (&(_EVAS_OBJECT_EVENT_FREE))
#define EVAS_OBJECT_EVENT_DEL (&(_EVAS_OBJECT_EVENT_DEL))
/**
* Evas events descriptions for Eo.
*/
#define DEFINE_EVAS_CALLBACKS(FUNC, LAST, ...) \
static const Efl_Event_Description *FUNC(unsigned int index) \
{ \
static const Efl_Event_Description *internals[LAST] = { NULL }; \
\
if (index >= LAST) return NULL; \
if (internals[0] == NULL) \
{ \
memcpy(internals, \
((const Efl_Event_Description*[]) { __VA_ARGS__ }), \
sizeof ((const Efl_Event_Description *[]) { __VA_ARGS__ })); \
} \
return internals[index]; \
}
DEFINE_EVAS_CALLBACKS(_legacy_evas_callback_table, EVAS_CALLBACK_LAST,
EFL_EVENT_POINTER_IN,
EFL_EVENT_POINTER_OUT,
EFL_EVENT_POINTER_DOWN,
EFL_EVENT_POINTER_UP,
EFL_EVENT_POINTER_MOVE,
EFL_EVENT_POINTER_WHEEL,
EFL_EVENT_FINGER_DOWN,
EFL_EVENT_FINGER_UP,
EFL_EVENT_FINGER_MOVE,
EVAS_OBJECT_EVENT_FREE,
EFL_EVENT_KEY_DOWN,
EFL_EVENT_KEY_UP,
EFL_EVENT_FOCUS_IN,
EFL_EVENT_FOCUS_OUT,
EFL_GFX_ENTITY_EVENT_SHOW,
EFL_GFX_ENTITY_EVENT_HIDE,
EFL_GFX_ENTITY_EVENT_POSITION_CHANGED,
EFL_GFX_ENTITY_EVENT_SIZE_CHANGED,
EFL_GFX_ENTITY_EVENT_STACKING_CHANGED,
EVAS_OBJECT_EVENT_DEL,
EFL_EVENT_HOLD,
EFL_GFX_ENTITY_EVENT_HINTS_CHANGED,
EFL_GFX_IMAGE_EVENT_IMAGE_PRELOAD,
EFL_CANVAS_SCENE_EVENT_SCENE_FOCUS_IN,
EFL_CANVAS_SCENE_EVENT_SCENE_FOCUS_OUT,
EVAS_CANVAS_EVENT_RENDER_FLUSH_PRE,
EVAS_CANVAS_EVENT_RENDER_FLUSH_POST,
EFL_CANVAS_SCENE_EVENT_OBJECT_FOCUS_IN,
EFL_CANVAS_SCENE_EVENT_OBJECT_FOCUS_OUT,
EFL_GFX_IMAGE_EVENT_IMAGE_UNLOAD,
EFL_CANVAS_SCENE_EVENT_RENDER_PRE,
EFL_CANVAS_SCENE_EVENT_RENDER_POST,
EFL_GFX_IMAGE_EVENT_IMAGE_RESIZED,
EFL_CANVAS_SCENE_EVENT_DEVICE_CHANGED,
EFL_EVENT_POINTER_AXIS,
EVAS_CANVAS_EVENT_VIEWPORT_RESIZE );
static inline Evas_Callback_Type
_legacy_evas_callback_type(const Efl_Event_Description *desc)
{
Evas_Callback_Type type;
for (type = 0; type < EVAS_CALLBACK_LAST; type++)
{
if (_legacy_evas_callback_table(type) == desc)
return type;
}
return EVAS_CALLBACK_LAST;
}
typedef enum {
EFL_EVENT_TYPE_NULL,
EFL_EVENT_TYPE_OBJECT,
EFL_EVENT_TYPE_STRUCT,
EFL_EVENT_TYPE_POINTER,
EFL_EVENT_TYPE_KEY,
EFL_EVENT_TYPE_HOLD,
EFL_EVENT_TYPE_FOCUS
} Efl_Event_Info_Type;
typedef struct
{
EINA_INLIST;
union {
Evas_Event_Cb evas_cb;
Evas_Object_Event_Cb object_cb;
} func;
void *data;
Evas_Callback_Type type;
Efl_Event_Info_Type efl_event_type;
Evas_Callback_Priority priority;
} Evas_Event_Cb_Wrapper_Info;
static int
_evas_event_efl_event_info_type(Evas_Callback_Type type)
{
switch (type)
{
case EVAS_CALLBACK_MOUSE_IN:
case EVAS_CALLBACK_MOUSE_OUT:
case EVAS_CALLBACK_MOUSE_DOWN:
case EVAS_CALLBACK_MOUSE_UP:
case EVAS_CALLBACK_MOUSE_MOVE:
case EVAS_CALLBACK_MOUSE_WHEEL:
case EVAS_CALLBACK_MULTI_DOWN:
case EVAS_CALLBACK_MULTI_UP:
case EVAS_CALLBACK_MULTI_MOVE:
case EVAS_CALLBACK_AXIS_UPDATE:
return EFL_EVENT_TYPE_POINTER;
case EVAS_CALLBACK_KEY_DOWN:
case EVAS_CALLBACK_KEY_UP:
return EFL_EVENT_TYPE_KEY;
case EVAS_CALLBACK_HOLD:
return EFL_EVENT_TYPE_HOLD;
case EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN:
case EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_OUT: /* Efl.Canvas.Object */
return EFL_EVENT_TYPE_OBJECT;
case EVAS_CALLBACK_RENDER_POST: /* Efl_Gfx_Event_Render_Post */
return EFL_EVENT_TYPE_STRUCT;
case EVAS_CALLBACK_DEVICE_CHANGED: /* Efl.Input.Device */
return EFL_EVENT_TYPE_OBJECT;
case EVAS_CALLBACK_FOCUS_IN:
case EVAS_CALLBACK_FOCUS_OUT:
return EFL_EVENT_TYPE_FOCUS;
default:
return EFL_EVENT_TYPE_NULL;
}
}
static void
_eo_evas_object_cb(void *data, const Efl_Event *event)
{
Evas_Event_Flags *event_flags = NULL, evflags = EVAS_EVENT_FLAG_NONE;
Efl_Input_Event *efl_event_info = event->info;
Evas_Event_Cb_Wrapper_Info *info = data;
void *event_info;
Evas *evas;
if (!info->func.object_cb) return;
evas = evas_object_evas_get(event->object);
event_info = event->info;
switch (info->efl_event_type)
{
case EFL_EVENT_TYPE_POINTER:
event_info = efl_input_pointer_legacy_info_fill(evas, efl_event_info, info->type, &event_flags);
break;
case EFL_EVENT_TYPE_KEY:
event_info = efl_input_key_legacy_info_fill(efl_event_info, &event_flags);
break;
case EFL_EVENT_TYPE_HOLD:
event_info = efl_input_hold_legacy_info_fill(efl_event_info, &event_flags);
break;
case EFL_EVENT_TYPE_FOCUS:
case EFL_EVENT_TYPE_NULL:
info->func.object_cb(info->data, evas, event->object, NULL);
return;
case EFL_EVENT_TYPE_STRUCT:
case EFL_EVENT_TYPE_OBJECT:
info->func.object_cb(info->data, evas, event->object, event_info);
return;
default: return;
}
if (!event_info) return;
if (event_flags) evflags = *event_flags;
info->func.object_cb(info->data, evas, event->object, event_info);
if (event_flags && (evflags != *event_flags))
efl_input_event_flags_set(efl_event_info, *event_flags);
}
static void
_eo_evas_cb(void *data, const Efl_Event *event)
{
Evas_Event_Cb_Wrapper_Info *info = data;
Efl_Input_Event *efl_event_info = event->info;
Evas *evas = event->object;
void *event_info;
if (!info->func.evas_cb) return;
if (event->desc == EFL_CANVAS_SCENE_EVENT_OBJECT_FOCUS_IN ||
event->desc == EFL_CANVAS_SCENE_EVENT_OBJECT_FOCUS_OUT)
{
event_info = efl_input_focus_object_get(efl_event_info);
goto emit;
}
event_info = event->info;
switch (info->efl_event_type)
{
case EFL_EVENT_TYPE_POINTER:
event_info = efl_input_pointer_legacy_info_fill(evas, efl_event_info, info->type, NULL);
break;
case EFL_EVENT_TYPE_KEY:
event_info = efl_input_key_legacy_info_fill(efl_event_info, NULL);
break;
case EFL_EVENT_TYPE_HOLD:
event_info = efl_input_hold_legacy_info_fill(efl_event_info, NULL);
break;
case EFL_EVENT_TYPE_FOCUS:
case EFL_EVENT_TYPE_NULL:
event_info = NULL;
break;
case EFL_EVENT_TYPE_STRUCT:
case EFL_EVENT_TYPE_OBJECT:
break;
}
emit:
info->func.evas_cb(info->data, event->object, event_info);
}
void
_evas_post_event_callback_call_real(Evas *eo_e, Evas_Public_Data *e, int min_event_id)
{
Evas_Post_Callback *pc;
Eina_List *l, *l_next;
int skip = 0;
if (e->delete_me) return;
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!
2017-02-15 23:47:57 -08:00
_evas_walk(e);
e->running_post_events++;
EINA_LIST_FOREACH_SAFE(e->post_events, l, l_next, pc)
{
if ((unsigned int) pc->event_id < (unsigned int) min_event_id) break;
e->post_events = eina_list_remove_list(e->post_events, l);
if ((!skip) && (!e->delete_me) && (!pc->delete_me))
{
if (!pc->func((void*)pc->data, eo_e)) skip = 1;
}
2011-12-14 21:56:19 -08:00
EVAS_MEMPOOL_FREE(_mp_pc, pc);
}
e->running_post_events--;
_evas_unwalk(e);
if (!e->running_post_events && e->post_events
&& (e->current_event == EVAS_CALLBACK_LAST))
{
WRN("Not all post-event callbacks have been processed!");
_evas_post_event_callback_call_real(eo_e, e, 0);
}
}
void
_evas_post_event_callback_free(Evas *eo_e)
{
Evas_Public_Data *e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
Evas_Post_Callback *pc;
2011-12-14 21:56:19 -08:00
if (EINA_LIKELY(!e->post_events)) return;
EINA_LIST_FREE(e->post_events, pc)
{
2011-12-14 21:56:19 -08:00
EVAS_MEMPOOL_FREE(_mp_pc, pc);
}
}
void
evas_object_event_callback_all_del(Evas_Object *eo_obj)
{
Evas_Event_Cb_Wrapper_Info *info;
Eina_Inlist *itr;
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
if (!obj) return;
if (!obj->callbacks) return;
EINA_INLIST_FOREACH_SAFE(obj->callbacks, itr, info)
{
efl_event_callback_del(eo_obj, _legacy_evas_callback_table(info->type), _eo_evas_object_cb, info);
obj->callbacks =
eina_inlist_remove(obj->callbacks, EINA_INLIST_GET(info));
free(info);
}
}
void
evas_object_event_callback_cleanup(Evas_Object *eo_obj)
{
evas_object_event_callback_all_del(eo_obj);
}
void
evas_event_callback_all_del(Evas *eo_e)
{
Evas_Event_Cb_Wrapper_Info *info;
Eina_Inlist *itr;
Evas_Public_Data *e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
if (!e) return;
if (!e->callbacks) return;
EINA_INLIST_FOREACH_SAFE(e->callbacks, itr, info)
{
efl_event_callback_del(eo_e, _legacy_evas_callback_table(info->type), _eo_evas_cb, info);
e->callbacks =
eina_inlist_remove(e->callbacks, EINA_INLIST_GET(info));
free(info);
}
}
void
evas_event_callback_cleanup(Evas *eo_e)
{
evas_event_callback_all_del(eo_e);
}
void
evas_event_callback_call(Evas *eo_e, Evas_Callback_Type type, void *event_info)
{
efl_event_callback_legacy_call(eo_e, _legacy_evas_callback_table(type), event_info);
}
static void
_evas_callback_legacy_smart_compatibility_do_it(Evas_Object *eo_obj, const Efl_Event_Description *efl_event_desc, void *event_info)
{
/* this is inverted: the base call is the legacy compat and this is the new event */
if ((efl_event_desc == EFL_GFX_ENTITY_EVENT_SHOW) || (efl_event_desc == EFL_GFX_ENTITY_EVENT_HIDE))
efl_event_callback_call(eo_obj, EFL_GFX_ENTITY_EVENT_VISIBILITY_CHANGED, event_info);
else if ((efl_event_desc == EFL_GFX_IMAGE_EVENT_IMAGE_PRELOAD) || (efl_event_desc == EFL_GFX_IMAGE_EVENT_IMAGE_UNLOAD))
efl_event_callback_call(eo_obj, EFL_GFX_IMAGE_EVENT_IMAGE_PRELOAD_STATE_CHANGED, event_info);
}
2002-11-08 00:02:15 -08:00
void
evas_object_event_callback_call(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj,
Evas_Callback_Type type, void *event_info, int event_id,
const Efl_Event_Description *efl_event_desc)
2002-11-08 00:02:15 -08:00
{
/* MEM OK */
const Evas_Button_Flags CLICK_MASK = EVAS_BUTTON_DOUBLE_CLICK | EVAS_BUTTON_TRIPLE_CLICK;
Evas_Button_Flags flags = EVAS_BUTTON_NONE;
Evas_Callback_Type prev_type;
Evas_Public_Data *e;
2005-05-21 19:49:50 -07:00
if (!obj) return;
if ((obj->delete_me) || (!obj->layer)) return;
if ((obj->last_event_id == event_id) &&
From: Hyoyoung Chang <hyoyoung.chang@samsung.com> Subject: [E-devel] [patch] evas - add checking event type Dear developers. I found a bug about evas event handling. In some situation, evas blocks some events by checking _evas_event_counter. So I made a patch that is checking event type also event counter. Reproduce steps: 1. make a window 2. show window before adding a elementary/genlist widget --- codes --- void _gl_mousedown_cb(void *data, Evas *evas, Evas_Object *obj, void *event_info) { printf("_gl_mousedown_cb !! \n"); } static Eina_Bool create_main_win(App *app) { app->win = elm_win_add(NULL, "genlist-win", ELM_WIN_BASIC); evas_object_show(app->win); <-- position 1 Evas_Object *genlist = elm_genlist_add(app->win); elm_win_resize_object_add(app->win, genlist); evas_object_event_callback_add(genlist, EVAS_CALLBACK_MOUSE_DOWN, _gl_mousedown_cb, NULL); evas_object_show(genlist); evas_object_resize(app->win, 320, 240); //evas_object_show(app->win); <-- position 2 return EINA_TRUE; } --- codes --- In common use case, apps don't show main window at position 1. However to reproduce, it can be at position 1. Then, focus is at just on main window. In that situation, if a user clicks a genlist, its event is dropped by evas. Because in mouse down callback, it give focus to genlist. Then two events is made. First is mouse down, second is focus handling. In event callback, evas processes mouse down after focus handling. But evas found that mouse event is retarded event than focus handling. So it ignores it. This patch is introduce event handling type checking to evas_object_event_callback_call. SVN revision: 61026
2011-07-04 18:33:59 -07:00
(obj->last_event_type == type)) return;
if (obj->last_event_id > event_id)
From: Hyoyoung Chang <hyoyoung@gmail.com> Subject: [E-devel] [patch] evas - preventing retard mouse event process in evas_object_event_callback_call I made a small patch to prevent retard mouse event process. At certain circumstance (like as genlist select callback + naviframe item push), some events are repeat processed. If some evas_objects're iterating in evas_event_feed_mouse_up and mouse_out event's emitted by other interrupt(such as naviframe item push), then some evas_objects events are multiple processed by evas_object_event_callback_call. More elaborating it with a example. There are a genlist and a multibuttonentry on genlist item. When a user clicks multibuttonentry then evas will process mouse down and up. in evas_event_feed_mouse_up, it gets evas object list to process mouse events. Then in the evas object list, there are two evas objects - rect and textblock. Two objects have its own parents. the rect has below parents. ---------------------------------------- edje - genlist item elm_genlist_pan edje multibuttonentry box entry els_scroller (0x2a601788) rect <== the rect the textblock has below parents. ---------------------------------------------- edje - genlist item elm_genlist_pan edje multibuttonentry box entry els_scroller(0x2a601788) edje elm_pan edje textblock <== the textblock (note : two evas object have same parent (els_scroller)) So normally mouse up callbacks event propagates to its own parent. the rect is processed to genlist item. and the textblock is processed to genlist item. but when els_scroller is processed, it's blocked by checking event type and event id checking. Mouse Up(rect) -> Mouse Up(textblock) event_id (3) -> event_id (3) evas_object_event_callback_call(Evas_Object *obj, Evas_Callback_Type type, void *event_info, int event_id) { ... if ((obj->delete_me) || (!obj->layer)) return; if ((obj->last_event == event_id) && (obj->last_event_type == type)) return; <=== blocked However if naviframe item is pushed in the middle of mouse up processing. It can break into mouse up. So it's processed like below. Mouse Up(rect) -> Mouse Out(rect) -> Mouse Out(textblock) -> Mouse Up(textblock) event_id (3) -> event_id(4) -> event_id(4) -> event_id(3) (note Mouse_Out is made by naviframe item push for event freezing) If that, there's no mechanism to block that repeat processing same event. So I suggest this patch. This patch blocks old events if there's no reason to process. (It blocks old mouse_up event because mouse_out is processed.) And I think it also clear the bug in "[E-devel] event repetition with elm_naviframe/elm_genlist" SVN revision: 67879
2012-02-13 03:25:23 -08:00
{
if ((obj->last_event_type == EVAS_CALLBACK_MOUSE_OUT) &&
((type >= EVAS_CALLBACK_MOUSE_DOWN) &&
(type <= EVAS_CALLBACK_MULTI_MOVE)))
{
return;
}
}
obj->last_event_id = event_id;
From: Hyoyoung Chang <hyoyoung.chang@samsung.com> Subject: [E-devel] [patch] evas - add checking event type Dear developers. I found a bug about evas event handling. In some situation, evas blocks some events by checking _evas_event_counter. So I made a patch that is checking event type also event counter. Reproduce steps: 1. make a window 2. show window before adding a elementary/genlist widget --- codes --- void _gl_mousedown_cb(void *data, Evas *evas, Evas_Object *obj, void *event_info) { printf("_gl_mousedown_cb !! \n"); } static Eina_Bool create_main_win(App *app) { app->win = elm_win_add(NULL, "genlist-win", ELM_WIN_BASIC); evas_object_show(app->win); <-- position 1 Evas_Object *genlist = elm_genlist_add(app->win); elm_win_resize_object_add(app->win, genlist); evas_object_event_callback_add(genlist, EVAS_CALLBACK_MOUSE_DOWN, _gl_mousedown_cb, NULL); evas_object_show(genlist); evas_object_resize(app->win, 320, 240); //evas_object_show(app->win); <-- position 2 return EINA_TRUE; } --- codes --- In common use case, apps don't show main window at position 1. However to reproduce, it can be at position 1. Then, focus is at just on main window. In that situation, if a user clicks a genlist, its event is dropped by evas. Because in mouse down callback, it give focus to genlist. Then two events is made. First is mouse down, second is focus handling. In event callback, evas processes mouse down after focus handling. But evas found that mouse event is retarded event than focus handling. So it ignores it. This patch is introduce event handling type checking to evas_object_event_callback_call. SVN revision: 61026
2011-07-04 18:33:59 -07:00
obj->last_event_type = type;
if (!(e = obj->layer->evas)) return;
_evas_walk(e);
// gesture hook
if ( type == EVAS_CALLBACK_MOUSE_MOVE ||
type == EVAS_CALLBACK_MULTI_MOVE ||
type == EVAS_CALLBACK_MOUSE_DOWN ||
type == EVAS_CALLBACK_MULTI_DOWN ||
type == EVAS_CALLBACK_MOUSE_UP ||
type == EVAS_CALLBACK_MULTI_UP)
_efl_canvas_gesture_manager_filter_event(e->gesture_manager, eo_obj, event_info);
if (obj->is_smart)
_evas_object_smart_callback_call_internal(eo_obj, efl_event_desc);
if (!_evas_object_callback_has_by_type(obj, type))
goto nothing_here;
if ((type == EVAS_CALLBACK_MOUSE_DOWN) || (type == EVAS_CALLBACK_MOUSE_UP))
{
flags = efl_input_pointer_button_flags_get(event_info);
if (flags & CLICK_MASK)
{
if (obj->last_mouse_down_counter < (e->last_mouse_down_counter - 1))
efl_input_pointer_button_flags_set(event_info, flags & ~CLICK_MASK);
}
obj->last_mouse_down_counter = e->last_mouse_down_counter;
}
if (!efl_event_desc)
{
/* This can happen for DEL and FREE which are defined only in here */
efl_event_desc = _legacy_evas_callback_table(type);
}
prev_type = e->current_event;
e->current_event = type;
efl_event_callback_legacy_call(eo_obj, efl_event_desc, event_info);
_evas_callback_legacy_smart_compatibility_do_it(eo_obj, efl_event_desc, event_info);
/* multi events with finger 0 - only for eo callbacks */
if (type == EVAS_CALLBACK_MOUSE_DOWN)
{
if (_evas_object_callback_has_by_type(obj, EVAS_CALLBACK_MULTI_DOWN))
{
e->current_event = EVAS_CALLBACK_MULTI_DOWN;
efl_event_callback_call(eo_obj, EFL_EVENT_FINGER_DOWN, event_info);
}
efl_input_pointer_button_flags_set(event_info, flags);
}
else if (type == EVAS_CALLBACK_MOUSE_UP)
{
if (_evas_object_callback_has_by_type(obj, EVAS_CALLBACK_MULTI_UP))
{
e->current_event = EVAS_CALLBACK_MULTI_UP;
efl_event_callback_call(eo_obj, EFL_EVENT_FINGER_UP, event_info);
}
efl_input_pointer_button_flags_set(event_info, flags);
}
else if (type == EVAS_CALLBACK_MOUSE_MOVE)
{
if (_evas_object_callback_has_by_type(obj, EVAS_CALLBACK_MULTI_MOVE))
{
e->current_event = EVAS_CALLBACK_MULTI_MOVE;
efl_event_callback_call(eo_obj, EFL_EVENT_FINGER_MOVE, event_info);
}
}
e->current_event = prev_type;
nothing_here:
if (!obj->no_propagate)
{
if ((obj->smart.parent || ((obj->events) && obj->events->parent)) &&
(type != EVAS_CALLBACK_FREE) &&
(type <= EVAS_CALLBACK_KEY_UP))
2011-12-14 21:56:19 -08:00
{
evas: add new event_grabber smart-ish object 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
2017-06-09 17:16:08 -07:00
Evas_Object_Protected_Data *parent_obj;
Eo *parent;
parent = ((obj->events) && obj->events->parent) ?
obj->events->parent: obj->smart.parent;
evas: add new event_grabber smart-ish object 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
2017-06-09 17:16:08 -07:00
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);
2011-12-14 21:56:19 -08:00
}
}
_evas_unwalk(e);
2002-11-08 00:02:15 -08:00
}
EAPI void
evas_object_event_callback_add(Evas_Object *eo_obj, Evas_Callback_Type type, Evas_Object_Event_Cb func, const void *data)
{
evas_object_event_callback_priority_add(eo_obj, type,
2011-12-14 21:56:19 -08:00
EVAS_CALLBACK_PRIORITY_DEFAULT, func, data);
}
EAPI void
evas_object_event_callback_priority_add(Evas_Object *eo_obj, Evas_Callback_Type type, Evas_Callback_Priority priority, Evas_Object_Event_Cb func, const void *data)
2002-11-08 00:02:15 -08:00
{
Evas_Object_Protected_Data *obj;
Evas_Event_Cb_Wrapper_Info *cb_info;
const Efl_Event_Description *desc;
2005-05-21 19:49:50 -07:00
EINA_SAFETY_ON_NULL_RETURN(eo_obj);
EINA_SAFETY_ON_NULL_RETURN(func);
EINA_SAFETY_ON_TRUE_RETURN(efl_invalidated_get(eo_obj));
obj = efl_data_scope_safe_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
EINA_SAFETY_ON_NULL_RETURN(obj);
2005-05-21 19:49:50 -07:00
cb_info = calloc(1, sizeof(*cb_info));
cb_info->func.object_cb = func;
cb_info->data = (void *)data;
cb_info->type = type;
cb_info->efl_event_type = _evas_event_efl_event_info_type(type);
2011-12-14 21:56:19 -08:00
desc = _legacy_evas_callback_table(type);
efl_event_callback_priority_add(eo_obj, desc, priority, _eo_evas_object_cb, cb_info);
obj->callbacks =
eina_inlist_append(obj->callbacks, EINA_INLIST_GET(cb_info));
2002-11-08 00:02:15 -08:00
}
EAPI void *
evas_object_event_callback_del(Evas_Object *eo_obj, Evas_Callback_Type type, Evas_Object_Event_Cb func)
2002-11-08 00:02:15 -08:00
{
Evas_Object_Protected_Data *obj;
Evas_Event_Cb_Wrapper_Info *info;
2005-05-21 19:49:50 -07:00
if (!eo_obj) return NULL;
EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
obj = efl_data_scope_safe_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
2005-05-21 19:49:50 -07:00
if (!obj->callbacks) return NULL;
2005-05-21 19:49:50 -07:00
EINA_INLIST_REVERSE_FOREACH(obj->callbacks, info)
{
if ((info->func.object_cb == func) && (info->type == type))
2011-12-14 21:56:19 -08:00
{
void *tmp = info->data;
efl_event_callback_del(eo_obj, _legacy_evas_callback_table(type), _eo_evas_object_cb, info);
2011-12-14 21:56:19 -08:00
obj->callbacks =
eina_inlist_remove(obj->callbacks, EINA_INLIST_GET(info));
free(info);
2011-12-14 21:56:19 -08:00
return tmp;
}
}
2002-11-08 00:02:15 -08:00
return NULL;
}
EAPI void *
evas_object_event_callback_del_full(Evas_Object *eo_obj, Evas_Callback_Type type, Evas_Object_Event_Cb func, const void *data)
{
Evas_Object_Protected_Data *obj;
Evas_Event_Cb_Wrapper_Info *info;
if (!eo_obj) return NULL;
EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
obj = efl_data_scope_safe_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
if (!obj->callbacks) return NULL;
EINA_INLIST_FOREACH(obj->callbacks, info)
{
if ((info->func.object_cb == func) && (info->type == type) && info->data == data)
2011-12-14 21:56:19 -08:00
{
void *tmp = info->data;
efl_event_callback_del(eo_obj, _legacy_evas_callback_table(type), _eo_evas_object_cb, info);
2011-12-14 21:56:19 -08:00
obj->callbacks =
eina_inlist_remove(obj->callbacks, EINA_INLIST_GET(info));
free(info);
2011-12-14 21:56:19 -08:00
return tmp;
}
}
return NULL;
}
EAPI void
evas_event_callback_add(Evas *eo_e, Evas_Callback_Type type, Evas_Event_Cb func, const void *data)
{
evas_event_callback_priority_add(eo_e, type, EVAS_CALLBACK_PRIORITY_DEFAULT,
2011-12-14 21:56:19 -08:00
func, data);
}
void
_deferred_callbacks_process(Evas *eo_e, Evas_Public_Data *e)
{
Evas_Event_Cb_Wrapper_Info *cb_info;
const Efl_Event_Description *desc;
while (e->deferred_callbacks)
{
cb_info = EINA_INLIST_CONTAINER_GET(e->deferred_callbacks,
Evas_Event_Cb_Wrapper_Info);
e->deferred_callbacks = eina_inlist_remove(e->deferred_callbacks,
e->deferred_callbacks);
desc = _legacy_evas_callback_table(cb_info->type);
efl_event_callback_priority_add(eo_e, desc, cb_info->priority, _eo_evas_cb, cb_info);
e->callbacks = eina_inlist_append(e->callbacks, EINA_INLIST_GET(cb_info));
}
}
EAPI void
evas_event_callback_priority_add(Evas *eo_e, Evas_Callback_Type type, Evas_Callback_Priority priority, Evas_Event_Cb func, const void *data)
{
Evas_Public_Data *e;
Evas_Event_Cb_Wrapper_Info *cb_info;
const Efl_Event_Description *desc;
EINA_SAFETY_ON_NULL_RETURN(eo_e);
EINA_SAFETY_ON_NULL_RETURN(func);
EINA_SAFETY_ON_TRUE_RETURN(efl_invalidated_get(eo_e));
e = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
EINA_SAFETY_ON_NULL_RETURN(e);
cb_info = calloc(1, sizeof(*cb_info));
cb_info->func.evas_cb = func;
cb_info->data = (void *)data;
cb_info->priority = priority;
cb_info->type = type;
cb_info->efl_event_type = _evas_event_efl_event_info_type(type);
2011-12-14 21:56:19 -08:00
if ((e->rendering || e->inside_post_render) && type == EVAS_CALLBACK_RENDER_POST)
{
e->deferred_callbacks = eina_inlist_append(e->deferred_callbacks,
EINA_INLIST_GET(cb_info));
}
else
{
desc = _legacy_evas_callback_table(type);
efl_event_callback_priority_add(eo_e, desc, priority, _eo_evas_cb, cb_info);
e->callbacks = eina_inlist_append(e->callbacks, EINA_INLIST_GET(cb_info));
}
}
EAPI void *
evas_event_callback_del(Evas *eo_e, Evas_Callback_Type type, Evas_Event_Cb func)
{
Evas_Public_Data *e;
Evas_Event_Cb_Wrapper_Info *info;
EINA_SAFETY_ON_NULL_RETURN_VAL(eo_e, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
e = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
if (!e->callbacks) return NULL;
if (type == EVAS_CALLBACK_RENDER_POST)
EINA_INLIST_REVERSE_FOREACH(e->deferred_callbacks, info)
{
if (info->func.evas_cb == func)
{
void *tmp = info->data;
e->deferred_callbacks =
eina_inlist_remove(e->deferred_callbacks, EINA_INLIST_GET(info));
free(info);
return tmp;
}
}
EINA_INLIST_REVERSE_FOREACH(e->callbacks, info)
{
if ((info->func.evas_cb == func) && (info->type == type))
2011-12-14 21:56:19 -08:00
{
void *tmp = info->data;
efl_event_callback_del(eo_e, _legacy_evas_callback_table(type), _eo_evas_cb, info);
e->callbacks =
eina_inlist_remove(e->callbacks, EINA_INLIST_GET(info));
free(info);
return tmp;
2011-12-14 21:56:19 -08:00
}
}
return NULL;
}
EAPI void *
evas_event_callback_del_full(Evas *eo_e, Evas_Callback_Type type, Evas_Event_Cb func, const void *data)
{
Evas_Public_Data *e;
Evas_Event_Cb_Wrapper_Info *info;
EINA_SAFETY_ON_NULL_RETURN_VAL(eo_e, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
e = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
if (!e->callbacks) return NULL;
if (type == EVAS_CALLBACK_RENDER_POST)
EINA_INLIST_REVERSE_FOREACH(e->deferred_callbacks, info)
{
if ((info->func.evas_cb == func) && (info->data == data))
{
void *tmp = info->data;
e->deferred_callbacks =
eina_inlist_remove(e->deferred_callbacks, EINA_INLIST_GET(info));
free(info);
return tmp;
}
}
EINA_INLIST_FOREACH(e->callbacks, info)
{
if ((info->func.evas_cb == func) && (info->type == type) && (info->data == data))
2011-12-14 21:56:19 -08:00
{
void *tmp = info->data;
efl_event_callback_del(eo_e, _legacy_evas_callback_table(type), _eo_evas_cb, info);
2011-12-14 21:56:19 -08:00
e->callbacks =
eina_inlist_remove(e->callbacks, EINA_INLIST_GET(info));
free(info);
2011-12-14 21:56:19 -08:00
return tmp;
}
}
return NULL;
}
EAPI void
evas_post_event_callback_push(Evas *eo_e, Evas_Object_Event_Post_Cb func, const void *data)
{
Evas_Public_Data *e;
Evas_Post_Callback *pc;
2011-12-14 21:56:19 -08:00
EINA_SAFETY_ON_NULL_RETURN(eo_e);
EINA_SAFETY_ON_TRUE_RETURN(efl_invalidated_get(eo_e));
e = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
EINA_SAFETY_ON_NULL_RETURN(e);
if (e->delete_me) return;
if (e->current_event == EVAS_CALLBACK_LAST)
{
ERR("%s() can only be called from an input event callback!", __FUNCTION__);
return;
}
EVAS_MEMPOOL_INIT(_mp_pc, "evas_post_callback", Evas_Post_Callback, 64, );
pc = EVAS_MEMPOOL_ALLOC(_mp_pc, Evas_Post_Callback);
if (!pc) return;
EVAS_MEMPOOL_PREP(_mp_pc, pc, Evas_Post_Callback);
2011-12-14 21:56:19 -08:00
pc->func = func;
pc->data = data;
pc->type = e->current_event;
pc->event_id = _evas_event_counter;
e->post_events = eina_list_prepend(e->post_events, pc);
}
EAPI void
evas_post_event_callback_remove(Evas *eo_e, Evas_Object_Event_Post_Cb func)
{
Evas_Public_Data *e;
Evas_Post_Callback *pc;
Eina_List *l;
2011-12-14 21:56:19 -08:00
EINA_SAFETY_ON_NULL_RETURN(eo_e);
e = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
EINA_SAFETY_ON_NULL_RETURN(e);
EINA_LIST_FOREACH(e->post_events, l, pc)
{
if (pc->func == func)
{
pc->delete_me = 1;
return;
}
}
}
EAPI void
evas_post_event_callback_remove_full(Evas *eo_e, Evas_Object_Event_Post_Cb func, const void *data)
{
Evas_Public_Data *e;
Evas_Post_Callback *pc;
Eina_List *l;
2011-12-14 21:56:19 -08:00
EINA_SAFETY_ON_NULL_RETURN(eo_e);
e = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
EINA_SAFETY_ON_NULL_RETURN(e);
EINA_LIST_FOREACH(e->post_events, l, pc)
{
if ((pc->func == func) && (pc->data == data))
{
pc->delete_me = 1;
return;
}
}
}
static void
_animator_repeater(void *data, const Efl_Event *event)
{
Evas_Object_Protected_Data *obj = data;
efl_event_callback_legacy_call(obj->object, EFL_CANVAS_OBJECT_EVENT_ANIMATOR_TICK, event->info);
DBG("Emitting animator tick on %p.", obj->object);
}
void
evas_object_callbacks_finalized(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj)
{
EINA_SAFETY_ON_NULL_RETURN(obj);
if (obj->animator_ref > 0)
{
if (obj->layer && obj->layer->evas)
{
efl_event_callback_add(obj->layer->evas->evas, EFL_CANVAS_OBJECT_EVENT_ANIMATOR_TICK, _animator_repeater, obj);
DBG("Registering an animator tick on canvas %p for object %p.",
obj->layer->evas->evas, obj->object);
}
}
}
void
evas_object_callbacks_event_catcher_add(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, const Efl_Callback_Array_Item *array)
{
Evas_Callback_Type type = EVAS_CALLBACK_LAST;
void *gd = NULL;
int i;
for (i = 0; array[i].desc != NULL; i++)
{
if (obj->layer && obj->layer->evas && obj->layer->evas->gesture_manager)
{
if (!gd) gd = _efl_canvas_gesture_manager_private_data_get(obj->layer->evas->gesture_manager);
_efl_canvas_gesture_manager_callback_add_hook(gd, obj->object, array[i].desc);
}
if (array[i].desc == EFL_CANVAS_OBJECT_EVENT_ANIMATOR_TICK)
{
if (obj->animator_ref++ > 0) break;
if (efl_finalized_get(eo_obj))
{
efl_event_callback_add(obj->layer->evas->evas, EFL_CANVAS_OBJECT_EVENT_ANIMATOR_TICK, _animator_repeater, obj);
DBG("Registering an animator tick on canvas %p for object %p.",
obj->layer->evas->evas, obj->object);
}
}
else if ((type = _legacy_evas_callback_type(array[i].desc)) != EVAS_CALLBACK_LAST)
{
obj->callback_mask |= (((uint64_t)1) << type);
}
else if (array[i].desc == EFL_GFX_ENTITY_EVENT_VISIBILITY_CHANGED)
{
obj->callback_mask |= (((uint64_t)1) << EVAS_CALLBACK_SHOW);
obj->callback_mask |= (((uint64_t)1) << EVAS_CALLBACK_HIDE);
}
}
}
void
evas_object_callbacks_event_catcher_del(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, const Efl_Callback_Array_Item *array)
{
void *gd = NULL;
int i;
if (!obj->layer ||
!obj->layer->evas)
return ;
for (i = 0; array[i].desc != NULL; i++)
{
if (obj->layer->evas->gesture_manager)
{
if (!gd) gd = _efl_canvas_gesture_manager_private_data_get(obj->layer->evas->gesture_manager);
_efl_canvas_gesture_manager_callback_del_hook(gd, obj->object, array[i].desc);
}
if (array[i].desc == EFL_CANVAS_OBJECT_EVENT_ANIMATOR_TICK)
{
if ((--obj->animator_ref) > 0) break;
efl_event_callback_del(obj->layer->evas->evas, EFL_CANVAS_OBJECT_EVENT_ANIMATOR_TICK, _animator_repeater, obj);
DBG("Unregistering an animator tick on canvas %p for object %p.",
obj->layer->evas->evas, obj->object);
}
}
}