next up previous
Next: Funciones auxiliares Up: Construcción de un programa Previous: Variables necesarias

Creación del programa

Una vez analizadas las variables que vamos a necesitar comencemos a crear el programa. Crearemos un fichero vacío que llamaremos circulo.c con cualquier editor ASCII. Para usar funciones de Xlib tenemos que incluir el fichero X11/Xlib.h. También incluimos los ficheros stdio.h y math.h pues usaremos funciones de estos ficheros de cabecera. Por ahora el fichero podría quedar como sigue:

[fontfamily=courier,fontsize=\relsize{-3},frame=single]
#include <X11/Xlib.h>
#include <stdio.h>
#include <math.h>

#define CHANGECENTER 0
#define CHANGERADIO 1
#define NOCHANGE 2

Display *display;
int screen_num;
int main(int argc,char **argv)
{
  int currentX=0,currentY=0,currentR=10;
  int mode=NOCHANGE;
  Window win; 
  unsigned int width, height, x, y; /* anchura de ventana y posición */
  unsigned int borderwidth = 4;	    /* 4 pixels */
  unsigned int display_width, display_height;
  unsigned long foreground_pixel, 
                background_pixel; /* valores de pixel (color) */
  XEvent report;
  GC gc;
  XGCValues values; 
}

El primer paso que hará el programa será la conexión con el display X mediante la función XOpenDisplay():

[fontfamily=courier,fontsize=\relsize{-3},frame=single]
if ( (display=XOpenDisplay(NULL)) == NULL ){
     (void) fprintf(stderr,"circulo: no puedo conectar al servidor X %s\\n");
     exit( -1 );
}

A continuación inializamos la variable screen_num con:

[fontfamily=courier,fontsize=\relsize{-3},frame=single]
screen_num = DefaultScreen(display);

Ahora calculamos anchura, altura y posición de la ventana en la siguiente forma:

[fontfamily=courier,fontsize=\relsize{-3},frame=single]
display_width = DisplayWidth(display, screen_num);
display_height = DisplayHeight(display, screen_num);
x = display_width/3, y = display_height/3;
width = display_width/3, height = display_height/4;

Los colores usados como foreground y background los definimos de la siguiente forma:

[fontfamily=courier,fontsize=\relsize{-3},frame=single]
background_pixel=WhitePixel(display,screen_num);
foreground_pixel=BlackPixel(display,screen_num);

Creamos la ventana de la aplicación:

[fontfamily=courier,fontsize=\relsize{-3},frame=single]
win = XCreateSimpleWindow(display, RootWindow(display,screen_num), x, y, 
         width, height, borderwidth, BlackPixel(display,screen_num),
         background_pixel);

Seleccionamos los eventos Expose (pérdida de contenidos en la ventana), ButtonPress (pulsación de un botón del ratón) y MotionNotify (movimiento del cursor del ratón) en la ventana de la aplicación:

[fontfamily=courier,fontsize=\relsize{-3},frame=single]
XSelectInput(display, win, ExposureMask | ButtonPressMask|
             ButtonMotionMask);

Creamos el contexto gráfico que será usado para dibujar el círculo en la ventana:

[fontfamily=courier,fontsize=\relsize{-3},frame=single]
gc = XCreateGC(display, win, 0 , &values);

Mapeamos la ventana en el display (hacemos que sea visible en pantalla):

[fontfamily=courier,fontsize=\relsize{-3},frame=single]
XMapWindow(display, win);

El programa tendría por ahora el siguiente contenido:

[fontfamily=courier,fontsize=\relsize{-3},frame=single]
#include <X11/Xlib.h>
#include <stdio.h>
#include <math.h>

#define CHANGECENTER 0
#define CHANGERADIO 1
#define NOCHANGE 2

