3

Les fenêtres

 

 

3.1. Les fenêtres

                  On a évoqué dans le premier chapitre le rôle central joué par les fenêtres dans l'architecture des programmes. C'est en effet par l'intermédiaire des fenêtres que sont récupérés la plupart des événements, et l'on dessine toujours à l'intérieur de leurs cadres.

 

                   Concernant leur organisation, on a vu que les fenêtres étaient placées dans une arborescence dont la racine était la fenêtre de fond d'un écran, chaque fenêtre ayant un parent unique déterminant un cadre en dehors duquel elle reste invisible. Entre sœurs, les fenêtres sont rangées selon un certain ordre d'empilement (cf. figure 1.4.) qui est visible quand leurs surfaces se recouvrent partiellement.

 

                  Les fenêtres possèdent un certain nombre d'attributs, parmi lesquels des attributs géométriques : position du coin haut le plus à gauche dans le repère de la fenêtre parent, largeur, hauteur. Les attributs géométriques représentent des dimensions qui sont exprimées en points d'écran (cf. figure 3.1.). Toutes les fenêtres ont des attributs géométriques de position (x,y) et de dimension (width, height). D'autres attributs sont plus spécifiques à l'apparence graphique et ne sont présents que dans certaine classe de fenêtre. Par exemple, les attributs concernant l'épaisseur et la couleur du bord, la couleur du fond, les points d'ancrage du dessin et des sous-fenêtres, la table de couleur, etc. ne sont présents que dans les fenêtres de classe InputOutput.

 

 

Classes de fenêtres

 

                  Il y a en effet deux classes de fenêtres, les fenêtres de classe InputOutput et les fenêtres de classe InputOnly. Le terme d'Input désigne ici les entrées qui seront en réalité des événements de type clavier ou souris alors que le terme d’Output désigne les sorties graphiques, c'est-à-dire les dessins qui pourront apparaître dans les fenêtres. Une fenêtre de classe InputOutput admet à la fois des entrées, en reconnaissant les événements survenant sur le clavier et la souris, et des sorties, en possédant en particulier un fond dans lequel on peut dessiner. A l'inverse, une fenêtre de classe  InputOnly est une fenêtre qui n'autorise aucun dessin et n'a pas même de bord. Les fenêtres de classe InputOnly sont, en quelque sorte, des fenêtres transparentes.

 

   

                                  

fig. 3.1. Le repérage géométrique des fenêtres

 

                  L'intérêt des fenêtres InputOnly est qu'elles occupent moins de place en mémoire et permettent tout de même de recevoir les événements émanant des dispositifs d'entrée. Elles rendent ainsi sensibles des zones particulières et simplifient souvent la programmation. On pourra bien souvent ne disposer que d'une fenêtre graphique (fond sur lequel on effectuera tous les dessins), tout en rendant certaines zones sensibles à différents événements d'entrée en rajoutant par superposition des fenêtres transparentes.

 

 

3.2. Création de fenêtres simples

                  La création de fenêtres possédant simplement une couleur de fond et une couleur de bord s'effectue avec la requête XCreateSimpleWindow.

Window XCreateSimpleWindow (dpy, parent, x, y, width, height,

                                                              border_width, border_color, background_color)

Display*                           dpy ;

Window                            parent ;

int                                        x , y ;

unsigned int                    width, height, border_width ;

unsigned long                 border_color, background_color ;

 

                  Les fenêtres créées par XCreateSimpleWindow héritent de la classe et des caractéristiques de traitement de la couleur de leur parent. On s'en servira principalement pour créer des fenêtres de classe InputOutput ayant un fond utilisant simplement une couleur[1]. Les fenêtres créées par XCreateSimpleWindow seront normalement placées en tête de pile par rapport à leurs sœurs mais ne seront pas immédiatement affichées à l'écran. On devra d'abord spécifier les événements que l'on souhaite recevoir sur ces fenêtres via un appel à la procédure

 

XSelectInput(dpy, window, event_mask)

Display*                           dpy ;

Window                            window ;

long                   event_mask ;

 

 et ce n'est qu'ensuite qu'on procédera à l'affichage proprement dit de la fenêtre. Ainsi, dans l’extrait de programme

 

win = XCreateSimpleWindow(dpy, root, x, y,

                           width, height, 3,

                           whitepixel, blackpixel);

XSelectInput(dpy, win, ButtonPressMask |

                           ButtonReleaseMask);

XMapWindow(dpy, win);

 

                  La fenêtre win créée par XCreateSimpleWindow est prête à être affichée sur la racine en (x,y) avec une largeur width, une hauteur height, un bord blanc de 3 pixels de large et un fond noir. La fonction XSelectInput permet ensuite de spécifier les événements qui intéressent le client pour cette fenêtre. Les masques ButtonPressMask et ButtonReleaseMask sélectionnent ici deux types d'événements : bouton de souris enfoncé et bouton de souris relâché. On combine ces deux masques entre eux avec l'opérateur "ou" bit à bit (noté par une barre verticale) pour demander la sélection de ces deux types d’événements.

 

                  Pour afficher véritablement la fenêtre, le client doit faire appel à la requête d'affichage proprement dite : XMapWindow.

 

En présence d'un window manager, les attributs géométriques demandés à la création peuvent ne pas être pris en compte au moment de l'affichage. Par exemple, les positions des fenêtres sont fréquemment ignorées du window manager pour laisser l'utilisateur placer lui-même interactivement la fenêtre à l'écran. Cette remarque ne s'applique bien entendu pas aux sous-fenêtres d'une fenêtre (autre que la racine), car ces dernières sont ignorées par le window manager et toujours bien positionnées relativement à leur parent.

 

 

3.3. Affichage des fenêtres

                  Des fenêtres créées ne sont pas pour autant affichées à l'écran. Pour les afficher, on a vu que l'on devait faire appel à la procédure

 

XMapWindow (dpy, win)

 

                  L'affichage des fenêtres pose souvent un problème aux débutants. En premier lieu parce que des fenêtres créées ne sont pas simultanément affichées, et en second lieu parce qu'une fenêtre affichée peut ne pas être visible si elle se trouve masquée par une autre. Le problème concernant le second point n'apparaît pas quand les fenêtres ont été créées avec XCreateSimpleWindow car, dans ce cas, elles sont toujours positionnées par défaut en tête de pile et se trouvent donc visibles quand elles sont affichées. Par contre, les fenêtres créées avec XCreateWindow peuvent être affichées — et donc potentiellement visibles à l’écran — sans pour autant être vues de l’utilisateur si par hasard elles se trouvent masquées par une autre fenêtre. Pour remédier à ce premier problème on utilisera la fonction

 

XMapRaised (dpy,win)

 

