Xlib
Xlib est le nom d'une bibliothÚque logicielle, offrant une implémentation de la partie cliente du protocole X Window System en C. Elle contient des fonctions de bas niveau pour interagir avec un serveur X. Ces fonctions permettent aux programmeurs d'écrire des programmes sans connaßtre les détails du protocole X. Peu d'applications utilisent la Xlib directement ; en général, elles exploitent d'autres bibliothÚques qui reposent sur la Xlib pour fournir des éléments d'une interface graphique.
Cette bibliothÚque est apparue autour de 1985, implémentée par XFree86, et elle est toujours trÚs utilisée par des systÚmes UNIX ou apparentés. Elle sert de base pour la plupart des toolkits graphiques de haut niveau comme :
- Intrinsics (Xt)
- Motif
- GTK
- Qt
Le projet XCB a pour objectif de se substituer Ă Xlib.
Types de données
Les principaux types de données de la Xlib sont les structures Display et les types des identificateurs.
En premiÚre approche, un display est un périphérique physique ou virtuel sur lequel les opérations graphiques sont effectuées. La structure Display de la bibliothÚque Xlib contient les informations à propos du display, mais sa partie la plus importante sont les informations sur le canal entre le client et le serveur. Par exemple, dans un systÚme d'exploitation de type UNIX, la structure Display contient le descripteur de la socket utilisée pour ce canal (il est possible de le retrouver avec la macro ConnectionNumber). La plupart des fonctions de la Xlib prennent une structure Display comme premier argument, car elles opÚrent sur un canal ou sont relatives à un canal particulier. Toutes les fonctions Xlib interagissant avec le serveur ont besoin de cette structure pour accéder au canal. Certaines autres fonctions, qui fonctionnent localement mais sur des données relatives au canal, nécessitent également cette structure pour identifier le canal. Ce sont par exemple les opérations sur les files d'événements, décrites plus bas.
Les fenĂȘtres, colormaps, etc. sont gĂ©rĂ©es par le serveur, ce qui signifie que les donnĂ©es Ă propos de leur implĂ©mentation sont toutes mĂ©morisĂ©es sur le serveur. Le client effectue des opĂ©rations sur ces objets en utilisant des identificateurs. Il n'a pas la possibilitĂ© d'agir directement sur les objets, il ne peut que demander au serveur d'effectuer une opĂ©ration sur un objet qu'il dĂ©signe par son identificateur.
Les types Window, Pixmap, Font, Colormap, etc. sont tous des identificateurs, qui sont convertis en nombres. Un client « crĂ©e » une fenĂȘtre en demandant la crĂ©ation d'une fenĂȘtre au serveur. Cette opĂ©ration est effectuĂ©e avec un appel Ă une fonction de la Xlib qui retourne l'identificateur de la fenĂȘtre, c'est-Ă -dire un nombre. Ce nombre peut ensuite ĂȘtre utilisĂ© par le client pour demander d'autres opĂ©rations sur la mĂȘme fenĂȘtre au serveur.
Les identificateurs sont uniques sur le serveur. La plupart permettent Ă diffĂ©rentes applications de rĂ©fĂ©rencer les mĂȘmes objets. Par exemple, deux applications connectĂ©es au mĂȘme serveur peuvent utiliser le mĂȘme nombre pour faire rĂ©fĂ©rence Ă la mĂȘme fenĂȘtre. Ces deux applications utilisent deux canaux diffĂ©rents, et ont par consĂ©quent deux structures Display diffĂ©rentes ; toutefois, quand elles demandent des opĂ©rations sur le mĂȘme identificateur, ces opĂ©rations affectent le mĂȘme objet.
Protocole et événements
Habituellement, les fonctions Xlib qui produisent des requĂȘtes pour le serveur ne les envoient pas immĂ©diatement, mais les mĂ©morisent dans un tampon, appelĂ© « tampon de sortie » (output buffer). Dans le prĂ©sent cas, le terme sortie fait rĂ©fĂ©rence aux donnĂ©es qui sortent du client pour aller vers le serveur : le tampon de sortie peut contenir tout type de requĂȘtes, et pas seulement celles qui ont un impact visible sur l'Ă©cran. Le tampon de sortie est assurĂ© d'ĂȘtre vidĂ© (c'est-Ă -dire que toutes les requĂȘtes sont envoyĂ©es au serveur) aprĂšs un appel aux fonctions XSync ou XFlush, un appel Ă une fonction qui retourne une valeur depuis le serveur (ces fonctions sont bloquantes jusqu'Ă ce qu'une rĂ©ponse soit reçue), et dans certaines autres conditions.
Xlib mémorise les événements reçus dans une file d'attente. L'application cliente peut inspecter et récupérer les événements de cette file. Alors que le serveur X envoie des événements asynchrones, les applications utilisant la bibliothÚque Xlib doivent appeler explicitement les fonctions de la Xlib pour accéder aux événements de la file. Certaines de ces fonctions sont bloquantes ; et dans ce cas, elles vident également le tampon de sortie.
Les erreurs sont quant à elles reçues et traitées de maniÚre asynchrone : l'application fournit un gestionnaire d'erreur, qui est sollicité quand un message d'erreur du serveur est reçu.
Le contenu d'une fenĂȘtre n'est pas assurĂ© d'ĂȘtre prĂ©servĂ© si elle est entiĂšrement ou partiellement recouverte. Dans ce cas, l'application reçoit un Ă©vĂ©nement Expose quand la fenĂȘtre est Ă nouveau visible. L'application est alors supposĂ©e redessiner le contenu de la fenĂȘtre Ă nouveau.
Fonctions
Les fonctions de la bibliothĂšque Xlib peuvent ĂȘtre regroupĂ©s de la façon suivante :
- Les opérations sur la connexion (XOpenDisplay, XCloseDisplay...) ;
- Les requĂȘtes vers le serveur, y compris les requĂȘtes pour opĂ©ration (XCreateWindow, XCreateGC...) et les requĂȘtes pour information (XGetWindowProperty ...) ;
- Les opérations locales au client : les opérations sur la file des événements (XNextEvent, XPeekEvent...) et les autres opérations sur les données locales (XLookupKeysym, XParseGeometry, XSetRegion, XCreateImage, XSaveContext...).
Exemple
Le programme suivant crĂ©e une fenĂȘtre contenant un petit carrĂ© noir Ă l'intĂ©rieur.
/*
* Application Xlib simple affichant un carrĂ© dans une fenĂȘtre.
*/
#include <X11/Xlib.h>
#include <stdio.h>
int main() {
Display *d;
int s;
Window w;
XEvent e;
/* Ouvrir la connexion avec le serveur. */
d = XOpenDisplay(NULL);
if (d == NULL) {
printf("Impossible d'ouvrir le Display\n");
return 1;
}
s = DefaultScreen(d);
/* CrĂ©er la fenĂȘtre. */
w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1,
BlackPixel(d, s), WhitePixel(d, s));
/* Choisir les événements qui nous intéressent. */
XSelectInput(d, w, ExposureMask | KeyPressMask);
/* Afficher la fenĂȘtre. */
XMapWindow(d, w);
/* Boucle des événements. */
while (1) {
XNextEvent(d, &e);
/* Dessiner ou redessiner la fenĂȘtre. */
if (e.type == Expose) {
XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10);
}
/* Sortir si une touche est pressée. */
if (e.type == KeyPress)
break;
}
/* Couper la connexion avec le serveur */
XCloseDisplay(d);
return 0;
}
Le client crĂ©e une connexion avec le serveur en appelant XOpenDisplay. Puis il demande la crĂ©ation d'une fenĂȘtre avec XCreateSimpleWindow. Un appel supplĂ©mentaire Ă XMapWindow est nĂ©cessaire pour « mapper » la fenĂȘtre, c'est-Ă -dire la rendre visible Ă l'Ă©cran.
Le carrĂ© est dessinĂ© en appelant la fonction XFillRectangle. Toutefois, cette opĂ©ration ne doit pas ĂȘtre effectuĂ©e qu'aprĂšs la crĂ©ation de la fenĂȘtre. En effet, la fenĂȘtre n'a pas la certitude que son contenu sera prĂ©servĂ©. Par exemple, si la fenĂȘtre est recouverte puis dĂ©couverte, il est possible que son contenu doive ĂȘtre redessinĂ©. Le programme est informĂ© que tout ou partie de la fenĂȘtre doit ĂȘtre redessinĂ© grĂące Ă la rĂ©ception d'un Ă©vĂ©nement Expose.
Le dessin du contenu de la fenĂȘtre est par consĂ©quent effectuĂ© au sein de la boucle des Ă©vĂ©nements. Avant d'entrer dans cette boucle, les Ă©vĂ©nements que l'application juge pertinents sont choisis, dans le cas prĂ©sent avec XSelectInput. La boucle des Ă©vĂ©nements attend l'arrivĂ©e des Ă©vĂ©nements : si l'Ă©vĂ©nement est l'appui sur une touche, l'application quitte ; si l'Ă©vĂ©nement indique qu'une partie de la fenĂȘtre est maintenant dĂ©couverte, le contenu de la fenĂȘtre est dessinĂ©. La fonction XNextEvent est bloquante, et vide le tampon de sortie quand aucun Ă©vĂ©nement ne se trouve dans la file d'attente.
Autres bibliothĂšques
La bibliothĂšque Xlib ne propose pas les fonctionnalitĂ©s graphiques telles que les boutons, les menus, les barres de dĂ©filement, etc. Ces Ă©lĂ©ments graphiques, appelĂ©s widgets, sont fournis par d'autres bibliothĂšques, qui utilisent elles-mĂȘmes la Xlib. Il existe deux types de bibliothĂšques dans ce cas :
- les bibliothÚques bùties sur la bibliothÚque Intrinsics (Xt), qui propose des fonctionnalités pour les widgets, mais aucun widget en particulier ; les widgets spécifiques sont fournis sous la forme de bibliothÚques de widgets s'appuyant sur Xt, telles que Xaw et Motif ;
- les bibliothĂšques qui fournissent des widgets en s'appuyant directement sur la Xlib, sans utiliser Xt, telles que les versions X11 de GTK+, Qt et FLTK.
GĂ©nĂ©ralement, les applications faisant appel Ă ces bibliothĂšques de widgets indiquent le contenu de la fenĂȘtre avant d'entrer dans la boucle des Ă©vĂ©nements, et n'ont pas besoin de prendre explicitement en charge les Ă©vĂ©nements Expose pour redessiner le contenu de la fenĂȘtre.
La bibliothÚque XCB est une solution de substitution à la Xlib. Elle a deux objectifs : la réduction de la taille de la bibliothÚque et un accÚs direct au protocole X11. Une version modifiée de la Xlib a été publiée, s'appuyant sur XCB.