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

543 lines
14 KiB
C
Raw Normal View History

2002-11-08 00:02:15 -08:00
#include "evas_common.h"
#include "evas_private.h"
static void evas_object_event_callback_clear(Evas_Object *obj);
static void evas_event_callback_clear(Evas *e);
int _evas_event_counter = 0;
EVAS_MEMPOOL(_mp_fn);
EVAS_MEMPOOL(_mp_cb);
EVAS_MEMPOOL(_mp_pc);
void
_evas_post_event_callback_call(Evas *e)
{
Evas_Post_Callback *pc;
int skip = 0;
if (e->delete_me) return;
_evas_walk(e);
EINA_LIST_FREE(e->post_events, pc)
{
if ((!skip) && (!e->delete_me) && (!pc->delete_me))
{
if (!pc->func((void*)pc->data, e)) skip = 1;
}
2011-12-14 21:56:19 -08:00
EVAS_MEMPOOL_FREE(_mp_pc, pc);
}
_evas_unwalk(e);
}
void
_evas_post_event_callback_free(Evas *e)
{
Evas_Post_Callback *pc;
2011-12-14 21:56:19 -08:00
EINA_LIST_FREE(e->post_events, pc)
{
2011-12-14 21:56:19 -08:00
EVAS_MEMPOOL_FREE(_mp_pc, pc);
}
}
void
evas_event_callback_list_post_free(Eina_Inlist **list)
{
Eina_Inlist *l;
2005-05-21 19:49:50 -07:00
/* MEM OK */
for (l = *list; l;)
{
2011-12-14 21:56:19 -08:00
Evas_Func_Node *fn;
2005-05-21 19:49:50 -07:00
2011-12-14 21:56:19 -08:00
fn = (Evas_Func_Node *)l;
l = l->next;
if (fn->delete_me)
{
*list = eina_inlist_remove(*list, EINA_INLIST_GET(fn));
EVAS_MEMPOOL_FREE(_mp_fn, fn);
2011-12-14 21:56:19 -08:00
}
}
}
static void
evas_object_event_callback_clear(Evas_Object *obj)
{
if (!obj->callbacks) return;
if (!obj->callbacks->deletions_waiting) return;
obj->callbacks->deletions_waiting = 0;
evas_event_callback_list_post_free(&obj->callbacks->callbacks);
if (!obj->callbacks->callbacks)
{
EVAS_MEMPOOL_FREE(_mp_cb, obj->callbacks);
2011-12-14 21:56:19 -08:00
obj->callbacks = NULL;
}
}
static void
evas_event_callback_clear(Evas *e)
{
if (!e->callbacks) return;
if (!e->callbacks->deletions_waiting) return;
e->callbacks->deletions_waiting = 0;
evas_event_callback_list_post_free(&e->callbacks->callbacks);
if (!e->callbacks->callbacks)
{
EVAS_MEMPOOL_FREE(_mp_cb, e->callbacks);
2011-12-14 21:56:19 -08:00
e->callbacks = NULL;
}
}
void
evas_object_event_callback_all_del(Evas_Object *obj)
{
Evas_Func_Node *fn;
if (!obj->callbacks) return;
EINA_INLIST_FOREACH(obj->callbacks->callbacks, fn)
2011-12-14 21:56:19 -08:00
fn->delete_me = 1;
}
void
evas_object_event_callback_cleanup(Evas_Object *obj)
{
/* MEM OK */
if (!obj->callbacks) return;
evas_event_callback_list_post_free(&obj->callbacks->callbacks);
EVAS_MEMPOOL_FREE(_mp_cb, obj->callbacks);
obj->callbacks = NULL;
}
void
evas_event_callback_all_del(Evas *e)
{
Evas_Func_Node *fn;
if (!e->callbacks) return;
EINA_INLIST_FOREACH(e->callbacks->callbacks, fn)
2011-12-14 21:56:19 -08:00
fn->delete_me = 1;
}
void
evas_event_callback_cleanup(Evas *e)
{
/* MEM OK */
if (!e->callbacks) return;
evas_event_callback_list_post_free(&e->callbacks->callbacks);
EVAS_MEMPOOL_FREE(_mp_cb, e->callbacks);
e->callbacks = NULL;
}
void
evas_event_callback_call(Evas *e, Evas_Callback_Type type, void *event_info)
{
Eina_Inlist **l_mod = NULL, *l;
_evas_walk(e);
if (e->callbacks)
{
2011-12-14 21:56:19 -08:00
l_mod = &e->callbacks->callbacks;
e->callbacks->walking_list++;
for (l = *l_mod; l; l = l->next)
{
2011-12-14 21:56:19 -08:00
Evas_Func_Node *fn;
fn = (Evas_Func_Node *)l;
if ((fn->type == type) && (!fn->delete_me))
{
Evas_Event_Cb func = fn->func;
if (func)
func(fn->data, e, event_info);
}
if (e->delete_me) break;
}
e->callbacks->walking_list--;
if (!e->callbacks->walking_list)
{
2011-12-14 21:56:19 -08:00
evas_event_callback_clear(e);
l_mod = NULL;
}
}
_evas_unwalk(e);
}
2002-11-08 00:02:15 -08:00
void
evas_object_event_callback_call(Evas_Object *obj, Evas_Callback_Type type, void *event_info, int event_id)
2002-11-08 00:02:15 -08:00
{
/* MEM OK */
Eina_Inlist **l_mod = NULL, *l;
Evas_Button_Flags flags = EVAS_BUTTON_NONE;
Evas *e;
2005-05-21 19:49:50 -07:00
if ((obj->delete_me) || (!obj->layer)) return;
if ((obj->last_event == 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;
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 > event_id)
{
if ((obj->last_event_type == EVAS_CALLBACK_MOUSE_OUT) &&
((type >= EVAS_CALLBACK_MOUSE_DOWN) &&
(type <= EVAS_CALLBACK_MULTI_MOVE)))
{
return;
}
}
obj->last_event = 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);
if (obj->callbacks)
{
2011-12-14 21:56:19 -08:00
l_mod = &obj->callbacks->callbacks;
switch (type)
{
2011-12-14 21:56:19 -08:00
case EVAS_CALLBACK_MOUSE_DOWN:
{
Evas_Event_Mouse_Down *ev = event_info;
flags = ev->flags;
if (ev->flags & (EVAS_BUTTON_DOUBLE_CLICK | EVAS_BUTTON_TRIPLE_CLICK))
{
if (obj->last_mouse_down_counter < (e->last_mouse_down_counter - 1))
ev->flags &= ~(EVAS_BUTTON_DOUBLE_CLICK | EVAS_BUTTON_TRIPLE_CLICK);
}
obj->last_mouse_down_counter = e->last_mouse_down_counter;
break;
}
case EVAS_CALLBACK_MOUSE_UP:
{
Evas_Event_Mouse_Up *ev = event_info;
flags = ev->flags;
if (ev->flags & (EVAS_BUTTON_DOUBLE_CLICK | EVAS_BUTTON_TRIPLE_CLICK))
{
if (obj->last_mouse_up_counter < (e->last_mouse_up_counter - 1))
ev->flags &= ~(EVAS_BUTTON_DOUBLE_CLICK | EVAS_BUTTON_TRIPLE_CLICK);
}
obj->last_mouse_up_counter = e->last_mouse_up_counter;
break;
}
default:
break;
}
obj->callbacks->walking_list++;
for (l = *l_mod; l; l = l->next)
{
2011-12-14 21:56:19 -08:00
Evas_Func_Node *fn;
fn = (Evas_Func_Node *)l;
if ((fn->type == type) && (!fn->delete_me))
{
Evas_Object_Event_Cb func = fn->func;
if (func)
func(fn->data, obj->layer->evas, obj, event_info);
}
if (obj->delete_me) break;
}
obj->callbacks->walking_list--;
if (!obj->callbacks->walking_list)
2011-12-14 21:56:19 -08:00
{
evas_object_event_callback_clear(obj);
l_mod = NULL;
}
if (type == EVAS_CALLBACK_MOUSE_DOWN)
{
Evas_Event_Mouse_Down *ev = event_info;
ev->flags = flags;
}
else if (type == EVAS_CALLBACK_MOUSE_UP)
{
Evas_Event_Mouse_Up *ev = event_info;
ev->flags = flags;
}
2002-11-08 00:02:15 -08:00
}
if (!((obj->no_propagate) && (l_mod) && (*l_mod)))
{
2011-12-14 21:56:19 -08:00
if (!obj->no_propagate)
{
if ((obj->smart.parent) && (type != EVAS_CALLBACK_FREE) &&
(type <= EVAS_CALLBACK_KEY_UP))
evas_object_event_callback_call(obj->smart.parent, type, event_info, event_id);
2011-12-14 21:56:19 -08:00
}
}
_evas_unwalk(e);
2002-11-08 00:02:15 -08:00
}
static int
_callback_priority_cmp(const void *_a, const void *_b)
{
const Evas_Func_Node *a, *b;
a = EINA_INLIST_CONTAINER_GET(_a, Evas_Func_Node);
b = EINA_INLIST_CONTAINER_GET(_b, Evas_Func_Node);
if (a->priority < b->priority)
2011-12-14 21:56:19 -08:00
return -1;
else
2011-12-14 21:56:19 -08:00
return 1;
}
EAPI void
evas_object_event_callback_add(Evas_Object *obj, Evas_Callback_Type type, Evas_Object_Event_Cb func, const void *data)
{
evas_object_event_callback_priority_add(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 *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
{
/* MEM OK */
2002-11-08 00:02:15 -08:00
Evas_Func_Node *fn;
2005-05-21 19:49:50 -07:00
2002-11-08 00:02:15 -08:00
MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
return;
MAGIC_CHECK_END();
2005-05-21 19:49:50 -07:00
2002-11-08 00:02:15 -08:00
if (!func) return;
2005-05-21 19:49:50 -07:00
if (!obj->callbacks)
{
EVAS_MEMPOOL_INIT(_mp_cb, "evas_callbacks", Evas_Callbacks, 64, );
obj->callbacks = EVAS_MEMPOOL_ALLOC(_mp_cb, Evas_Callbacks);
if (!obj->callbacks) return;
EVAS_MEMPOOL_PREP(_mp_cb, obj->callbacks, Evas_Callbacks);
}
2011-12-14 21:56:19 -08:00
EVAS_MEMPOOL_INIT(_mp_fn, "evas_func_node", Evas_Func_Node, 128, );
fn = EVAS_MEMPOOL_ALLOC(_mp_fn, Evas_Func_Node);
2002-11-08 00:02:15 -08:00
if (!fn) return;
EVAS_MEMPOOL_PREP(_mp_fn, fn, Evas_Func_Node);
2002-11-08 00:02:15 -08:00
fn->func = func;
fn->data = (void *)data;
fn->type = type;
fn->priority = priority;
obj->callbacks->callbacks =
2011-12-14 21:56:19 -08:00
eina_inlist_sorted_insert(obj->callbacks->callbacks, EINA_INLIST_GET(fn),
_callback_priority_cmp);
2002-11-08 00:02:15 -08:00
}
EAPI void *
evas_object_event_callback_del(Evas_Object *obj, Evas_Callback_Type type, Evas_Object_Event_Cb func)
2002-11-08 00:02:15 -08:00
{
/* MEM OK */
Evas_Func_Node *fn;
2005-05-21 19:49:50 -07:00
2002-11-08 00:02:15 -08:00
MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
return NULL;
MAGIC_CHECK_END();
2005-05-21 19:49:50 -07:00
2002-11-08 00:02:15 -08:00
if (!func) return NULL;
2005-05-21 19:49:50 -07:00
if (!obj->callbacks) return NULL;
2005-05-21 19:49:50 -07:00
EINA_INLIST_FOREACH(obj->callbacks->callbacks, fn)
{
2011-12-14 21:56:19 -08:00
if ((fn->func == func) && (fn->type == type) && (!fn->delete_me))
{
void *tmp;
tmp = fn->data;
fn->delete_me = 1;
obj->callbacks->deletions_waiting = 1;
if (!obj->callbacks->walking_list)
evas_object_event_callback_clear(obj);
return tmp;
}
}
2002-11-08 00:02:15 -08:00
return NULL;
}
EAPI void *
evas_object_event_callback_del_full(Evas_Object *obj, Evas_Callback_Type type, Evas_Object_Event_Cb func, const void *data)
{
/* MEM OK */
Evas_Func_Node *fn;
MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
return NULL;
MAGIC_CHECK_END();
if (!func) return NULL;
if (!obj->callbacks) return NULL;
EINA_INLIST_FOREACH(obj->callbacks->callbacks, fn)
{
2011-12-14 21:56:19 -08:00
if ((fn->func == func) && (fn->type == type) && (fn->data == data) && (!fn->delete_me))
{
void *tmp;
tmp = fn->data;
fn->delete_me = 1;
obj->callbacks->deletions_waiting = 1;
if (!obj->callbacks->walking_list)
evas_object_event_callback_clear(obj);
return tmp;
}
}
return NULL;
}
EAPI void
evas_event_callback_add(Evas *e, Evas_Callback_Type type, Evas_Event_Cb func, const void *data)
{
evas_event_callback_priority_add(e, type, EVAS_CALLBACK_PRIORITY_DEFAULT,
2011-12-14 21:56:19 -08:00
func, data);
}
EAPI void
evas_event_callback_priority_add(Evas *e, Evas_Callback_Type type, Evas_Callback_Priority priority, Evas_Event_Cb func, const void *data)
{
/* MEM OK */
Evas_Func_Node *fn;
MAGIC_CHECK(e, Evas, MAGIC_EVAS);
return;
MAGIC_CHECK_END();
if (!func) return;
if (!e->callbacks)
{
EVAS_MEMPOOL_INIT(_mp_cb, "evas_callbacks", Evas_Callbacks, 64, );
e->callbacks = EVAS_MEMPOOL_ALLOC(_mp_cb, Evas_Callbacks);
if (!e->callbacks) return;
EVAS_MEMPOOL_PREP(_mp_cb, e->callbacks, Evas_Callbacks);
}
2011-12-14 21:56:19 -08:00
EVAS_MEMPOOL_INIT(_mp_fn, "evas_func_node", Evas_Func_Node, 128, );
fn = EVAS_MEMPOOL_ALLOC(_mp_fn, Evas_Func_Node);
if (!fn) return;
EVAS_MEMPOOL_PREP(_mp_fn, fn, Evas_Func_Node);
fn->func = func;
fn->data = (void *)data;
fn->type = type;
fn->priority = priority;
e->callbacks->callbacks = eina_inlist_sorted_insert(e->callbacks->callbacks,
2011-12-14 21:56:19 -08:00
EINA_INLIST_GET(fn), _callback_priority_cmp);
}
EAPI void *
evas_event_callback_del(Evas *e, Evas_Callback_Type type, Evas_Event_Cb func)
{
/* MEM OK */
Evas_Func_Node *fn;
MAGIC_CHECK(e, Evas, MAGIC_EVAS);
return NULL;
MAGIC_CHECK_END();
if (!func) return NULL;
if (!e->callbacks) return NULL;
EINA_INLIST_FOREACH(e->callbacks->callbacks, fn)
{
2011-12-14 21:56:19 -08:00
if ((fn->func == func) && (fn->type == type) && (!fn->delete_me))
{
void *data;
data = fn->data;
fn->delete_me = 1;
e->callbacks->deletions_waiting = 1;
if (!e->callbacks->walking_list)
evas_event_callback_clear(e);
return data;
}
}
return NULL;
}
EAPI void *
evas_event_callback_del_full(Evas *e, Evas_Callback_Type type, Evas_Event_Cb func, const void *data)
{
/* MEM OK */
Evas_Func_Node *fn;
MAGIC_CHECK(e, Evas, MAGIC_EVAS);
return NULL;
MAGIC_CHECK_END();
if (!func) return NULL;
if (!e->callbacks) return NULL;
EINA_INLIST_FOREACH(e->callbacks->callbacks, fn)
{
2011-12-14 21:56:19 -08:00
if ((fn->func == func) && (fn->type == type) && (fn->data == data) && (!fn->delete_me))
{
void *tmp;
tmp = fn->data;
fn->delete_me = 1;
e->callbacks->deletions_waiting = 1;
if (!e->callbacks->walking_list)
evas_event_callback_clear(e);
return tmp;
}
}
return NULL;
}
EAPI void
evas_post_event_callback_push(Evas *e, Evas_Object_Event_Post_Cb func, const void *data)
{
Evas_Post_Callback *pc;
2011-12-14 21:56:19 -08:00
MAGIC_CHECK(e, Evas, MAGIC_EVAS);
return;
MAGIC_CHECK_END();
2011-12-14 21:56:19 -08:00
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);
if (e->delete_me) return;
2011-12-14 21:56:19 -08:00
pc->func = func;
pc->data = data;
e->post_events = eina_list_prepend(e->post_events, pc);
}
EAPI void
evas_post_event_callback_remove(Evas *e, Evas_Object_Event_Post_Cb func)
{
Evas_Post_Callback *pc;
Eina_List *l;
2011-12-14 21:56:19 -08:00
MAGIC_CHECK(e, Evas, MAGIC_EVAS);
return;
MAGIC_CHECK_END();
2011-12-14 21:56:19 -08:00
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 *e, Evas_Object_Event_Post_Cb func, const void *data)
{
Evas_Post_Callback *pc;
Eina_List *l;
2011-12-14 21:56:19 -08:00
MAGIC_CHECK(e, Evas, MAGIC_EVAS);
return;
MAGIC_CHECK_END();
2011-12-14 21:56:19 -08:00
EINA_LIST_FOREACH(e->post_events, l, pc)
{
if ((pc->func == func) && (pc->data == data))
{
pc->delete_me = 1;
return;
}
}
}