efl/legacy/ecore/src/lib/ecore/ecore_timer.c

241 lines
5.8 KiB
C

#include "ecore_private.h"
#include "Ecore.h"
static void _ecore_timer_set(Ecore_Timer *timer, double at, double in, int (*func) (void *data), void *data);
static int timers_added = 0;
static int timers_delete_me = 0;
static Ecore_Timer *timers = NULL;
static double last_check = 0.0;
/**
* @defgroup Ecore_Time_Group Ecore Time Functions
*
* Functions that deal with time. These functions include those that simply
* retrieve it in a given format, and those that create events based on it.
*/
/**
* Creates a timer to call the given function in the given period of time.
* @param in The interval in seconds.
* @param func The given function. If @p func returns 1, the timer is
* rescheduled for the next interval @p in.
* @param data Data to pass to @p func when it is called.
* @return A timer object on success. @c NULL on failure.
* @ingroup Ecore_Time_Group
*
* This function adds a timer and returns its handle on success and NULL on
* failure. The function @p func will be called every @in@ seconds. The
* function will be passed the @p data pointer as its parameter.
*
* When the timer @p func is called, it must return a value of either 1 or 0.
* If it returns 1, it will be called again at the next tick, or if it returns
* 0 it will be deleted automatically making any references/handles for it
* invalid.
*/
EAPI Ecore_Timer *
ecore_timer_add(double in, int (*func) (void *data), const void *data)
{
double now;
Ecore_Timer *timer;
if (!func) return NULL;
if (in < 0.0) in = 0.0;
timer = calloc(1, sizeof(Ecore_Timer));
if (!timer) return NULL;
ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER);
now = ecore_time_get();
_ecore_timer_set(timer, now + in, in, func, (void *)data);
return timer;
}
/**
* Delete the specified timer from the timer list.
* @param timer The timer to delete.
* @return The data pointer set for the timer when @ref ecore_timer_add was
* called. @c NULL is returned if the function is unsuccessful.
* @ingroup Ecore_Time_Group
*
* Note: @p timer must be a valid handle. If the timer function has already
* returned 0, the handle is no longer valid (and does not need to be delete).
*/
EAPI void *
ecore_timer_del(Ecore_Timer *timer)
{
if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
{
ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
"ecore_timer_del");
return NULL;
}
if (timer->delete_me) return timer->data;
timers_delete_me++;
timer->delete_me = 1;
return timer->data;
}
/**
* Change the interval the timer ticks of. If set during
* a timer call, this will affect the next interval.
*
* @param timer The timer to change.
* @param in The interval in seconds.
* @ingroup Ecore_Time_Group
*/
EAPI void
ecore_timer_interval_set(Ecore_Timer *timer, double in)
{
if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
{
ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
"ecore_timer_interval_set");
return;
}
timer->in = in;
}
void
_ecore_timer_shutdown(void)
{
while (timers)
{
Ecore_Timer *timer;
timer = timers;
timers = _ecore_list2_remove(timers, timer);
ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
free(timer);
}
}
void
_ecore_timer_cleanup(void)
{
Ecore_List2 *l;
if (!timers_delete_me) return;
for (l = (Ecore_List2 *)timers; l;)
{
Ecore_Timer *timer;
timer = (Ecore_Timer *)l;
l = l->next;
if (timer->delete_me)
{
timers = _ecore_list2_remove(timers, timer);
ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
free(timer);
timers_delete_me--;
if (timers_delete_me == 0) return;
}
}
timers_delete_me = 0;
}
void
_ecore_timer_enable_new(void)
{
Ecore_List2 *l;
if (!timers_added) return;
timers_added = 0;
for (l = (Ecore_List2 *)timers; l; l = l->next)
{
Ecore_Timer *timer;
timer = (Ecore_Timer *)l;
timer->just_added = 0;
}
}
double
_ecore_timer_next_get(void)
{
double now;
double in;
if (!timers) return -1;
now = ecore_time_get();
in = timers->at - now;
if (in < 0) in = 0;
return in;
}
int
_ecore_timer_call(double when)
{
Ecore_List2 *l;
Ecore_Timer *timer;
if (!timers) return 0;
if (last_check > when)
{
/* User set time backwards */
for (l = (Ecore_List2 *)timers; l; l = l->next)
{
timer = (Ecore_Timer *)l;
timer->at -= (last_check - when);
}
}
last_check = when;
for (l = (Ecore_List2 *)timers; l; l = l->next)
{
timer = (Ecore_Timer *)l;
if ((timer->at <= when) &&
(!timer->just_added) &&
(!timer->delete_me))
{
timers = _ecore_list2_remove(timers, timer);
_ecore_timer_call(when);
if ((!timer->delete_me) && (timer->func(timer->data)))
{
/* if the timer would have gone off more than 30 seconds ago,
* assume that the system hung and set the timer to go off
* timer->in from now.
*/
if (!timer->delete_me)
{
if ((timer->at + timer->in) < (when - 30.0))
_ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data);
else
_ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);
}
else
free(timer);
}
else
free(timer);
return 1;
}
}
return 0;
}
static void
_ecore_timer_set(Ecore_Timer *timer, double at, double in, int (*func) (void *data), void *data)
{
Ecore_List2 *l;
timers_added = 1;
timer->at = at;
timer->in = in;
timer->func = func;
timer->data = data;
timer->just_added = 1;
if (timers)
{
for (l = ((Ecore_List2 *)(timers))->last; l; l = l->prev)
{
Ecore_Timer *t2;
t2 = (Ecore_Timer *)l;
if (timer->at > t2->at)
{
timers = _ecore_list2_append_relative(timers, timer, t2);
return;
}
}
}
timers = _ecore_list2_prepend(timers, timer);
}