Previous Next Table of Contents

3. Creación y manipulación de ventanas

3.1 Jerarquía de ventanas

Todas las ventanas en el sistema X Window están dentro de una jerarquía, cuya primera ventana es siempre la ventana raíz. La ventana raíz es la única ventana padre, es decir, es la raíz de la jerarquía. La ventana raíz se crea automáticamente cuando se inicializa el servidor, y cubre toda la pantalla.

Siempre que se crea una ventana se debe especificar la ventana dentro de la cual se creará la nueva ventana. A la ventana que se crea se le denomina ventana hija, y a la ventana donde se crea ventana madre. La ventana raíz puede especificarse como ventana la madre de una o más ventanas. Una vez que las otras ventanas están creadas, se pueden utilizar como ventanas madres.

El término subventana tiene el mismo significado que el de ventana hija.

El término descendiente hace referencia a los hijos y a los hijos de los hijos, etc., así como el término ancestro se refiere a la madre o a la madre de la madre, etc.

3.2 Orden de apilamiento de ventanas

Las ventanas hermanas de cada nivel de la jerarquía de ventanas están ordenadas en una pila. Esta pila decide el orden de solapamiento de las ventanas hermanas. Si una ventana está en la cima de la pila, no está oculta por sus otras hermanas, aunque podría estarlo por otras hermanas de la jerarquía.

3.3 Geometria de ventanas

La geometría de una ventana comprende los siguientes valores:

anchura

anchura de la ventana en pixels, sin contar el borde.

altura

altura de la ventana en pixels, sin contar el borde.

anchura del borde

anchura del borde en pixels

posición

coordenadas de la esquina superior del borde relativas a la ventana madre.

origen

esquina superior izquierda dentro del borde.

3.4 Recorte de ventanas

Una ventana hija está siempre "recortada" por su ventana madre, es decir, sólo muestra aquella área comprendida dentro de los límites de la ventana madre. Si se crea una ventana hija fuera de los límites de su ventana madre, sólo será visible el área de intersección, si no intersecta con su ventana madre, la ventana hija será invisible.

3.5 Llamada Xlib: crear una ventana

Window XCreateSimpleWindow( Display *display, Window madre,
                            int x, int y,
                            unsigned int anchura, unsigned int altura,
                            unsigned int anchuraBorde,
                            unsigned long colorBorde,
                            unsigned long colorFondo )

El display especifica la conexión con el servidor. La madre especifica la ventana madre donde se creará la ventana. Normalmente la primera o primeras ventanas que se crean son hijas de la ventana raíz, para obtener dicha ventana se pueden usar las macros RootWindow o DefaultRootWindow.

Los argumentos x, y, anchura y altura especifican la geometría de la ventana. La anchuraBorde es la anchura del borde en píxels. El borde y el fondo indican los valores de píxel para el borde y el fondo de la ventana respectivamente. Si se quiere especificar como colores el blanco o el negro pueden usarse las macros WhitePixel o BlackPixel para obtener los valores de píxel correspondientes.

3.6 Visibilidad de ventana

Una ventana no se "mapea" justo después de ser creada por XCreateSimpleWindow, su estado es de no mapeada. Las condiciones para que una ventana sea visible son las siguientes:

  1. Que la ventana esté mapeada
  2. Que todos sus ancestros estén mapeados
  3. Que otras ventanas no la oculten completamente

3.7 Llamadas Xlib: mapear y desmapear ventanas

XMapWindow( Display *d, Window w )

mapea la ventana especificada.

XMapRaised( Display *d, Window w )

mapea la ventana especificada y la pone en la cima de la pila

XMapSubWindows( Display *d, Window w )

mapea las subventanas de la ventana especificada, pero no mapea la ventana especificada.

XUnmapWindow( Display *d, Window w )

desmapea la ventana especificada

XUnmapSubWindows( Display *d, Window w )

desmapea las subventanas de la ventana especificada, pero no desmapea la ventana especificada.

3.8 Llamada Xlib: enviar peticiones

