efl/legacy/ecore/doc/examples.dox

576 lines
25 KiB
Plaintext

/**
* @page Examples Examples
*
* Here is a page with some Ecore examples explained:
*
* @li @ref ecore_time_functions_example_c
* @li @ref ecore_timer_example_c
* @li @ref ecore_idler_example_c
* @li @ref ecore_job_example_c
* @li @ref ecore_event_example_c
* @li @ref ecore_fd_handler_example_c
* @li @ref ecore_poller_example_c
*
*/
/**
* @page ecore_time_functions_example_c ecore_time - Differences between time functions
*
* This example shows the difference between calling ecore_time_get(),
* ecore_loop_time_get() and ecore_time_unix_get().
*
* It initializes ecore, then sets a timer with a callback that, when called,
* will retrieve the system time using these 3 different functions. After
* displaying the time, it sleeps for 1 second, then call display the time
* again using the 3 functions.
*
* Since everything occurs inside the same mainloop iteration, the internal
* ecore time variable will not be updated, and calling ecore_loop_time_get()
* before and after the sleep() call will return the same result.
*
* The two other functions will return a difference of 1 second, as expected.
* But ecore_time_unix_get() returns the number of seconds since 00:00:00 1st
* January 1970, while ecore_time_get() will return the time since a
* unspecified point, but that never goes back in time, even when the timezone
* of the machine changes.
*
* @note The usage of ecore_loop_time_get() should be preferred against the
* two other functions, for most time calculations, since it won't produce a
* system call to get the current time. Use ecore_time_unix_get() when you need
* to know the current time and date, and ecore_time_get() when you need a
* monotonic and more precise time than ecore_loop_time_get().
*
* @include ecore_time_functions_example.c
*/
/**
* @page ecore_timer_example_c ecore timers - Scheduled events
* @dontinclude ecore_timer_example.c
*
* 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 firts timer still executing with
* a different API, to demonstrate its usage. To see the full code for this
* example, click @ref ecore_timer_example.c "here".
*
* To demonstrate this, let's define some constants that will determine at which
* time each timer will expire:
*
* @until INTERVAL1
*
* 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:
*
* @li The timer2, after 3 seconds of the program being executed, will add a delay
* of 3 seconds to timer1;
* @li The timer3 will pause timer1 at 8.2 seconds;
* @li timer4 will resume timer1 at 11.0 seconds;
* @li timer5 will will change the interval of timer1 to 2 seconds;
* @li 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;
* @li timer7 and timer8 will just print their expiration time.
*
* @until ecore_time_get
* @until }
*
* 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 @c _initial_time, and use the function
* @c _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:
*
* @until _timer6_cb
* @until }
*
* It's possible to see the same behavior as other Ecore callbacks here,
* returning @ref ECORE_CALLBACK_RENEW when the timer needs to continue ticking,
* and @ref 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 @c NULL when we are returning @ref
* ECORE_CALLBACK_CANCEL. Otherwise the pointer would still be not @c 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:
*
* @until ecore_shutdown
* @until }
*
* This code is very simple. Just after starting the library, it will save the
* current time to @c _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.
*
*/
/**
* @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_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 (@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
*/
/**
* @page ecore_job_example_c ecore_job - Queuing tasks
*
* This example shows how an @ref Ecore_Job can be added, how it can be
* deleted, and that they always execute in the added order.
*
* First, 2 callback functions are declared, one that prints strings passed to
* it in the @c data pointer, and another one that quits the main loop. In the
* @c main function, 3 jobs are added using the first callback, and another one
* is added using the second one.
*
* Then the second added job is deleted just to demonstrate the usage of
* ecore_job_del(), and the main loop is finally started. Run this example to
* see that @c job1, @c job3 and @c job_quit are ran, in this order.
*
* @include ecore_job_example.c
*/
/**
* @page ecore_event_example_c ecore events and handlers - Setup and use
* This example shows how to create a new type of event, setup some event
* handlers to it, fire the event and have the callbacks called. After
* finishing, we delete the event handlers so no memory will leak.
*
* See the full source code for this example @ref ecore_event_example.c "here".
*
* Let's start the example from the beginning:
*
* @dontinclude ecore_event_example.c
* @until _event_type
*
* First thing is to declare a struct that will be passed as context to the
* event handlers. In this structure we will store the event handler pointers,
* and two strings that will be used by the first event handler. We also will
* use a global integer to store the event type used for our event. It is
* initialized with 0 in the beginning because the event wasn't created yet.
* Later, in the main function we will use ecore_event_type_new() to associate
* another value to it. Now the event handler callbacks:
*
* @until }
*
* This is the first event handler callback. It prints the event data received
* by the event, and the data passed to this handler when it was added. Notice
* that this callback already knows that the event data is an integer pointer,
* and that the handler data is a string. It knows about the first one because
* this is based on the type of event that is going to be handled, and the
* second because it was passed to the ecore_event_handler_add() function when
* registering the event handler.
*
* Another interesting point about this callback is that it returns @ref
* ECORE_CALLBACK_DONE (0) if the event data is even, swallowing the event and
* don't allowing any other callback to be called after this one for this event.
* Otherwise it returns @ref ECORE_CALLBACK_PASS_ON, allowing the event to be
* handled by other event handlers registered for this event. This makes the
* second event handler be called just for "odd" events.
*
* @until ECORE_CALLBACK_DONE
* @until }
*
* The second event handler will check if the event data is equal to 5, and if
* that's the case, it will change the event handler data of the first event
* handler to another string. Then it checks if the event data is higher than
* 10, and if so, it will request the main loop to quit.
*
* An interesting point of this example is that although the second event
* handler requests the main loop to finish after the 11th event being received,
* it will process all the events that were already fired, and call their
* respective event handlers, before the main loop stops. If we didn't want
* these event handlers to be called after the 11th event, we would need to
* unregister them with ecore_event_handler_del() at this point.
*
* Now some basic initialization of the context, and the Ecore library itself:
*
* @until type_new
*
* This last line is interesting. It creates a new type of event and returns a
* unique ID for this event inside Ecore. This ID can be used anywhere else in
* your program to reference this specific type of event, and to add callbacks
* to it.
*
* It's common if you are implementing a library that declares new types of
* events to export their respective types as extern in the header files. This
* way, when the library is initialized and the new type is created, it will be
* available through the header file to an application using it add some
* callbacks to it. Since our example is self-contained, we are just putting it
* as a global variable.
*
* Now we add some callbacks:
*
* @until ctxt);
*
* This is very simple. Just need to call ecore_event_handler_add() with the
* respective event type, the callback function to be called, and a data pointer
* that will be passed to the callback when it is called by the event.
*
* Then we start firing events:
*
* @until }
*
* This @c for will fire 16 events of this type. Notice that the events will be
* fired consecutively, but any callback will be called yet. They are just
* called by the main loop, and since it wasn't even started, nothing happens
* yet. For each event fired, we allocate an integer that will hold the number
* of the event (we are arbitrarily creating these numbers just for
* demonstration purposes). It's up to the event creator to decide which type of
* information it wants to give to the event handler, and the event handler must
* know what is the event info structure for that type of event.
*
* Since we are not allocating any complex structure, just a simple integer, we
* don't need to pass any special free function to ecore_event_add(), and it
* will use a simple @c free on our data. That's the default behavior.
*
* Now finishing our example:
*
* @until }
*
* We just start the main loop and watch things happen, waiting to shutdown
* Ecore when the main loop exits and return.
*/
/**
* @page ecore_fd_handler_example_c ecore fd handlers - Monitoring file descriptors
* @dontinclude ecore_fd_handler_example.c
*
* This is a very simple example where we will start monitoring the stdin of the
* program and, whenever there's something to be read, we call our callback that
* will read it.
*
* Check the full code for this example @ref ecore_fd_handler_example.c "here".
*
* This seems to be stupid, since a similar result could be achieved by the
* following code:
*
* @code
* while (nbytes = read(STDIN_FILENO, buf, sizeof(buf)))
* {
* buf[nbytes - 1] = '\0';
* printf("Read %zd bytes from input: \"%s\"\n", nbytes - 1, buf);
* }
* @endcode
*
* However, the above code is blocking, and won't allow you to do anything else
* other than reading the input. Of course there are other methods to do a
* non-blocking reading, like setting the file descriptor to non-blocking and
* keep looping always checking if there's something to be read, and do other
* things otherwise. Or use a @c select call to watch for more than one file
* descriptor at the same time.
*
* The advantage of using an @ref Ecore_Fd_Handler is that you can monitor a
* file descriptor, while still iterating on the Ecore main loop. It will allow
* you to have timers working and expiring, events still being processed when
* received, idlers doing its work when there's nothing happening, and whenever
* there's something to be read from the file descriptor, your callback will be
* called. And it's everything monitored in the same main loop, no threads are
* needed, thus reducing the complexity of the program and any overhead caused
* by the use of threads.
*
* Now let's start our program. First we just declare a context structure that
* will be passed to our callback, with pointers to our handler and to a timer
* that will be used later:
*
* @until };
*
* Then we will declare a prepare_callback that is called before any fd_handler
* set in the program, and before the main loop select function is called. Just
* use one if you really know that you need it. We are just putting it here to
* exemplify its usage:
*
* @until }
*
* Now, our fd handler. In its arguments, the @c data pointer will have any data
* passed to it when it was registered, and the @c handler pointer will contain
* the fd handler returned by the ecore_main_fd_handler_add() call. It can be
* used, for example, to retrieve which file descriptor triggered this callback,
* since it could be added to more than one file descriptor, or to check what
* tipe of activity there's in the file descriptor.
*
* The code is very simple: we first check if the type of activity was an error.
* It probably won't happen with the default input, but could be the case of a
* network socket detecting a disconnection. Next, we get the file descriptor
* from this handler (as said before, the callback could be added to more than
* one file descriptor), and read it since we know that it shouldn't block,
* because our fd handler told us that there's some activity on it. If the
* result of the read was 0 bytes, we know that it's an end of file (EOF), so we
* can finish reading the input. Otherwise we just print the content read from
* it:
*
* @until }
*
* Also notice that this callback returns @ref ECORE_CALLBACK_RENEW to keep
* being called, as almost all other Ecore callbacks, otherwise if it returns
* @ref ECORE_CALLBACK_CANCEL then the file handler would be deleted.
*
* Just to demonstrate that our program isn't blocking in the input read but
* still can process other Ecore events, we are going to setup an @ref
* Ecore_Timer. This is its callback:
*
* @until }
*
* Now in the main code we are going to initialize the library, and setup
* callbacks for the file descriptor, the prepare callback, and the timer:
*
* @until timer_add
*
* Notice that the use of ecore_main_fd_handler_add() specifies what kind of
* activity we are monitoring. In this case, we want to monitor for read (since
* it's the standard input) and for errors. This is done by the flags @ref
* ECORE_FD_READ and @ref ECORE_FD_ERROR. For the three callbacks we are also
* giving a pointer to our context structure, which has pointers to the handlers
* added.
*
* Then we can start the main loop and see everything happening:
*
* @until }
*
* In the end we are just deleting the fd handler and the timer to demonstrate
* the API usage, since Ecore would already do it for us on its shutdown.
*/
/**
* @page ecore_poller_example_c ecore poller - Repetitive polling tasks
* @dontinclude ecore_poller_example.c
*
* This example show how to setup, and explains how an @ref Ecore_Poller is
* called. You can @ref ecore_poller_example.c "see the full source code here".
*
* In this example we store the initial time of the program just to use as
* comparison to the time when the poller callbacks are called. It will be
* stored in @c _initial_time :
*
* @until initial_time
*
* Then next step is to define the poller callback. This callback assumes that a
* @c data pointer is passed to it on creation, and is a string just used to
* identify the poller. The callback prints this string and the time since the
* program started, and returns @ref ECORE_CALLBACK_RENEW to keep being called.
*
* @until }
*
* Now in the main function we initialize Ecore, and save the initial time of
* the program, so we can compare it later with the time that the pollers are
* being called:
*
* @until initial_time
*
* Then we change the poll interval to 0.3 seconds (the default is 0.125
* seconds) just to show the API usage.
*
* Finally, we create two pollers, one that will be called every 4 ticks, and
* another one that will be called every 8 ticks. This means the the first
* poller interval will be around 1.2 seconds, and the second one will be
* around 2.4 seconds. But the most important point is: since the second poller
* interval is a multiple of the first one, they will be always synchronized.
* Ecore calls pollers that are in the "same tick" together. It doesn't go back
* to the main loop and check if there's another poller to execute at this
* time, but instead it calls all the pollers registered to this "tick" at the
* same time. See the description of ecore_poller_add() for more details. This
* is easy to see in the time printed by both of them.
*
* If instead of two synchronized pollers, we were using two different timers,
* one with interval of 1.2 seconds and another one with an interval of 2.4
* seconds, there would be no guarantee that they would be totally in sync. Some
* delay in the execution of another task, or even in the task called in the
* callback, could make them get out of sync, forcing Ecore's main loop to wake
* up more than necessary.
*
* Well, this is the code that create these two pollers and set the poll
* interval, then starts the main loop:
*
* @until ecore_main_loop_begin
*
* If you hit CTRL-C during the execution of the program, the main loop will
* quit, since there are some signal handlers already set by default to do this.
* So after the main loop begin call, we change the second poller's interval to
* 16 ticks, so it will happen each 4.8 seconds (or each 4 times that the first
* poller is called).
*
* This means: the program is started, the first poller is called each 4 ticks
* and the second is called each 8 ticks. After CTRL-C is used, the second
* poller will be called each 16 ticks.
*
* @until }
*
* The rest of the program is just deleting the pollers and shutting down the
* library.
*/
/**
* @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_job_example.c
* This example shows how to use an @ref Ecore_Job. See
* @ref ecore_job_example_c "the explanation here".
*/
/**
* @example ecore_time_functions_example.c
* Shows the difference between the three time functions. See @ref
* ecore_time_functions_example_c "the example explained".
*/
/**
* @example ecore_timer_example.c
* This example show how to use timers to have timed events inside ecore.
* See @ref ecore_timer_example_c "the example explained".
*/
/**
* @example ecore_fd_handler_example.c
* This example shows how to setup and use an fd_handler. See
* @ref ecore_fd_handler_example_c "the explanation here".
*/
/**
* @example ecore_poller_example.c
* This example shows how to setup and use a poller. See
* @ref ecore_poller_example_c "the explanation here".
*/
/**
* @example ecore_event_example.c
* This example shows how to setup, change, and delete event handlers. See
* @ref ecore_event_example_c "the explanation here".
*/
/**
* @example ecore_fd_handler_gnutls_example.c
* Shows how to use fd handlers.
*/
/**
* @page tutorial_ecore_pipe_gstreamer_example
*
* Here is an example that uses the pipe wrapper with a Gstreamer
* pipeline. For each decoded frame in the Gstreamer thread, a handle
* is called in the ecore thread.
*
* @include ecore_pipe_gstreamer_example.c
* @example ecore_pipe_gstreamer_example.c
*/
/**
* @page tutorial_ecore_pipe_simple_example
* @dontinclude ecore_pipe_simple_example.c
*
* This example shows some simple usage of ecore_pipe. We are going to create a
* pipe, fork our process, and then the child is going to comunicate to the
* parent the result of its processing through the pipe.
*
* As always we start with our includes, nothing especial:
* @skip #include
* @until Ecore.h
*
* The first thing we are going to define in our example is the function we are
* going to run on the child process, which, as mentioned, will do some
* processing and then will write the result to the pipe:
* @until }
* @until }
* @note The sleep was added so the parent process would think the child process
* was doing something interesting...
*
* Next up is our function for handling data arriving in the pipe. It copies the
* data to another buffer, adds a terminating NULL and prints it. Also if it
* receives a certain string it stops the main loop(efectvely ending the
* program):
* @until }
* @until }
*
* And now on to our main function, we start by declaring some variables and
* initializing ecore:
* @until ecore_init
*
* And since we are talking about pipes let's create one:
* @until pipe_add
*
* Now we are going to fork:
* @until fork
* @note duh...
*
* The child process is going to do the our fancy processing:
* @until }
* @note It's very important to call ecore_pipe_read_close() here so that the
* child process won't read what it is writing to the pipe itself.
*
* And the parent is going to run ecore's main loop waiting for some data:
* @until }
* @note Calling ecore_pipe_write_close() here isn't important but since we
* aren't going to write in the pipe it is good practice.
*
* And finally when done processing(the child) or done receiving(the parent) we
* delete the pipe and shutdown ecore:
* @until }
*
* @example ecore_pipe_simple_example.c
*/