A la demande de nombreux lecteurs, nous ouvrons une rubrique programmation sous Linux. Vous trouverez tous les mois des articles destinés à vous convaincre qu'Unix mérite amplement son surnom de "Programmer's dream". Comprenons nous bien: cette série d'articles n'est en aucun cas une initiation à la programmation. Elle s'adresse à ceux qui possèdent les bases du métier et souhaitent simplement se mettre à Lionux. En particulier, la connaissance du C est indispensable et pour ce qui est de la programmation X, il faut également possèder quelques notions de programmation orientée objets (relisez au moins l'article sur les ressources).
Aujourd'hui, nous allons commencer l'exploration de X-Window et en particulier du X Toolkit.
X11 est un véritable chaméléon, tant pour l'utilisateur que pour le programmeur. Nous allons nous intéresser à la manière "officielle" de le programmer, en passant par le X Toolkit, dont Fred vous a déjà un peu parlé dans son article sur Motif.
X-Window est un système client-serveur organisé en couches dont il faut se faire une petite idée. Le mot-clef est "client-serveur": un travail effectué sous X Window fait intervenir divers protagonistes qui ne tournent pas forcément sur la même station, ni le même système.

C'est la base de tout le système. Ce serveur s'exécute localement sur une station de travail (quel que soit son système d'exploitation) et son rôle est principalement d'exécuter les ordres graphiques et gérer les événements. Les clients communiquent avec lui grâce au protocole X11, qui permet la communication aussi bien entre un serveur et un client sur la mêeme machine que d'un bout du monde à l'autre à travsers Internet.
Il serait théoriquemzent possible d'écrire une application X complète en faisant tout "à la main", c'est à dire en ouvrant une connexion à un serveur et en dialoguant avec lui à travers un pipe par read et wrtie. Il est toutefois évident que ce serait un exercice de pur masochisme (je n'ai pas envie de passer ma vie à écrire un programme incompréhensible et pas portable pour un sou!)
Les appels à X se font normalement par la bibliothèque Xlib, qui contient l'API complète de X Window. Elle se charge de communiquer avec le serveur et lui transmettre vos requêtes lancées par l'appel des fonction Xlib. Par ailleurs, elle peut effectuer de nombreux calculs en local, sans solliciter le serveur, ce qui permet d'améliorer l'efficacité.
Le serveur X et la Xlib ne constituent pas encore un environnement graphique mais un support sur lequel un tel environnement peut être construit. Afin de gérer boîtes de dialogue et autres menus déroulants, il faut une brique supplémentaire.
Le Xt est un environnement orienté objet qui permet de construire les interfaces à l'aide des "widgets", des sortes de briques de Lego, autonomes et réutilisables, qui peuvent s'assembler pour consituer les applications. Si la plupart des widgets sont des objets d'interface classiques (boutons, ascenceurs), il y en a aussi de plus originaux, comme le Mailbox qui réagit à la réception d'un mail, un browser HTML ou encore l'éditeur Emacs lui-même!
L'une des particularités du Xt est d'être implémenté en C et non en C++. Tant qu'on n'utilise que des widgets existants, c'est d'une limpidité déconcertante, mais si vous voules créer un nouveau widget, ça devient assez ésotérique (je n'ai pas dit difficile)! Du point de vue du programmeur, les widgets sont simplement des variables du type Widget, totalement opaques au C (comprenez par là qu'il ne faut jamais aller voir "ce qu'il y a dedans", mais toujours passer exclusivement par les appels documentés).
Mais le Xt ne définit pas encore des widgets mais seulement toute la mécanique qui permet de travailler avec. Le Xt ne contient en fait que les Intrinsics, propriétés génériques de tous les widgets, et quelques widgets élémentaires comme le Core dont tous les autres widgets héritent.
La dernière couche est la bibliothèque de widgets utilisée. Il y en a vraiment beaucoup, les plus connues sont Xaw et Motif. Remarquons qu'il est tout à fait possible de mixer des widgets de provenance différente au sein d'une même application, mais c'est assez stupide!
L'empilement de ces couches peut se représenter à l'aide du schéma désormais classique, apparaissant dans tous les ouvrages traitant de la programmation sous X11:

Nous allons réaliser un petit utilitaire, afin que vous puissiez voir le Xt en action. Cet utilitaire, baptisé Xdown, vous permet de lacner un shutdown en appuyant sur un bouton, comme sous MacOS ou Windows. Il aura sûrement une place d'honneur dans le menu principal du root!
On commence par inclure les entêtes standard:
#include <stdlib.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
On charge maintyenant les entêtes des widgets que nous allons utiliser. Nous nous servons de ceux de la bibliothèque Xaw que tout le monde possède (contrairement à Motif)
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Command.h>
Le widget Form est un conteneur, c'est à dire in widget qui contient d'autres widgets arrangès selon un certain schéma (ici dans un formulaire).
Le widget Command est un simple bouton: il va déclencher le shutdown lorsqu'on cliquera dessus.
Widget application, form, bouton;
void main(int argc, char **argv) {
La première chose à faire est initializer le Xt.. L'appel suivant réalise cette tâche et crée le widget principal de l'application. Le premier paramètre est le nom de l'application, le second est sa classe (rappelez-vous l'article sur les ressources: elle doit toujours commencer par une Majuscule), vient ensuite la liste d'options et leur nombre (on en aprlera une autre fois) et enfin les paramètres de la ligne de commande.
application=XtInitialize(argv[0], "Xdown", NULL, 0, &argc, argv);
Maintenant que le widget racine est créé, il faut lui donner une taille. Pour cela, on utilise la fonction XtVaSetValues qui permet de modifier "au vol" les valeurs des ressources d'un widget. On donne d'abord le widget, puis alternativement la ressource et sa valeur ety enfin un NULL pour signaler que la liste est terminée.
XtVaSetValues(application, XtNwidth, 200, XtNheight, 130, NULL);
Nous allons à présent créer notre formulaire en invoquant le constructeur du widget Form. La fonction suivante s'en occupe. Il faut donner d'abord le nom de l'instance du widget, puis sa classe, son parent et enfin une liste de ressources, comme dans XtVaSetValues.
form=XtVaCreateManagedWidget("form", formWidgetClass, application, NULL)
;
On crée de la même manière le bouton, qui se trouve dans le formulaire.
bouton=XtVaCreateManagedWidget("down", commandWidgetClass, form,
XtNlabel, "Shutdown", NULL);
A présent, il faut dire au widget bouton que doit-il faire lorsqu'on clique dessus. La fonction suivante permet de poser un "Callback", c'est à dire déclarer la fonction à appeler lorque l'événement attendu se produt. Vous devinez que le premier paramètre est le widget auquel on donne ce callback et le troiqsième paramètre est un pointeur sur la fonction à rappeler. Nous ne aprlerons pas du rôle du second paramètre cette fois, et le qautrième est un pointeur sur les "client data", c'est à dire un pointeur que le widget n'utilise pas mais qu'il transmet à la fonction lorsqu'il l'appelle.
XtAddCallback(bouton, XtNcallback, shutdown, NULL);
On termine par deux fonctions "magiques": la première dessine le widget donné en paramètre ainsi que ses descendants (c'est à dire, dans notre cas, tout ce qu'on a créé) et la seconde passe la main au Xt pour que l'application prenne vie. A partir de cet instant, tout marche!
XtRealizeWidget(application);
XtMainLoop();
}
Il nous reste à écrire la fonction shutdown. Elle est plutôt triviale:
void shutdown(Widget widget, XtPointer ev, XtPointer client) {
system("shutdown -h now");
}
Observez ses paramètres: le premier est le widget qui l'a appelé, le secont un pointeur sur l'événement qui a provoqué cet appel (on y reviendra) et le troisième est le fameux pointeur client data. Toutes les fonctions de callback ont ce même prototype.
Vous pouvez maintenant compiler ce petit programme en tapant:
gcc xdown.c -o xdown -L/usr/X11/lib -lXaw -lXt -lX11
et admirer le résultat. Si vous avez envie de programmer, réalisez un programme identique sous Windows ou MacOS et comparez le nombre de lignes!
Je vous laisse méditer sur ce petit exemple. En attendant la prochaine fois, avec des exercices plus complets, essayez déjà de jouer avec: modifiez par exemple les ressources, utilisez editres, ajoutez un bouton "cancel"... Vous avez sous les yeux 80% de ce qu'il faut connaître pour développer des applications avec le Xt!
Jakub Zimmermann
zimmerma@ie2.u-psud.fr