qui met en avant-plan et affiche la fenêtre considérée. Une deuxième difficulté provient du fait que la requête XMapWindow est empilée localement par la librairie Xlib avant d'être envoyée au serveur. En outre, en présence d'un window manager, cette requête n'est pas exécutée par le serveur mais redirigée vers le window manager. Au lieu d’exécuter la requête, le serveur envoie un événement de type MapRequest au window manager. Le window manager est alors libre de reformuler ou d’ignorer la requête. Normalement, il la reformule, mais il en résulte un décalage incontrôlable entre l’exécution de la requête au niveau de l'application et l'apparition effective de la fenêtre à l'écran[2].

 

On peut cependant toujours être informé, dans l'application, de la présence de la fenêtre à l'écran. En effet, dès que la fenêtre sera effectivement affichée, le serveur émettra un événement de type MapNotify. En outre, si la fenêtre est visible à l'écran, elle recevra un événement de type Expose[3] informant l'application de la mise en avant de son contenu graphique. Ce n'est qu'après réception de ce premier événement de type Expose qu'on pourra dessiner dans la fenêtre. (Pour recevoir cet événement; il faudra en avoir fait la demande auprès du serveur en sélectionnant explicitement cet événement sur la fenêtre avec XSelectInput.)

 

L'appel à XMapWindow a généralement lieu en début de programme, après création et spécification des événements à récupérer sur la fenêtre. Mais on peut également demander l'affichage d'une fenêtre quand un événement particulier se produit, comme l'enfoncement d'un bouton de souris dans le cas d'un menu déroulant. Par contre, on ne dessinera dans une fenêtre qu'après réception d'un événement de type Expose car sinon, la fenêtre pourrait ne pas être encore affichée et les ordres de dessin sont alors tout simplement ignorés.

 

                  Pour éviter des problèmes de synchronisation, on prendra soin en outre d'afficher les sous-fenêtres avant la fenêtre mère pour avoir l'affichage simultané des deux[4]. Pour cela, on utilisera la fonction

XMapSubwindows (dpy, parent)

Window           parent ;

 

avant d’appeler XMapWindow  sur la fenêtre parent. 

 

                  Inversement, on peut vouloir supprimer momentanément de l'affichage une fenêtre potentiellement visible à l'écran en faisant un appel; à

 

XUnMapWindow (dpy,win)

 

                  C'est ce qui se produit lorsque l'on "icônifie" une fenêtre. Pour chaque fenêtre, le window manager crée une fenêtre duale plus petite servant à représenter la fenêtre sous forme iconique. L'opération  consiste alors à faire un appel à UnMapWindow sur la fenêtre d'origine suivi d'un appel à XMapWindow sur son icône.

                  Les fenêtres qui sont ainsi retirées de l'affichage ne sont pas pour autant détruites et on peut en modifier les attributs.

 

                  Il existe également une fonction de destruction de fenêtre

 

XDestroyWindow (dpy,win)

 

qui permet de libérer entièrement la mémoire allouée pour cette fenêtre. L’exécution de cette requête provoque l’envoi d’événement DestroyNotify aux fenêtres intéressées par cet événement.

 

On prendra garde avant de détruire une fenêtre à ce qu'aucun événement la concernant ne soit encore accessible dans la pile des événements non traités, car sinon, un accès aux ressources de la fenêtre produira une erreur fatale.

 

                  Signalons également les procédures

 

XUnmapSubwindows (dpy, parent)

XDestroySubwindows (dpy, parent)

 

qui permettent d'effectuer ces opérations sur toutes les sous-fenêtres d'une fenêtre parent donnée.

 

 

3.4. Les attributs des fenêtres

                  Les attributs géométriques sont initialisés à la création des fenêtres et pourront être modifiés en cours de programme par diverses fonctions que nous présenterons dans la section suivante. Dans cette section, nous allons présenter les attributs des fenêtres qui peuvent être initialisés avec XCreateWindow et/ou modifiés ensuite par XChangeWindowAttributes.

 

 

Les attributs graphiques des fenêtres InputOutput

 

                  Les fenêtres de classe InputOutput possèdent les attributs graphiques suivants:

 

background_pixmap     Cet attribut permet d'indiquer un Pixmap pour paver le fond de la fenêtre ou indique celui du parent (ParentRelative). La valeur par défaut est la constante None. Dans ce cas, la fenêtre n'a pas de fond si elle n'a pas non plus de couleur de fond.

 

background_pixel        Cet attribut (type unsigned long) indique la couleur du fond. C'est une alternative à un motif pour paver le fond qui prévaut sur la valeur donnée à l'attribut précédent. Il n'a par conséquent pas de valeur de défaut.

 

border_pixmap                Cet attribut contient éventuellement un Pixmap pour paver le bord de la fenêtre. Sa valeur de défaut est CopyFromParent.

 

border_pixel                   Cet attribut (type unsigned long) indique une couleur de bord. C'est une alternative au pavage d'un motif de bord qui prévaut sur la valeur de l'attribut précédent.

 

Il ne faut pas oublier d'attribuer un fond aux fenêtres de classe InputOutput que l'on crée à l'aide de la procédure XCreateWindow. En effet, le fond de la fenêtre (qui par défaut vaut la constante None) n'existe pas réellement sinon. En outre, même si l'on hérite de celui du parent, la valeur dont on hérite peut encore être None. Dans ce cas, les dessins effectués dans la fenêtre n'apparaissent pas à l'écran et le fond de la fenêtre est arbitraire.

 

                  Inversement, il ne faut donner aucun des attributs précédents aux fenêtres InputOnly ou une erreur de type BadMatch se produira.

 

                  Signalons les fonctions qui permettent de modifier ces attributs en cours de programme :

 

XSetWindowBackgroundPixmap (dpy, win, pixmap)

XSetWindowBackground (dpy, win, pixel)

XSetWindowBorderPixmap (dpy, win, pixmap)

XSetWindowBorder (dpy, win, pixel)

Display*                           dpy ;

Window                            win ;

unsigned long                 pixel ;

Pixmap                              pixmap ;

 

Les débutants sont souvent surpris, après un appel à l’une des requêtes précédentes, de ne pas voir immédiatement la modification apparaître à l’écran. En réalité, l’attribut de la fenêtre a bien été modifié, mais pas l'écran. Le changement ne sera perceptible que si une requête de dessin utilisant cet attribut est employée, comme par exemple

 

XClearWindow (dpy, win)

 

 qui repeint le fond de la fenêtre en effaçant les dessins antérieurs.

 

 

