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_Idle_Enterer *enterer;
Ecore_Idler *idler;
Ecore_Idle_Exiter *exiter;
Ecore_Event_Handler *handler;
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;
}
ecore_main_loop_quit();
}
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);
ecore_main_loop_begin();
ecore_shutdown();
return 0;
}
Ecore_Event_Handler
struct _Ecore_Event_Handler Ecore_Event_Handler
A handle for an event handler.
Definition Ecore_Common.h:576
ecore_event_type_new
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_add
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_add
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_add
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
ecore_idle_exiter_del
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
Ecore_Idle_Exiter
struct _Ecore_Factorized_Idle Ecore_Idle_Exiter
A handle for idle exiters.
Definition Ecore_Common.h:3195
ecore_idler_add
Ecore_Idler * ecore_idler_add(Ecore_Task_Cb func, const void *data)
Adds an idler handler.
Definition ecore_idler.c:109
ecore_idle_enterer_del
void * ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer)
Deletes an idle enterer callback.
Definition ecore_idle_enterer.c:40
Ecore_Idle_Enterer
struct _Ecore_Factorized_Idle Ecore_Idle_Enterer
A handle for idle enterers.
Definition Ecore_Common.h:3190
ecore_idle_exiter_add
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
Ecore_Idler
struct _Ecore_Factorized_Idle Ecore_Idler
A handle for idlers.
Definition Ecore_Common.h:3185
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_CALLBACK_RENEW
#define ECORE_CALLBACK_RENEW
Return value to keep a callback.
Definition Ecore_Common.h:153
ECORE_CALLBACK_DONE
#define ECORE_CALLBACK_DONE
Return value to stop event handling.
Definition Ecore_Common.h:156
ecore_main_loop_quit
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
ECORE_CALLBACK_CANCEL
#define ECORE_CALLBACK_CANCEL
Return value to remove a callback.
Definition Ecore_Common.h:152
ecore_main_loop_begin
void ecore_main_loop_begin(void)
Runs the application main loop.
Definition ecore_main.c:1311
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
Eo Ecore_Timer
A handle for timers.
Definition Ecore_Common.h:3085
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