GCompris is made of 2 major distinct parts. The core and the activities.
The GCompris core
In many games the concept of a core has been introduced. The goal of the core is to separate the gaming data from the general and common utilities. For example, in GCompris we provide an advanced way to manage data resources, users, classroom, profiles. It is not up to each activity developer to take care of that. An API is provided to let them focus on what matters to them, making a fun and highly educational activity.
GCompris core provides:
- configuration: A configuration dialog that lets the user select his/her preferences. The preferences are saved in the home directory under ~/.config/gcompris/gcompris.conf
- activity database. Each activity describes itself with an xml based menu file. Having such a large number of activities requires a lot of processing time at startup. To avoid this, the first time GCompris is started, we create an sqlite database. This way, the next run will be faster.
- control bar: An activity can select which icons in the control bar are available to the user. It can also hide the bar when no control must be accepted.
- help: The inline help is extracted from the board menu. If no help is provided in the menu entry, the help button is not displayed in the bar.
- file manager: A simplistic but children friendly file manager.
- image selector: Provides a way for image drawing activities to let the children select an image. Images can come from a predefined dataset or by dynamically scanning a specified directory.
- dialog box: It's sometimes useful to display a dialog box that integrates well in GCompris and the current skin.
- locale: Unlike regular desktop applications, it may be useful to run GCompris in a target language. In this case, the user can select the language to use in GCompris. Only the language for which we have a translation, even if it is outdated, is listed.
- logging: A log with the date, activity, level/sublevel, success and in some cases bad response.
- skin: We provide a way to create new skins for GCompris. A skin must have a separate directory in boards/skins and must contain at least a file named skin.xml. Two skins are provided by default. It's easy to create one by creating new images and changing the content of skin.xml
- cursor: Activities can select an alternate cursor
- audio player: We include a threaded audio player which plays ogg vorbis encoded files (based on the SDL Mixer library or gstreamer). There are two threads. One is for background music and one is for voices and sound effects. Each one can be disabled independently in the configuration dialog.
- relative file loading: Activities do not have to care where files are located on the system.
- bonus: When an activity is complete, we can display different kinds of bonuses. Also available are audio voices to appreciate your efforts.
- timer: Some activities use this to restrict the user to a specified number of 'tries' or a timer.
- score: To display the current score within the activity.
- animation: An API to play predefined animations. All graphical object states can be described in a single file. Then, the activity will request a specific state of the object to be displayed. Each state points to a graphical image which can be a static image or an animated gif.
- activity configuration: Each activity can implement some specific configurations. For example, you may want to let the teacher play your activity only with capital letters. These options are saved within the sqlite database if present.
When GCompris is started, it first starts the menu named menu, unless a specific activity is provided using gcompris -l. In GCompris, the menu is an activity like any other one. Only its role is different. It is in charge of starting other activities.
GCompris doesn't know statically which menu entry goes with which activity code. When parsing the menus, it checks if it can find an activity code able to handle it. If not, the activity icon won't appear in the list.
When the child clicks on the activity, its start entry point is called. Then the activity code is in charge of the activity area. It needs to initialize it with its graphical elements and initiate the activity game. It must initialize the control bar to display only the relevant buttons.
When the activity is done, or the user clicks on the activity exit button, the end entry point is called. The activity must cleanup the display area and all its internal structure.
- Have a look also at the API of the gnomecanvas
- Check also GTK for documentation and tutorial for GTK programming.
- In order to keep the code portable, C code must be based on the GLib. Glib is the low-level core library that forms the basis of GTK+ and GNOME. It provides data structure handling for C, portability wrappers, and interfaces for such runtime functionality as an event loop, threads, dynamic loading, and an object system.
Each activity may be run and distributed independently. For example SugarLabs distributes each GCompris activities individually.
Each activity must have its own directory under src. It contains all it needs to be installed and run. For example, a python activity will have these files:
- myactivity.xml.in : the GCompris menu
- myactivity.py : The python source code
There are 2 ways to run GCompris: installed or in the source with runit.sh. In both cases we expect GCompris to find its images. What is important to see, when you run GCompris a line is display that looks like this:
- package_data_dir = /usr/local/share/gcompris/boards
Or like this with runit.sh:
- Overloaded package_data_dir = anim-activity//resources
This will be the base directory where GCompris will search for its resources, images, sounds, data file. This means that if you reference an image as gcompris.utils.load_pixmap("myimage.png") it expects to find the image in 'package_data_dir'.
But since we have a single 'package_data_dir' for the whole GCompris, we don't want each activity to overwrite others images. For if activity 'A' wants an image myimage.png and activity 'B' a different red.png, these would end up in the same directory. To avoid this, each activity loads its images this way:
This is why you have to create a directory resources/A in activity A.
The legacy way for creating new activities is to code them in C using GTK/GLib and the GooCanvas.
To make a clean separation between the core and the activity, each activity is an independent plugin. The plugin must implements a set of functions in order to be operated by the core:
Mandatory entry point:
- start: You are requested to start. You get the board display area for you to display your activity.
- end: You are requested to end now. Cleanup the board display area, free the memory.
- is_our_board: The activity is provided with a menu entry. It tell the core if it knows how to run it. This is the process we use to bind a menu entry to an activity. For python activities this is done auto magically by giving your activity class name the same as the one in the menu.
Optional entry point:
- pause: If your activity includes a timer, you must stop it. It is called when we display dialog over the activity like the configuration or the about box.
- set_level: The user clicked on the level change button. the activity must display the requested level.
- repeat: The user did not understood the goal of the activity. She want you to repeat the question.
- config: You can have a specific set of configuration option for your activity. If you implement this entry point, the core will display the 'configuration' icon in the bar. You then display a config dialog specific to your activity. The core provides an API to easily create such dialog. It will take care of the persistence, the options selected will be saved in the database.