Xlib

Xlib/XCB, le serveur d'affichage et le gestionnaire de fenêtre

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 :

Le projet XCB a pour objectif de se substituer à Xlib.

Types de données

[modifier | modifier le code]

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

[modifier | modifier le code]

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.

Les fonctions de la bibliothèque Xlib peuvent être regroupés de la façon suivante :

  1. Les opérations sur la connexion (XOpenDisplay, XCloseDisplay...) ;
  2. Les requêtes vers le serveur, y compris les requêtes pour opération (XCreateWindow, XCreateGC...) et les requêtes pour information (XGetWindowProperty ...) ;
  3. 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...).

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

[modifier | modifier le code]

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.

Articles connexes

[modifier | modifier le code]

Liens externes

[modifier | modifier le code]