Previous Next Table of Contents

6. Dibujo de gráficos

6.1 Las dos cosas que se deben especificar al dibujar gráficos

Para dibujar gráficos se deben especificar dos cosas: las primitivas gráficas y los atributos gráficos. Las primitivas gráficas son los objetos fundamentales que se pueden dibujar mediante llamadas a la Xlib. La relación entre ambas se puede ver en la tabla 6.1:

+-------------------+-------------------------------------+
|Llamada a la Xlib  |Primitiva gráfica                    |
+-------------------+-------------------------------------+
|XDrawPoint         |punto                                | 
+-------------------+-------------------------------------+
|XDrawPoints        |puntos                               | 
+-------------------+-------------------------------------+
|XDrawLine          |línea entre los dos puntos           | 
+-------------------+-------------------------------------+
|XDrawLines         |polilínea                            | 
+-------------------+-------------------------------------+
|XDrawSegments      |segmentos de línea                   | 
+-------------------+-------------------------------------+
|XDrawRectangle     |rectángulo                           | 
+-------------------+-------------------------------------+
|XDrawRectangles    |rectángulos                          | 
+-------------------+-------------------------------------+
|XDrawArc           |arco de circunferencia               | 
+-------------------+-------------------------------------+
|XDrawArcs          |arcos de circunferencia              | 
+-------------------+-------------------------------------+
|XFillRectangle     |rectángulo relleno                   | 
+-------------------+-------------------------------------+
|XFillRectangles    |rectángulos rellenos                 | 
+-------------------+-------------------------------------+
|XFillPolygon       |polígono relleno                     | 
+-------------------+-------------------------------------+
|XFillArc           |arco de circunferencia relleno       | 
+-------------------+-------------------------------------+
|XFillArcs          |arcos de circunferencia rellenos     | 
+-------------------+-------------------------------------+
|XDrawText          |                                     |
|XDrawString        |texto                                |
|XDrawImageString   |                                     |
+-------------------+-------------------------------------+
|XDrawText16        |                                     |
|XDrawString16      |texto especial (alfabetos no latinos)| 
|XDrawImageString16 |                                     | 
+-------------------+-------------------------------------+
   Tabla 6.1: primitivas gráficas y llamadas a la Xlib

Los atributos gráficos son las características relacionadas con las primitivas gráficas, por ejemplo, para la primitiva gráfica línea los atributos gráficos son el ancho de la línea, el color y el estilo con que se debe dibujar.

6.2 Manejo de atributos gráficos

Hay dos métodos de manejar los atributos gráficos. El primero consiste en enviar los atributos al servidor al mismo tiempo que las peticiones de dibujo de primitivas. El segundo método consiste en enviar los atributos previamente al servidor, que los almacena, y enviar las peticiones de las primitivas gráficas sin volver a enviar los atributos. El segundo método es mucho más eficiente ya que sobrecarga menos la red.

6.3 Contexto gráfico

Un contexto gráfico o simplemente, un GC, es el recurso del servidor donde se almacenan los atributos de los gráficos. Es necesario al menos un GC para que el servidor acepte peticiones de primitivas gráficas por parte del cliente, ya que cada petición de primitiva gráfica debe especificar el identificador del GC que se debe usar.

Los GCs se crean y se almacenan en el servidor. Los clientes pueden solicitar la creación de un GC en el servidor y obtener su identificador, mediante el cual pueden establecer o cambiar los atributos almacenados en el GC.

6.4 Los tres pasos para dibujar gráficos

Los tres pasos necesarios para poder dibujar gráficos son los siguientes:

  1. Obtener un GC o crearlo.
  2. Establecer los atributos del GC apropiadamente.
  3. Enviar las peticiones de las primitivas gráficas.

Para el primer paso hay tres métodos posibles:

  1. Crear un GC y obtener su ID.
  2. Copiar sobre un nuevo GC un GC ya creado y obtener su ID.
  3. Obtener el ID del GC creado por defecto en el servidor.

6.5 Creación y establecimiento de atributos de GCs

Se puede crear un GC y especificar los atributos gráficos al mismo tiempo. También se pueden cambiar los atributos una vez creado un GC. Un GC puede almacenar 23 atributos gráficos. La estructura XGCValues se usa para especificar todos o algunos de los 23 atributos a la hora de crear o cambiar un GC. En la mayoría de los casos sólo habrá que especificar algunos de los 23 atributos, no todos.

Para especificar qué valores de atributos se deben tomar como válidos en la estructura XCGValues se usa una máscara de valores, en la que cada bit del 0 al 22 se corresponde con cada uno de los 23 miembros, de forma que si el bit está a 1 se toma el valor del campo como válido, y si está a 0 no se tiene en cuenta.

Para establecer los valores de la máscara se pueden usar los siguientes símbolos. Si se quiere especificar más de un cambio se puede hacer mediante la operacion OR. Los símbolos son los siguientes:

