Ce document est le premier d'une série d'articles sur la programmation sous GNOME. Nous commencerons doucement par les principes de programmation des interfaces graphiques puis nous étudierons successivement des sujets allant de la gestion de sessions à l'utilisation de CORBA, en passant par le dessin dans le cannevas. Ce mois ci, premier pas dans l'environnement Gnome.
Si vous lisez Linux Magazine France , vous savez déjà que Linux est un système d'exploitation merveilleux. Si vous programmez déjà sous Linux, vous savez aussi que c'est un environnement de développement de choix. Mais vous aurez aussi très certainement remarqué que, jusqu'à une date récente, il était très difficile d'y développer des applications avec interface graphique. Un grand nombre de solutions existaient, mais aucune n'était pleinement satisfaisante. Depuis l'apparition de Gtk, il est enfin possible de développer librement des applications puissantes et conviviales sans effort. Gimp est probablement l'exemple le plus connu, et pour cause (GTK signifie Gimp ToolKit). Cependant, certaines tâches récurrentes dans le développement d'applications ne peuvent être traitées dans une librairie graphique. Citons en vrac, la gestion des fichiers de configuration de votre application, du son, des formats d'images, des aides, des communications inter processus, des accès réseau. Cette liste n'est évidemment pas exhaustive. Par ailleurs des applications, même développées avec Gtk, peuvent avoir des aspects et des modes de fonctionnement complètement différents. Du point de vue de l'utilisateur, cela implique une période de prise en main répétée pour chaque nouvelle application. L'utilisation de Gnome vous permettra de résoudre efficacement l'ensemble de ces problèmes.
Dans ce premier article, nous allons passer rapidement en revue les avantages essentiels du développement sous Gnome. Nous ferons ensuite nos premiers pas dans ce nouvel environnement. Nous verrons comment compiler une application Gnome, puis à titre d'exemple, nous écrirons notre premier programme Gnome. Nous lui ajouterons une barre de menus, puis une barre d'outils. Les images ci jointes montrent notre exemple dans deux configurations utilisateur différentes.
Gnome pour l'utilisateur
Programmer une application Gnome, c'est avant tout faire le choix de l'utilisabilité. Gnome, avant d'être un environnement de programmation, est un environnement utilisateur. Il est fourni en standard avec un gestionnaire de fichiers, un gestionnaire de bureau, un panel, un panneau de contrôle. Les applications sont automatiquement prises en charge par le gestionnaire de sessions. Ainsi, à chaque redémarrage de l'environnement, les applications sont relancées automatiquement, et les documents en cours d'édition sont rechargés dans les applications.
Les parties communes à toutes les applications Gnome sont configurées via le panneau de contrôle central, permettant notamment à l'utilisateur de personnaliser les interfaces graphiques de toutes ses applications en une seule opération.
D'autre part, la majorité des opérations entre les applications ou au sein d'une même fenêtre peuvent se faire via le Drag'n'Drop.
La liste des avantages offerts à l'utilisateur est longue et ne peut être parcourue exhaustivement ici.
Gnome pour le développeur
Programmer une application Gnome, c'est aussi faire le choix de la performance et de la fiabilité. En utilisant les librairies utilisées par des milliers d'autres programmeurs, vous éviterez de nombreux écueils. Vous gagnerez du temps, en évitant de réinventer la roue, mais surtout en utilisant des composants logiciels qu'un seul développeur ne peut physiquement créer seul. Une application Gnome sait, par exemple, en standard, se déclarer au gestionnaire de sessions, elle sait lire les fichiers de configuration par défaut mis en place par l'administrateur, mais aussi les fichiers de configuration personnalisés de l'utilisateur. Elle sait communiquer avec les autres applications via CORBA, peut afficher une applet dans le panel ou ajouter un module dans le centre de contrôle. Elle sait communiquer avec le serveur de son (esound) et émettre des sons même si une autre application utilise déjà les ressources audio. Elle sait lire toutes sortes de formats d'images et les afficher dans toutes les résolutions et ce quel que soit le nombre de couleurs disponibles sur le serveur X. Elle peut afficher des graphiques anti-aliasés (c'est à dire sans effet d'escalier) et en transparence grâce au, déjà fameux, canevas. Vous pourrez développer vos application en C, en C++, en Objective C, en Perl, en Python, ou encore en Scheme. Là aussi, la liste est longue, et la place nous manque pour décrire les horizons qui s'offrent à vous.
Rappelons enfin que Gnome sera inclu en standard dans les prochaines distributions Debian et Redhat.
Il est temps maintenant de nous aventurer dans le monde de Gnome, petit à petit.
Compiler une application Gnome
Pour la suite de l'article, nous supposerons que l'environnement de développement Gnome est installé sur votre machine. Si tel n'est pas le cas, allez chercher les paquetages précompilés sur le site mirroir ftp.fr.gnome.org.
Si vous n'avez pas de connexion internet, attendez les prochaines versions des distributions Debian ou Redhat.
Suivant les bonnes habitudes établies par les développeurs de Gtk+, l'équipe de Gnome a inclu un programme destiné à simplifier vos lignes de compilation. Cette commande s'appelle gnome-config. Tapez simplement "gnome-config --help" dans une fenêtre shell pour avoir la liste complète des options de ce programme. Dans le cadre de cette introduction, nous n'utiliserons "gnome-config" que de deux façons différentes:
gnome-config --cflags liste de modules
gnome-config --libs liste de modules
La première ligne renvoie les options à indiquer à gcc lors de la compilation des fichiers (il s'agit essentiellement des chemins indiquant où trouver les fichiers ".h" de Gnome). La seconde donne les options permettant d'effectuer l'édition de liens (c'est à dire la liste des librairies à inclure ainsi que les repertoires où les trouver).
Dans les deux lignes précédentes, la liste de modules est à remplacer par l'ensemble des modules de Gnome que vous utiliserez. Par exemple, si votre programme a une interface graphique Gnome standard, mais crée aussi une applet dans le panel, vous préciserez les modules "gnomeui" et "applet".
La liste complète des modules est accessible via la commande
"gnome-config --help".
Pour l'instant, nous n'utiliserons que le module "gnomeui" (ce qui veut dire Gnome User Interface - Interface Utilisateur Gnome). Ainsi, supposons que votre application Gnome tienne dans un seul fichier source appelé "mon_app.c", la ligne de compilation sera :
gcc -c mon_app.o `gnome-config --cflags gnomeui` mon_app.c
et la ligne d'édition de liens sera :
gcc -o mon_app mon_app.o `gnome-config --libs gnomeui`
(Les cha"nes entre deux caractères " ` " sont interprétées par le shell et remplacées par le résultat)
Premier programme Gnome
Comme nous vous l'avons déjà indiqué plus haut, un programme avec interface graphique sous Gnome est avant tout un programme Gtk. Les objets graphiques de Gnome ne sont ni plus ni moins des objets Gtk spécialisés. Nous vous renvoyons d'ailleurs à l'article d'introduction à Gtk paru dans le numéro 1 de Linux Magazine France pour plus de détails concernant les fondements de la programmation en Gtk.
Certains détails, cependant, différencient une application Gnome d'une application Gtk. Par exemple :
- Vous appellerez la fonction "gnome_init" plutôt que "gtk_init".
- Vous créerez un object "GnomeApp" plutôt qu'un objet "GtkWindow" pour creer la fenêtre principale de votre application.
Voici le listing d'un programme Gnome complet. En dehors des deux particularités mentionnées ci-dessus, ce programme pourrait être un programme Gtk. D'ailleurs, pour l'instant, il ne fait rien qu'un programme Gtk ne pourrait faire simplement. Vous verrez pourtant, au cours des différents sujets que nous aborderons, que les conséquences de l'introduction des quelques instructions Gnome vont être fondamentales.
/************************************************/
/* LFM1.c */
/* */
/* Pour compiler cet exemple, copiez/collez ces */
/* lignes dans une fenetre shell */
/*
gcc -o LFM1 `gnome-config --cflags gnomeui` \
LFM1.c `gnome-config --libs gnomeui`
*/
/************************************************/
/* inclure le header principal de Gnome */
/* il se chargera d'inclure tous les headers */
/* necessaires a la compilation utilisant les */
/* librairies Gnome */
#include <gnome.h>
/* Callback appele lorsque l'utilisateur clique */
/* sur le bouton principal de l'exemple */
static void
button_cb (GtkWidget *widget, void *data)
{
g_print ("Fin du programme d'exemple\n");
gtk_main_quit ();
return;
}
/* Callback appele lorsque l'application recoit */
/* un signal indiquant qu'elle va etre fermée. */
/* C'est la par exemple que vous demandriez */
/* confirmation a l'utilisateur ou que vous lui */
/* proposeriez de sauver ses documents. */
/* L'application recoit le signal "delete_event" */
/* principalement lorsque le gestionnaire de */
/* fenetre tente de detruire sa fenetre */
/* principale */
static void
quit_cb (GtkWidget *widget, void *data)
{
gtk_main_quit ();
return;
}
/* Creer un objet graphique. Ici il s'agit d'un */
/* bouton contenant un simple texte. Cela */
/* pourrait etre n'importe quel descendant du */
/* type "widget". */
static GtkWidget *
create_main_widget()
{
GtkButton *button;
/* creer le bouton principal de la
fenetre d'exemple ... */
button = GTK_BUTTON(gtk_button_new_with_label
("Quitter le programme d'exemple"));
/* et quand l'utilsateur clique dessus,
appeler la routine "button_cb" */
gtk_signal_connect (GTK_OBJECT (button),
"clicked",
GTK_SIGNAL_FUNC (button_cb), NULL);
/* mettre de l'espace autour du bouton pour
faire joli */
gtk_container_set_border_width
(GTK_CONTAINER (button), 60);
return GTK_WIDGET(button);
}
int
main(int argc, char *argv[])
{
GtkWidget *application;
GtkWidget *main_widget;
/* la precieuse fonction d'initialisation
des librairies Gnome */
gnome_init ("Bonjour", "1.0", argc, argv);
/* creer l'objet Gnome de Haut niveau */
application = gnome_app_new
("Linux France Magazine 1",
"Premier programme d'exemple");
/* lorsque la fenetre recoit l'ordre
de se fermer, appeler le callback
"quit_cb" */
gtk_signal_connect (GTK_OBJECT (application),
"delete_event",
GTK_SIGNAL_FUNC (quit_cb), NULL);
/* creer l'objet graphique principal */
main_widget = create_main_widget();
/* ajouter le bouton a la fenetre
principale de l'application */
gnome_app_set_contents (
GNOME_APP (application), main_widget);
/* dire a tout le monde de se montrer */
gtk_widget_show (main_widget);
gtk_widget_show (application);
/* donner la main a la boucle de traitement
des evenements de GTK */
gtk_main ();
return 0;
}
Eclaircissons un peu le rôle joué par la fonction "gnome-init". C'est elle qui est chargée d'initialiser pour vous l'ensemble des ressources auxquelles une application Gnome peut faire appel. C'est elle, par exemple, qui va initialiser les sons et lire les fichiers de configuration (personnalisés via le panneau de contrôle de Gnome). C'est elle qui se chargera d'initialiser imlib (gestion performante des images), qui contactera le gestionnaire de sessions. Bref, elle fait à votre place énormément de choses très utiles qu'il serait fastidieux de faire vous même.
L'objet "GnomeApp" quant à lui est une fenêtre Gtk à laquelle vous pouvez attacher très simplement des barres de menus, des barres d'outils et des barres d'états. C'est aussi cet objet qui gèrera vos raccourcis clavier.
Avançons maintenant un petit peu. Nous allons consacrer la fin de cet article à quelques exemples de ce que vous pourrez ajouter à vos fenêtres Gnome. Ces exemples vous permettront de vous familiariser avec les méthodes de programmation sous Gnome.
Ajouter une barre de Menus.
Ajouter une barre de menus à un objet GnomeApp se fait via l'appel de la fonction
gnome_app_create_menus (application, main_menu)
"application" est l'objet de type "GnomeApp" auquel vous voulez ajouter une barre de menus.
"main_menu" est un vecteur de structures de type "GnomeUIInfo".
Les structures "GnomeUIInfo" sont très génériques et servent aussi bien à définir des arborescences de menus que des éléments de barres d'outils ou encore des cases à cocher. Pour les créer, vous disposez d'un grand nombre de macros prédéfinies et adaptées à la majorité des cas que vous rencontrerez.
Cela ne vous parait pas très clair ? Les exemples qui suivent vous éclaireront très probablement.
Nous allons créer une barre de menus constituée, pour l'instant d'un seul menu. Ce menu portera le nom "Fichier".
Créons donc une structure "main_menu" qui définisse cette barre de menus :
GnomeUIInfo main_menu [] = {
GNOMEUIINFO_SUBTREE ("Fichier", &file_menu),
GNOMEUIINFO_END
};
Lorsque l'utilisateur cliquera sur l'étiquette "Fichier" de la barre de menus, un menu appara"tra. Ce menu est défini dans la structure nommée "file_menu". Nous voulons que ce menu ne contienne qu'un élément appelé "Sortir" permettant de quitter l'application. Cet élément doit, en plus du texte, posséder une petite icône de menu :
GnomeUIInfo file_menu [] = {
GNOMEUIINFO_ITEM_STOCK ("Sortir", NULL, quit_cb, GNOME_STOCK_MENU_EXIT),
GNOMEUIINFO_END
};
Pour les actions standards, Gnome possède de nombreux éléments graphiques par défaut. Dans les menus, ces éléments sont accessibles, par exemple, via la macro :
GNOMEUIINFO_ITEM_STOCK ( texte, tooltip, callback, ref_icone )
où "texte" est la cha"ne de caractères à afficher dans le menu, "callback" est la routine à appeler quand l'utilisateur clique sur cet élément, et "ref_icone" est à remplacer par la référence de l'icône que vous voulez afficher. Ces références sont disponibles dans la documentation de l'objet "GnomeStock". Nous avons mis le paramètre "tooltip" à NULL car il ne peut pas être utilisé pour les éléments de menus. Sachez cependant qu'il représente une petite cha"ne de caractères qui est affichée dans une bulle d'aide lorsque l'utilisateur place sa souris sur l'élément.
Il existe d'autres macros de création d'éléments de menu, vous permettant notamment d'utiliser vos propres fichiers d'images plutôt que les icônes standards de Gnome. La liste de ces macros est disponible dans la documentation de gnomeui à la rubrique "gnome-app-helper". Vous constaterez, en lisant cette documentation, qu'il existe de nombreuses autres macros que celles que nous avons citées.
Par exemple, pour homogénéiser les applications Gnome, il est souhaitable que les éléments de menu communs aux applications soient exactement semblables. Dans notre exemple, un autre programmeur aurait très bien pu appeler l'élément de menu "Quitter" plutôt que "Sortir". D'autre part, nous verrons par la suite que vos applications peuvent être traduites. Quand bien même feriez-vous très attention que vos applications respectent les conventions de nommage, il serait très difficile de vérifier que les traducteurs fassent de même. Un certain nombre de macros ont donc été écrites pour vous simplifier la tâche. En les utilisant, nous aurions pu écrire :
GnomeUIInfo file_menu [] = {
GNOMEUIINFO_MENU_EXIT_ITEM(quit_cb, NULL),
GNOMEUIINFO_END
};
GnomeUIInfo main_menu [] = {
GNOMEUIINFO_MENU_FILE_TREE(file_menu),
GNOMEUIINFO_END
};
Ce que nous n'avons d'ailleurs pas fait pour des raisons pédagogiques uniquement.
Ajouter une barre d'outils.
Ajouter une barre d'outils ressemble fort à ajouter une barre de menus, à ceci près que cette fois-ci, il n'y a pas de structure arborescente. Les choses sont donc un peu plus simples. La commande à appeler pour ajouter une barre d'outils est
gnome_app_create_toolbar (application, main_toolbar)
"main_toolbar" est aussi un vecteur de structures de type "GnomeUIInfo".
Voici comment le créer :
GnomeUIInfo main_toolbar[] =
{
GNOMEUIINFO_ITEM_STOCK ("Sortir", "Quitter l'application", quit_cb, GNOME_STOCK_PIXMAP_QUIT),
GNOMEUIINFO_SEPARATOR,
GNOMEUIINFO_END
};
Le principe est exactement le même que dans le cas des définitions de menus. Remarquez toutefois que, cette fois-ci, nous avons defini le tooltip.
L'élément "GNOMEUIINFO_SEPARATOR" permet d'insérer une barre de séparation entre l'élément "Sortir" et l'élément que vous ajouterez ensuite. Ces barres de séparation apparaissent ou non, selon la configuration choisie par l'utilisateur dans le panneau de contrôle de Gnome.
Conclusion
Au cours de ce premier article, nous avons parcouru pas mal de chemin. Nous avons vu quels étaient les avantages des applications écrites pour Gnome. Nous avons appris à compiler simplement un programme Gnome. Nous en avons écrit un. Puis, nous avons vu comment y ajouter une barre de menus et une barre d'outils.
La prochaine fois, nous continuerons ce tour d'horizon des éléments graphiques de Gnome. Nous commencerons à aborder des sujets un peu plus pointus tels que, par exemple, le système d'aide.
references
Les exemples de programmes écrits au cours de cet article sont disponibles à l'adresse :
http://perso.cybercable.fr/guiheneu
La documentation de référence Gnome :
http://www.gnome.org/devel/docs/index.shtml
La documentation de référence Gtk+ 1.2
Le tutoriel Gtk+ 1.2 :
http://www.gtk.org/tutorial1.2/