How to Create an Enlightenment Module

Module writing is one of the primary ways to expand the functionality of Enlightenment. By dynamically loading modules, the compositor is able to import code that has access to most Enlightenment internals. This allows developers to modify the desktop environment in nearly any way they can imagine, from new gadgets to compositor effects. This article will take a look at the basics of creating an Enlightenment module.

The first part of creating a module is setting up a .desktop file for it. This allows the module to be visible for users within the module configuration dialog. An example file looks something like this:

[Desktop Entry]
Type=Link
Name=My Module
Icon=e-module-mymodule
Comment=This is the description visible to the user
X-Enlightenment-ModuleType=Category

The ‘Name’ is the user-visible name of your module, and the ‘Icon’ is the filename of the .edj file which accompanies the module. The ‘Comment’ field provides supplementary information to the user that describes the functionality of the module. ‘Category’ is the category under which the module will be listed in the module configuration. With all of these fields provided the module will be displayed to the user with all possible information available.

Next up are the required hooks in the module code. These are namespaced symbols the compositor looks for when attempting to load a module. The first such symbol is the module API declaration:

E_API E_Module_Api e_modapi =
{
   E_MODULE_API_VERSION,
   "My Module"
};

The version here is used to ensure that the module has been compiled against a compatible version of Enlightenment; older modules will be prevented from loading to avoid crashes and other unintended behaviors resulting from ABI breakages. The second member of the struct is the module’s name.

Additionally, there are three function hooks which a module provides. The first one, the init function, is mandatory:

E_API void *(*e_modapi_init)(E_Module *m);

This function runs the necessary setup calls for the module, returning a non-null value that will be attached to the module object as its data pointer. If this function returns null, the module is considered to have failed to load and appropriate error messages will be displayed automatically to the user.

Modules also have access to a special function for saving data:

E_API int (*e_modapi_shutdown)(E_Module *m EINA_UNUSED);

This function is optional. When provided, it’s called whenever Enlightenment saves its configuration so that the module may also save its own configuration. The code for this function could be as simple as:

e_config_domain_save("module.mymodule", myconfig_eet_data_descriptor_struct, myconfig_struct);

This function returns 1 for success and 0 for failure, though the value is never checked.

Lastly, modules are able to have an optional shutdown function that is called whenever the module is unloaded:

E_API int (*e_modapi_shutdown)(E_Module *m EINA_UNUSED);

If this exists, it will trigger just prior to removing the module from configuration. This function can be used to clean up any persisting data structures or objects and it returns 1 on success and 0 on failure, but this value is never used.

That concludes the basics of Enlightenment module development. For some examples of existing module code, check out the repository category on git!

Author: Mike Blumenkrantz

Mike is the release manager for Enlightenment as well as a core developer of the EFL toolkit.