#define GCFunction              (1L<<0)
#define GCPlaneMask             (1L<<1)
#define GCForeground            (1L<<2)
#define GCBackground            (1L<<3)
#define GCLineWidth             (1L<<4)
#define GCLineStyle             (1L<<5)
#define GCCapStyle              (1L<<6)
#define GCJoinStyle             (1L<<7)
#define GCFillStyle             (1L<<8)
#define GCFillRule              (1L<<9)
#define GCTile                  (1L<<10)
#define GCStipple               (1L<<11)
#define GCTileStipXOrigin       (1L<<12)
#define GCTileStipYOrigin       (1L<<13)
#define GCFont                  (1L<<14)
#define GCSubwindowMode         (1L<<15)
#define GCGraphicsExposures     (1L<<16)
#define GCClipXOrigin           (1L<<17)
#define GCClipYOrigin           (1L<<18)
#define GCClipMask              (1L<<19)
#define GCDashOffset            (1L<<20)
#define GCDashList              (1L<<21)
#define GCArcMode               (1L<<22)

La estructura XGCValues está definida como sigue:

typedef struct {
    int function;             /* operación lógica */
    unsigned long plane_mask; /* máscara de plano */
    unsigned long foreground; /* color de primer plano */
    unsigned long background; /* color de fondo */
    int line_width;           /* ancho de linea */
    int line_style;           /* LineSolid, LineOfOffDash, LineDoubleDash */
    int cap_style;            /* CapNotLast, CapButt, CapRound, CapProjecting */
    int join_style;           /* JoinMiter, JoinRound, JoinBevel */
    int fill_style;           /* FillSolid,FillTiled,FillStippled,FillOpaeueStippled */
    int fill_rule;            /* EvenOddRule, WindingRule */
    int arc_mode;             /* ArcChord, ArcPieSlice */
    Pixmap tile;              /* pixmap para operaciones de "tile" */
    Pixmap stipple;           /* pixmap para operaciones de "stipple" */
    int ts_x_origin;          /* desplazamiento del pixmap en las */
    int ts_y_origin;          /* de "tile" y "stipple" */
    Font font;                /* fuente por defecto para las operaciones de texto */
    int subwindow_mode;       /* ClipByChildren, IncludeInferiors */
    Bool graphic_exposures;   /* deben generarse exposiciones ? */
    int clip_x_origin;        /* origen de recortado */
    int clip_y_origin;
    Pixmap clip_mask;         /* recorte de mapa de bits */
    int dash_offset;          /* información de la linea dashed/patterned */
    char dashes;
} XGCValues;

6.6 Llamadas Xlib: creación y modificación de GCs

GC XCreateGC( Display *display, Drawable drw,
              unsigned long mascara, XGCValues *valores );
XChangeGC( Display *display, GC gc,
           unsigned long mascara, XCGValues *valores );

Mediante XCreateGC se puede crear un GC en el servidor y obtener su ID. Al mismo tiempo se pueden establecer todos o algunos de los 23 atributos gráficos del GC usando los argumentos mascara y valores, los cúales, si toman los valores 0 y NULL respectivamente, hacen que GC tome los atributos por defecto. Los valores por defecto se pueden ver en la tabla 6.2.

Mediante XChangeGC se pueden cambiar todos o algunos de los 23 atributos gráficos de un GC especificando los valores de los campos y de máscara adecuados.

6.7 Ejemplo: código

GC gc;                                                         /* A */
XGCValues valores1, valores2;                                  /* B */
 
valores1.foreground = color1.pixel;                            /* C */
valores1.line_width = 10;
 
gc = XCreateGC( d, w, GCForeground | GCLineWidth, &valores1 ); /* D */
 
valores2.line_style = LineOnOffDash;                           /* E */
valores2.cap_style  = CapButt;
 
XChangeGC( d, gc, GCLineStyle | GCCapStyle, &valores2 );       /* F */
XDrawLine( d, w, gc, 50, 150, 350, 150 );                      /* G */

En A se declara el contexto gráfico y en B las estructuras para los atributos gráficos. En C y D establecemos los valores de color de fondo y ancho de línea y creamos el GC con dichos valores. En E y F cambiamos dos atributos del GC creado anteriormente y en G dibujamos una línea con el GC actual.

