ecore timers - Scheduled events

This example shows how to setup timer callbacks. It starts a timer that will tick (expire) every 1 second, and then setup other timers that will expire only once, but each of them will affect the first timer still executing with a different API, to demonstrate its usage. To see the full code for this example, click here.

To demonstrate this, let's define some constants that will determine at which time each timer will expire:

//Compile with:
// gcc -o ecore_timer_example ecore_timer_example.c `pkg-config --libs --cflags ecore`
#include <Ecore.h>
#include <unistd.h>
#define TIMEOUT_1 1.0 // interval for timer1
#define TIMEOUT_2 3.0 // timer2 - delay timer1
#define TIMEOUT_3 8.2 // timer3 - pause timer1
#define TIMEOUT_4 11.0 // timer4 - resume timer1
#define TIMEOUT_5 14.0 // timer5 - change interval of timer1
#define TIMEOUT_6 18.0 // top timer1 and start timer7 and timer8 with changed precision
#define TIMEOUT_7 1.1 // interval for timer7
#define TIMEOUT_8 1.2 // interval for timer8
#define DELAY_1 3.0 // delay time for timer1 - used by timer2
#define INTERVAL1 2.0 // new interval for timer1 - used by timer5

These constants should tell by themselves what will be the behavior of the program, but I'll explain it anyway. The first timer is set to tick every 1 second, but all the other timers until the 6th one will be started concurrently at the beginning of the program. Each of them will expire at the specified time in these constants:

- The timer2, after 3 seconds of the program being executed, will add a delay of 3 seconds to timer1;
- The timer3 will pause timer1 at 8.2 seconds;
- timer4 will resume timer1 at 11.0 seconds;
- timer5 will will change the interval of timer1 to 2 seconds;
- timer6 will stop timer1 and start timer7 and timer8, with 1.1 and 1.2 seconds of interval, respectively; it also sets the precision to 0.2 seconds;
- timer7 and timer8 will just print their expiration time.

static double _initial_time = 0;
struct context // helper struct to give some context to the callbacks
{
Ecore_Timer *timer1;
Ecore_Timer *timer2;
Ecore_Timer *timer3;
Ecore_Timer *timer4;
Ecore_Timer *timer5;
Ecore_Timer *timer6;
Ecore_Timer *timer7;
Ecore_Timer *timer8;
};
static double
_get_current_time(void)
{
return ecore_time_get() - _initial_time;
ecore_time_get
double ecore_time_get(void)
Retrieves the current system time as a floating point value in seconds.
Definition ecore_time.c:33
Ecore_Timer
Eo Ecore_Timer
A handle for timers.
Definition Ecore_Common.h:3085
}

As almost all the other examples, we create a context structure to pass to our callbacks, so they can have access to the other timers. We also store the time of the program start in `_initial_time`, and use the function `_get_current_time` to retrieve the current time relative to that time. This will help demonstrate what is going on.

Now, the behavior and relationship between the timers that was described above is dictated by the following timer callbacks:

static Eina_Bool
_timer1_cb(void *data EINA_UNUSED)
{
printf("Timer1 expired after %0.3f seconds.\n", _get_current_time());
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_timer2_cb(void *data)
{
struct context *ctxt = data;
printf("Timer2 expired after %0.3f seconds. "
"Adding delay of %0.3f seconds to timer1.\n",
_get_current_time(), DELAY_1);
ecore_timer_delay(ctxt->timer1, DELAY_1);
ctxt->timer2 = NULL;
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool
_timer3_cb(void *data)
{
struct context *ctxt = data;
printf("Timer3 expired after %0.3f seconds. "
"Freezing timer1.\n", _get_current_time());
ecore_timer_freeze(ctxt->timer1);
ctxt->timer3 = NULL;
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool
_timer4_cb(void *data)
{
struct context *ctxt = data;
printf("Timer4 expired after %0.3f seconds. "
"Resuming timer1, which has %0.3f seconds left to expire.\n",
_get_current_time(), ecore_timer_pending_get(ctxt->timer1));
ecore_timer_thaw(ctxt->timer1);
ctxt->timer4 = NULL;
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool
_timer5_cb(void *data)
{
struct context *ctxt = data;
double interval = ecore_timer_interval_get(ctxt->timer1);
printf("Timer5 expired after %0.3f seconds. "
"Changing interval of timer1 from %0.3f to %0.3f seconds.\n",
_get_current_time(), interval, INTERVAL1);
ecore_timer_interval_set(ctxt->timer1, INTERVAL1);
ctxt->timer5 = NULL;
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool
_timer7_cb(void *data)
{
struct context *ctxt = data;
printf("Timer7 expired after %0.3f seconds.\n", _get_current_time());
ctxt->timer7 = NULL;
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool
_timer8_cb(void *data)
{
struct context *ctxt = data;
printf("Timer8 expired after %0.3f seconds.\n", _get_current_time());
ctxt->timer8 = NULL;
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool
_timer6_cb(void *data)
ECORE_CALLBACK_RENEW
#define ECORE_CALLBACK_RENEW
Return value to keep a callback.
Definition Ecore_Common.h:153
ECORE_CALLBACK_CANCEL
#define ECORE_CALLBACK_CANCEL
Return value to remove a callback.
Definition Ecore_Common.h:152
ecore_timer_interval_get
double ecore_timer_interval_get(const Efl_Loop_Timer *obj)
Interval the timer ticks on.
Definition efl_loop_timer_eo.legacy.c:9
ecore_timer_interval_set
void ecore_timer_interval_set(Efl_Loop_Timer *obj, double in)
Interval the timer ticks on.
Definition efl_loop_timer_eo.legacy.c:3
ecore_timer_delay
void ecore_timer_delay(Efl_Loop_Timer *obj, double add)
Adds a delay to the next occurrence of a timer.
Definition efl_loop_timer_eo.legacy.c:33
ecore_timer_freeze
void ecore_timer_freeze(Ecore_Timer *timer)
Pauses a running timer.
Definition ecore_timer.c:334
ecore_timer_thaw
void ecore_timer_thaw(Ecore_Timer *timer)
Resumes a frozen (paused) timer.
Definition ecore_timer.c:377
ecore_timer_pending_get
double ecore_timer_pending_get(const Efl_Loop_Timer *obj)
Pending time regarding a timer.
Definition efl_loop_timer_eo.legacy.c:15
Eina_Bool
unsigned char Eina_Bool
Type to mimic a boolean.
Definition eina_types.h:527
EINA_UNUSED
#define EINA_UNUSED
Used to indicate that a function parameter is purposely unused.
Definition eina_types.h:339
{
struct context *ctxt = data;
printf("Timer6 expired after %0.3f seconds.\n", _get_current_time());
printf("Stopping timer1.\n");
ecore_timer_del(ctxt->timer1);
ctxt->timer1 = NULL;
printf("Starting timer7 (%0.3fs) and timer8 (%0.3fs).\n",
TIMEOUT_7, TIMEOUT_8);
ctxt->timer7 = ecore_timer_add(TIMEOUT_7, _timer7_cb, ctxt);
ctxt->timer8 = ecore_timer_add(TIMEOUT_8, _timer8_cb, ctxt);
ecore_timer_precision_set(0.2);
ctxt->timer6 = NULL;
return ECORE_CALLBACK_CANCEL;
}
ecore_timer_del
void * ecore_timer_del(Ecore_Timer *timer)
Deletes the specified timer from the timer list.
Definition ecore_timer.c:238
ecore_timer_add
Ecore_Timer * ecore_timer_add(double in, Ecore_Task_Cb func, const void *data)
Creates a timer to call the given function in the given period of time.
Definition ecore_timer.c:189
ecore_timer_precision_set
void ecore_timer_precision_set(double precision)
Sets the precision to be used by timer infrastructure.
Definition ecore_timer.c:76

It's possible to see the same behavior as other Ecore callbacks here, returning ECORE_CALLBACK_RENEW when the timer needs to continue ticking, and ECORE_CALLBACK_CANCEL when it needs to stop its execution. Also notice that later on our program we are checking for the timers pointers in the context to see if they are still executing before deleting them, so we need to set these timer pointers to `NULL` when we are returning ECORE_CALLBACK_CANCEL. Otherwise the pointer would still be not `NULL`, but pointing to something that is invalid, since the timer would have already expired without renewing.

Now the main code, which will start the timers:

int
main(void)
{
struct context ctxt = {0};
if (!ecore_init())
{
printf("ERROR: Cannot init Ecore!\n");
return -1;
}
_initial_time = ecore_time_get();
ctxt.timer1 = ecore_timer_add(TIMEOUT_1, _timer1_cb, &ctxt);
ctxt.timer2 = ecore_timer_add(TIMEOUT_2, _timer2_cb, &ctxt);
ctxt.timer3 = ecore_timer_add(TIMEOUT_3, _timer3_cb, &ctxt);
ctxt.timer4 = ecore_timer_add(TIMEOUT_4, _timer4_cb, &ctxt);
ctxt.timer5 = ecore_timer_add(TIMEOUT_5, _timer5_cb, &ctxt);
ctxt.timer6 = ecore_timer_add(TIMEOUT_6, _timer6_cb, &ctxt);
printf("start the main loop.\n");
ecore_main_loop_begin();
if (ctxt.timer1)
ecore_timer_del(ctxt.timer1);
if (ctxt.timer2)
ecore_timer_del(ctxt.timer2);
if (ctxt.timer3)
ecore_timer_del(ctxt.timer3);
if (ctxt.timer4)
ecore_timer_del(ctxt.timer4);
if (ctxt.timer5)
ecore_timer_del(ctxt.timer5);
if (ctxt.timer6)
ecore_timer_del(ctxt.timer6);
if (ctxt.timer7)
ecore_timer_del(ctxt.timer7);
if (ctxt.timer8)
ecore_timer_del(ctxt.timer8);
ecore_shutdown();
ecore_shutdown
EAPI int ecore_shutdown(void)
Shuts down connections, signal handlers sockets etc.
Definition ecore.c:371
ecore_init
EAPI int ecore_init(void)
Sets up connections, signal handlers, sockets etc.
Definition ecore.c:230
ecore_main_loop_begin
void ecore_main_loop_begin(void)
Runs the application main loop.
Definition ecore_main.c:1311
return 0;
}

This code is very simple. Just after starting the library, it will save the current time to `_initial_time`, start all timers from 1 to 6, and begin the main loop. Everything should be running right now, displaying the time which each timer is expiring, and what it is doing to affect the other timers.

After returning from the main loop, every timer is checked to see if it's still alive and, in that case, deleted, before finalizing the library. This is not really necessary, since ecore_shutdown() will already delete them for you, but it's good practice if you have other things going on after this point that could restart the main loop.