X est un protocole de commandes échangées entre une application et un terminal graphique spécial appelé serveur X (désormais, nous l'appelerons le serveur). [En l'occurence, le terme ``serveur'' est ambigü, parce qu'il y a de nombreux serveurs X sur chaque machine cliente, et que l'utilisateur se trouve du côté serveur.] Classiquement, c'est l'inverse.] Concernant la manière avec laquelle le serveur effectue des tracés graphiques sur une unité matérielle,les développeurs d'applications graphiques ne doivent pas se préoccuper de la manière dont le serveur X interprète les graphiques. l'application doit juste savoir que, si elle envoye une séquence particulière d'octets par TCP/IP, le serveur interprétera ces octets de sorte qu'une ligne, un cercle, une boîte, une police de caractères ou toute autre objet graphique soit affiché à l'écran. En retour, l'application doit savoir qu'aux séquences particulières d'octets correspond l'enfoncement d'une touche d'un clavier ou le déplacement d'une souris. Cette communication TCP est appelée protocole X.
Quand vous utilisez X, nous ne réalisez pas forcément que l'intéraction décrite ci-dessus a lieu. Le serveur et l'application peuvent se trouver sur la même machine. La puissance réelle d'X ressort lorsque l'application et le serveur ne fonctionnent pas sur la même machine. Supposons, par exemple, que 20 utilisateurs soient connectés à un même ordinateur et qu'ils employent des programmes différents dont l'affichage est réalisé sur 20 serveurs X. Tout se passe comme si une machine unique permettait l'usage d'écrans et de claviers multiples. C'est pour cette raison qu'X est défini comme un système de fenêtrage transparent en mode réseau.
Les développeurs d'applications graphiques sont donc dispensés de connaître les propriétés graphiques du matériel (comparons cela avec les applications DOS où chacun doit construire le support de nombreuses cartes graphiques); ils ne doivent pas connaître le type de machines sur lesquelles l'application graphique sera affichée.
Le programme qui réalise cette opération miraculeuse se trouve dans /usr/X11/bin/X. La séquence typique des événements qui permettent à un programme graphique d'être exécuté est donnée ci-dessous. Il s'agit d'une description simplifiée car, en pratique, de nombreux utilitaires sont mis à contribution.
Les programmeurs d'applications X ne sont pas forcément concernés par ces requêtes. Une bibliothèque de haut-niveau traitent les tâches relatives à l'interaction avec le serveur. Cette bibliothèque est appelée la bibilothèque X, /usr/X11R6/lib/libX11.so.6.
Une des limitations du protocole X tient en ce que les développeurs ne peuvent utiliser que le jeu de commandes qui a été définis. X contourne ce problème en rendant le protocole ``extensible'' depuis le début, c'est-à-dire en permettant que soient ajoutées des extensions ou des améliorations sans compliquer ou affecter la compatibilité. A l'heure actuelle, il existe des extensions à X pour permettre l'affichage 3D sur le serveur, l'interprétation des commandes PostScript, et bien d'autres possibilités qui améliorent l'esthétique et les performances. A chaque extension sont associés des requêtes et des événements du protocole X ainsi que des interfaces de bibliothèques de programmation.
Voici un exemple de programme X réel. Il s'agit d'un programme
très simple qui affiche un fichier image XPM dans une fenêtre et attend
qu'une touche soit enfoncée ou qu'un clic de souris ait lieu pour
se terminer. Vous pouvez le compiler avec gcc
-o splash splash.c -lX11 -L/usr/X11R6/lib. Vous verrez de suite
pourquoi il y a peu d'applications écrites directement avec X.
Notez que toutes les fonctions des bibliothèques X sont préfixées
avec un X.
/* splash.c - display an image
*/
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <X11/Xlib.h> /* XPM */ static char *graham_splash[] = { ``28 32 16 1'' `` c #34262e'', ``. c #4c3236'', ``X c #673a39'', ``o c #543b44'', ``O c #724e4e'', ``+ c #6a5459'', ``@ c #6c463c'', ``# c #92706c'', ``$ c #92685f'', ``% c #987e84'', ``& c #aa857b'', ``n c #b2938f'', ``= c #bca39b'', ``- c #a89391'', ``; c #c4a49e'', ``: c #c4a8a4'', /* pixels */ ``-%#%%nnnn#-nnnnnn=====;;=;:'', ``----n-nnnnnn=n==;==;=:;:'', ``--n-n-n-n-n-nn===:::::::'', ``---&---nn-n=n====::::::'', ``--------n===;=::::::'', ``--%&-%-%##%--n===:::::::'', ``---%#%+++o+++--=:::::::'', ``-#-%%#+++oo. oo+#-=:::::::'', ``-%%%%++++o.. .++&-==:::::'', ``--%#+#+++o. oo+&n=::::'', ``-%###+$+++Oo. o+#-:=::'', ``-&%########++Oo @$-==:'', ``####$$$+###$++OX .O+&=='', ``&##$O+OXo+++$#+Oo. ..O&&-'', ``&##+OX..... .oOO@@... o@+&SPMamp;'', ``&###$Oo.o++ ..oX@oo@O$&-'', ``n###$$$$O$o ...X.. .XXX@$$$SPMamp;'', ``nnn##$$#$00. .XX+@ .XXX@$$#SPMamp;'', ``nnn&&####$OX.X$$@. XX$$$$SPMamp;'', ``nnnnn&&###$$$OX$$X..XXX@O$&n'', ``nnnnnn&&%###$$$$@XXXXX@O$&&n'', ``;n=;nnnn&&&#$$$$$@@@@@@O$&n;'', ``;n;=nn;nnnn#&$$$@X@O$@@$$&n;'', ``=n=;;;n;;nn&&&$$$$OO$$$$$&;;'', ``n;=n;;=nn&n&&&&&&$$$$$##&&n;'', ``n;=;;;;;;;;&&&n&&&&&&&&#&n=;'', ``;n;n;;=n;&;&;&n&&&&&&&#nn;;;'', ``n;=;;;;;;;;n;&&n&&&n&n&nnnn;'', ``n=;;:;;=;;nn;&n;&n&nnnnnnn=;'', ``nn;;;;;;;;;;;;;;n&nnnnnn===;'', ``=nn;;:;n;;;;&&&&n&&nnnnnn;=;'', ``n====;;;;&&&&&&&nnnnnnnnnn;;'' }; int main (int argc, char **argv) { int i, j, x, y, width, height, n_colors; XSetWindowAttributes xswa; XGCValues gcv; Display *display; char *display_name = 0; int depth = 0; Visual *visual; Window window; Pixmap pixmap; XImage *image; Colormap colormap; GC gc; int bytes_per_pixel; unsigned long colors[256]; unsigned char **p, *q; for (i=1; i < argc -1; i++) if (argv[i]) if (!strcmp (argv[i], ``-display'')) display_name = argv[i+1]; display = XOpenDisplay (display_name); if (!display) { printf (``splash: cannot open display\n''); exit(1); } depth = DefaultDepth (display, DefaultScreen (display)); visual = DefaultVisual (display, DefaultScreen (display)); p = (unsigned char **) graham_splash; q = p[0]; width = atoi ((const char *) q); q = (unsigned char *) strchr (q, ' '); height = atoi ((const char *) ++q); q = (unsigned char *) strchr (q, ' '); n_colors = atoi ((const char *) ++q); colormap = DefaultColormap (display, DefaultScreen (display)); pixmap = XCreatePixmap (display, DefaultRootWindow (display), width, height, depth); gc = XCreateGC (display, pixmap, 0, &gcv); image = XCreateImage (display, visual, depth, ZPixmap, 0, 0, width, height, 8, 0); image->data = (char *) malloc (image->bytes_per_line * height + 16); /* create color palette */ for (p = p + 1, i = 0; i < n_colors; p++, i++) { XColor c, c1; unsigned char *x; x = *p + 4; if (*x == '#') { unsigned char *h = (unsigned char *) ``0123456789abcdef''; x++; c.red = ((unsigned long) strchr (h, *x++) - (unsigned long) h) « 12; c.red |= ((unsigned long) strchr (h, *x++) - ((unsigned long) h) «8; c.green = ((unsigned long) strchr (h, *x++) - (unsigned long) h) « 12; c.green |= ((unsigned long) strchr (h, *x++) - ((unsigned long) h) « 8; c.blue = ((unsigned long) strchr (h, *x++) - (unsigned long) h) « 12; c.blue |= ((unsigned long) strchr (h, *x++) - ((unsigned long) h) « 8; if (!XAllocColor (display, colormap, &c)) printf (``splash: could not allocate color cell\n''); } else { if (!XAllocNamedColor (display, colormap, (char *) x, &c, &c1)) printf (``splash: could not allocate color cell\n'') } colors[(*p)[0]] = c.pixel; } bytes_per_pixel = image->bytes_per_line / width; /* cope with servers having different byte ordering and depths */ for (j = 0; j < height; j++, p++) { unsigned char *r; unsigned long c; q = image->data + image->bytes_per_line *j; r = *p; if (image->byte_order == MSBFirst) { switch (bytes_per_pixel) { case 4: for (i = 0; i < width; i++) { c = colors[*r++]; *q++ = c » 24; *q++ = c » 16; *q++ = c » 8; *q++ = c; } break; case 3: for (i = 0; i < width; i++) { c = colors[*r++]; *q++ = c » 16; *q++ = c » 8; *q++ = c; } break; case 2: for (i = 0; i < width; i++) { c = colors[*r++]; *q++ = c » 8; *q++ = c; } break; case 1: for (i = 0; i < width; i++) *q++ = colors[*r++]; break; } } else { switch (bytes_per_pixel) { case 4: for (i = 0; i < width; i++) { c = colors[*r++]; *q++ = c; *q++ = c » 8; *q++ = c » 16; *q++ = c » 24; } break; case 3: for (i = 0; i < width; i++) { c = colors[*r++]; *q++ = c ; *q++ = c » 8; *q++ = c » 16; } break; case 2: for (i = 0; i < width; i++) { c = colors[*r++]; *q++ = c; *q++ = c » 8; } break; case 1: for (i = 0; i < width; i++) *q++ = colors[*r++]; break; } } } XPutImage (display, pixmap, gc, image, 0, 0, 0, 0, width, height); x = (DisplayWidth (display, DefaultScreen (display)) - width) / 2; y = (DisplayHeight (display, DefaultScreen (display)) - heigth) / 2; xswa.colormap = colormap; xswa.background_pixmap = pixmap; window = XCreateWindow (display, DefaultRootWindow (display), x, y, width, height, 0, depth, InputOutput, visual, CWColormap | CWBackPixmap, &xswa); XSelectInput (display, window, KeyPressMask | ButtonPressMask); XMapRaised (display, window); while (1) { XEvent event; XNextEvent (display, &event); if (event.xany.type == KeyPress || event.xany.type == ButtonPressMask) break; } XUnmapWindow (display, window), XCloseDisplay (display); return 0; } |