ecore idle state - Idlers, enterers and exiters

This example demonstrates how to manage the idle state of the main loop.

Once a program knows that the main loop is going to enter in idle state, it could start doing some processing until getting out of this state.

To exemplify this, we also add events and a timer to this program, so we can see the idle exiter callback being called before processing the event and/or timer, the event/timer callback being called (processed), then the idle enterer being called before entering in idle state again. Once in idle, the main loop keeps calling the idler callback continuously until a new event or timer is received.

First, we declare a struct that will be used as context to be passed to every callback. It's not useful everywhere, since this example is very simple and doesn't do anything other than printing messages, but using this context will make it a little bit more real. Our context will be used to delete the timer, idler, idle enterer and exiter, and the event handler, and also to count how many times the idler was called.

Then we start declaring callbacks for the idle enterer, idle exiter and the idler itself. Idle enterer and exiter callbacks just print a message saying that they were called, while the idler, in addition to printing a message too, also sends an event every 10 times that it is called, incrementing the context count variable. This event will be used to make the main loop exit the idle state and call the event callback.

These callbacks return ECORE_CALLBACK_RENEW, since we want them to keep being called every time the main loop changes to/from idle state. Otherwise, if we didn't want them to be called again, they should return ECORE_CALLBACK_CANCEL.

The next function declared is the event callback _event_handler_cb. It will check if the idler was called more than 100 times already (ctxt->count > 100), and will delete the idler, idle enterer and exiter, the timer (if it still exists), and request that the main loop stop running. Then it returns ECORE_CALLBACK_DONE to indicate that the event shouldn't be handled by any other callback.

Finally, we add a callback to the timer, that will just print a message when it is called, and this will happen only once (ECORE_CALLBACK_CANCEL is being returned). This timer callback is just here to show that the main loop gets out of idle state when processing timers too.

The main function is simple, just creates a new type of event that we will use to demonstrate the event handling together with the idle state, adds the callbacks that we declared so far, fill the context struct, and starts running the main loop.