+--------------------+--------------------------------------+
| Campo de XCGValues |          Valor por defecto           |
+--------------------+--------------------------------------+
|function            |GXcopy                                |
+--------------------+--------------------------------------+
|plane_mask          |todo a 1                              |
+--------------------+--------------------------------------+
|foreground          |0                                     |
+--------------------+--------------------------------------+
|background          |1                                     |
+--------------------+--------------------------------------+
|line_width          |0                                     |
+--------------------+--------------------------------------+
|line_style          |LineSolid                             |
+--------------------+--------------------------------------+
|cap_style           |CapButt                               |
+--------------------+--------------------------------------+
|join_style          |JoinMiter                             |
+--------------------+--------------------------------------+
|fill_style          |FillSolid                             |
+--------------------+--------------------------------------+
|fill_rule           |EvenOddRule                           |
+--------------------+--------------------------------------+
|arc_mode            |ArcPieSlice                           |
+--------------------+--------------------------------------+
|tile                |pixmap relleno con el color de fondo  |
+--------------------+--------------------------------------+
|stipple             |pixmap relleno de 1s                  |
+--------------------+--------------------------------------+
|ts_x_origin         |0                                     |
+--------------------+--------------------------------------+
|ts_y_origin         |0                                     |
+--------------------+--------------------------------------+
|font                |depende de la implementación          |
+--------------------+--------------------------------------+
|subwindow_mode      |ClipByChildren                        |
+--------------------+--------------------------------------+
|graphics_exposures  |True                                  |
+--------------------+--------------------------------------+
|clip_x_origin       |0                                     |
+--------------------+--------------------------------------+
|clip_x_origin       |0                                     |
+--------------------+--------------------------------------+
|clip_mask           |Ninguno                               |
+--------------------+--------------------------------------+
|dash_offset         |0                                     |
+--------------------+--------------------------------------+
|dashes              |4 (es decir, la lista [4,4])          |
+--------------------+--------------------------------------+
       Tabla 6.2: valores por defecto de XGCValues

6.8 Funciones de conveniencia

Se pueden establecer y cambiar algunos o todos los atributos gráficos usando las funciones vistas hasta ahora, es decir, XCreateGC y XChangeGC. Una forma alternativa es usar las funciones de conveniencia, que cambian los atributos individualmente o en pequeños grupos. Estas funciones tienen unos nombres significativos y sencillos de recordar, y por tanto hacen más fácil el mantenimiento del código.

La forma usual de usar estas funciones de conveniencia es crear un GC sin especificar ningún valor, es decir, con los valores por defecto, y a continuación usar las funciones de conveniencia correspondientes para establecer los valores deseados. La tabla 6.3 muestra la relación entre los campos de XGCValues y las funciones de conveniencia.

+--------------------+--------------------------------------+
| Campo de XCGValues |          Valor por defecto           |
+--------------------+--------------------------------------+
|function            |XSetState, XSetFunction               |
+--------------------+--------------------------------------+
|plane_mask          |XSetState, XSetPlaneMask              |
+--------------------+--------------------------------------+
|foreground          |XSetState, XSetForeground             |
+--------------------+--------------------------------------+
|background          |XSetState, XSetBackground             |
+--------------------+--------------------------------------+
|line_width          |XSetLineAttributes                    |
+--------------------+--------------------------------------+
|line_style          |XSetLineAttributes                    |
+--------------------+--------------------------------------+
|cap_style           |XSetLineAttributes                    |
+--------------------+--------------------------------------+
|join_style          |XSetLineAttributes                    |
+--------------------+--------------------------------------+
|fill_style          |XSetArcMode                           |
+--------------------+--------------------------------------+
|fill_rule           |XSetFillRule                          |
+--------------------+--------------------------------------+
|arc_mode            |XSetArcMode                           |
+--------------------+--------------------------------------+
|tile                |XSetTile                              |
+--------------------+--------------------------------------+
|stipple             |XSetStipple                           |
+--------------------+--------------------------------------+
|ts_x_origin         |XSetTSOrigin                          |
+--------------------+--------------------------------------+
|ts_y_origin         |XSetTSOrigin                          |
+--------------------+--------------------------------------+
|font                |XSetFont                              |
+--------------------+--------------------------------------+
|subwindow_mode      |XSetSubwindowMode                     |
+--------------------+--------------------------------------+
|graphics_exposures  |XSetGraphicsExposures                 |
+--------------------+--------------------------------------+
|clip_x_origin       |XSetClipOrigin                        |
+--------------------+--------------------------------------+
|clip_x_origin       |XSetClipOrigin                        |
+--------------------+--------------------------------------+
|clip_mask           |XSetClipMask, XSetClipRectangle       |
+--------------------+--------------------------------------+
|dash_offset         |XSetDashes                            |
+--------------------+--------------------------------------+
|dashes              |XSetDashes                            |
+--------------------+--------------------------------------+
  Tabla 6.3: campos de XGCValues y funciones de conveniencia

6.9 Ejemplo: código

GC gc; /* A */
gc = XCreateGC( d, w, 0, NULL ); /* B */
XSetForeground( d, gc, color.pixel ); /* C */
XSetLineAttributes( d, gc, 10, LineOffDash, CapButt, JoinRound );
XDrawLine( d, w, gc, 50, 150, 350, 150 ); /* D */

En A declaramos el GC de la forma habitual, sin embargo en B lo creamos sin especificar ningún atributo. A continuación en C establecemos los valores de fondo y varios de atributos de línea usando dos funciones de conveniencia. Por último en D dibujamos una línea de la forma usual.

6.10 Dibujable (Drawable)

