Tizen Native API  4.0
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 = eo_add(ECORE_IDLER_CLASS, NULL, ecore_idler_constructor(_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;
}