forked from enlightenment/efl
700 lines
20 KiB
C
700 lines
20 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#define EFL_LOOP_PROTECTED
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <math.h>
|
|
#include <sys/time.h>
|
|
#include <errno.h>
|
|
|
|
#include "Ecore.h"
|
|
#include "ecore_private.h"
|
|
|
|
#include "ecore_main_common.h"
|
|
|
|
typedef struct _Efl_Loop_Promise_Simple_Data Efl_Loop_Promise_Simple_Data;
|
|
typedef struct _Efl_Internal_Promise Efl_Internal_Promise;
|
|
|
|
struct _Efl_Loop_Promise_Simple_Data
|
|
{
|
|
union {
|
|
Efl_Loop_Timer *timer;
|
|
Ecore_Idler *idler;
|
|
};
|
|
Eina_Promise *promise;
|
|
};
|
|
GENERIC_ALLOC_SIZE_DECLARE(Efl_Loop_Promise_Simple_Data);
|
|
|
|
Eo *_mainloop_singleton = NULL;
|
|
Efl_Loop_Data *_mainloop_singleton_data = NULL;
|
|
|
|
ECORE_API Eo *
|
|
efl_main_loop_get(void)
|
|
{
|
|
return efl_app_main_get();
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_loop_iterate(Eo *obj, Efl_Loop_Data *pd)
|
|
{
|
|
_ecore_main_loop_iterate(obj, pd);
|
|
}
|
|
|
|
EOLIAN static int
|
|
_efl_loop_iterate_may_block(Eo *obj, Efl_Loop_Data *pd, int may_block)
|
|
{
|
|
return _ecore_main_loop_iterate_may_block(obj, pd, may_block);
|
|
}
|
|
|
|
EOLIAN static Eina_Value *
|
|
_efl_loop_begin(Eo *obj, Efl_Loop_Data *pd)
|
|
{
|
|
_ecore_main_loop_begin(obj, pd);
|
|
if (pd->thread_children)
|
|
{
|
|
Eina_List *l, *ll;
|
|
Eo *child;
|
|
|
|
// request all child threads to die and defer the quit until
|
|
// the children have all died and returned.
|
|
// run main loop again to clean out children and their exits
|
|
pd->quit_on_last_thread_child_del = EINA_TRUE;
|
|
EINA_LIST_FOREACH_SAFE(pd->thread_children, l, ll, child)
|
|
{
|
|
Efl_Task_Flags task_flags = efl_task_flags_get(child);
|
|
|
|
if (task_flags & EFL_TASK_FLAGS_EXIT_WITH_PARENT)
|
|
efl_task_end(child);
|
|
else
|
|
_efl_thread_child_remove(obj, pd, child);
|
|
}
|
|
if (pd->thread_children) _ecore_main_loop_begin(obj, pd);
|
|
}
|
|
return &(pd->exit_code);
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_loop_quit(Eo *obj, Efl_Loop_Data *pd, Eina_Value exit_code)
|
|
{
|
|
_ecore_main_loop_quit(obj, pd);
|
|
pd->exit_code = exit_code;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_loop_time_set(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd, double t)
|
|
{
|
|
pd->loop_time = t;
|
|
}
|
|
|
|
EOLIAN static double
|
|
_efl_loop_time_get(const Eo *obj EINA_UNUSED, Efl_Loop_Data *pd)
|
|
{
|
|
return pd->loop_time;
|
|
}
|
|
|
|
ECORE_API void
|
|
efl_exit(int exit_code)
|
|
{
|
|
Eina_Value v = EINA_VALUE_EMPTY;
|
|
|
|
eina_value_setup(&v, EINA_VALUE_TYPE_INT);
|
|
eina_value_set(&v, exit_code);
|
|
efl_loop_quit(efl_main_loop_get(), v);
|
|
}
|
|
|
|
ECORE_API int
|
|
efl_loop_exit_code_process(Eina_Value *value)
|
|
{
|
|
Eina_Value def = EINA_VALUE_EMPTY;
|
|
const Eina_Value_Type *t;
|
|
int r = 0;
|
|
|
|
if (value == NULL ||
|
|
!value->type)
|
|
{
|
|
def = eina_value_int_init(0);
|
|
value = &def;
|
|
}
|
|
|
|
t = eina_value_type_get(value);
|
|
|
|
if (t == EINA_VALUE_TYPE_UCHAR ||
|
|
t == EINA_VALUE_TYPE_USHORT ||
|
|
t == EINA_VALUE_TYPE_UINT ||
|
|
t == EINA_VALUE_TYPE_ULONG ||
|
|
t == EINA_VALUE_TYPE_UINT64 ||
|
|
t == EINA_VALUE_TYPE_CHAR ||
|
|
t == EINA_VALUE_TYPE_SHORT ||
|
|
t == EINA_VALUE_TYPE_INT ||
|
|
t == EINA_VALUE_TYPE_LONG ||
|
|
t == EINA_VALUE_TYPE_INT64 ||
|
|
t == EINA_VALUE_TYPE_FLOAT ||
|
|
t == EINA_VALUE_TYPE_DOUBLE)
|
|
{
|
|
Eina_Value v = EINA_VALUE_EMPTY;
|
|
|
|
eina_value_setup(&v, EINA_VALUE_TYPE_INT);
|
|
if (!eina_value_convert(value, &v)) r = -1;
|
|
else eina_value_get(&v, &r);
|
|
}
|
|
else
|
|
{
|
|
FILE *out = stdout;
|
|
char *msg;
|
|
|
|
msg = eina_value_to_string(value);
|
|
|
|
if (t == EINA_VALUE_TYPE_ERROR)
|
|
{
|
|
r = -1;
|
|
out = stderr;
|
|
}
|
|
fprintf(out, "%s\n", msg);
|
|
free(msg);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static void
|
|
_poll_trigger(void *data, const Efl_Event *event)
|
|
{
|
|
Eo *parent = efl_parent_get(event->object);
|
|
|
|
efl_event_callback_call(parent, data, NULL);
|
|
}
|
|
|
|
static void
|
|
_check_event_catcher_add(void *data, const Efl_Event *event)
|
|
{
|
|
const Efl_Callback_Array_Item_Full *array = event->info;
|
|
Efl_Loop_Data *pd = data;
|
|
int i;
|
|
|
|
for (i = 0; array[i].desc != NULL; i++)
|
|
{
|
|
if (array[i].desc == EFL_LOOP_EVENT_IDLE)
|
|
{
|
|
++pd->idlers;
|
|
}
|
|
// XXX: all the below are kind of bad. ecore_pollers were special.
|
|
// they all woke up at the SAME time based on interval, (all pollers
|
|
// of interval 1 woke up together, those with 2 woke up when 1 and
|
|
// 2 woke up, 4 woke up together along with 1 and 2 etc.
|
|
// the below means they will just go off whenever but at a pre
|
|
// defined interval - 1/60th, 6 and 66 seconds. not really great
|
|
// pollers probably should be less frequent that 1/60th even on poll
|
|
// high, medium probably down to 1-2 sec and low - yes maybe 30 or 60
|
|
// sec... still - not timed to wake up together. :(
|
|
else if (array[i].desc == EFL_LOOP_EVENT_POLL_HIGH)
|
|
{
|
|
if (!pd->poll_high)
|
|
{
|
|
// Would be better to have it in sync with normal wake up
|
|
// of the main loop for better energy efficiency, I guess.
|
|
pd->poll_high = efl_add
|
|
(EFL_LOOP_TIMER_CLASS, event->object,
|
|
efl_event_callback_add(efl_added,
|
|
EFL_LOOP_TIMER_EVENT_TIMER_TICK,
|
|
_poll_trigger,
|
|
EFL_LOOP_EVENT_POLL_HIGH),
|
|
efl_loop_timer_interval_set(efl_added, 1.0 / 60.0));
|
|
}
|
|
++pd->pollers.high;
|
|
}
|
|
else if (array[i].desc == EFL_LOOP_EVENT_POLL_MEDIUM)
|
|
{
|
|
if (!pd->poll_medium)
|
|
{
|
|
pd->poll_medium = efl_add
|
|
(EFL_LOOP_TIMER_CLASS, event->object,
|
|
efl_event_callback_add(efl_added,
|
|
EFL_LOOP_TIMER_EVENT_TIMER_TICK,
|
|
_poll_trigger,
|
|
EFL_LOOP_EVENT_POLL_MEDIUM),
|
|
efl_loop_timer_interval_set(efl_added, 6));
|
|
}
|
|
++pd->pollers.medium;
|
|
}
|
|
else if (array[i].desc == EFL_LOOP_EVENT_POLL_LOW)
|
|
{
|
|
if (!pd->poll_low)
|
|
{
|
|
pd->poll_low = efl_add
|
|
(EFL_LOOP_TIMER_CLASS, event->object,
|
|
efl_event_callback_add(efl_added,
|
|
EFL_LOOP_TIMER_EVENT_TIMER_TICK,
|
|
_poll_trigger,
|
|
EFL_LOOP_EVENT_POLL_LOW),
|
|
efl_loop_timer_interval_set(efl_added, 66));
|
|
}
|
|
++pd->pollers.low;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_check_event_catcher_del(void *data, const Efl_Event *event)
|
|
{
|
|
const Efl_Callback_Array_Item_Full *array = event->info;
|
|
Efl_Loop_Data *pd = data;
|
|
int i;
|
|
|
|
for (i = 0; array[i].desc != NULL; i++)
|
|
{
|
|
if (array[i].desc == EFL_LOOP_EVENT_IDLE)
|
|
{
|
|
--pd->idlers;
|
|
}
|
|
else if (array[i].desc == EFL_LOOP_EVENT_POLL_HIGH)
|
|
{
|
|
--pd->pollers.high;
|
|
if (!pd->pollers.high)
|
|
{
|
|
efl_del(pd->poll_high);
|
|
pd->poll_high = NULL;
|
|
}
|
|
}
|
|
else if (array[i].desc == EFL_LOOP_EVENT_POLL_MEDIUM)
|
|
{
|
|
--pd->pollers.medium;
|
|
if (!pd->pollers.medium)
|
|
{
|
|
efl_del(pd->poll_medium);
|
|
pd->poll_medium = NULL;
|
|
}
|
|
}
|
|
else if (array[i].desc == EFL_LOOP_EVENT_POLL_LOW)
|
|
{
|
|
--pd->pollers.low;
|
|
if (!pd->pollers.low)
|
|
{
|
|
efl_del(pd->poll_low);
|
|
pd->poll_low = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
EFL_CALLBACKS_ARRAY_DEFINE(event_catcher_watch,
|
|
{ EFL_EVENT_CALLBACK_ADD, _check_event_catcher_add },
|
|
{ EFL_EVENT_CALLBACK_DEL, _check_event_catcher_del });
|
|
|
|
EOLIAN static Efl_Object *
|
|
_efl_loop_efl_object_constructor(Eo *obj, Efl_Loop_Data *pd)
|
|
{
|
|
obj = efl_constructor(efl_super(obj, EFL_LOOP_CLASS));
|
|
if (!obj) return NULL;
|
|
|
|
efl_event_callback_array_add(obj, event_catcher_watch(), pd);
|
|
|
|
pd->loop_time = ecore_time_get();
|
|
pd->epoll_fd = -1;
|
|
pd->timer_fd = -1;
|
|
pd->future_message_handler = efl_add(EFL_LOOP_MESSAGE_FUTURE_HANDLER_CLASS, obj);
|
|
efl_provider_register(obj, EFL_LOOP_MESSAGE_FUTURE_HANDLER_CLASS, pd->future_message_handler);
|
|
|
|
return obj;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_loop_efl_object_invalidate(Eo *obj, Efl_Loop_Data *pd)
|
|
{
|
|
efl_invalidate(efl_super(obj, EFL_LOOP_CLASS));
|
|
|
|
_ecore_main_content_clear(obj, pd);
|
|
|
|
pd->poll_low = NULL;
|
|
pd->poll_medium = NULL;
|
|
pd->poll_high = NULL;
|
|
|
|
// After invalidate, it won't be possible to parent to the singleton anymore
|
|
if (obj == _mainloop_singleton)
|
|
{
|
|
_mainloop_singleton = NULL;
|
|
_mainloop_singleton_data = NULL;
|
|
}
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_loop_efl_object_destructor(Eo *obj, Efl_Loop_Data *pd)
|
|
{
|
|
pd->future_message_handler = NULL;
|
|
while (pd->thread_children)
|
|
_efl_thread_child_remove(obj, pd, pd->thread_children->data);
|
|
efl_destructor(efl_super(obj, EFL_LOOP_CLASS));
|
|
}
|
|
|
|
static Eina_Value
|
|
_efl_loop_arguments_send(Eo *o EINA_UNUSED, void *data, const Eina_Value v)
|
|
|
|
{
|
|
static Eina_Bool initialization = EINA_TRUE;
|
|
Efl_Loop_Arguments arge;
|
|
Eina_Array *arga = data;
|
|
|
|
arge.argv = arga;
|
|
arge.initialization = initialization;
|
|
initialization = EINA_FALSE;
|
|
|
|
efl_event_callback_call(efl_main_loop_get(),
|
|
EFL_LOOP_EVENT_ARGUMENTS, &arge);
|
|
return v;
|
|
}
|
|
|
|
static void
|
|
_efl_loop_arguments_cleanup(Eo *o EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED)
|
|
{
|
|
Eina_Array *arga = data;
|
|
Eina_Stringshare *s;
|
|
|
|
while ((s = eina_array_pop(arga))) eina_stringshare_del(s);
|
|
eina_array_free(arga);
|
|
}
|
|
|
|
// It doesn't make sense to send those argument to any other mainloop
|
|
// As it also doesn't make sense to allow anyone to override this, so
|
|
// should be internal for sure, not even protected.
|
|
ECORE_API void
|
|
ecore_loop_arguments_send(int argc, const char **argv)
|
|
{
|
|
Eina_Array *arga, *cml;
|
|
int i = 0;
|
|
|
|
arga = eina_array_new(argc);
|
|
cml = eina_array_new(argc);
|
|
for (i = 0; i < argc; i++)
|
|
{
|
|
Eina_Stringshare *arg;
|
|
|
|
arg = eina_stringshare_add(argv[i]);
|
|
eina_array_push(arga, arg);
|
|
arg = eina_stringshare_add(argv[i]);
|
|
eina_array_push(cml, arg);
|
|
}
|
|
|
|
efl_core_command_line_command_array_set(efl_app_main_get(), cml);
|
|
efl_future_then(efl_main_loop_get(), efl_loop_job(efl_main_loop_get()),
|
|
.success = _efl_loop_arguments_send,
|
|
.free = _efl_loop_arguments_cleanup,
|
|
.data = arga);
|
|
}
|
|
|
|
static Eina_Future *
|
|
_efl_loop_job(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
|
|
{
|
|
// NOTE: Eolian should do efl_future_then() to bind future to object.
|
|
return efl_future_then(obj,
|
|
eina_future_resolved(efl_loop_future_scheduler_get(obj), EINA_VALUE_EMPTY));
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_loop_throttle_set(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd, double amount)
|
|
{
|
|
pd->throttle = ((double)amount) * 1000000.0;
|
|
}
|
|
|
|
EOLIAN static double
|
|
_efl_loop_throttle_get(const Eo *obj EINA_UNUSED, Efl_Loop_Data *pd)
|
|
{
|
|
return (double)(pd->throttle) / 1000000.0;
|
|
}
|
|
|
|
static void
|
|
_efl_loop_idle_cancel(void *data, const Eina_Promise *dead_ptr EINA_UNUSED)
|
|
{
|
|
Efl_Loop_Promise_Simple_Data *d = data;
|
|
|
|
ecore_idler_del(d->idler);
|
|
d->idler = NULL;
|
|
d->promise = NULL;
|
|
efl_loop_promise_simple_data_mp_free(d);
|
|
}
|
|
|
|
static Eina_Bool
|
|
_efl_loop_idle_done(void *data)
|
|
{
|
|
Efl_Loop_Promise_Simple_Data *d = data;
|
|
eina_promise_resolve(d->promise, EINA_VALUE_EMPTY);
|
|
d->idler = NULL;
|
|
d->promise = NULL;
|
|
efl_loop_promise_simple_data_mp_free(d);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
static Eina_Future *
|
|
_efl_loop_idle(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
|
|
{
|
|
Efl_Loop_Promise_Simple_Data *d;
|
|
Eina_Promise *p;
|
|
Eina_Future_Scheduler *sched = efl_loop_future_scheduler_get(obj);
|
|
|
|
d = efl_loop_promise_simple_data_calloc(1);
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(d, NULL);
|
|
|
|
d->idler = ecore_idler_add(_efl_loop_idle_done, d);
|
|
EINA_SAFETY_ON_NULL_GOTO(d->idler, idler_error);
|
|
|
|
p = eina_promise_new(sched, _efl_loop_idle_cancel, d);
|
|
// d is dead if p is NULL
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(p, NULL);
|
|
d->promise = p;
|
|
|
|
// NOTE: Eolian should do efl_future_then() to bind future to object.
|
|
return efl_future_then(obj, eina_future_new(p));
|
|
|
|
idler_error:
|
|
d->idler = NULL;
|
|
d->promise = NULL;
|
|
efl_loop_promise_simple_data_mp_free(d);
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
_efl_loop_timeout_cancel(void *data, const Eina_Promise *dead_ptr EINA_UNUSED)
|
|
{
|
|
Efl_Loop_Promise_Simple_Data *d = data;
|
|
|
|
if (d->timer)
|
|
efl_del(d->timer);
|
|
}
|
|
|
|
static void
|
|
_efl_loop_timeout_done(void *data, const Efl_Event *event)
|
|
{
|
|
Efl_Loop_Promise_Simple_Data *d = data;
|
|
|
|
eina_promise_resolve(d->promise, EINA_VALUE_EMPTY);
|
|
d->timer = NULL;
|
|
efl_del(event->object);
|
|
}
|
|
|
|
static void
|
|
_efl_loop_timeout_del(void *data, const Efl_Event *event EINA_UNUSED)
|
|
{
|
|
Efl_Loop_Promise_Simple_Data *d = data;
|
|
|
|
d->timer = NULL;
|
|
d->promise = NULL;
|
|
efl_loop_promise_simple_data_mp_free(d);
|
|
}
|
|
|
|
static Eina_Future *
|
|
_efl_loop_timeout(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED, double tim)
|
|
{
|
|
Efl_Loop_Promise_Simple_Data *d;
|
|
Eina_Promise *p;
|
|
Eina_Future_Scheduler *sched = efl_loop_future_scheduler_get(obj);
|
|
|
|
d = efl_loop_promise_simple_data_calloc(1);
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(d, NULL);
|
|
|
|
d->timer = efl_add(EFL_LOOP_TIMER_CLASS, obj,
|
|
efl_loop_timer_interval_set(efl_added, tim),
|
|
efl_event_callback_add(efl_added,
|
|
EFL_LOOP_TIMER_EVENT_TIMER_TICK,
|
|
_efl_loop_timeout_done, d),
|
|
efl_event_callback_add(efl_added,
|
|
EFL_EVENT_DEL,
|
|
_efl_loop_timeout_del, d)
|
|
);
|
|
EINA_SAFETY_ON_NULL_GOTO(d->timer, timer_error);
|
|
|
|
p = eina_promise_new(sched, _efl_loop_timeout_cancel, d);
|
|
// d is dead if p is NULL
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(p, NULL);
|
|
d->promise = p;
|
|
|
|
// NOTE: Eolian should do efl_future_then() to bind future to object.
|
|
return efl_future_then(obj, eina_future_new(p));
|
|
|
|
timer_error:
|
|
d->timer = NULL;
|
|
d->promise = NULL;
|
|
efl_loop_promise_simple_data_mp_free(d);
|
|
return NULL;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_efl_loop_register(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED,
|
|
const Efl_Class *klass, const Efl_Object *provider)
|
|
{
|
|
return efl_provider_register(obj, klass, provider);
|
|
}
|
|
|
|
EFL_FUNC_BODYV(efl_loop_register, Eina_Bool, EINA_FALSE, EFL_FUNC_CALL(klass, provider), const Efl_Class *klass, const Efl_Object *provider);
|
|
|
|
static Eina_Bool
|
|
_efl_loop_unregister(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED,
|
|
const Efl_Class *klass, const Efl_Object *provider)
|
|
{
|
|
return efl_provider_unregister(obj, klass, provider);
|
|
}
|
|
|
|
EFL_FUNC_BODYV(efl_loop_unregister, Eina_Bool, EINA_FALSE, EFL_FUNC_CALL(klass, provider), const Efl_Class *klass, const Efl_Object *provider);
|
|
|
|
void
|
|
_efl_loop_messages_filter(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd, void *handler_pd)
|
|
{
|
|
Message *msg;
|
|
|
|
pd->message_walking++;
|
|
EINA_INLIST_FOREACH(pd->message_queue, msg)
|
|
{
|
|
if ((msg->handler) && (msg->message) && (!msg->delete_me))
|
|
{
|
|
if (!_ecore_event_do_filter(handler_pd,
|
|
msg->handler, msg->message))
|
|
{
|
|
efl_del(msg->message);
|
|
msg->handler = NULL;
|
|
msg->message = NULL;
|
|
msg->delete_me = EINA_TRUE;
|
|
}
|
|
}
|
|
}
|
|
pd->message_walking--;
|
|
}
|
|
|
|
void
|
|
_efl_loop_messages_call(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd, void *func, void *data)
|
|
{
|
|
Message *msg;
|
|
|
|
pd->message_walking++;
|
|
EINA_INLIST_FOREACH(pd->message_queue, msg)
|
|
{
|
|
if ((msg->handler) && (msg->message) && (!msg->delete_me))
|
|
{
|
|
Eina_Bool (*fn) (void *data, void *handler, void *msg);
|
|
|
|
fn = func;
|
|
if (!fn(data, msg->handler, msg->message))
|
|
{
|
|
efl_del(msg->message);
|
|
msg->handler = NULL;
|
|
msg->message = NULL;
|
|
msg->delete_me = EINA_TRUE;
|
|
}
|
|
}
|
|
}
|
|
pd->message_walking--;
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_efl_loop_message_process(Eo *obj, Efl_Loop_Data *pd)
|
|
{
|
|
if (!pd->message_queue) return EINA_FALSE;
|
|
pd->message_walking++;
|
|
_ecore_event_filters_call(obj, pd);
|
|
while (pd->message_queue)
|
|
{
|
|
Message *msg = (Message *)pd->message_queue;
|
|
if (!msg->delete_me)
|
|
efl_loop_message_handler_message_call(msg->handler, msg->message);
|
|
else
|
|
{
|
|
if (msg->message) efl_del(msg->message);
|
|
pd->message_queue =
|
|
eina_inlist_remove(pd->message_queue,
|
|
pd->message_queue);
|
|
free(msg);
|
|
}
|
|
}
|
|
pd->message_walking--;
|
|
if (pd->message_walking == 0)
|
|
{
|
|
Message *msg;
|
|
|
|
EINA_INLIST_FREE(pd->message_queue, msg)
|
|
{
|
|
if (msg->message)
|
|
{
|
|
if (!msg->delete_me)
|
|
ERR("Found unprocessed event msg=%p handler=%p on queue",
|
|
msg->message, msg->handler);
|
|
efl_del(msg->message);
|
|
}
|
|
else free(msg);
|
|
}
|
|
|
|
while (pd->message_pending_queue)
|
|
{
|
|
msg = (Message *)pd->message_pending_queue;
|
|
pd->message_pending_queue = eina_inlist_remove(pd->message_pending_queue,
|
|
pd->message_pending_queue);
|
|
pd->message_queue = eina_inlist_append(pd->message_queue, EINA_INLIST_GET(msg));
|
|
}
|
|
}
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
ECORE_API ECORE_API_WEAK EFL_FUNC_BODY(efl_loop_message_process, Eina_Bool, 0);
|
|
|
|
ECORE_API ECORE_API_WEAK void
|
|
efl_build_version_set(int vmaj, int vmin, int vmic, int revision,
|
|
const char *flavor, const char *build_id)
|
|
{
|
|
// note: EFL has not been initialized yet at this point (ie. no eina call)
|
|
_app_efl_version.major = vmaj;
|
|
_app_efl_version.minor = vmin;
|
|
_app_efl_version.micro = vmic;
|
|
_app_efl_version.revision = revision;
|
|
free((char *)_app_efl_version.flavor);
|
|
free((char *)_app_efl_version.build_id);
|
|
_app_efl_version.flavor = flavor ? strdup(flavor) : NULL;
|
|
_app_efl_version.build_id = build_id ? strdup(build_id) : NULL;
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_efl_loop_efl_task_run(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
|
|
{
|
|
efl_loop_exit_code_process(efl_loop_begin(obj));
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_loop_efl_task_end(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
|
|
{
|
|
efl_loop_quit(obj, eina_value_int_init(0));
|
|
}
|
|
|
|
EFL_SCHEDULER_ARRAY_DEFINE(loop_scheduler,
|
|
EFL_LOOP_EVENT_IDLE_ENTER,
|
|
EFL_LOOP_EVENT_IDLE);
|
|
|
|
ECORE_API Eina_Future_Scheduler *
|
|
efl_loop_future_scheduler_get(const Eo *obj)
|
|
{
|
|
Efl_Loop *loop;
|
|
|
|
if (!obj) return NULL;
|
|
|
|
if (efl_isa(obj, EFL_LOOP_CLASS))
|
|
{
|
|
Efl_Loop_Data *pd = efl_data_scope_get(obj, EFL_LOOP_CLASS);
|
|
|
|
if (!pd) return NULL;
|
|
return efl_event_future_scheduler_get(obj, loop_scheduler());
|
|
}
|
|
if (efl_isa(obj, EFL_LOOP_CONSUMER_CLASS))
|
|
return efl_loop_future_scheduler_get(efl_loop_get(obj));
|
|
|
|
loop = efl_provider_find(obj, EFL_LOOP_CLASS);
|
|
if (loop)
|
|
return efl_loop_future_scheduler_get(loop);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#define EFL_LOOP_EXTRA_OPS \
|
|
EFL_OBJECT_OP_FUNC(efl_loop_message_process, _efl_loop_message_process), \
|
|
EFL_OBJECT_OP_FUNC(efl_loop_register, _efl_loop_register), \
|
|
EFL_OBJECT_OP_FUNC(efl_loop_unregister, _efl_loop_unregister)
|
|
|
|
#include "efl_loop.eo.c"
|