Un dibujable es un recurso en el que se pueden dibujar gráficos, es decir, una ventana o un pixmap. Un pixmap es un área de memoria en la que se pueden almacenar gráficos, aunque no son visibles. Los gráficos de un pixmap se usan copiándolos sobre las ventanas o bien como patrón de relleno.

6.11 Llamadas Xlib: especificación de colores

XSetForeground( Display *display, GC gc, unsigned long pixel )
XSetBackground( Display *display, GC gc, unsigned long pixel )
XSetForeground

establece el atributo de frente del GC pasado como argumento. El color se frente determina el color de todas las primitivas gráficas, aunque hay algunas que también tiene partes del color del atributo de fondo.

XSetBackground

establece el atributo de fondo del GC pasado como argumento. El color afecta a parte del color de las siguientes primitivas gráficas: líneas discontínuas, patrones con zonas transparentes (stipples) y texto.

6.12 Ejemplo: código

El siguiente programa dibuja dos líneas, una de color verde desde el punto (50,100) al (350,100), y otra de color rojo desde el (50,200) al (350,200).


#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
 
extern unsigned long Color( Display *display, const char *nombreColor );
 
main()
    {
    Display *d;
    Window w;
    unsigned long verde, rojo;
    GC gc;
 
    d = XOpenDisplay( NULL );
 
    verde = Color( d, "green" );
    rojo  = Color( d, "red"   );
 
    w = XCreateSimpleWindow( d, DefaultRootWindow( d ), 250, 50, 400, 300, 2,
        BlackPixel( d, DefaultScreen( d ) ),
        WhitePixel( d, DefaultScreen( d ) ) );
 
    XMapWindow( d, w );
 
    gc = XCreateGC( d, w, 0, NULL );
 
    XSetForeground( d, gc, verde );
    XDrawLine( d, w, gc, 50, 100, 350, 100 );
 
    XSetForeground( d, gc, rojo );
    XDrawLine( d, w, gc, 50, 200, 350, 200 );
 
    XFlush( d );
    getchar();
    }

6.13 Llamadas Xlib: dibujo de puntos

XDrawPoint( Display *d, Drawable drw, GC gc, int x, int y )
XDrawPoints( Display *d, Drawable drw, GC gc, XPoint *puntos, int n, int modo )

XDrawPoint dibuja un punto en las coordenadas especificadas. XDrawPoints dibuja un conjunto de n puntos pasado como un array. La definición de XPoint es la siguiente:

typedef struct {
    short x, y;
} XPoint;

El argumento modo puede tomar los valores CoordModeOrigin o CoordModePrevious. El primero toma las coordenadas como absolutas mientras que el segundo las toma como relativas a partir del segundo punto ( el primer punto siempre se toma en coordenadas absolutas).

6.14 Ejemplo: código

El siguiente programa crea una ventana de 400 por 300 píxels y dibuja en ella los siguientes puntos: (100,500), (200,100), (200,200), (250,150), (300,100) y (300,200).


#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
 
main()
    {
    Display *d;
    Window w;
    GC gc;
    XPoint puntos[] = {
        { 200,100 }, { 200,200 }, { 250,150 }, { 300,100 }, { 300,200 }
    };
 
    d = XOpenDisplay( NULL );
 
    w = XCreateSimpleWindow( d, DefaultRootWindow( d ), 250, 50, 400, 300, 2,
        BlackPixel( d, DefaultScreen( d ) ),
        WhitePixel( d, DefaultScreen( d ) ) );
 
    XMapWindow( d, w );
 
    gc = XCreateGC( d, w, 0, NULL );
 
    XDrawPoint( d, w, gc, 100, 150 );
    XDrawPoints( d, w, gc, puntos, 5, CoordModeOrigin );
 
    XFlush( d );
    getchar();
    }

6.15 Llamadas Xlib: dibujo de líneas

XDrawLine( Display *d, Drawable drw, GC gc,
           int x1, int y1, int x2, int y2 )
XDrawSegments( Display *d, Drawable drw, GC gc,
               XSegment *segmentos, int n )
XDrawLines( Display *d, Drawable drw, GC gc,
            XPoint *puntos, int n, int modo )

XDrawLine dibuja una línea entre ambos pares de coordenadas pasados como argumentos. XDrawSegments dibuja un conjunto de n segmentos pasados como argumentos. La estructura XSegment tiene la siguiente definición:

typedef structure {
    short x1, y1, x2, y2;
} XSegment;

Por último, XDrawLines dibuja la polilínea especificada por los puntos contenidos en el array pasado como argumento.

6.16 Atributos gráficos de líneas

Los atributos gráficos relacionados con el dibujo de líneas son los siguientes:

foreground   background   line_width   line_style   cap_style   join_style

Los atributos foreground (color de primer plano) y background (color de fondo) se pueden especificar con las funciones de conveniencia vistas en el apartado 6.11. Los demás atributos, ancho, estilo, terminación y unión, se pueden especificar mediante la función de conveniencia XSelLineAttributes.

Estilo de terminación (cap_stile)

Hay cuatro estilos de terminación de línea:

