This documentation presents the core library of Cairo-Dock: libgldi (GL Desktop Interface).
It is useful if you want to write a plug-in, add new features in the core, or just love C.
Note: to write applets in any language very easily, see http://doc.glx-dock.org.
The installation is very easy and uses cmake. In a terminal, copy-paste the following commands :
To install unstable plug-ins, add -Denable-xxx=yes to the cmake command, where xxx is the lower-case name of the applet.
Any element in libgldi is a _GldiObject.
An Object is created by an ObjectManager, which defines the properties and notifications of its children.
It has a reference counter, can be deleted from the current theme, and can be reloaded.
An Object can cast notifications; notifications are broadcasted on its ObjectManager.
An ObjectManager can inherit from another ObjectManager; in this case, all methods of the parent ObjectManagers are called recursively, and likewise all notifications on an Object are casted recursively to all parent ObjectManagers.
The core is divided in several internal modules, called Managers.
Each Manager manages a set of parameters and objects (for instance, the Dock Manager manages the list of all Docks and their parameters).
Containers are generic animated windows. They can hold Icons and support cairo/OpenGL drawing.
Icons are elements inside a Container on which the user can interact. For instance, a Launcher is an Icon that launches a program on left-click.
Docks are a kind of Container that sits on a border of the screen.
Desklets are a kind of Container that stays on the desktop and holds one or many icons.
Dialogs are a kind of Container that holds no icon, but rather point to an icon, and are used to display some information or interact with the user.
A Module is an Object representing a plug-in for libgldi.
It defines a set of properties and an interface for init/stop/reload.
A Module that adds an Icon is called an "applet".
Note: the cairo-dock-plug-ins project is a set of modules in the form of loadable libraries (.so files).
the cairo-dock-plug-ins-extra project is a set of modules in the form of scripts (Python or any language) that interact on the core through Dbus.
A Module-Instance is an actual instance of a Module.
It holds a set of parameters and data (amongst them the Applet-Icon if it's an applet).
A Module can have several instances.
libgldi keeps track of all the currently existing windows, with all their properties, and notifies everybody of any change. It is used for the Taskbar.
Each window has a corresponding _GldiWindowActor object.
See cairo-dock-windows-manager.h for more details.
Go to the "plug-ins" folder, and run the generate-applet.sh script. Answer the few questions, and you're done!
The script creates a <module-name> folder, with src and data sub-folders, which contain the following:
Note: when adding a new file, don't forget to add it in the CMakeLists.txt.
when changing something in the config file, don't forget to update the version number of the applet, in the main CMakeLists.txt.
when changing anything, don't forget to install (sudo make install)
Edit the file src/applet-inic.c; the macro CD_APPLET_DEFINITION is a convenient way to define an applet: just fill its name, its category, a brief description, and your name.
In the section CD_APPLET_INIT_BEGIN/CD_APPLET_INIT_END, write the code that will run on startup.
In the section CD_APPLET_STOP_BEGIN/CD_APPLET_STOP_END, write the code that will run when the applet is deactivated: remove any timer, destroy any allocated ressources, unregister notifications, etc.
In the section CD_APPLET_RELOAD_BEGIN/CD_APPLET_RELOAD_END section, write the code that will run when the applet is reloaded; this can happen in 2 cases:
Edit the file src/applet-config.c; In the section CD_APPLET_GET_CONFIG_BEGIN/CD_APPLET_GET_CONFIG_END, get all your config parameters (don't forget to define them in applet-struct.h).
In the section CD_APPLET_RESET_CONFIG_BEGIN/CD_APPLET_RESET_CONFIG_END, free any config parameter that was allocated (for instance, strings).
Edit the file src/applet-notifications.c;
In the section CD_APPLET_ON_CLICK_BEGIN/CD_APPLET_ON_CLICK_END, write the code that will run when the user clicks on the icon (or an icon of the sub-dock).
There are other similar sections available:
To register to an event, use one of the following convenient macro during the init:
Note: don't forget to unregister during the stop.
A lot of useful macros are provided in cairo-dock-applet-facility.h to make your life easier.
The applet instance is myApplet, and it holds the following:
There are 3 cases :
There are also a lot of convenient functions you can use to draw in OpenGL. See cairo-dock-draw-opengl.h for loading and drawing textures and paths, and cairo-dock-particle-system.h for an easy way to draw particle systems.
If you want to animate your icon easily, to signal some action (like Music-Player when a new song starts), you can simply request for one of the registered animations with CD_APPLET_ANIMATE_MY_ICON and stop it with CD_APPLET_STOP_ANIMATING_MY_ICON. You just need to specify the name of the animation (like "rotate" or "pulse") and the number of time it will be played.
But you can also make your own animation, like Clock of Cairo-Penguin. You will have to integrate yourself into the rendering loop of your container. Don't panic, here again, Cairo-Dock helps you !
First you will register to the "update container" notification, with a simple call to CD_APPLET_REGISTER_FOR_UPDATE_ICON_SLOW_EVENT or CD_APPLET_REGISTER_FOR_UPDATE_ICON_EVENT, depending on the refresh frequency you need : ~10Hz or ~33Hz. A high frequency needs of course more CPU, and most of the time the slow frequancy is enough.
Then you will just put all your code in a CD_APPLET_ON_UPDATE_ICON_BEGIN/CD_APPLET_ON_UPDATE_ICON_END section. That's all ! In this section, do what you want, like redrawing your icon, possibly incrementing a counter to know until where you went, etc. See the previous paragraph to draw on your icon. Inside the rendering loop, you can skip an iteration with CD_APPLET_SKIP_UPDATE_ICON, and quit the loop with CD_APPLET_STOP_UPDATE_ICON or CD_APPLET_PAUSE_UPDATE_ICON (don't forget to quit the loop when you're done, otherwise your container may continue to redraw itself, which means a needless CPU load).
To know the size allocated to your icon, use the convenient CD_APPLET_GET_MY_ICON_EXTENT.
Say for instance you want to download a file on the Net, it is likely to take some amount of time, during which the dock will be frozen, waiting for you. To avoid such a situation, Cairo-Dock defines Tasks. They perform their job asynchronously, and can be periodic. See cairo-dock-task.h for a quick explanation on how a Task works.
You can bind an action to a shortkey with the following macro: CD_APPLET_BIND_KEY.
For instance, the GMenu applet displays the menu on ctrl+F1.
You get a GldiShortkey that you simply destroy when the applet stops (with gldi_object_unref).
See cairo-dock-keybinder.h for more details.
In dock mode, your icon can have a sub-dock; in desklet mode, you can load a list of icons into your desklet. Cairo-Dock provides a convenient macro to quickly load a list of icons in both cases : CD_APPLET_LOAD_MY_ICONS_LIST to load a list of icons and CD_APPLET_DELETE_MY_ICONS_LIST to destroy it. Thus you don't need to know in which mode you are, neither to care about loading the icons, freeing them, or anything.
Cairo-Dock can build itself the config panel of your applet from the config file. Moreover, it can do the opposite : update the conf file from the config panel. However, it is limited to the widgets it knows, and there are some cases it is not enough. Because of that, Cairo-Dock offers 2 hooks in the process of building/reading the config panel : when defining your applet in the CD_APPLET_DEFINE_BEGIN/CD_APPLET_DEFINE_END section, add to the interface the 2 functions pInterface->load_custom_widget and pInterface->save_custom_widget. They will be respectively called when the config panel of your applet is raised, and when it is validated.
If you want to modify the content of an existing widget, you can grab it with cairo_dock_gui_find_group_key_widget_in_list. To add your custom widgets, insert in the conf file an empty widget (with the prefix '_'), then grab it and pack some GtkWidget inside. If you want to dynamically alter the config panel (like having a "new" button that would make appear new widgets on click), you can add in the conf file the new widgets, and then call cairo_dock_reload_current_module_widget to reload the config panel. See the AlsaMixer or Weather applets for an easy example, and Clock or Mail for a more advanced example.
Say your applet launches an external application that has its own window. It is logical to make your applet control this application, rather than letting the Taskbar do. All you need to do is to call the macro CD_APPLET_MANAGE_APPLICATION, indicating which application you wish to manage (you need to enter the class of the application, as you can get from "xprop | grep CLASS"). Your applet will then behave like a launcher that has stolen the appli icon.
Cairo-Dock offers a powerful and versatile architecture for this case : _CairoDataRenderer. A DataRenderer is a generic way to render a set of values on an icon; there are several implementations of this class : Gauge, CairoDockGraph, Bar, and it is quite easy to implement a new kind of DataRenderer.
Each kind of renderer has a set of attributes that you can use to customize it; you just need to call the CD_APPLET_ADD_DATA_RENDERER_ON_MY_ICON macro with the attributes, and you're done ! Then, each time you want to render some new values, simply call CD_APPLET_RENDER_NEW_DATA_ON_MY_ICON with the new values.
When your applet is reloaded, you have to reload the DataRenderer as well, using the convenient CD_APPLET_RELOAD_MY_DATA_RENDERER macro. If you don't specify attributes to it, it will simply reload the current DataRenderer, otherwise it will load the new attributes; the previous data are not lost, which is useful in the case of Graph for instance.
You can remove it at any time with CD_APPLET_REMOVE_MY_DATA_RENDERER.
Applets can be launched several times, an instance will be created each time. To ensure your applet can be instanciated several times, you just need to pass myApplet to any function that uses one of its fields (myData, myIcon, etc). Then, to indicate Cairo-Dock that your applet is multi-instanciable, you'll have to define the macro CD_APPLET_MULTI_INSTANCE in each file. A convenient way to do that is to define it in the CMakeLists.txt by adding the following line:
Say you want to draw directly on your container, like CairoPenguin or ShowMouse do. This can be achieved easily by registering to the NOTIFICATION_RENDER notification. You will then be notified eash time a Dock or a Desklet is drawn. Register AFTER so that you will draw after the view.