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.