CapNotLast

Termina la linea de forma cuadrada y sin llegar al punto final.

CapButt

Termina la linea de forma cuadrada y llegando justo al punto final.

CapRound

Sobrepasa (en un número de píxels igual a la mitad del ancho de linea) el punto final y termina en forma redondeada.

CapProyecting

Igual que CapRound, pero de forma cuadrada.

Estilo de unión (join_stile)

Hay tres estilos de unión de líneas que se aplican cuando se una la función XDrawLine:

JoinMiter

Con esquina cuadrada

JoinRound

Con esquina arqueada

JoinBevel

Con esquina triangular

6.17 Llamadas Xlib: establecimiento de atributos de línea

XSetLineAttributes( Display *display, GC gc,
                    unsigned int anchoLinea, int estiloLinea,
                    int estiloTerminacion, int estiloUnion );

El anchoLinea especifica el ancho de la línea en píxels. El valor por defecto es 0, que produce la línea más fina posible. El estiloLinea puede tener uno de los siguientes valores:

LineSolid   LineOnOffDash   LineDoubleDash

Los otros dos argumentos pueden tomar los valores que pueden verse en 6.16.1 y 6.16.2.

Por ejemplo, si se selecciona LineDoubleDash como el valor de estilo de línea se dibujan líneas discontinuas, en las que los atributos de frente y fondo determinan los dos colores de la línea.

6.18 Ejemplo: código

El siguiente programa dibuja una línea discontinua de dos colores entre los puntos (50,100) y (150,100).


#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <stdio.h> 
 
extern unsigned long Color( Display *display, const char *nombreColor ); 
 
main() 
    { 
    Display *d; 
    int pantalla; 
    Window w; 
    long amarillo, rojo; 
    GC gc; 
 
    d        = XOpenDisplay( NULL ); 
    pantalla = DefaultScreen( d ); 
 
    amarillo = Color( d, "yellow" );
    rojo     = Color( d, "red"   );
 
    w = XCreateSimpleWindow( d, DefaultRootWindow( d ), 400, 200, 300, 200, 2,
        BlackPixel( d, pantalla ), WhitePixel( d, pantalla ) );
 
    XMapWindow( d, w );
 
    gc = XCreateGC( d, w, 0, NULL );
 
    XSetLineAttributes( d, gc, 5, LineDoubleDash, CapButt, JoinMiter );
    XSetForeground( d, gc, rojo );
    XSetBackground( d, gc, amarillo );
 
    XDrawLine( d, w, gc, 50, 100, 250, 100 );
 
    XFlush( d );
    getchar();
    }

6.19 Llamadas Xlib: definición de patrones de linea

XSetDashes( Display *display, GC gc, int offset, char lista[], int n )

Se pueden definir patrones de línea dando la longitud en píxels de las zonas de primer plano y fondo. Para ello se utiliza la función XSetDashes. El argumento offset indica la distancia en píxels desde el comienzo de la línea hasta donde se desea que empiece a dibujarse el patrón. En lista se pasan los valores correspondientes a número de píxels con color de primer plano, número de píxels con color de fondo, etc, siendo n el número de elementos del array, que siempre debe ser par.

Por ejemplo, si se quiere que el patrón de dibujo de líneas sea 20 píxels con color de primer plano, 10 con color de fondo, 10 con color de primer plano y 5 con color de fondo el código que lo haría sería el siguiente:

char patron[] = { 20, 10, 10, 5 };
...
XSetDashes( d, gc, 0, patron, 4 );
XDrawLine( d, w, gc, 100, 100, 400, 100 );
...

6.20 LAB: Dibujo de líneas y segmentos

Escribir un programa que dibuje líneas con todo tipo de estilo, terminación y unión.

6.21 Llamadas Xlib: dibujo de rectángulos

XDrawRectangle( Display *d, Drawable drw, GC gc, int x, int y,
                unsigned int anchura, unsigned int altura )
XDrawRectangles( Display *d, Drawable drw, GC gc,
                 XRectangle rectangulos[], int n )
XDrawRectangle

dibuja un rectángulo cuya esquina superior izquierda está en la posición especificada por x e y, y tiene la altura (sobre y) y la anchura (sobre x) especificadas.

XDrawRectangles

dibuja un conjunto de n rectángulos pasado como un array de XRectangles.

La definición de XRectangle es la siguiente:

typedef struct {
    short x, y;
    unsigned short width, height;
} XRectangle;

Las siguientes funciones hacen lo mismo pero dibujan un rectángulo relleno:

XFillRectangle( Display *d, Drawable drw, GC gc, int x, int y,
                unsigned int anchura, unsigned int altura )
XFillRectangles( Display *d, Drawable drw, GC gc,
                 XRectangle rectangulos[], int n )

6.22 Llamadas Xlib: dibujo de arcos

XDrawArc( Display *d, Drawable drw, GC gc, int x, int y,
          unsigned int anchura, unsigned int altura,
          int angulo1, angulo2 );