Attributs de changement de taille des fenêtres

 

                  Si une fenêtre est simplement déplacée sur l'écran sans que sa taille soit modifiée, son contenu reste intact. Par contre, si la fenêtre est agrandie, le serveur ne sait pas où replacer le précédent contenu, ni où replacer ses sous-fenêtres. Les attributs qui suivent permettent d’indiquer au serveur quoi faire en cas de changement de taille de la fenêtre mère.

 

 

 

 

fig. 3.2. Effet d’un changement de taille de la fenêtre

sur la position des dessins selon les valeurs de bit_gravity

 

 

bit_gravity                       Permet d'indiquer au serveur où il devra repeindre le précédent contenu de la fenêtre quand la fenêtre changera de taille. Il ne concerne que les fenêtres de classe InputOutput puisque ce sont les seules à pouvoir contenir des dessins.

win_gravity                      Cet attribut indique où le serveur doit replacer les sous-fenêtres dans le cas d'un changement de taille de la fenêtre mère. (Par défaut NorthWestGravity.)

                  Ces attributs permettent en quelque sorte d'attacher le contenu d'une fenêtre (ou la position d'une sous-fenêtre) à un autre point que le coin supérieur gauche. Les valeurs possibles pour les champs win_gravity et bit_gravity utilisent la métaphore géographique des points cardinaux. On pourra leur attribuer les valeurs NorthWestGravity, NorthGravity, NorthEastGravity, WestGravity, CenterGravity, EastGravity, SouthWestGravity, SouthGravity et SouthEastGravity. Ces deux attributs peuvent également prendre la valeur StaticGravity, qui indique que la position des sous-fenêtres ou le contenu du dessin ne sont pas déplacés par rapport à la racine (root window).

                  Par défaut l'attribut bit_gravity vaut ForgetGravity. Ce qui signifie que par défaut le serveur ne mémorise aucun dessin et repeint simplement le fond de la fenêtre si elle en possède un. Pour avertir l'application que les dessins doivent être réaffichés, le serveur pourra cependant envoyer des événements de type Expose. La figure 3.2. (page précédente) illustre le réaffichage du contenu d'une fenêtre qui vient d'être agrandie, selon les valeurs de son attribut bit_gravity.

                  L'attribut win_gravity peut également prendre la valeur UnmapGravity  qui supprime les sous-fenêtres de l'affichage quand la taille du parent est modifiée (leurs positions par contre n'étant pas modifiées, comme avec NorthWestGravity). Le serveur émet alors des événements de type UnmapNotify qui permettent à l'application d'être informée et de repositionner elle-même les sous-fenêtres.

 

 

Attributs de mémoire d'écran

 

                  Par défaut (et en dehors des simples déplacements des fenêtres), le serveur ne mémorise pas le contenu des fenêtres. Seul le fond sera repeint lorsque tout ou partie d’une fenêtre cachée se trouvera remis en avant. Certains serveurs sont cependant capables de mémoriser le contenu des fenêtres. Dans ce cas, le contenu ne sera pas perdu lorsqu’une fenêtre se trouvera partiellement couverte puis remise en avant-plan[5]. Les trois attributs suivants permettent de spécifier quand le contenu d’une fenêtre doit être sauvegardé et quels plans de couleurs doivent être préservés. Ces attributs ne sont pas pertinents sur les implantations ne possédant pas de mémoire de sauvegarde et ne concernent que les fenêtres de type InputOutput.

 

backing_store                 (type int) indique s'il y a lieu et quand sauvegarder le contenu de la fenêtre en cas de perte de son contenu par recouvrement. Il peut prendre les valeurs NotUseful (valeur par défaut), WhenMapped, ou Always.

 

backing_planes              (type unsigned long) est un masque indiquant quels plans de couleurs doivent être sauvegardés en cas de recouvrement.

 

backing_pixel                 (type unsigned long) spécifie la couleur à restaurer sur les plans non sauvegardés.

 

                  Pour savoir si le serveur possède de telles capacités mémoire, on utilise la macro DoesBackingStore (screen_ptr).

                 

Cependant, même si l’attribut backing_store est positionné à Always, il n'y a pas de réaffichage du contenu en cas de changement de taille de la fenêtre. Pour obtenir le réaffichage en cas de changement de taille il faut avoir affecté correctement l’attribut bit_gravity (dont la valeur par défaut est, on l'a vu, ForgetGravity). C’est logique en effet, car sinon le serveur ne sait pas où replacer ce contenu, même s'il a été sauvegardé.

 

                  L’attribut save_under, littéralement sauver en dessous, concerne non pas les dessins contenus dans la fenêtre, mais ceux situés sous une fenêtre de type InputOutput, c'est-à-dire ceux que la fenêtre viendrait à effacer si elle venait s'afficher par dessus d'autres fenêtres.

 

save_under                         Cet attribut booléen permet d'indiquer s'il y a lieu de sauvegarder le dessin situé sous la fenêtre avant de l’afficher (cas d'un pop-up menu par exemple).

 

                  La macro DoesSaveUnder (screen_ptr) permet de savoir si le serveur utilise cet attribut.

 

Attributs de communication

 

                  Les trois attributs suivants sont destinés à la gestion des événements et à la communication avec le window manager. Ils concernent cette fois toutes les classes de fenêtres.

 

event_mask                         Ce masque indique l’ensemble des types d'événements que l'application veut recevoir sur la fenêtre. Les événements correspondants seront envoyés à l'application lorsqu'ils se produiront dans cette fenêtre[7]. Par défaut, cet attribut est positionné à NoEventMask, ce qui signifie que par défaut l'application ne recevra pas d'événement dans cette fenêtre.

                   Il existe de nombreux masques précisant le type des événements pouvant se produire dans une fenêtre. Par exemple, ButtonPressMask décrit l’enfoncement d’un bouton de souris, KeyPressMask l’enfoncement d’une touche du clavier et ExposureMask le fait qu’une partie de la fenêtre devient visible. Il faut que l'attribut event_mask d'une fenêtre soit affecté par une combinaison de ces masques pour que l'application reçoive ces événements quand ils se produisent.

                  La fonction XSelectInput que nous avons rencontrée pour sélectionner les événements modifie en réalité l'attribut event_mask de la fenêtre.

 

do_not_propagate_mask ; Ce masque indique l’ensemble des événements que l'application ne souhaite pas voir propager aux ancêtres. Cet attribut modifie la propagation des événements (cf. le chapitre sur les événements) en empêchant qu'un événement se produisant sur une fenêtre fille soit transmis à la mère.

 

                  Les valeurs de masques que l'on peut donner à cet attribut sont les mêmes que ceux de l'attribut event_mask. Cependant, seuls les événements concernant les dispositifs d'entrée sont concernés par le phénomène de propagation. On ne propage pas en effet les événements graphiques de type Expose ni les événements informant de changements survenus sur une fenêtre donnée. (Les mécanismes en jeu dans la propagation des événements seront détaillés dans les chapitres 4 et 5.)

 

                  Le troisième attribut concerne la communication avec le window manager. Nous avons déjà vu que par défaut, les requêtes concernant l’affichage et la configuration des fenêtres filles de la racine ne sont pas effectuées par le serveur mais redirigées (sous la forme d’un événement) vers le window manager. Le window manager intercepte ainsi les requêtes de configuration et les reformule avant qu’elles ne soient finalement effectuées sur sa demande (cf. figure 2.9.). Les informations d'affichage, taille et position, sont en effet nécessaires au window manager pour qu'il puisse afficher ses décorations.

 

override_redirect  Cette valeur booléenne indique si la redirection des requêtes de configuration et d'affichage concernant cette fenêtre doit être ignorée par le window manager. Par défaut, cette valeur est à False pour les fenêtres filles de la racine, ce qui signifie que par défaut, il y a redirection des requêtes de configuration pour ces fenêtres.

 

                  L’attribut override_redirect permet donc d’empêcher la redirection des requêtes au window manager pour des fenêtres filles de la racine qui ne nécessitent pas de décoration. C'est le cas principalement des menus destinés à pendre hors du cadre de la fenêtre ayant permis de les faire apparaître.

On ne mettra l’attribut override_redirect à True que dans des cas très particuliers, comme celui des menus. On peut sinon communiquer avec le window manager au moyen de propriétés pour aménager les attributs qu'il utilise conformément aux souhaits de l'application. Par exemple, on peut lui indiquer un nom pour l'application grâce à la fonction XStoreName (dpy, win, string). On peut également indiquer que l'on ne souhaite pas de décoration. C'est la solution qui sera retenue pour des boîtes de dialogue qui pourront être déplacées par le window manager mais n'auront cependant pas ses décorations[8]. Le cas du menu est différent, car on ne souhaite pas que le menu soit déplacé.

 

 

Attributs de couleurs et de curseur

 

                  Les deux derniers attributs permettent d’associer directement à une fenêtre une table de couleurs particulière et une forme de pointeur de souris :

 

colormap                               Cet attribut indique la table de couleurs associée à la fenêtre. Il ne concerne que les fenêtres de classe InputOutput et prend par défaut la valeur CopyFromParent.

cursor                                     Ce curseur (type Cursor) désigne l'image de la position de la souris à l'écran lorsque le pointeur se trouve dans la fenêtre. C'est le serveur qui est chargé de l'affichage du curseur et de la sauvegarde des dessins situés en dessous. Sa valeur par défaut est la constante None qui signifie que le curseur est hérité de la fenêtre parent.

 

                  On notera que les fenêtres transparentes de classe InputOnly ne peuvent avoir de table de couleurs mais peuvent néanmoins posséder un curseur propre. La modification du curseur permettra de rendre sensible à l'utilisateur l'entrée dans la fenêtre transparente.

 Un curseur à None ne signifie pas que la fenêtre n'a pas de curseur. Cela signifie que la fenêtre hérite du curseur de son parent.

 

 

3.5. La création de fenêtres

                  On a vu section 3.2. que l'on pouvait créer des fenêtres de même classe que leur parent avec XCreateSimpleWindow. La fonction XCreateWindow permet de créer des fenêtres d'attributs quelconques, et en particulier de n'importe quelle classe, à la restriction près qu'une fenêtre InputOutput ne peut être fille que d'une fenêtre InputOutput. Autrement dit, les fenêtres InputOnly ne pourront avoir que des filles InputOnly.

 

Window XCreateWindow (dpy, parent, x, y,width, height, border_width,

                                                               depth, class, visual, mask,  &xswa)

Display*                                             dpy ;

Window                                              parent ;

int                                                         x ,y ;

unsigned int                                      width, height, border_width ;

int                                                         depth ;

unsigned int                                      class ;

Visual*                                               visual ;

unsigned long                                  mask ;

XSetWindowAttributes               xswa;

 

 

      La fonction XCreateWindow est plus lourde d'utilisation que XCreateSimpleWindow car elle requiert (entre autres) l'initialisation d'une structure de type XSetWindowAttributes contenant les attributs de la fenêtre à créer.  Il faut d'abord déclarer cette structure, puis en initialiser les champs que l'on souhaite positionner. On passe alors l'adresse de la structure en argument ainsi qu'un masque précisant les champs qui doivent être pris en considération dans la requête (ceux que l'on aura initialisés). La liste des masques de modification d'attribut est énumérée figure 3.3. et la structure XSetWindowAttributes est représentée figure 3.4.

 

        CWBackPixmap        CWBackingPixel

        CWBackPixel         CWOverrideRedirect

        CWBorderPixmap      CWSaveUnder

        CWBorderPixel       CWEventMask

        CWBitGravity        CWDontPropagate

        CWWinGravity        CWColormap

        CWBackingStore      CWCursor

        CWBackingPlanes    

 

fig. 3.3. Masques d'attributs des fenêtres pour

la création ou la modification.

 

typedef struct {

   Pixmap background_pixmap;            /* pixmap de fond */

         unsigned long background_pixel;                   /* couleur de fond */

   Pixmap border_pixmap;               /* bord de la fenêtre */

   unsigned long border_pixel;          /* couleur du bord */

   int bit_gravity;                 /* où replacer le contenu */

   int win_gravity;                                    /* où replacer les sous-fenêtres */

   int backing_store;       /* NotUseful, WhenMapped, Always */

   unsigned long backing_planes;      /* plans à sauvegarder */

   unsigned long backing_pixel;               /* couleur pour restaurer */

   Bool save_under;                                           /* doit-on sauver en dessous */

   long event_mask;              /* les événements à recevoir */

   long do_not_propagate_mask;            /* les événements à bloquer */

   Bool override_redirect;       /* pour empêcher la redirection

                                                        des requêtes de configuration au window manager */

   Colormap colormap;           /* la table de couleurs associée */

   Cursor cursor; /* le curseur de souris dans cette fenêtre (ou None) */

} XSetWindowAttributes;

 

fig. 3.4. La structure de données XSetWindowAttributes

pour spécifier les attributs d'une fenêtre

 

                  Une fenêtre créée par XCreateWindow est fille de la fenêtre indiquée par l'argument parent. Les arguments x, y, width et height donnent la position de la fenêtre relativement au coin supérieur gauche de son parent, et les dimensions sont exprimées en pixels. L'épaisseur du bord est spécifiée pour les fenêtres de classe InputOutput ainsi que la profondeur du Pixmap de fond associé à la fenêtre (indiquer 0 pour les fenêtres de classe InputOnly). On peut utiliser la constante CopyFromParent pour obtenir la même profondeur que le parent.  La classe et le type visuel doivent être compatibles avec ceux du parent (cf. le chapitre sur la couleur). On pourra également indiquer la constante CopyFromParent pour hériter du type visuel du parent. (C'est ce que l'on fera sur des écrans monochromes.)

 

                                   Il existe autant de masques prédéfinis que de champs dans la structure XSetWindowAttributes. Tous ces masques commencent par CW (pour Change Window) et sont de la forme CWAttributName, où AttributName est formé à partir du nom d'un champ de la structure, en utilisant des majuscules pour séparer les mots au lieu de caractères soulignés. Ainsi par exemple le masque CWOverrideRedirect correspond à l'attribut override_redirect de la struc­ture et le masque CWEventMask à l'attribut event_mask. Il y a quelques exceptions cependant : CWBackPimap et CWBackpixel correspondent aux attributs background_pixmap et background_pixel, et CWDontPropagate correspond à l'attribut do_not_propagate_mask.

 

La technique utilisée ici — passer en argument une adresse de structure et un masque correspondant aux champs pertinents de la structure — est fréquemment utilisée dans la Xlib (par exemple, avec les fonctions XChangeWindowAttributes et XChangeGC). Les débutants veilleront à bien se familiariser avec elle. Ainsi :

 

XSetWindowAttributes xswa;

Window               win;

 

/*

 * initialisation de la structure de type XSetWindowAttributes

 */

xswa.event_mask = ButtonPressMask | ButtonReleaseMask;

xswa.background_pixel = BlackPixel(dpy,screen);

/*

 * demande de création de la fenêtre

 */

win = XCreateWindow(dpy, root,10,100, width, height,2,

                     CopyFromParent, InputOutput,

                     CopyFromParent,

                     CWEventMask |  CWBackPixel, &xswa);

 

                  La fenêtre win est créée au point de coordonnées (10,100) sur la fenêtre racine, avec une certaine largeur width et une certaine hauteur height. L'épaisseur du bord est de 2 points. C'est une fenêtre de classe InputOutput qui hérite des caractéristiques visuelles de son parent, la fenêtre racine. On notera en particulier que c’est l’adresse de la structure xswa  qui est passée en argument à la fonction. Cette structure et le masque confère à la fenêtre une valeur pour deux attributs supplémentaires : un masque d'événement et un fond.

                  En effet, le masque combinant CWEventMask et CWBackPixel (sur la dernière ligne) indique que les seuls champs à prendre en considération dans la structure sont les champs event_mask et background_pixel. Ces champs ont été correctement initialisés par les deux affectations précédant l’appel à XCreateWindow. La fenêtre créée aura donc un fond noir et recevra les événements souris de type ButtonPress et ButtonRelease.

 

                  Remarquons au passage qu'on peut initialiser l'attribut event_mask d'une fenêtre dès sa création en utilisant la fonction XCreateWindow. On évite ainsi un appel à la fonction XSelectInput.

 

Dans la pratique XCreateWindow est souvent source d'erreurs, car il faut faire attention à bien faire coïncider les champs de la structure d'attributs et le masque passé en argument. En particulier, pour ajouter un attribut il devient nécessaire de modifier le programme en deux endroits différents : au niveau du champ de la structure et au niveau du masque d'attribut passé en argument à XCreateWindow.

 

                  Il est cependant recommandé d'utiliser XCreateWindow dès que l'on veut instancier un nombre non négligeable d'attributs (autres que ceux autorisés par XCreateSimpleWindow), car on économise ainsi le nombre de requêtes envoyées au serveur. En outre c'est la seule procédure qui permette de créer une première fenêtre de classe InputOnly.  

 

On veillera à ne pas spécifier d'attributs graphiques pour les fenêtres de classe InputOnly. Ces fenêtres n'ont ni couleur de bord, ni  profondeur (depth=0), ni fond, ni épaisseur de bord. On peut cependant leur associer un curseur de souris particulier qui permettra d'avertir l'utilisateur qu'il se trouve dans une zone sensible.

 

3.6. La récupération des attributs d'une fenêtre

                  Les attributs géométriques s’obtiennent avec la fonction

 

Status XGetGeometry(dpy, drawable, &root_return, &x, &y, &width, &height,

                                                               &border_width,&depth)

Drawable        drawable ;              /* type union : Pixmap ou Window */

Window           root_return ;         

                 

                  Cette fonction retourne une variable Status qui vaut zéro en cas d'échec et un en cas de succès. Les attributs géométriques sont normalement initialisés à la création des fenêtres mais peuvent être modifiés par le window manager qui intercepte les requêtes de création, reparente les fenêtres et assure lui-même l'affichage. Les fenêtres créées n'auront donc pas nécessairement les attributs géométriques initialement demandés par la requête de création. On utilisera XGetGeometry pour récupérer les dimensions des fenêtres avant d'effectuer un traitement graphique.    

 

                  Le mécanisme utilisé par XGetGeometry pour récupérer les valeurs des attributs des fenêtres ;est toujours celui du passage par adresse. On déclare simplement des variables entières puis on passe l’adresse de ces variables. La Xlib répond alors en remplissant les adresses pointées, ce qui permet de récupérer les valeurs en sortie de procédure. Ainsi, après un appel à XGetGeometry, les variables x, y, width et height (dont on a passé les adresses) contiennent les valeurs de position et de dimension de la fenêtre.

 

Si on utilise XGetGeometry pour déterminer seulement la largeur et la hauteur de la fenêtre, il est agréable de déclarer une variable entière dont le nom évoquera l’inutilité (comme bidon, nul, vide, nil etc.) pour rendre le code plus lisible :

 

Window   fen_bidon;

int width, height

         nil;

   ...

XGetGeometry(dpy, win, &fen_bidon, &nil, &nil, &width,

                     &height, &nil, &nil);

 

                  Plus généralement, les valeurs des autres attributs pourront être récupérées avec la fonction XGetWindowAttributes.

typedef struct {

          int x, y;                                                              /* position relative à la mère */

          int width, height;                                  /* largeur, hauteur (en pixels) */

          int border_width;                                                /* taille du bord (en sus) */

          int depth;                      /* profondeur des pixmaps  (traitement couleur) */

          Visual *visual;                                          /* structure visuelle associée  */

          Window root;                                      /* fenêtre racine contenant la fenêtre */

          int class;                                                             /* InputOutput ou InputOnly*/

          int bit_gravity;                                        /* point d’ancrage des dessins */

          int win_gravity;                            /* point d’ancrage des sous-fenêtres */

          int backing_store;                   /* NotUseful, WhenMapped, Always */

          unsigned long backing_planes;                      /* plans à préserver */

          unsigned long backing_pixel; /* couleur à utiliser pour restaurer

                                                                                                          les plans non sauvegardés */

          Bool save_under;      /* pour sauvegarder  les pixels situés en dessous

                                                                                                                                 (pop-up menu)*/

          Colormap colormap;                                   /* table de couleurs associées */

          Bool map_installed;                /* si une table de couleur est installée */

          int map_state;             /* IsUnmapped, IsUnviewable, ou IsViewable */

          long all_event_masks;        /* les événements sélectionnés par toutes

                                                                                                                              les applications */

          long your_event_mask;      /* les ev. sélectionnés par  l’application */

          long do_not_propagate_mask;  /* ens. des ev. à ne pas propager */

          Bool override_redirect;                             /* bloquer la redirection  */

          Screen *screen_num;                                /* l'écran contenant la fenêtre */

} XWindowAttributes;

fig. 3.5. La structure XWindowAttributes

 

XGetWindowAttributes (dpy, win, &win_att)

Window                            win ;

XWindowAttributes    win_att ;

                 

                  La fonction XGetWindowAttributes utilise une structure de type XWindowAttributes (différent du type XSetWindowAttributes, cf. figure 3.5. ci-dessus). On remarquera au passage que les Pixmap utilisés pour paver le fond d'une fenêtre ne peuvent pas être récupérés par cette procédure car ils ne figurent pas dans la structure de récupération. Par contre, on peut récupérer de cette manière l'ensemble des événements qui ont été sélectionnés par tous les clients sur la fenêtre grâce au champ all_events_mask.

                  Cette fois-ci encore, on passe directement l’adresse d’une variable (de type XWindowAttributes) et le serveur répond en remplissant tous les champs de la structure. Cette procédure est donc relativement coûteuse puisqu'elle nécessite un double échange avec le serveur.

On veillera bien ici :

                  • A passer l'adresse de la structure déclarée dans le programme.

                  • A ne pas confondre les structures XSetWindowAttributes (pour l'affectation des valeurs) et XWindowAttributes (pour la récupération). Cette erreur ne serait pas détectée à la compilation.

                  • A ne pas utiliser XGetWindowAttributes et XGetGeometry sans nécessité car les procédures qui retournent des valeurs ralentissent la communication avec le serveur[9]. De manière générale, on tâchera dans la mesure du possible de récupérer les informations concernant la géométrie des fenêtres au travers des événements (qui sont envoyés par paquet à moindre coût).

                 

                  Signalons aussi la fonction XQueryTree qui permet de récupérer toute la liste des filles[10] d'une fenêtre parent dans un tableau alloué par le serveur (la plus en avant étant placée en tête) :

 

Status XQueryTree(dpy,win,&root,&parent, children, &nchild)

Window           win, root, parent ;

Window**      children;

unsigned int   nchild ;

 

                  XQueryTree retourne zéro en cas d'échec et 1 sinon. L'argument nchild permet de connaître le nombre de fenêtres retournées dans le tableau de fenêtres children. On pourra ensuite libérer le tableau de fenêtres avec la fonction

Status XFree(data)

caddr_t             data ;       /* un pointeur sur l'adresse des données à libérer */

 

                  Cette fonction permet en général de libérer la mémoire allouée par le serveur[11].

3.7. La modification des attributs des fenêtres

                  Les attributs affectables dès la création par XCreateWindow[12] ;sont également modifiables par la fonction

 

XChangeWindowAttributes (dpy, win, mask, &xswa)

Window                                              win ;

unsigned long                                  mask ;

XSetWindowAttributes                xswa;

 

                  Cette fonction prend en argument l'adresse d'une structure de type XSetWindowAttributes et un masque permettant d’indiquer les attributs à modifier. Comme dans le cas de XCreateWindow, il faut prendre garde à bien faire coïncider les attributs initialisés dans la structure avec le masque passé en argument.

                  Il existe également des fonctions spécifiques permettant de changer directement la valeur d'un attribut donné. Nous les avons pour la plupart déjà mentionnées section 3.4 dans la présentation des attributs. Ces fonctions effectuent en réalité un appel à XChangeWindowAttributes mais sont moins lourdes d'emploi pour le program­meur. Toutes ces procédures commencent par XSetWindow. Ainsi, nous avons déjà mentionné

 

XSetWindowBackgroundPixmap (dpy, win, pixmap) 

XSetWindowBackground (dpy, win, pixel) 

XSetWindowBorderPixmap (dpy, win, pixmap) 

XSetWindowBorder (dpy, win, pixel)

 

 etc. Signalons encore

 

XSetWindowColormap (dpy,win,cmap)

XSetWindowBorderWidth (dpy, win, width)

 

                  Les attributs géométriques de position et dimension ne peuvent être modifiés par la requête XChangeWindowAttributes car la structure d'affectation XSetWindowAttributes ne les contient pas. La librairie a prévu que l'on utilise une structure plus petite regroupant tous les attributs liés à la configuration des fenêtres à l'écran. Il s'agit de la structure XWindowChanges (cf. figure 3.6.).

           typedef struct {

                   int     x, y;

                   int     width, height;

                   int     border_width;

                   Window sibling;    /* sœur*/

                   int     stack_mode;

           } XWindowChanges;

 

           #define CWX            (1<<0)

           #define CWY            (1<<1)

           #define CWWidth        (1<<2)

           #define CWHeight       (1<<3)

           #define CWBorderWidth  (1<<4)

           #define CWSibling      (1<<5)

           #define CWStackMode    (1<<6)

 

fig. 3.6. La structure de données et les masques pour reconfigurer les fenêtres

                  La structure XWindowChanges s'utilise avec la fonction

XConfigureWindow (dpy, win, value_mask, &xwcvalues)

Display*                           dpy ;

Window                            win ;

unsigned int                    value_mask ;

XWindowChanges       xwcvalues ;

 

                  Il existe également des requêtes permettant de modifier directement les attributs géométriques, comme par exemple :

XMoveWindow ;(dpy, win, x, y)

XResizeWindow (dpy, win, width, height)

XMoveResizeWindow (dpy, win, x, y, width, height)

 

      XMoveWindow place la fenêtre win en (x,y) par rapport à l'origine (coin haut gauche) de sa mère, XResizeWindow modifie sa taille et XMoveResizeWindow effectue ces deux opérations simultanément.

Toutes ces requêtes de configuration peuvent surprendre quand elles sont utilisées pour les filles de la racine. En effet, la plupart des window manager reparentent les fenêtres par une fenêtre englobante contenant des décorations diverses. Les coordonnées indiquées par ces requêtes étant relatives à la fenêtre parent, elles sont relatives à cette nouvelle fenêtre (qui appartient au window manager) et non pas relatives à la racine comme peut le croire le programmeur.

                  Ce problème est en réalité facile à contourner. L'application pourra en effet récupérer le parent effectif grâce à l'événement de type ReparentNotify. En outre la Xlib possède une fonction de translation

 

Bool XTranslateCoordinates (dpy, source_win, dest_win, source_x,

                                                                                 source_y, &dest_x, &dest_y, &fille_return)

Display*          dpy ;

Window           source_win, dest_win;

int                      source_x, source_y,

                            dest_x, dest_y ;

Window           fille_return;

 

qui permet de changer facilement de repère. XTranslateCoordinates traduit les coordonnées source_x, source_y relative à source_win (fenêtre source), en coordonnées dest_x et dest_y relative à dest_win (fenêtre destination).

 

                  Signalons encore:

 

XRaiseWindow (dpy, win)

XLowerWindow (dpy, win)

      La fonction XRaiseWindow permet de placer une fenêtre devant ses sœurs et XLowerWindow de la placer derrière. D'autres fonctions effectuent des permutations et changements divers dans la pile, par exemple XRestackWindow, XCirculateSubwindowsUp ou XCirculateSubwindowsDown.

 

3.8. Création de fonds de fenêtres

                  On a vu que les fonds des fenêtres pouvaient être pavés avec un Pixmap (grâce à l'attribut background_pixmap). Les requêtes proposées par la librairie ne permettent cependant de lire et de ne sauvegarder sur disque que des bitmap (i.e. des Pixmap de profondeur 1). Pour créer des motifs de fond aux fenêtres, on passera donc par l'intermédiaire de fichiers contenant des sauvegardes de bitmap. Ces fichiers sont des fichiers de caractères codant les données dans un certain format, appelé format bitmap.

                  On trouvera des fichiers au format bitmap dans la distribution standard. Ces fichiers sont en général placés dans le répertoire <X11/bitmaps>. Ils contiennent divers motifs de gris, des flèches, des logos, etc.

                 

                  Il existe également sous shell une commande X appelée bitmap qui permet de créer interactivement des données au format bitmap et de les sauver dans un fichier. Ces données pourront ensuite être récupérées dans un Pixmap; manipulable par le serveur grâce aux  fonctions suivantes :

 

Pixmap XCreatePixmapFromBitmapData (dpy, draw, data, width, height,

                                                                                                  foreground, background, depth)

Pixmap XCreateBitmapFromData (dpy, draw, data, width, height)

 

Status XReadBitmapFile (dpy, draw, filename, &width, &height,

                                                               &pixmap, &x_hot, &y_hot)

Drawable                          draw ;

char *                                 data ;

unsigned int                    width, height, depth ;

unsigned long                 foreground, background ;

Pixmap                              pixmap ;

int                                        x_hot, y_hot ;

 

                  Les Pixmap ainsi créés à partir de données bitmap sont des Pixmap de profondeur 1 correspondant aux données bitmap. Cependant, la fonction XCreatePixmapFromBitmapData permet de créer un véritable Pixmap bicolore en effectuant une transformation de l'image : tous les points à 1 dans le bitmap se trouvent affectés de la couleur d'avant-plan (argument foreground) et ceux marqués de 0 se trouvent affectés par la couleur de fond (argument background).

 

                  Supposons par exemple que le bitmap de la figure 3.7. ait été défini interacti­vement à l’aide de la commande bitmap et qu’il ait été sauvé dans un fichier nommé fleche ou fleche.bm (cela n'a pas d'importance, car la commande bitmap ignore les caractères situés après le point pour générer le contenu du fichier). Ce fichier (créé automatiquement avec la commande bitmap) contiendra les lignes suivantes :

 

#define fleche_width 8

#define fleche_height 8

#define fleche_x_hot 1

#define fleche_y_hot 1

 

static char fleche_bits[] = {

   0x00, 0x1e, 0x06, 0x1a, 0x3a, 0x70, 0x60, 0x00};

 

                  Les coordonnées fleche_x_hot et fleche_y_hot sont les coordonnées du point de référence du bitmap. Ces données sont optionnelles dans la définition d'un Pixmap. Elles peuvent être définies interactivement avec le logiciel bitmap et pourront être utilisées pour définir la position du Pixmap, par exemple lorsqu'il s'agit d'un curseur.

 

 

fig. 3.7. Un bitmap défini

à l'aide de la commande bitmap

                  On pourra inclure directement ce fichier dans le programme (ou le faire avec #include) et utiliser la fonction XCreatePixmapFromBitmapData pour convertir les données fleche_bits, fleche_width, fleche_height au format Pixmap. L’argument de type Drawable[13] est utilisé ici pour déterminer les caractéristiques de l’écran. On peut donc passer simplement la racine :

 

#include “fleche.bm”

Pixmap mon_pixmap;

...

int foreground = BlackPixel(dpy, screen);

int background = WhitePixel(dpy, screen);

 

mon_pixmap = XCreatePixmapFromBitmapData(dpy, root,

                     fleche_bits, fleche_width,

                     fleche_height, foreground,

                     background, DefaultDepth(dpy));

 

                  L'alternative serait de lire directement le fichier fleche.bm en passant son nom en argument à la fonction XReadBitmapFile. Cette fonction prend des adresses en argument pour y placer les valeurs lues en retour. Elle utilise la fenêtre passée en argument pour y récupérer les caractéristiques de l'écran (par exemple, la profondeur) et retourne un Pixmap et ses dimensions. Ainsi, on pourra écrire :

 

#include <X11/Xlib.h>

#include <X11/Xutil.h>

 

Pixmap         mon_pixmap;

unsigned int  width, height;

int            rapport, ignore;

 

rapport = XReadBitmapFile(dpy,DefaultRootWindow(dpy),

                     “/users/cathy/fleche.bm”, &width,

                     &height, &mon_pixmap, &ignore,

                     &ignore);

if (rapport != BitmapSuccess)

         erreur(...);

else ...

 

On notera que pour pouvoir utiliser les constantes de retour de cette fonction on a dû inclure le fichier <X11/Xutil.h>. L'entier retourné peut prendre les valeurs BitmapSucess, BitmapNoMemory ou BitmapOpenFailed.

 

                  Inversement, on pourra écrire dans un fichier les données correspondant à un Pixmap plan grâce à la fonction

 

int XWriteBitmapFile (dpy, filename, pixmap, widh, height, x_hot, y_hot)

 

                  Signalons également les fonctions suivantes :

 

Pixmap XCreatePixmap (dpy, draw, width, height, depth)

XFreePixmap (dpy, pixmap)

 

 

      XCreatePixmap crée un Pixmap de contenu quelconque, aux dimensions spécifiées par les arguments. On utilisera cette fonction pour créer un Pixmap dont le contenu d'origine n'a pas d'importance. XFreePixmap permet de libérer la mémoire d'un Pixmap qu'on n'utilise plus.

 

 

 

       Les fonctions importantes

 

          Window  XCreateSimpleWindow (dpy, parent, x, y, width, height,

                                                              border_width, border_color, background_color)

          Window XCreateWindow (dpy, parent, x, y,width, height, border_width,

                                                                                 depth, class, visual, mask,  &xswa)

 

   XMapWindow (dpy, win)

   XMapSubwindows (dpy, parent)

   XMapRaised (dpy,win)

 

          Status XGetGeometry (dpy, drawable, &root_return, &x, &y, &width,

                                                                                &height, &border_width,&depth)

   XGetWindowAttributes (dpy, win, &win_att)

 

   XChangeWindowAttributes (dpy, win, value_mask, &win_att)

   XSetWindowBackgroundPixmap (dpy, win, pixmap) 

   XSetWindowBackground (dpy, win, pixel) 

   XSetWindowBorderPixmap (dpy, win, pixmap) 

   XSetWindowBorder (dpy, win, pixel)

          XSetWindowColormap (dpy,win,cmap)

          XSetWindowBorderWidth (dpy, win, width)

          XStoreName (dpy, win, string)

 

   XConfigureWindow (dpy, win, value_mask, &xwcvalues)

   XMoveWindow (dpy, win, x, y)

          XResizeWindow (dpy, win, width, height)

          XMoveResizeWindow (dpy, win, x, y, width, height)

          Bool XTranslateCoordinates (dpy, source_win, dest_win, source_x,

                                                                                 source_y, &dest_x, &dest_y, &fille_return)

          DoesBackingStore (screen_ptr)

          DoesSaveUnder (screen_ptr)

 

 

          Pixmap XCreatePixmapFromBitmapData (dpy, draw, data, width,

                                                                                height, foreground, background, depth)

          Pixmap XCreateBitmapFromData (dpy, draw, data, width, height)

          Status XReadBitmapFile (dpy, draw, filename, &width, &height,

                                                                                                   &pixmap, &x_hot, &y_hot)

         

Exercices sur les fenêtres

Les corrigés des exercices sont regroupés pages 269 et suivantes.

 

Exercice 1 :  (Création de fenêtres)

Créer une fenêtre de fond noir avec XCreateSimpleWindow et une deuxième, fille de la première, avec un bord blanc d'une certaine épaisseur. On utilisera pour créer la fenêtre fille la fonction XCreateWindow. Afficher ensuite les deux fenêtres à l'écran.  Le programme déplacera ensuite la fenêtre fille horizontalement d'une distance perceptible (150 points, par exemple). Après lecture d'un caractère (avec getchar), on quittera le programme. Pour être sûr que la librairie Xlib a bien envoyé les requêtes au serveur, on utilisera la requête

 

      XFlush (dpy).

 

Remarque : La fonction XFlush n'est pas utilisée habituellement, car la fonction qui récupère les événements (XNextEvent) effectue elle-même un envoi des requêtes au serveur. Cependant, le débutant qui souhaite juste afficher une fenêtre et sortir sans récupérer d'événement se trouve confronté à un problème s'il n'envoie pas lui-même explicitement les requêtes au serveur.

 

Suggestion :  Ecrire une variante où la fenêtre principale est déplacée sur la racine. Tester ce nouveau programme en présence et en l'absence de window manager.

 

 

Exercice2Exercice 2 :  (Fond de fenêtres)

Créer une fenêtre dont le fond est constitué par un Pixmap créé interactivement à l'aide de l'utilitaire bitmap. On pourra faire deux versions. Une première version dans laquelle le fichier généré par l'utilitaire bitmap est inclu directement dans le programme et une deuxième dans laquelle le fichier est chargé en cours d'exécution. Quels sont les avantages et inconvénients des deux méthodes  ?

 

 

Exercice 3 : (Nom d'une fenêtre et attributs de gravité des sous-fenêtres)

Créer une fenêtre possédant une bannière dont le titre, inscrit par le window manager, est suggéré dans le programme avec la fonction XStoreName (dpy, win, string). Cette fenêtre comportera un certain nombre de sous-fenêtres, rangées en ligne, et possédant un fond différent de la fenêtre principale. Faire varier les valeurs de l'attribut win_gravity et observer les modifications obtenues lors d'un changement de taille de la fenêtre parent.



[1] Par opposition à un Pixmap de fond ou à une couleur provenant d'une table de couleur spéciale. Les fenêtres créées avec XCreateSimpleWindow héritent en effet des attributs depth et visual de leur parent, les autres attributs ayant les valeurs par défaut.

[2] Si l'on fait par exemple dans le programme un appel à XMapWindow, suivi immédiatement d'un appel à getchar pour lire un caractère, il est probable qu'on lira le caractère avant de voir effectivement la fenêtre apparaître à l'écran. Pour remédier aux problèmes de synchronisation, on dispose de deux fonctions XSync et XSynchronize. Mais ces fonctions ne permettent pas de résoudre ce problème. En effet en présence d'un window manager, l'exécution de XMapWindow consiste à informer le window manager de l'émission de cette requête. Le fait de synchroniser la requête n'apporte donc aucune garantie, bien qu’améliorant les choses. On est simplement assuré que la requête a bien été redirigée vers le window manager sous la forme d'un événement.

[3] Seules le fenêtres de type InputOutput peuvent recevoir des événement de type Expose.

[4] L'affichage des sous-fenêtres ne peut de toute manière se produire que si la mère est affichée puisque que cette dernière sert de cadre à l’affichage de ses filles.

[5]  Et l'application ne recevra pas d'événement de type Expose.

[6]  Et l'application ne recevra pas d'événement de type Expose.

[7] On verra chapitres 4 et 5 le sens qu'il faut donner à cette expression.

[8] On peut en effet autoriser le window manager à effectuer des déplacements et iconification de la fenêtre sans y placer de décoration grâce à la propriété WM_TRANSIENT_FOR (cf. chapitre 10 sur la communication entre clients).

[9] C’est la raison pour laquelle il est recommandé d’éviter les requêtes comportant les mots Get, Fetch ou Query.

[10] Cette fonction n'est pas récursive et ne rapporte pas les sous-fenêtres des sous-fenêtres.

[11] Cette fonction est assez fréquemment utilisée pour libérer des données allouées par le serveur, mais il existe aussi des fonctions de libération plus spécifiques comme XFreeColors ou XFreeFonts que nous indiquerons au moment opportun.

[12] Ce sont ceux qui figurent dans la structure de type XSetWindowAttributes que nous avons introduite dans le paragraphe de création de fenêtres

[13] Fenêtre de classe InputOutput ou Pixmap.