forked from enlightenment/efl
440 lines
12 KiB
C
440 lines
12 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <Ecore.h>
|
|
|
|
#include "ecore_private.h"
|
|
|
|
#define MY_CLASS ECORE_EVENT_MESSAGE_HANDLER_CLASS
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef struct _Handler Handler;
|
|
typedef struct _Filter Filter;
|
|
|
|
struct _Handler
|
|
{
|
|
EINA_INLIST;
|
|
Ecore_Event_Handler_Cb func;
|
|
void *data;
|
|
int type;
|
|
Eina_Bool delete_me : 1;
|
|
Eina_Bool to_add : 1;
|
|
Eina_Bool prepend : 1;
|
|
};
|
|
|
|
struct _Filter
|
|
{
|
|
EINA_INLIST;
|
|
Ecore_Data_Cb func_start;
|
|
Ecore_Filter_Cb func_filter;
|
|
Ecore_End_Cb func_end;
|
|
void *data;
|
|
void *loop_data;
|
|
Eina_Bool delete_me : 1;
|
|
};
|
|
|
|
typedef struct _Ecore_Event_Message_Handler_Data Ecore_Event_Message_Handler_Data;
|
|
|
|
struct _Ecore_Event_Message_Handler_Data
|
|
{
|
|
int event_type_count;
|
|
Eina_Inlist **handlers; // array of event_type_count inlists of handlers
|
|
Eina_Inlist *filters;
|
|
Eina_List *handlers_delete;
|
|
Eina_List *handlers_add;
|
|
Eina_List *filters_delete;
|
|
Eina_List *filters_add;
|
|
void *current_event_data;
|
|
int current_event_type;
|
|
int handlers_walking;
|
|
int filters_walking;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
Eina_Bool
|
|
_ecore_event_do_filter(void *handler_pd, Eo *msg_handler, Eo *msg)
|
|
{
|
|
Filter *f;
|
|
void *ev;
|
|
int type;
|
|
Ecore_Event_Message_Handler_Data *eemhd = handler_pd;
|
|
|
|
if (!eemhd->filters) return EINA_TRUE;
|
|
if (!efl_isa(msg_handler, MY_CLASS)) return EINA_TRUE;
|
|
eemhd->filters_walking++;
|
|
EINA_INLIST_FOREACH(eemhd->filters, f)
|
|
{
|
|
if (f->delete_me) continue;
|
|
type = -1;
|
|
ev = NULL;
|
|
ecore_event_message_data_get(msg, &type, &ev, NULL, NULL);
|
|
if (type >= 0)
|
|
{
|
|
if (!f->func_filter(f->data, f->loop_data, type, ev))
|
|
_efl_loop_message_unsend(msg);
|
|
}
|
|
}
|
|
eemhd->filters_walking--;
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
void
|
|
_ecore_event_filters_call(Eo *obj, Efl_Loop_Data *pd)
|
|
{
|
|
Filter *f;
|
|
Ecore_Event_Message_Handler_Data *eemhd;
|
|
Eo *ecore_event_handler = efl_provider_find(obj, ECORE_EVENT_MESSAGE_HANDLER_CLASS);
|
|
/* If this is not != NULL, then _ecore_event_init was not called yet, which means,
|
|
there cannot be any registered events yet
|
|
*/
|
|
if (!ecore_event_handler) return;
|
|
|
|
eemhd = efl_data_scope_get(ecore_event_handler, MY_CLASS);
|
|
if (!eemhd) return;
|
|
if (!eemhd->filters) return;
|
|
eemhd->filters_walking++;
|
|
EINA_INLIST_FOREACH(eemhd->filters, f)
|
|
{
|
|
if (f->delete_me) continue;
|
|
if (f->func_start) f->loop_data = f->func_start(f->data);
|
|
}
|
|
_efl_loop_messages_filter(obj, pd, eemhd);
|
|
EINA_INLIST_FOREACH(eemhd->filters, f)
|
|
{
|
|
if (f->delete_me) continue;
|
|
if (f->func_end) f->func_end(f->data, f->loop_data);
|
|
}
|
|
eemhd->filters_walking--;
|
|
if (eemhd->filters_walking == 0)
|
|
{
|
|
EINA_LIST_FREE(eemhd->filters_delete, f)
|
|
{
|
|
free(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
EOLIAN static Ecore_Event_Message *
|
|
_ecore_event_message_handler_message_type_add(Eo *obj, Ecore_Event_Message_Handler_Data *pd EINA_UNUSED)
|
|
{
|
|
// XXX: implemented event obj cache
|
|
return efl_add(ECORE_EVENT_MESSAGE_CLASS, obj);
|
|
}
|
|
|
|
EOLIAN static int
|
|
_ecore_event_message_handler_type_new(Eo *obj EINA_UNUSED, Ecore_Event_Message_Handler_Data *pd)
|
|
{
|
|
Eina_Inlist **tmp;
|
|
int evnum;
|
|
|
|
evnum = pd->event_type_count + 1;
|
|
tmp = realloc(pd->handlers, sizeof(Eina_Inlist *) * (evnum + 1));
|
|
if (!tmp) return 0;
|
|
pd->handlers = tmp;
|
|
pd->handlers[ECORE_EVENT_NONE] = NULL;
|
|
pd->handlers[evnum] = NULL;
|
|
pd->event_type_count = evnum;
|
|
return evnum;
|
|
}
|
|
|
|
EOLIAN static void *
|
|
_ecore_event_message_handler_handler_add(Eo *obj EINA_UNUSED, Ecore_Event_Message_Handler_Data *pd, int type, void *func, void *data)
|
|
{
|
|
Handler *h;
|
|
|
|
EINA_SAFETY_ON_TRUE_RETURN_VAL((type <= 0) || (type > pd->event_type_count) || (!func), NULL);
|
|
h = calloc(1, sizeof(Handler));
|
|
if (!h) return NULL;
|
|
h->func = func;
|
|
h->data = data;
|
|
h->type = type;
|
|
if (pd->current_event_type == type)
|
|
{
|
|
h->to_add = EINA_TRUE;
|
|
pd->handlers_add = eina_list_append(pd->handlers_add, h);
|
|
}
|
|
else
|
|
pd->handlers[type] = eina_inlist_append(pd->handlers[type],
|
|
EINA_INLIST_GET(h));
|
|
return h;
|
|
}
|
|
|
|
EOLIAN static void *
|
|
_ecore_event_message_handler_handler_prepend(Eo *obj EINA_UNUSED, Ecore_Event_Message_Handler_Data *pd, int type, void *func, void *data)
|
|
{
|
|
Handler *h;
|
|
|
|
if ((type < 0) || (type > pd->event_type_count) || (!func)) return NULL;
|
|
h = calloc(1, sizeof(Handler));
|
|
if (!h) return NULL;
|
|
h->func = func;
|
|
h->data = data;
|
|
h->type = type;
|
|
if (pd->current_event_type == type)
|
|
{
|
|
h->to_add = EINA_TRUE;
|
|
h->prepend = EINA_TRUE;
|
|
pd->handlers_add = eina_list_append(pd->handlers_add, h);
|
|
}
|
|
else
|
|
pd->handlers[type] = eina_inlist_prepend(pd->handlers[type],
|
|
EINA_INLIST_GET(h));
|
|
return h;
|
|
}
|
|
|
|
EOLIAN static void *
|
|
_ecore_event_message_handler_handler_del(Eo *obj EINA_UNUSED, Ecore_Event_Message_Handler_Data *pd, void *handler)
|
|
{
|
|
Handler *h = handler;
|
|
void *data;
|
|
|
|
if (!h) return NULL;
|
|
if ((h->type < 0) || (h->type > pd->event_type_count)) return NULL;
|
|
data = h->data;
|
|
if (pd->handlers_walking > 0)
|
|
{
|
|
if (h->to_add)
|
|
{
|
|
h->to_add = EINA_FALSE;
|
|
pd->handlers_add = eina_list_remove(pd->handlers_add, h);
|
|
}
|
|
|
|
h->delete_me = EINA_TRUE;
|
|
pd->handlers_delete = eina_list_append(pd->handlers_delete, h);
|
|
}
|
|
else
|
|
{
|
|
if (h->to_add)
|
|
pd->handlers_add = eina_list_remove(pd->handlers_add, h);
|
|
else
|
|
pd->handlers[h->type] = eina_inlist_remove(pd->handlers[h->type],
|
|
EINA_INLIST_GET(h));
|
|
free(h);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
EOLIAN static void *
|
|
_ecore_event_message_handler_handler_data_get(Eo *obj EINA_UNUSED, Ecore_Event_Message_Handler_Data *pd EINA_UNUSED, void *handler)
|
|
{
|
|
Handler *h = handler;
|
|
|
|
if (!h) return NULL;
|
|
return h->data;
|
|
}
|
|
|
|
EOLIAN static void *
|
|
_ecore_event_message_handler_handler_data_set(Eo *obj EINA_UNUSED, Ecore_Event_Message_Handler_Data *pd EINA_UNUSED, void *handler, void *data)
|
|
{
|
|
Handler *h = handler;
|
|
void *prev_data;
|
|
|
|
if (!h) return NULL;
|
|
prev_data = h->data;
|
|
h->data = data;
|
|
return prev_data;
|
|
}
|
|
|
|
EOLIAN static void *
|
|
_ecore_event_message_handler_filter_add(Eo *obj EINA_UNUSED, Ecore_Event_Message_Handler_Data *pd, void *func_start, void *func_filter, void *func_end, void *data)
|
|
{
|
|
Filter *f;
|
|
|
|
if (!func_filter) return NULL;
|
|
f = calloc(1, sizeof(Filter));
|
|
if (!f) return NULL;
|
|
f->func_start = func_start;
|
|
f->func_filter = func_filter;
|
|
f->func_end = func_end;
|
|
f->data = data;
|
|
pd->filters = eina_inlist_append(pd->filters, EINA_INLIST_GET(f));
|
|
return f;
|
|
}
|
|
|
|
EOLIAN static void *
|
|
_ecore_event_message_handler_filter_del(Eo *obj EINA_UNUSED, Ecore_Event_Message_Handler_Data *pd, void *filter)
|
|
{
|
|
Filter *f = filter;
|
|
void *data;
|
|
|
|
if (!f) return NULL;
|
|
data = f->data;
|
|
if (pd->filters_walking > 0)
|
|
{
|
|
f->delete_me = EINA_TRUE;
|
|
pd->filters_delete = eina_list_append(pd->filters_delete, f);
|
|
}
|
|
else
|
|
{
|
|
pd->filters = eina_inlist_remove(pd->filters, EINA_INLIST_GET(f));
|
|
free(f);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
EOLIAN static int
|
|
_ecore_event_message_handler_current_type_get(Eo *obj EINA_UNUSED, Ecore_Event_Message_Handler_Data *pd)
|
|
{
|
|
return pd->current_event_type;
|
|
}
|
|
|
|
EOLIAN static void *
|
|
_ecore_event_message_handler_current_event_get(Eo *obj EINA_UNUSED, Ecore_Event_Message_Handler_Data *pd)
|
|
{
|
|
return pd->current_event_data;
|
|
}
|
|
|
|
EOLIAN static Efl_Object *
|
|
_ecore_event_message_handler_efl_object_constructor(Eo *obj, Ecore_Event_Message_Handler_Data *pd)
|
|
{
|
|
obj = efl_constructor(efl_super(obj, MY_CLASS));
|
|
pd->event_type_count = 0;
|
|
pd->current_event_type = -1;
|
|
return obj;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_ecore_event_message_handler_efl_object_destructor(Eo *obj, Ecore_Event_Message_Handler_Data *pd)
|
|
{
|
|
Handler *h;
|
|
int i;
|
|
|
|
if (pd->handlers_walking == 0)
|
|
{
|
|
EINA_LIST_FREE(pd->handlers_delete, h)
|
|
{
|
|
pd->handlers[h->type] =
|
|
eina_inlist_remove(pd->handlers[h->type],
|
|
EINA_INLIST_GET(h));
|
|
free(h);
|
|
}
|
|
EINA_LIST_FREE(pd->handlers_add, h)
|
|
{
|
|
free(h);
|
|
}
|
|
for (i = 1; i <= pd->event_type_count; i++)
|
|
{
|
|
EINA_INLIST_FREE(pd->handlers[i], h)
|
|
{
|
|
pd->handlers[i] = eina_inlist_remove(pd->handlers[i],
|
|
EINA_INLIST_GET(h));
|
|
free(h);
|
|
}
|
|
}
|
|
free(pd->handlers);
|
|
pd->handlers = NULL;
|
|
}
|
|
else
|
|
{
|
|
ERR("Destruction of ecore_event_message_handler while walking events");
|
|
}
|
|
efl_destructor(efl_super(obj, MY_CLASS));
|
|
}
|
|
|
|
EOLIAN static void
|
|
_ecore_event_message_handler_efl_loop_message_handler_message_call(Eo *obj, Ecore_Event_Message_Handler_Data *pd, Efl_Loop_Message *message)
|
|
{
|
|
Handler *h;
|
|
int type = -1;
|
|
void *data = NULL, *free_func = NULL, *free_data = NULL;
|
|
Ecore_End_Cb fn_free = NULL;
|
|
Eina_List *l, *l2;
|
|
int handled = 0;
|
|
|
|
// call legacy handlers which are controled by this class' custom api
|
|
ecore_event_message_data_steal
|
|
(message, &type, &data, &free_func, &free_data);
|
|
if ((type >= 0) && (type <= pd->event_type_count))
|
|
{
|
|
if (free_func) fn_free = free_func;
|
|
pd->current_event_data = data;
|
|
pd->current_event_type = type;
|
|
pd->handlers_walking++;
|
|
EINA_INLIST_FOREACH(pd->handlers[type], h)
|
|
{
|
|
if (h->delete_me) continue;
|
|
handled++;
|
|
if (!h->func(h->data, h->type, data)) break;
|
|
}
|
|
pd->handlers_walking--;
|
|
pd->current_event_data = NULL;
|
|
pd->current_event_type = -1;
|
|
EINA_LIST_FOREACH_SAFE(pd->handlers_add, l, l2, h)
|
|
{
|
|
if (h->type == type)
|
|
{
|
|
h->to_add = EINA_FALSE;
|
|
pd->handlers_add =
|
|
eina_list_remove_list(pd->handlers_add, l);
|
|
if (h->prepend)
|
|
pd->handlers[type] =
|
|
eina_inlist_prepend(pd->handlers[type], EINA_INLIST_GET(h));
|
|
else
|
|
pd->handlers[type] =
|
|
eina_inlist_append(pd->handlers[type], EINA_INLIST_GET(h));
|
|
}
|
|
}
|
|
if (pd->handlers_walking == 0)
|
|
{
|
|
EINA_LIST_FREE(pd->handlers_delete, h)
|
|
{
|
|
if (h->to_add)
|
|
pd->handlers_add = eina_list_remove(pd->handlers_add, h);
|
|
else
|
|
pd->handlers[h->type] =
|
|
eina_inlist_remove(pd->handlers[h->type],
|
|
EINA_INLIST_GET(h));
|
|
free(h);
|
|
}
|
|
}
|
|
if ((type == ECORE_EVENT_SIGNAL_EXIT) && (handled == 0))
|
|
{
|
|
Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
|
|
if (loop) efl_loop_quit(loop, eina_value_int_init(0));
|
|
}
|
|
}
|
|
|
|
efl_event_callback_call
|
|
(obj, ECORE_EVENT_MESSAGE_HANDLER_EVENT_MESSAGE_ECORE_EVENT, message);
|
|
efl_loop_message_handler_message_call
|
|
(efl_super(obj, MY_CLASS), message);
|
|
|
|
if (data)
|
|
{
|
|
if (fn_free) fn_free(free_data, data);
|
|
else free(data);
|
|
}
|
|
}
|
|
|
|
static Eina_Bool
|
|
_flush_cb(void *data, void *handler EINA_UNUSED, void *message)
|
|
{
|
|
int *type = data;
|
|
int evtype = -1;
|
|
|
|
if (!efl_isa(message, ECORE_EVENT_MESSAGE_CLASS)) return EINA_TRUE;
|
|
ecore_event_message_data_get(message, &evtype, NULL, NULL, NULL);
|
|
return *type != evtype;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_ecore_event_message_handler_type_flush(Eo *obj, Ecore_Event_Message_Handler_Data *pd EINA_UNUSED, int type)
|
|
{
|
|
Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
|
|
Efl_Loop_Data *loop_data = efl_data_scope_get(loop, EFL_LOOP_CLASS);
|
|
|
|
if (loop && loop_data)
|
|
{
|
|
_efl_loop_messages_call(loop, loop_data, _flush_cb, &type);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "ecore_event_message_handler.eo.c"
|