XDrawArcs( Display *d, Drawable drw, GC gc, XArc arcos[], int n )
XDrawArc

dibuja un arco. El angulo1 especifica el comienzo del arco en unidades de grado multiplicadas por 64. El angulo2 especifica la extensión del arco relativo al comienzo del arco (no al origen de ángulos).

XDrawArcs

dibuja un conjunto de n arcos pasado como un array de XArcs.

La definición de XArc es la siguiente:

typedef struct {
    short x, y;
    unsigned short width, height;
    short angle1, angle2;
} XArc

Las siguientes funciones hacen lo mismo pero dibujan el arco relleno:

XFillArc( Display *d, Drawable drw, GC gc, int x, int y,
          unsigned int anchura, unsigned int altura,
          int angulo1, int angulo2 )
XFillArcs( Display *d, Drawable drw, GC gc, XArc arcos[], int n )

Hay dos modos de relleno, ArcPieSlice y ArcChord, que se establecen con XSetArcMode:

XSetArcMode( Display *d, GC gc, int modo )

6.23 Llamadas Xlib: relleno de polígonos

XFillPolygon( Display *d, Drawable drw, GC gc, XPoint puntos[],
              int n, int forma, int modo )
XSetFillRule( Display *d, GC gc, int reglaRelleno )

XFillPolygon dibuja un polígono relleno cuyos n puntos se encuentran en el array de XPoints pasado como argumento. El argumento forma indica el tipo de polígono, y puede tomar los siguientes valores:

Convex

el polígono es convexo.

Nonconvex

el polígono es cóncavo y no tiene intersección de líneas.

Complex

el polígono tiene líneas que intersectan.

El argumento modo tiene el mismo significado que en las llamadas vistas anteriormente, indica si las coordenadas han de tomarse como absolutas o como relativas al primer punto.

XSetFillRule establece el modo de relleno de polígonos que tengan líneas que intersectan. Puede tomar dos valores:

EvenOddRule

si varias areas del polígono se superponen un número impar de veces no se dibuja el area de intersección.

WindingRule

las areas de intersección se rellenan siempre.

6.24 Dibujo de texto

Para dibujar texto hacen falta dos pasos previos:

  1. Cargar una fuente Es necesario decirle al servidor qué fuente debe usar para que la cargue. Esto se hace mediante la función XLoadFont que devuelve el ID de la fuente para posteriores referencias.
  2. Establecer fuente Hay que establecer el fuente como el atributo correspondiente del GC mediante la función XSetFont.

6.25 Llamadas Xlib: dibujo de texto

Font XLoadFont( Display *display, char *nombreFuente )
XSetFont( Display *display, GC gc, Font fuente )
XDrawString( Display *d, GC gc, Drawable drw,
             int x, int y, char *cadena, int n )
XLoadFont

carga el fuente cuyo nombre se especifica devolviendo un identificador. Los nombres válidos de fuente se pueden encontrar en el directorio /usr/lib/X11/fonts, donde tienen el sufijo .snf, que no hace falta especificar en el nombre de fuente. Se puede ver el aspecto de una fuente con la utilidad xfd.

XSetFont

establece el fuente pasado como argumento como el fuente del GC también pasado como argumento.

XDrawString

dibuja la cadena de longitud n tomando las coordenadas x e y como el comienzo de la línea base del primer caracter de la cadena.

6.26 Ejemplo problema

Escribir un programa que dibuje la cadena "Abcde" en la posición (100,100) usando el fuente "9x15".

6.27 Ejemplo: solución


#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <stdio.h> 
 
main() 
    { 
    Display *d; 
    Window w; 
    GC gc; 
    Font fuente; 
    char cadena[] = "Abcde"; 
 
    d = XOpenDisplay( NULL ); 
 
    w = XCreateSimpleWindow( d, DefaultRootWindow( d ), 
            200, 300, 400, 300, 2, 0, 1 ); 
     XMapWindow( d, w ); 
 
    gc = XCreateGC( d, w, 0, NULL ); 
 
    fuente = XLoadFont( d, "9x15" ); 
    XSetFont( d, gc, fuente ); 
 
    XDrawString( d, w, gc, 100, 100, cadena, strlen( cadena ) ); 
 
    XFlush( d ); 
    getchar(); 
    }

6.28 Llamada Xlib: dibujar imágenes de texto

Una imágen de texto tiene el fondo opaco del color del atributo de fondo del GC actual, mientras que un texto normal tiene el fondo transparente. La llamada para dibujar una imágen de texto es:

XDrawImageString( Display *d, Drawable drw, GC gc,
                  int x, int y, char *cadena, int n )

En el ejemplo anterior, si se hubiera querido dibujar la cadena como una imágen de texto con el frente rojo y el fondo azul habría que haber hecho lo siguiente:

...
azul = Color( "blue" );
rojo = Color( "red" );
...
XSetFont( d, gc, fuente );
XSetForeground( d, gc, rojo );
XSetBackground( d, gc, azul );
 
