From d83f1749299d167df01b2752509aff4f4cb949d8 Mon Sep 17 00:00:00 2001 From: Rafael Antognolli Date: Wed, 22 Jun 2011 18:29:38 +0000 Subject: [PATCH] ecore/idler - Improve documentation and add an example. SVN revision: 60602 --- legacy/ecore/doc/examples.dox | 67 +++++++++++ legacy/ecore/src/examples/Makefile.am | 2 + .../ecore/src/examples/ecore_idler_example.c | 113 ++++++++++++++++++ .../ecore/src/lib/ecore/ecore_idle_enterer.c | 6 + .../ecore/src/lib/ecore/ecore_idle_exiter.c | 3 + legacy/ecore/src/lib/ecore/ecore_idler.c | 7 ++ 6 files changed, 198 insertions(+) create mode 100644 legacy/ecore/src/examples/ecore_idler_example.c diff --git a/legacy/ecore/doc/examples.dox b/legacy/ecore/doc/examples.dox index 1395b064a1..07c59cb774 100644 --- a/legacy/ecore/doc/examples.dox +++ b/legacy/ecore/doc/examples.dox @@ -4,6 +4,7 @@ * Here is a page with some Ecore examples explained: * * @li @ref ecore_time_example_c + * @li @ref ecore_idler_example_c * */ @@ -37,6 +38,72 @@ * @include ecore_time_example.c */ +/** + * @page ecore_idler_example_c 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 @ref 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 @ref + * ECORE_CALLBACK_CANCEL. + * + * The next function declared is the event callback @c _event_handler_cb. It + * will check if the idler was called more than 100 times already @c + * (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 @ref ECORE_CALLBACK_CANCEL to indicate that the event handler + * shouldn't be called anymore (this will delete it). If the @c count is still + * smaller than 100, the event callback just returns @ref ECORE_CALLBACK_RENEW + * and will keep being called every time that this event type is called. + * + * Finally, we add a callback to the timer, that will just print a message when + * it is called, and this will happen only once (@ref 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 @b 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. + * + * @include ecore_idler_example.c + */ + +/** + * @example ecore_idler_example.c + * This example shows when @ref Ecore_Idler, @ref Ecore_Idle_Enterer and @ref + * Ecore_Idle_Exiter are called. See + * @ref ecore_idler_example_c "the explanation here". + */ + /** * @example ecore_time_example.c * Shows the difference between the three time functions. See @ref diff --git a/legacy/ecore/src/examples/Makefile.am b/legacy/ecore/src/examples/Makefile.am index 42b1f6afd2..088e64b150 100644 --- a/legacy/ecore/src/examples/Makefile.am +++ b/legacy/ecore/src/examples/Makefile.am @@ -12,6 +12,7 @@ LDADD = \ @dlopen_libs@ @EINA_LIBS@ @EVIL_LIBS@ @GLIB_LIBS@ @WIN32_LIBS@ @LTLIBINTL@ @EFL_PTHREAD_LIBS@ @rt_libs@ -lm SRCS = \ + ecore_idler_example.c \ ecore_time_example.c \ client_bench.c \ server_bench.c \ @@ -31,6 +32,7 @@ endif if EFL_BUILD_EXAMPLES pkglib_PROGRAMS += \ + ecore_idler_example \ ecore_time_example endif diff --git a/legacy/ecore/src/examples/ecore_idler_example.c b/legacy/ecore/src/examples/ecore_idler_example.c new file mode 100644 index 0000000000..c6d08982de --- /dev/null +++ b/legacy/ecore/src/examples/ecore_idler_example.c @@ -0,0 +1,113 @@ +#include +#include + +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 _event_type = 0; // a new type of event will be defined and stored here + +static Eina_Bool +_enterer_cb(void *data) // 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) // 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, void *event) // 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_CANCEL; // same as EINA_FALSE + } + + return ECORE_CALLBACK_RENEW; // same as EINA_TRUE +} + +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_TRUE +} + +int main(int argc, char **argv) +{ + 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.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; +} diff --git a/legacy/ecore/src/lib/ecore/ecore_idle_enterer.c b/legacy/ecore/src/lib/ecore/ecore_idle_enterer.c index be1fc4e050..a9ae80deea 100644 --- a/legacy/ecore/src/lib/ecore/ecore_idle_enterer.c +++ b/legacy/ecore/src/lib/ecore/ecore_idle_enterer.c @@ -41,6 +41,9 @@ static int idle_enterers_delete_me = 0; * @param data The data to be passed to the @p func call * @return A handle to the idle enterer callback if successful. Otherwise, * NULL is returned. + * @note The function func will be called every time the main loop is entering + * idle state, as long as it returns 1 (or ECORE_CALLBACK_RENEW). A return of 0 + * (or ECORE_CALLBACK_CANCEL) deletes the idle enterer. */ EAPI Ecore_Idle_Enterer * ecore_idle_enterer_add(Ecore_Task_Cb func, const void *data) @@ -63,6 +66,9 @@ ecore_idle_enterer_add(Ecore_Task_Cb func, const void *data) * @param data The data to be passed to the @p func call * @return A handle to the idle enterer callback if successful. Otherwise, * NULL is returned. + * @note The function func will be called every time the main loop is entering + * idle state, as long as it returns 1 (or ECORE_CALLBACK_RENEW). A return of 0 + * (or ECORE_CALLBACK_CANCEL) deletes the idle enterer. */ EAPI Ecore_Idle_Enterer * ecore_idle_enterer_before_add(Ecore_Task_Cb func, const void *data) diff --git a/legacy/ecore/src/lib/ecore/ecore_idle_exiter.c b/legacy/ecore/src/lib/ecore/ecore_idle_exiter.c index 43c9e47067..bbe969a47a 100644 --- a/legacy/ecore/src/lib/ecore/ecore_idle_exiter.c +++ b/legacy/ecore/src/lib/ecore/ecore_idle_exiter.c @@ -40,6 +40,9 @@ static int idle_exiters_delete_me = 0; * @param func The function to call when exiting an idle state. * @param data The data to be passed to the @p func call * @return A handle to the idle exiter callback on success. NULL otherwise. + * @note The function func will be called every time the main loop is exiting + * idle state, as long as it returns 1 (or ECORE_CALLBACK_RENEW). A return of 0 + * (or ECORE_CALLBACK_CANCEL) deletes the idle exiter. */ EAPI Ecore_Idle_Exiter * ecore_idle_exiter_add(Ecore_Task_Cb func, const void *data) diff --git a/legacy/ecore/src/lib/ecore/ecore_idler.c b/legacy/ecore/src/lib/ecore/ecore_idler.c index edc04d791b..0a056b3c32 100644 --- a/legacy/ecore/src/lib/ecore/ecore_idler.c +++ b/legacy/ecore/src/lib/ecore/ecore_idler.c @@ -55,6 +55,13 @@ process. Exiter callbacks are called when the main loop wakes up from an idle state. + +@note Idle state doesn't mean that the @b program is idle, but that the main +loop is idle. It doesn't have any timers, events, fd handlers or anything +else to process (which in most event driven programs also means that the @b +program is idle too, but it's not a rule). The program itself may be doing a lot of +processing in the idler, or in another thread, for example. + * @{ */