Ecore is the glue that holds all the EFL libraries together. You can use most EFL libraries by themselves but Ecore gives you the plumbing you need to make them work all together in an elegant way. It also gives you additional programming constructs that will make EFL development a little easier.
Unlike Evas and Edje, Ecore is a non-GUI library. Although it deals with graphics in a sense (abstracting some X functions for example) you can perfectly program a command line application in Ecore. Ecore is the foundation of the EFL family implementing job handling, networking functions, timers, configuration management, IPC, and several other aspects of an application that you would have to write yourself if your program used only Evas/Edje.
You might think that Ecore is to EFL what Glib is to GTK+. This is only partially true. While Glib is the non-GUI part of GTK+ which is even used by non-GTK+ apps, in practice all GTK+ applications depend on Glib. Ecore in contrast, is an add-on library that boosts your EFL application. It should be clear from the previous chapters that you can use only Evas for an application.
As with Evas engines all different modules of Ecore (IPC, Jobs, X abstraction e.t.c.) come in different libraries in your system so you can selectively choose what you want to link with your application. If your system does not employ the DBUS daemon for example you can leave out the ecore_dbus module during linking. For a console application you can leave out the ecore_x module and so on.
The next section briefly covers the Ecore capabilities.
This section is a general list of Ecore capabilities.
- Job Handling
You can add and remove jobs (that call your functions) in the event loop of your application. The event loop and what ecore does with it are explained in a separate section.
- Idle Handlers
You can define what your application does in its idle time. You can even define what it should do before entering and after exiting an idle state. Again this functionality is explained in a separate section.
- Configuration management
Ecore does away with the traditional text based UNIX configuration files. Instead it employs configuration keys stored in binary (powered by the Eet storage library). You can even register listeners that are called when configuration changes. A separate section is devoted to storing/loading configuration too.
- Process Spawning functions
An abstraction over UNIX fork, popen, exec, getpid system calls. You also have the ability to send individual UNIX signals to the processes spawned this way.
- Data structures
A hash table, a linked list and a tree data structure are offered. A doubly linked list is available too. Notice that these implementations do not require Evas to be present (as we said before Evas includes code for some simple data structures too).
- File monitoring
You are offered the ability to monitor a file descriptor and have a callback function when there is activity on the file managed by this descriptor (e.g. reading/writing).
Searching a file in a set of directories
Similar to the PATH variable on UNIX system where an executable is searched on a predefined set of directories, Ecore allows you to do this for any file your application wants. Of course the directories contained in the search set are defined by the programmer.
- Ecore plugins
Loading additional Ecore plugins during run-time. The usual dlopen stuff.
Programmable timers. Complete with interval changing after the timer has already started.
- Network Connections
An abstraction over BSD sockets. Can also use local UNIX sockets for localhost communication.
- Framebuffer Utilities
Several helper functions for Framebuffer devices. Calibration stuff mostly. Backlight/Display and double click interval too.
- Generic IPC
IPC is Inter Process Communication. An abstraction over UNIX IPC.
- Ecore X
An abstraction over X. You don't need to use X specific functions to set the class/icon/title of your application any more. Display, windows, properties, synchronization/flushing, pixmap, geometry functions are available which wrap around the respective X function.
- Ecore dbus
Dbus bindings. Dbus in an emerging technology offered as a freedesktop.org standard. It is already used by Gnome and recently adopted by KDE. Its objective is system-wide IPC.
The first Ecore feature we will focus on is configuration for an application. Any non-trivial application needs to store somewhere the options selected by the user. Once the application is started the second time it should "remember" the user choices. This implies the saving of configuration parameters on disk (filesystem) between runs.
The traditional way to store configuration in a UNIX system is well known. Each application reads and writes a text file which is human readable. Most times this text file contains key-value pairs on each line, but there are applications with more complicated configuration files which actually define their own configuration language schematics. Several of the heavyweight UNIX servers (web, mail, FTP) can even have configurations which span multiple files and directories.
This approach was chosen for its universality. Changing the configuration of any program means using any text editor to change the text file. Configuration files are usable across any architecture since they are text based. Contrast this to the commercial (closed-source) world where configuration is stored into cryptic binary files. These files are contained in a non-documented format known only to the company that produces the respective application. If the company dies you are out of luck. You cannot move configuration files around and several times you even need special programs (converters) just to upgrade configuration files to newer versions.
Of course the UNIX approach has its drawbacks too. First of all casual users do not really like to manually edit text files. While a UNIX administrator is happy that with a single SSH shell and his trusty VI editor can completely (and remotely) manage the whole system, a non-expert user prefers GUI dialogs with buttons and entries for configuration parameters. Then there is the problem of the actual text format. While the configuration of most programs in a UNIX system are in text, the exact layout of the text file differs from application to application. A comment can start with #,; or % for example. Comments may or may not span multiple lines. The order of lines may be important or not. Some lines will be in blocks some other will not. You get the idea. The fact that other UNIX programs also use text files for input (Makefiles, Latex, e.t.c) makes things even worse. A non-expert user is afraid that she even may change the configuration file to a non valid state which will be not understood by the application.
Another problem (from the development view) is the fact that each application must now implement a text parser for its specific file format. While specialized tools exist for this purpose (lex/flex, yacc/bison), for small applications this is simply an overkill. Not to mention the fact that text parsing is almost always slower that reading binary data. For small configuration files this is not a problem but for huge applications this becomes quickly evident.
Finally a big question is what happens when someone changes the configuration file while the UNIX application is actually running. If the application does not support this, one must simply restart it so that the new changes take effect. Otherwise the application is informed that its configuration file has changed and it automatically fetches the new values from disk. There is even a well-accepted convention just for UNIX servers for this reason. Once an application of this kind receive an NOHUP UNIX signal it is expected to read again from the disk its configuration file and adapt accordingly. So in effect the NOHUP signal is the "restart" signal.
When XML appeared on the scene people started using it for many things and one of them was of course configuration files. While XML may be marketed as the universal format of the Internet we are not really sure that applications really gain from storing configuration in XML. The fact remains that the application must implement a text parser. And in this case the parser must be also an XML validator so the complexity and effort is greater for the programmer. Also, since XML files are either valid or not by definition, it is easy for a non-expert user to make an XML file unreadable after manual editing. A single syntax errors means that the application must reject the whole XML file. This does not happen with traditional UNIX applications which could dismiss lines they do not understand and load the rest of the values. Today several applications indeed use XML for storing configuration but it is not yet clear if this is an improvement or not over the past.
Ecore breaks away from the traditional UNIX approach and offers a configuration API which is based on binary format. While this decision may seem controversial at first, it is actually well thought of. Ecore provides functions used to store primitives on disk without specifying any additional details of where and how (the location or format of the file that is).
|Integer||A simple number|
|Float||Floating point number|
|Colour||RGB description of a colour|
|Theme||Definition of a theme|
|Boolean||Binary (true/false) value|
Notice that you do not need to write any code on how to store and load these values. All the low-level code is handled by Ecore. The values are stored in the home directory of the user that runs your application in the file $HOME/.e/apps/YOUR_APP/config.eet. Notice the .eet extension. Ecore uses the Eet Storage library for configuration which is the same one used by Edje for themes (and Enlightenment for backgrounds, eapps, themes, splash screens e.t.c). The only thing that matters to you as a programmer is the name of the value that you can use to load and store information. Everything else is abstracted away by Ecore.
So why this approach is better? First of all binary files are (as expected) faster that text files. Secondly you don't need to deal with any text parsing at all. Your application does not contain any low level I/O code at all. It just links to the Ecore_Config library. You need of course to provide some GUI for your users to change the values if that is required.
The fact that all configuration files are actually Eet files gives applications two advantages. Eet is designed so that its files are architecture independent. Despite being binary Eet files can be freely moved around on different systems. Additionally it is trivial to program a command line application which will read/dump the values stored on any configuration file. Therefore universality is accomplished in a way too. Expert users who want to bypass the GUI and directly edit in the command line can do so, since their Eet reading application will be compatible with all configuration files that use Ecore for storage. The Eet library is open source so the binary format does not need reverse engineering.
Last thing to notice is that Ecore gives you the capability of Configuration Listeners. These Listeners register to configuration parameters and when they are changed they trigger the callback function you have specified. This means that you don't need special "restart" code. Your application can be informed during run-time on configuration changes and act accordingly.
In summary, Ecore provides a unified way to store configuration values which makes things easier for the programmer. It may feel a bit strange to know that your application stores configuration in binary but you should quickly see the advantages.
You might be surprised to read that Ecore provides IPC and networking abstractions but not any kind of thread API. Thread support seems to be important these days and most support libraries (as Ecore in the case of EFL) usually offer some sort of wrapper around UNIX threads. The fact is that Ecore takes a completely different approach when it comes to "parallelism". Rather than employing threads, Ecore focuses instead on a powerful event loop mechanism. If you know everything about thread versus event based programming feel free to skip ahead.
Console programs are straightforward to program when it comes to parallelism. The application is in control, while the user just waits the execution to finish. Interaction happens either before the application starts (command line arguments) or only at rare cases during runtime. In the latter case the application stops working and asks the user for required input. With GUI applications the situation is reversed. The user is now in control and the application must respond to user actions (which come in the form of events). Since a GUI application must continue working and updating its window even when the user has assigned some work to it, a form of parallelism is needed. The GUI application must do at least two things at once (GUI in the foreground, processing in the background).
Threads come in the rescue for this kind of problem. One thread is managing the GUI and one or more are processing in the background. The concept is well known but also well known is the fact that thread programming is difficult. When threads have to share common resources the programmer must be extra careful to avoid racing conditions and use locking to avoid corruption of data. Without getting into details, we should just say that a badly written threaded application has bad performance in the best case (because of locks) and serious problems in the worst (deadlocks which result in application freezing). Threads need also special libraries for implementation and special debugging support from the run-time system.
An alternative approach for this is event driven programming. Here all pending actions (jobs to do) are queued in a single "list". The running application looks at this queue, selects one job to serve, then comes back, selects another one and so on. There is only one control flow at a time which simplifies programming (no locks/racing conditions). If you have ever used the poll() or select() UNIX system calls which act on file descriptors you are already familiar with event handling. Of course even driven programming has its drawbacks too. The performance is not always optimal if the queue is too large (compared with using threads). Threads also have gained great momentum with the coming of multiprocessors (where a thread can be served by another CPU in a truly parallel way). The following table compares the two different approaches.
|Good for||Many independent workloads||A few intermixed workloads|
|Bad for||Too many shared resources||Too many workloads|
|Ideal in||Multi processor/core systems||Single processor/core systems|
Ecore chooses the Event-driven approach. Notice than in the case of uniprocessor systems, since only one control flow is active at a time, you never have true parallelism no matter the approach you choose. It is just a matter of convenience.
The Ecore event loop already deals away with a lot of events. You do not need to write event handlers for several window actions such as moving/resizing/exposing. You do not even need to decide when to repaint your main window (previously shown in the Evas chapter). In general if your application is simple enough you do not need to deal with events at all. Just draw your items in Evas/Edje and everything is done automatically for you behind the scenes. When the interface changes (values updated, UI elements added/removed) the application will manage everything by itself.
So why do we devote a separate section on the Event loop in Ecore? For the simple reason that you have some capabilities not easily found in other toolkits. The first is that you can add manually jobs in the event loop of the application. These will be served by Ecore in a best effort manner. This means that they will be served eventually by the application but you cannot predict when exactly.
The second capability (which is more interesting) is that you are able to decide what your program does when idle. That is, you can specify a callback function for situations where your application waits for I/O or user input. The callback function will be run using whatever CPU percentage is available to the application. Taking this idea a bit further, Ecore additionally allows to define what happens when the application enters and exits the idle state. In result, you can program a really complex EFL application without using any threads at all and delegate all processing into "idler" functions. This gives EFL programmer great flexibility.
If you still believe that threads are essential, you might not know that your X-Server is a single user-level process (no ties with the kernel OS) which handles all on screen drawing via Events. If a whole implementation of the X architecture is possible with events then certainly your application can refrain from using threads too.
Closing this section, we need to note that if you need to run a function at a specific interval during run-time you are always free to use the traditional timers which are offered by Ecore.