XDrawImageString( d, w, gc, 100, 100, cadena, strlen( cadena ) );
...

6.29 Manejo de eventos de exposición

Las ventanas pueden estar superpuestas unas a otras, con lo que la información gráfica de las ventanas ocultas puede perderse si no se almacena. Algunas estaciones de trabajo con grandes cantidades de memoria se encargan de restaurar las partes ocultas de las ventanas, aunque la mayoría no lo hace, ya que resulta más eficiente manejar el problema usando el evento Expose.

Un evento de tipo Expose ocurre siempre que toda o parte de una ventana queda expuesta a la visión del usuario, es decir, cuando deja de estar oculta por otras ventanas. Estas situaciones se pueden dar cuando una ventana pasa de estar no mapeada a mapeada, cuando se la eleva en la pila, cuando se mueve una ventana que la ocultaba total o parcialmente, etc.

El tipo de evento como ya se ha dicho es Expose, la máscara de evento asociada es ExposureMask, y la estructura de evento es XExposeEvent, cuyos campos más importantes son x, y, width, height y count.

Cuando se produce un evento de tipo Expose se deben restaurar los gráficos de alguna de estas tres formas:

Cuando se produce un evento de tipo Expose, las áreas expuestas se descomponen en uno o más rectángulos, cada uno de los cúales genera un evento de tipo Expose. Como resultado, una exposición produce una seria de eventos de tipo Expose. El campo count indica cúantos eventos tipo Expose han ocurrido. Cuando es cero indica que es el último evento de la serie. Cada rectángulo expuesto se define mediante los campos x, y, width y height.

6.30 Ejemplo: código

El siguiente programa detecta los eventos de exposición y redibuja todos los gráficos (un rectángulo) cada vez. No hace falta dibujarlos antes de entrar en el bucle de eventos porque al mapear la ventana ya se produce un evento tipo Expose.


#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <stdio.h> 
 
extern unsigned long Color( Display *display, const char *nombreColor ); 
 
main() 
    { 
    Display *d; 
    Window w; 
    XEvent e; 
    GC gc; 
 
    d = XOpenDisplay( NULL ); 
 
    w = XCreateSimpleWindow( d, DefaultRootWindow( d ), 
            200, 300, 400, 300, 2, 0, 1 ); 
 
    XSelectInput( d, w, ExposureMask | KeyPressMask ); 
 
    gc = XCreateGC( d, w, 0, NULL ); 
    XSetForeground( d, gc, Color( d, "green" ) ); 
 
    XMapWindow( d, w ); 
 
    while ( True ) 
        { 
        XNextEvent( d, &e ); 
        if ( e.type == Expose ) 
            XFillRectangle( d, w, gc, 50, 50, 400, 300 ); 
        else if ( e.type == KeyPress ) 
            exit( 0 ); 
        }
    }

6.31 Manejo de eventos de exposición gráfica

Las funciones XCopyArea y XCopyPlane pueden copiar un área específica de una ventana sobre un dibujable. Si dicha área está tapada por otras ventanas, la imagen no se puede copiar de forma completa. Para solucionar este problema se usan los eventos especiales GraphicsExpose y NoExpose. El evento GraphicsExpose se envía desde el servidor si el área que se copia está tapada parcial o totalmente por otras ventanas, en caso contrario se envía al evento NoExpose.

Estos dos eventos no tienen una máscara de eventos propia (recordemos que estaban marcados con un asterisco en la tabla 4.3) sino que se controlan con el atributo graphics_exposures del GC. Si dicho atributo está a True, se envían los eventos, si está a False no se envían. Las estructuras de los eventos correspondientes son las siguientes:

typedef struct {
    int type;
    unsigned long serial;   /* no. de la última petición atendida por el servidor */
    Bool send_event;        /* verdadero si procede de una petición SendEvent */
    Display *display;       /* Display donde ocurrió el evento */
    Drawable drawable;
    int x, y;
    int width, height;
    int count;
    int major_code;
    int minor_code
} XGraphicsExposeEvent;
typedef struct {
    int type;
    unsigned long serial;   /* no. de la última petición atendida por el servidor */
    Bool send_event;        /* verdadero si procede de una petición SendEvent */
    Display *display;       /* Display donde ocurrió el evento */
    Drawable drawable;
    int major_code;
    int minor_code
} XNoExposeEvent;

Los campos x, y, width y height tienen el mismo significado que en la estructura del evento XExposeEvent, y hacen referencia a los dibujables de destino, que es a quienes están dirigidos estos eventos. El campo major_code puede tomar los valores X_CopyArea o X_CopyPlane, e indica que la causa que provocó el evento fué una función XCopyArea o una función XCopyPlane. El campo drawable es el ID de la ventana o pixmap sobre el que se hizo la copia.

6.32 Ejemplo: programa

Se quiere realizar el siguiente programa:

6.33 LAB: manejo de exposiciones

