Correction du TD X-Window numéro 1



#include <X11/Xlib.h>

#include <stdio.h>
#include <math.h>

/* Les ecrans (screen) et les displays sont des arguments de presque toutes les
   fonctions Xlib. C'est plus simple de les declarer en variables globales
   Les mettre en extern, si on decoupe l'application en plusieurs modules. */

/* Declarer une variable du type Display */
Display *display;

/* Specifier le nom du serveur X auquel on veut se connecter NULL
   signifie que l'on veut se connecter sur le serveur precise dans la
   variable d'environnement DISPLAY */
char *display_name=NULL;            

/* Declarer une variable contenant le numero d'ecran (screen) */
int screen;


/*-----*/
main()
/*-----*/
{
  Window win;                          /* descripteur de la fenetre */

  int display_width, display_height;   /* taille de l'ecran (root window) */
  int width, height;                   /* taille de la fenetre */
  unsigned int border_width=4;         /* largeur de la bordure */
  int x=0, y=0;                       /* position de la fenetre */

  XEvent report;                      /* structure des evenements */

  GC gc;                              /* ID du contexte graphique */

  /* Ouvrir une connection avec le serveur X a l'aide de la fonction
     XOpenDisplay(). Nous allons egalement traiter le cas ou la
     connexion n'a pu etre realisee en affichant un message d'erreur
     du type "pas de connexion avec le serveur <nom du
     serveur>. Attention, comme nous avons initialise le nom du
     serveur a NULL, le nom du serveur sera obtenu a l'aide de la
     fonction XDisplayName() */
  
  if((display=XOpenDisplay(display_name))==NULL) {
    fprintf(stderr,"fenetre de base: ne peut pas se connecter ");
    fprintf(stderr,"au serveur %s\n",XDisplayName(display_name));
    exit(-1);
  }

  /* Recuperer les informations concernant l'ecran (root window) sur
     lequel on va afficher notre application. Le numero de l'ecran
     par defaut s'obtient a l'aide de la macro DefaultScreen(), la
     taille a l'aide des macros DisplayWidth() et
     DisplayHeight(). Il existe de nombreuses macros de ce type.*/
    
  screen = DefaultScreen(display);
  display_width = DisplayWidth(display,screen);
  display_height = DisplayHeight(display,screen);

  /* Initialiser la taille de la fenetre en fonction de la taille de l'ecran */
  width = display_width/3;
  height = display_height/4;

  /* creation d'une fenetre opaque a l'aide de la fonction
     XCreateSimpleWindow(). L'appel de XCreateSimpleWindow au lieu de
     XCreateWindow fait que la fenetre cree herite de tous les
     attributs de la fenetre parent */

  win = XCreateSimpleWindow(display, RootWindow(display, screen), x, y,
                width, height, border_width,
                BlackPixel(display,screen),
                WhitePixel(display,screen));

  /* selection des evenements que l'on desirera traiter pour cette fenetre */

  XSelectInput(display, win, ExposureMask | KeyPressMask |
           ButtonPressMask | StructureNotifyMask | PointerMotionMask);

  /* creation d'un contexte graphique pour cette fenetre,
     indispensable pour dessiner ou afficher du texte */
  get_GC(win, &gc);

  /* affichage (mapping) de la fenetre, on mappe les differentes
     fenetres juste avant la gestion des evenements */

  XMapWindow(display,win);

  /* gestion des evenements:
     -prend un evenement
     -utilise le premier expose pour afficher texte et graphiques
     -utilise ConfigureNotify pour reafficher la fenetre a la taille
     voulue.
     -utilise ButtonPress ou KeyPress pour sortir du programme */

  while(1) {
    XNextEvent(display, &report);
    switch (report.type) {
    case Expose:
      /* on purge la queue des evenements de tous les Expose, pour
     ne redessiner la fenetre qu'une seule fois */
  
      while(XCheckTypedEvent(display, Expose, &report));
         
      break;
    case ConfigureNotify:
      /* La fenetre a ete resizee. On met a jour les variables width
     et height pour que les routines draw_text et draw_graphics
     reaffichent correctement la fenetre, lors du prochain Expose */
       
      width  = report.xconfigure.width;
      height = report.xconfigure.height;

      printf("fenetre retaillee: width = %d height = %d\n", width, height);
      break;
    case ButtonPress:
      printf("Bouton %d enfonce\n", report.xbutton.button);
      draw_rectangle(report.xbutton.window, gc, report.xbutton.x, report.xbutton.y);

      break;
    case KeyPress:
      {
    char buffer;
    int bufsize=1;
    int charcount;

    charcount = XLookupString(&report, &buffer, bufsize, NULL, 
                  NULL);
    printf("Touche %c appuyee\n", buffer);

    if(buffer=='q') {
      XCloseDisplay(display);
      exit(1);
    }
      }
      break;
    case MotionNotify:
      printf("Position curseur = %d %d\n",report.xmotion.x, report.xmotion.y);
      break;
    default:
      /* tous les evenements selectionnes par StructureNotifyMask 
     (DestroyNotify, GravityNotify, etc...) sont filtres ici. */
      break;
    } 
  } 
} 

/*----------------------*/
get_GC(win, gc)
/*----------------------*/
Window win;
GC *gc;
{
  unsigned long valuemask = 0;                /* Ignore XGCvalues et prend les 
                             valeurs par defaut */
  XGCValues values;

  /* creation d'un contexte graphique par defaut */
  *gc = XCreateGC(display, win, valuemask, &values);


  /* specification d'un background noir, puisque par defaut on fait du
     blanc sur du blanc */
  XSetForeground(display, *gc, BlackPixel(display, screen));
}

/*-----------------------*/
draw_rectangle(win, gc, x, y)
/*-----------------------*/
Window win;
GC gc;
int x, y;
{
  XDrawRectangle(display, win, gc, x, y, 50, 50);
}



michel.buffa@essi.fr