Note
We use timer and event callbacks to demonstrate the idle state changing, but it also happens for file descriptor handlers, pipe handlers, etc.
//Compile with:
// gcc -o ecore_idler_example ecore_idler_example.c `pkg-config --libs --cflags ecore eo`
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <Ecore.h>
#include <Eo.h>
#include <unistd.h>
struct context // helper struct to give some context to the callbacks
{
int count;
Ecore_Idler *idler;
Ecore_Timer *timer;
};
static int _event_type = 0; // a new type of event will be defined and stored here
static Eina_Bool
_enterer_cb(void *data EINA_UNUSED) // the idle enterer callback
{
printf("IDLE ENTERER: Ecore entering in idle state.\n");
return ECORE_CALLBACK_RENEW; // same as EINA_TRUE
}
static Eina_Bool
_exiter_cb(void *data EINA_UNUSED) // the idle exiter callback
{
printf("IDLE EXITER: Ecore exiting idle state.\n");
return ECORE_CALLBACK_RENEW; // same as EINA_TRUE
}
static Eina_Bool
_idler_cb(void *data) // the idler callback - ran while the mainloop is idle
{
struct context *ctxt = data;
printf("IDLER: executing idler callback while in idle state.\n");
ctxt->count++;
/* each 10 times that the callback gets called, generate an event that
* will wake up the main loop, triggering idle enterers, exiters, etc. */
if ((ctxt->count % 10) == 0)
ecore_event_add(_event_type, NULL, NULL, NULL);
return ECORE_CALLBACK_RENEW; // same as EINA_TRUE
}
static Eina_Bool
_event_handler_cb(void *data, int type EINA_UNUSED, void *event EINA_UNUSED) // event callback
{
struct context *ctxt = data;
printf("EVENT: processing callback for the event received.\n");
if (ctxt->count > 100)
{
ecore_idle_enterer_del(ctxt->enterer);
ecore_idle_exiter_del(ctxt->exiter);
// ecore_idler_del(ctxt->idler);
ctxt->enterer = NULL;
ctxt->exiter = NULL;
ctxt->idler = NULL;
if (ctxt->timer)
{
ecore_timer_del(ctxt->timer);
ctxt->timer = NULL;
}
}
return ECORE_CALLBACK_DONE; // same as EINA_FALSE
}
static Eina_Bool
_timer_cb(void *data)
{
struct context *ctxt = data;
printf("TIMER: timer callback called.\n");
if (ctxt->timer)
ctxt->timer = NULL;
return ECORE_CALLBACK_CANCEL; // same as EINA_FALSE
}
int
main(void)
{
struct context ctxt = {0};
if (!ecore_init())
{
printf("ERROR: Cannot init Ecore!\n");
return -1;
}
_event_type = ecore_event_type_new();
ctxt.enterer = ecore_idle_enterer_add(_enterer_cb, &ctxt);
ctxt.exiter = ecore_idle_exiter_add(_exiter_cb, &ctxt);
ctxt.idler = ecore_idler_add(_idler_cb, &ctxt);
// ctxt.idler = efl_add_ref(ECORE_IDLER_CLASS, NULL, ecore_idler_constructor(efl_added, _idler_cb, &ctxt));
ctxt.handler = ecore_event_handler_add(_event_type,
_event_handler_cb,
&ctxt);
ctxt.timer = ecore_timer_add(0.0005, _timer_cb, &ctxt);
return 0;
}
struct _Ecore_Event_Handler Ecore_Event_Handler
A handle for an event handler.
Definition: Ecore_Common.h:576
int ecore_event_type_new(void)
Allocates a new event type id sensibly and returns the new id.
Definition: ecore_events.c:80
Ecore_Event * ecore_event_add(int type, void *ev, Ecore_End_Cb func_free, void *data)
Adds an event to the event queue.
Definition: ecore_events.c:52
Ecore_Event_Handler * ecore_event_handler_add(int type, Ecore_Event_Handler_Cb func, const void *data)
Adds an event handler.
Definition: ecore_events.c:13
Ecore_Idle_Enterer * ecore_idle_enterer_add(Ecore_Task_Cb func, const void *data)
Adds an idle enterer handler.
Definition: ecore_idle_enterer.c:18
void * ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter)
Deletes an idle exiter handler from the list to be run on exiting idle state.
Definition: ecore_idle_exiter.c:24
struct _Ecore_Factorized_Idle Ecore_Idle_Exiter
A handle for idle exiters.
Definition: Ecore_Common.h:3189
Ecore_Idler * ecore_idler_add(Ecore_Task_Cb func, const void *data)
Adds an idler handler.
Definition: ecore_idler.c:109
void * ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer)
Deletes an idle enterer callback.
Definition: ecore_idle_enterer.c:40
struct _Ecore_Factorized_Idle Ecore_Idle_Enterer
A handle for idle enterers.
Definition: Ecore_Common.h:3184
Ecore_Idle_Exiter * ecore_idle_exiter_add(Ecore_Task_Cb func, const void *data)
Adds an idle exiter handler.
Definition: ecore_idle_exiter.c:17
struct _Ecore_Factorized_Idle Ecore_Idler
A handle for idlers.
Definition: Ecore_Common.h:3179
EAPI int ecore_shutdown(void)
Shuts down connections, signal handlers sockets etc.
Definition: ecore.c:371
EAPI int ecore_init(void)
Sets up connections, signal handlers, sockets etc.
Definition: ecore.c:230
#define ECORE_CALLBACK_RENEW
Return value to keep a callback.
Definition: Ecore_Common.h:153
#define ECORE_CALLBACK_DONE
Return value to stop event handling.
Definition: Ecore_Common.h:156
void ecore_main_loop_quit(void)
Quits the main loop once all the events currently on the queue have been processed.
Definition: ecore_main.c:1321
#define ECORE_CALLBACK_CANCEL
Return value to remove a callback.
Definition: Ecore_Common.h:152
void ecore_main_loop_begin(void)
Runs the application main loop.
Definition: ecore_main.c:1311
void * ecore_timer_del(Ecore_Timer *timer)
Deletes the specified timer from the timer list.
Definition: ecore_timer.c:238
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
Eo Ecore_Timer
A handle for timers.
Definition: Ecore_Common.h:3079
unsigned char Eina_Bool
Type to mimic a boolean.
Definition: eina_types.h:527
#define EINA_UNUSED
Used to indicate that a function parameter is purposely unused.
Definition: eina_types.h:339