Display *display;
int screen_num;
int main(int argc,char **argv)
{
  int currentX=0,currentY=0,currentR=10;
  int mode=NOCHANGE;
  Window win; 
  unsigned int width, height, x, y; /* anchura de ventana y posición */
  unsigned int borderwidth = 4;	    /* 4 pixels */
  unsigned int display_width, display_height;
  unsigned long foreground_pixel, 
                background_pixel; /* valores de pixel (color) */
  XEvent report;
  GC gc;
  XGCValues values; 
  
  if ( (display=XOpenDisplay(NULL)) == NULL ){
      (void) fprintf(stderr,"circulo: no puedo conectar al servidor X %s\\n");
      exit( -1 );
  }
  screen_num = DefaultScreen(display);
  display_width = DisplayWidth(display, screen_num);
  display_height = DisplayHeight(display, screen_num);
  x = display_width/3, y = display_height/3;
  width = display_width/3, height = display_height/4;
  background_pixel=WhitePixel(display,screen_num);
  foreground_pixel=BlackPixel(display,screen_num);
  win = XCreateSimpleWindow(display, RootWindow(display,screen_num), x, y, 
         width, height, borderwidth, BlackPixel(display,screen_num),
         background_pixel);
  XSelectInput(display, win, ExposureMask | ButtonPressMask|
               ButtonMotionMask);
  gc = XCreateGC(display, win, 0 , &values);
  XMapWindow(display, win);
}

Ya sólo nos queda construir el bucle de eventos del programa. Es un bucle infinito en el que en cada pasada se lee un evento, se ve de qué tipo es y se realiza una u otra acción dependiendo del tipo. El esqueleto de este bucle a falta de incluir el código para cada evento quedaría de la siguiente forma:

[fontfamily=courier,fontsize=\relsize{-3},frame=single]
while (1)  {
  XNextEvent(display, &report);
  switch  (report.type) {
    case Expose:
         break;
    case ButtonPress:
         break;
    case MotionNotify:
         break;
  }
}

El código para el evento Expose debe dibujar el círculo en su posición actual con su radio correspondiente:

[fontfamily=courier,fontsize=\relsize{-3},frame=single]
case Expose:
     XSetFunction(display, gc, GXcopy);
     XSetForeground(display,gc,foreground_pixel);
     XDrawArc(display,win,gc,currentX-currentR,currentY-currentR,
              currentR*2,currentR*2,0,360*64);
     break;

En el evento ButtonPress debemos ver si hemos pinchado en el botón izquierdo (Button1) o el botón derecho (Button3). Si se ha pinchado con el botón izquierdo pasaremos a modo CHANGECENTER, borramos el círculo de su posición anterior, cambiamos la posición del centro a la posición del cursor, y dibujamos el círculo en la nueva posición. Si se ha pinchado con el botón derecho pasaremos a modo CHANGERADIO, borramos el círculo de su posición anterior, asignamos al radio del círculo la distancia entre el centro del círculo y la posición del cursor del ratón, y dibujamos el círculo con el nuevo radio:

[fontfamily=courier,fontsize=\relsize{-3},frame=single]
case ButtonPress:
     if(report.xbutton.button==Button1){
         mode=CHANGECENTER;
         XSetFunction(display, gc, GXxor);
         XSetForeground(display,gc,foreground_pixel^background_pixel);
         XDrawArc(display, win, gc, currentX-currentR,
                  currentY-currentR,currentR*2,currentR*2,0,360*64);		  
         currentX=report.xbutton.x;
         currentY=report.xbutton.y;
         XDrawArc(display, win, gc, currentX-currentR,
                  currentY-currentR,currentR*2,currentR*2,0,360*64);		  
     } 
     else if(report.xbutton.button==Button3){
	 mode=CHANGERADIO;
         XSetFunction(display, gc, GXxor);
         XSetForeground(display,gc,foreground_pixel^background_pixel);
         XDrawArc(display, win, gc, currentX-currentR,
                  currentY-currentR,currentR*2,currentR*2,0,360*64);		  
         currentR=distancia(report.xbutton.x,report.xbutton.y,
			    currentX,currentY);
         XDrawArc(display, win, gc, currentX-currentR,
                  currentY-currentR,currentR*2,currentR*2,0,360*64);		  
     }       
     else 
	 mode=NOCHANGE;
     break;

Se deja como ejercicio incluir el código para el evento MotionNotify.


next up previous
Next: Funciones auxiliares Up: Construcción de un programa Previous: Variables necesarias
Andrés Cano Utrera 2010-10-19