Crear un programa que haga lo siguiente:

  1. Crear una ventana blanca grande con borde negro. Establecer la máscara de eventos para que se detecten pulsaciones del botón del ratón, exposiciones y pulsaciones de teclas.
  2. Crear un GC.
  3. Desarrollar un bucle de eventos que:
    1. Para cada pulsación del botón del ratón (después de la primera) dibuje una línea desde la posición actual hasta la última posición del ratón.
    2. Si se detecta una exposición después de que se hayan dibujado varias líneas, redibujar todas las líneas hasta un máximo de 99 líneas.
    3. Salir del programa cuando se pulse una tecla.

6.34 LAB (6.20): Solución


#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <stdlib.h> 
#include <stdio.h> 
 
extern unsigned long Color( Display *display, char *nombreColor ); 
 
main() 
    { 
    Display *d; 
    Window w; 
    GC gc; 
    unsigned long azul, blanco, naranja, negro, rojo, verde; 
    XSetWindowAttributes atributos; 
 
    XPoint lineas1[] = { 
        { 200,300 }, { 250,200 }, { 300,250 }, { 350,100 }, { 400,300 } 
    }; 
 
    XPoint lineas2[] = { 
        { 200,50 }, { 450,50 }, { 450, 375 } 
    }; 
 
    XSegment segmentos[] = { 
        { 50,200,100,300 }, { 100,150,50,300 }, { 150,100,150,300 } 
    }; 
 
    char patron[] = { 20, 5, 10, 15 }; 
 
    d = XOpenDisplay( NULL ); 
 
    azul    = Color( d, "blue"   ); blanco = Color( d, "white" ); 
    naranja = Color( d, "orange" ); negro  = Color( d, "black" ); 
    rojo    = Color( d, "red"    ); verde  = Color( d, "green" ); 
 
    w = XCreateSimpleWindow( d, DefaultRootWindow( d ), 100, 200, 
                             500, 400, 10, negro, blanco ); 
    atributos.override_redirect = True; /* para puentear al WM */ 
    XChangeWindowAttributes( d, w, CWOverrideRedirect, &atributos ); 
 
    XMapWindow( d, w ); 
 
    gc = XCreateGC( d, w, 0, NULL ); 
 
    XSetForeground( d, gc, negro ); 
    XSetLineAttributes( d, gc, 4, LineSolid, CapButt, 0 ); 
    XDrawLine( d, w, gc, 50, 350, 450, 350 ); 
 
    XSetForeground( d, gc, azul ); 
    XSetBackground( d, gc, verde ); 
    XSetLineAttributes( d, gc, 8, LineDoubleDash, CapButt, 0); 
    XDrawSegments( d, w, gc, segmentos, 3 ); 
 
    XSetLineAttributes( d, gc, 15, LineSolid, CapRound, JoinRound ); 
    XDrawLines( d, w, gc, lineas1, 5, CoordModeOrigin ); 
 
    XSetForeground( d, gc, naranja ); 
    XSetBackground( d, gc, verde ); 
    XSetLineAttributes( d, gc, 20, LineDoubleDash, CapProjecting, JoinBevel ); 
    XDrawLines( d, w, gc, lineas2, 3, CoordModeOrigin ); 
 
    XFlush( d ); 
    getchar(); 
    }

6.35 LAB (6.33): Solución


#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <string.h> 
#include <stdlib.h> 
 
#define MAXPOS 100 
 
main() 
    { 
    Display *d; 
    Window w; 
    XEvent e; 
    GC gc; 
    XPoint puntos[ MAXPOS ]; 
    int p = 0; 
 
    d = XOpenDisplay( NULL ); 
    w = XCreateSimpleWindow( d, DefaultRootWindow( d ), 100, 100, 400, 400, 2, 
                             BlackPixel( d, DefaultScreen( d ) ), 
                             WhitePixel( d, DefaultScreen( d ) ) ); 
    gc = XCreateGC( d, w, 0, NULL ); 
    XSelectInput( d, w, ExposureMask | ButtonPressMask | KeyPressMask ); 
    XMapWindow( d, w ); 
 
    while ( True ) 
        { 
        XNextEvent( d, &e ); 
        switch( e.type ) 
            { 
            case ButtonPress: 
                puntos[ p ].x = e.xbutton.x; 
                puntos[ p ].y = e.xbutton.y; 
                if ( p ) /* si no es el primer punto */ 
                    XDrawLines( d, w, gc, &puntos[p-1], 2, CoordModeOrigin ); 
                if ( p < MAXPOS ) p++; 
                else /* array circular de andar por casa */ 
                    memmove( puntos, &puntos[1], (MAXPOS-1) * sizeof(XPoint)); 
                break; 
            case Expose:        /* si es el último evento de exposición */ 
                if ( !e.xexpose.count ) 
                    XDrawLines( d, w, gc, puntos, p, CoordModeOrigin ); 
                break; 
            case KeyPress: exit( 0 ); 
            } 
        } 
    }


Previous Next Table of Contents