En el sistema de la Xlib, las peticiones realizadas por los clientes se almacenan en el buffer de la Xlib. Hasta que alguna condición, buffer lleno, petición de información, petición de evento, etc., no se satisface, las peticiones permanecen en el buffer y no se envían al servidor.

XFlush( Display *d )

Para vaciar el buffer y enviar las peticiones al servidor se usa la llamada a la Xlib XFlush. Cada cliente tiene su propio buffer de peticiones, y sólo se vacía el buffer del cliente que hace XFlush.

3.9 LAB: Creación de ventanas

Escribir un programa que cree una ventana w0 situada en las coordenadas (100,100) y de dimensión 600x400 y tres subventanas de 200x150 cuyas coordenadas sean (50,50), (200,200) y (350,350) respectivamente.

3.10 Mover y redimensionar ventanas

Se puede manipular la geometría de una ventana de las siguientes formas:

3.11 Llamadas Xlib: cambio de la geometria de ventana

XMoveWindow( Display *d, Window w, int x, int y )

mueve la posición de la ventana a las coordenadas especificadas.

XResizeWindow( Display *d, Window w, unsigned int anchura, unsigned int altura )

cambia la anchura y la altura de la ventana a los valores especificados.

XMoveResizeWindow( Display *d, Window w, int x, int y, int achura, int altura )

cambia la posición, la anchura y la altura de la ventana al mismo tiempo.

XSetWindowBorderWidth( Display *d, Window w, unsigned int anchura )

cambia la anchura en pixels del borde de la ventana al valor indicado.

3.12 Ejemplo: problema

Se trata de un programa que haga lo siguiente:

  1. Crear una ventana con tamaño 100 por 80 en la posición (10,10)
  2. Moverla a la posición (250,100)
  3. Cambiarle el tamaño a 140 por 120
  4. Moverla a la posición (100,300) mientras que cambia de tamaño a 200 por 50

3.13 Ejemplo: solución


#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>

#define X1          10
#define Y1          10
#define ANCHO1      100
#define ALTO1       80
#define X2          250
#define Y2          100
#define ANCHO2      140
#define ALTO2       120
#define X3          100
#define Y3          300
#define ANCHO3      200
#define ALTO3       50
 
main()
    {
    Display *d;
    Window w;
    int pantalla;
    unsigned long negro, blanco;
 
    d = XOpenDisplay( NULL );
 
    pantalla = DefaultScreen( d );
    blanco   = WhitePixel( d, pantalla );
    negro    = BlackPixel( d, pantalla );
    w = XCreateSimpleWindow( d, DefaultRootWindow( d ),
                X1, Y1, ANCHO1, ALTO1, 2, negro, blanco );
    XMapWindow( d, w );
    XFlush( d );
 
    puts( "Pulse una tecla para mover la ventana..." );
    getchar();
    XMoveWindow( d, w, X2, Y2 );
    XFlush( d );
 
    puts ("Pulse una tecla para cambiar el tamaño de la ventana..." );
    getchar();
    XResizeWindow( d, w, ANCHO2, ALTO2 );
    XFlush( d );
    puts( "Pulse una tecla para cambiar el tamaño de la ventana y moverla..." );
 
    getchar();
    XMoveResizeWindow( d, w, X3, Y3, ANCHO3, ALTO3 );
    XFlush( d );
 
    puts( "Pulse una tecla para finalizar el programa..." );
    getchar();
   }

3.14 Cambiar el orden en la pila de ventanas

Para poner una ventana en la cima de la pila se puede usar XRaiseWindow y para ponerla en el fondo XLowerWindow. También puede hacerse circular las ventanas dentro de la pila usando XCirculateSubwindows, XCirculateSubwindowsUp y XCirculateSubwindowsDown.

3.15 Llamadas Xlib: elevar y hundir ventanas en la pila

XRaiseWindow( Display *d, Window w )

eleva la ventana especificada a la cima de la pila de forma que ninguna ventana hermana la oculte.

XLowerWindow( Display *d, Window w )

hunde la ventana especificada en el fondo de la pila de forma que no oculte a ninguna ventana hermana.

3.16 Llamadas Xlib: circulación de las ventanas en la pila

XCirculateSubwindows( Display *d, Window w, int direccion )

hace circular la pila de las ventanas hijas de la ventana especificada en la direccion indicada, RaiseLowest indica hacia arriba y LowerHighest hacia abajo.

XCirculateSubwindowsUp( Display *d, Window w )

es una función que equivale a XCirculateSubwindows( d, w, RaiseLowest ).

XCirculateSubwindowsDown( Display *d, Window w )

es una función que equivale a XCirculateSubwindows( d, w,LowerHighest ).

3.17 Llamadas Xlib: reordenamiento aleatorio

XRestackWindows( Display *d, Window ventanas, int n )

reapila las ventanas en el orden especificado en el array de ventanas pasado como argumento, desde la cima hasta el fondo, es decir, la nueva cima será ventanas[0] y el fondo ventanas[n-1].

3.18 Ejemplo: problema

Escribir un programa que haga lo siguiente:

  1. Crear tres ventanas, w1, w2 y w3 en éste orden.
  2. Poner w2 en la cima de la pila.
  3. Hacer circular la pila hacia arriba de las ventanas.
  4. Reapilar las ventanas en el orden w3, w2, w1, de arriba abajo.

3.19 Ejemplo: solución


#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
 
main()
    {
    Display *d;
    Window madre, w1, w2, w3, w[3];
    int pantalla;
    unsigned long negro, blanco;
   
    d = XOpenDisplay( NULL );
   
    pantalla = DefaultScreen( d );
    blanco   = WhitePixel( d, pantalla );
    negro    = BlackPixel( d, pantalla );
   
    madre = XCreateSimpleWindow( d, DefaultRootWindow( d ),
                                 200, 100, 400, 300, 2, negro, blanco );
 
    w1 = XCreateSimpleWindow( d, madre,  40,  40, 160, 120, 2, negro, blanco );
    w2 = XCreateSimpleWindow( d, madre,  80,  80, 160, 120, 2, negro, blanco );
    w3 = XCreateSimpleWindow( d, madre, 120, 120, 160, 120, 2, negro, blanco );
   
    XMapWindow( d, madre );
    XMapSubwindows( d, madre );
    XFlush( d );
   
    puts( "Pulse una tecla para poner w2 en la cima de la pila..." );
    getchar();
   
    XRaiseWindow( d, w2 );
    XFlush( d );
   
    puts( "Pulse una tecla para hacer circular hacia arriba las ventanas..." );
    getchar();
   
    XCirculateSubwindows( d, madre, RaiseLowest );
    XFlush( d );
 
    puts( "Pulse una tecla para reapilar como w3, w2 y w1..." );
    getchar();
 
    w[0] = w3;
    w[1] = w2;
    w[2] = w1;
    XRestackWindows( d, w, 3 );
    XFlush( d );
   
    puts( "Pulse una tecla para finalizar el programa..." );
    getchar();
    }

3.20 Configuración de ventanas

Hay otra llamada a la Xlib que puede usarse para cambiar la posición, anchura, altura, ancho del borde y orden de apilamiento de una ventana al mismo tiempo: XConfigureWindow. Para especificar varias variables al mismo tiempo se usa la estructura XWindowChanges y una máscara de bits. Cada campo tiene su bit correspondiente en la máscara, de forma que si el bit correspondiente está a 1 el valor se toma como válido y se cambia; si está a 0 se ignora.

3.21 Llamada Xlib: configuración de ventanas

XConfigureWindow( Display *d, Window w,
                  unsigned int mascara, XWindowChanges *valores )

La estructura XWindowChanges está definida de la siguiente forma:

typedef struct {
    int x, y;
    int width, height;
    int border, width;
    Window sibling;
    int stack_mode;
} XWindowChanges;

Los símbolos para cada bit de la máscara son los siguientes:

#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)

Para especificar varios campos se puede hacer una operación OR con los símbolos adecuados.

3.22 Reapilamiento condicional

Para realizar un reapilamiento condicional, se pueden usar los campos sibling y stack_mode de la estructura XWindowChanges. El campo stack_mode puede tener los siguientes valores: Above, Below, TopIf, BottomIf y Opposite. El significado de stack_mode depende de si se especifica el campo sibling o no:

Si sibling no se especifica

Above

La ventana se pone en la cima de la pila.

Below

La ventana se pone en el fondo de la pila.

TopIf

Si alguna hermana oculta a la ventana, la ventana se pone en la cima de la pila.

BottomIf

Si la ventana oculta a alguna hermana, la ventana se pone en el fondo de la pila.

Opposite

Si alguna hermana oculta a la ventana, la ventana se pone en la cima de la pila. En caso contrario, si la ventana oculta a otra hermana, la ventana se pone en el fondo de la pila.

Si sibling se especifica

Above

La ventana se pone justo sobre la hermana.

Below

La ventana se pone justo debajo de la hermana.

TopIf

Si la hermana oculta a la ventana, la ventana se pone justo sobre la hermana.

BottomIf

Si la ventana oculta a la hermana, la ventana se pone justo debajo de la hermana.

Opposite

Si la hermana oculta la ventana, la ventana se pone justo sobre la hermana. En caso contrario, si la ventana oculta a la hermana, la ventana se pone justo debajo de la hermana.

3.23 Ejemplo: problema

Supongamos el siguiente programa: si una hermana oculta una ventana, poner la ventana en la cima de la pila. En otro caso, si la ventana oculta a alguna hermana, poner la ventana en el fondo de la pila.


#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>

main()
    {
    Display *d;
    Window madre, w1, w2, w3, w[3];
    XWindowChanges c;
    int pantalla;
    unsigned long negro, blanco;
 
    d = XOpenDisplay( NULL );
 
    pantalla = DefaultScreen( d );
    blanco   = WhitePixel( d, pantalla );
    negro    = BlackPixel( d, pantalla );
 
    madre = XCreateSimpleWindow( d, DefaultRootWindow( d ),
                                 200, 100, 400, 300, 2, negro, blanco );
    w1 = XCreateSimpleWindow( d, madre,  40,  40, 160, 120, 2, negro, blanco );
    w2 = XCreateSimpleWindow( d, madre,  80,  80, 160, 120, 2, negro, blanco );
    w3 = XCreateSimpleWindow( d, madre, 120, 120, 160, 120, 2, negro, blanco );
 
    XMapWindow( d, madre );
    XMapSubwindows( d, madre );
    XFlush( d );
 
    puts( "Pulse una tecla para poner w1 en la cima de la pila si..." );
    getchar();
 
    c.stack_mode = Opposite;
 
    while( TRUE )
        {
        XConfigureWindow( d, w1, CWStackMode, &c );
        XFlush( d );
        puts( "Pulse una tecla para poner w1 en la cima de la pila si..." );
        getchar();
        }
    } 

3.24 LAB: solución


#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
 
main()
    {
    Display *d;
    Window madre, w1, w2, w3, w[3];
    int pantalla;
    unsigned long negro, blanco;
 
    d = XOpenDisplay( NULL );
 
    pantalla = DefaultScreen( d );
    blanco   = WhitePixel( d, pantalla );
    negro    = BlackPixel( d, pantalla );
 
    madre = XCreateSimpleWindow( d, DefaultRootWindow( d ),
                                 200, 100, 400, 300, 2, negro, blanco );
 
    w1 = XCreateSimpleWindow( d, madre,  50,  50, 200, 150, 2, negro, blanco );
    w2 = XCreateSimpleWindow( d, madre, 200, 100, 200, 150, 2, negro, blanco );
    w3 = XCreateSimpleWindow( d, madre, 350, 200, 200, 150, 2, negro, blanco );
 
    XMapWindow( d, madre );
    XMapSubwindows( d, madre );
    XFlush( d );
    getchar();
    }


Previous Next Table of Contents