Ejemplos java y C/linux

Tutoriales

Enlaces

Licencia

Creative Commons License
Esta obra está bajo una licencia de Creative Commons.
Para reconocer la autoría debes poner el enlace http://www.chuidiang.com

Algunos detalles sobre las librerías de X11

XOpenDisplay()

En un ordenador con dos (o más) pantallas podemos hacer dos cosas: Instalar un único servidor que controle las dos pantallas o instalar dos servidores de X que controlen una cada uno. Los servidores se numeran de 0 en adelante. Para cada servidor, las pantallas que controlan se numeran de 0 en adelante. Lo habitual es tener un servidor (número 0) con una única pantalla (número 0).

La función XOpenDisplay() admite de parámetro una cadena de caracteres, cuyo formato es "<nombre_ordenador>:<numero_servidor_X>.<numero_pantalla>".

El nombre_ordenador puede ser el nombre en red de nuestro ordenador, su dirección IP o bien dejarlo en blanco para que se conecte al servidor X de la máquina local.

El número_servidor_X y el numero_pantalla ya deben estar claros. Lo habitual es poner ":0.0", con lo que nos conectamos al servidor de nuestra pantalla y a la única pantalla que hay.

Si le pasamos NULL, lee el valor de dicha cadena de la variable de entorno DISPLAY, que habitualmente contiene el valor ":0.0". Esta es la opción más versátil, ya que antes de ejecutar el programa, podemos decir dónde queremos que salga. Si tienes posibilidad de jugar con varios ordenadores linux/unix en red, prueba a poner el DISPLAY a otro ordenador y ejecutar, por ejemplo, un xterm. Si tienes problemas, echa un ojo al comando xhost en el siguiente apartado.

El comando xhost

El comando de unix xhost permite a un usuario dar permisos a otros para que puedan sacar ventanas en su pantalla. El propietario de la pantalla es el que ha entrado en sesión en dicha pantalla. Sólo el puede cambiar los permisos con el comando xhost.

Si has entrado en sesión y ejecutas xhost +, estás dando permiso a todos los demás usuarios para dibujar en tu pantalla. Si estás, por ejemplo, en el ordenador A, un usuario en el ordenador B podría poner DISPLAY=B:0.0; export DISPLAY y mostrar cualquier ventana en tu ordenador. Por ejemplo, si ejecuta xterm, la terminal saldrá en tu pantalla.

La función XFlush()

Normalmente no es necesario llamar a XFlush(). El servidor de X va encolando las peticiones y ejecutándolas en el orden que le llegan. Si no se llama a XFlush(), el único efecto es que hay un retraso mínimo desde que le indicamos que dibuje algo hasta que realmente lo dibuja.

Sin embargo, en mi linux (mandrake 7.2 con kde), si no llamo a XFlush() no dibuja absolutamente nada. En Solaris (unix de Sun microsystems) no he tenido esos problemas.

El contexto gráfico GC

El contexto gráfico es una estructura bastante grande en la que se guarda información para dibujar. Por ejemplo, en esta estructura se guarda el tipo de línea (continua, punteada, ...), la fuente para dibujar texto en un gráfico, tramas de relleno para figuras rellenas y background, etc, etc. Lo normal cuando dibujamos es obtener un GC, rellenar en el el tipo de linea, color, etc y luego utilizarlo.

Funciones en plural

Como ya hemos indicado, cuando mandamos dibujar algo en realidad estamos mandando un mensaje al servidor de X. Es muchísimo más ineficiente y lento mandar muchos mensajes pequeños que uno grande. Por eso, casi todas las funciones de pintado tienen una versión "en plural". Por ejemplo, existen XDrawPoint() y XDrawPoints(). La primera manda dibujar un punto y la segunda un array de puntos. Por eficiencia, siempre que sea posible, utilizarmos las funciones en plural.

Esto puede en ocasiones ser un engorro. Por ejemplo, si queremos dibujar puntos de varios colores, puesto que XDrawPoints() pinta todos los puntos del mismo color, estamos obligados a "clasificar" primero los puntos para agruparlos por colores y luego ir pintando cada grupo con una llamada a XDrawPoints().

Los colores

El sistema de colores de X es bastante complejo, aunque bastante potente. Vamos a tratar de explicarlo un poco, pero no es necesario entenderlo para hacer gráficos de colores simples. Si quieres pasar del rollo, pero quieres saber qué funciones llamar para poder pintar del color que tú quieras, vete directamente al siguiente punto.

El servidor de X puede tener configurados sus colores de varias maneras: pseudocolor, truecolor, directcolor, grayscale, etc. Cada una de ellas tiene más o menos una utilidad concreta. Por ejemplo, y no te fies mucho de esto porque lo digo de memoria, pseudocolor es útil para aplicaciones en que queremos hacer gráficos con capas, truecolor es para aplicaciones de fotografía, directcolor es más útil para aplicaciones de dibujo en 3d, con renders y demás:

En función de esta configuración, podemos tener más o menos colores disponibles y se manejan de distinta forma. Como antes, no te fies mucho de los datos que te doy que van de memoria, pero pseudocolor dispone de 256 colores (0 a 255), true color de 65536 (0 a 65534), etc.

Lo habitual para nuestro pc/linux, es que la configuración sea truecolor. Esto nos da 65536 colores prefijados del que podemos usar el que más nos guste.

En pseudocolor, por ejemplo, sólo tenemos 256 colores, pero no están predefinidos, la paleta de colores esta "vacía" (no es totalmente cierto, siempre hay algunos ya definidos por otras aplicaciones, incluida la ventana raíz). La aplicación debe elegir cuales quiere que sean esos 256 colores.

Otro tema a tener en cuenta es que cada ventana puede tener su propia paleta de colores. Es decir, si la paleta de pseudocolor es de 256 colores, podemos tener varias ventanas distintas cada una con su propia paleta. Si hacemos que cada ventana tenga su propia paleta de colores, podemos tener un efecto curioso que a lo mejor has visto alguna vez. Lo normal es que sólo una paleta esté "activa" y sólo se vean en pantalla los colores de esa paleta. Cuando el ratón entra en una ventana, la paleta de esa ventana se convierte en "activa" y los colores de las demás ventanas pueden "estropearse". El efecto es que sólo se ven bien los colores de la ventana que tiene el ratón y según paseamos el ratón de una ventana a otra, vemos como todos los colores nos van cambiando bruscamente.

Por ello, y salvo que sea imprescindible, se suele usar la paleta de color de la ventana raíz (que es la ventana primera que se crea, que ocupa toda la pantalla y sobre la que va nuestro fondo de escritorio). De esta forma, todas las ventanas comparten la misma paleta de colores y no tenemos ese efecto extraño, aunque corremos el riesgo de que una aplicación "golosa" en colores los coja todos y tengamos que conformarnos con los colores que ella ha elegido. Todas las aplicaciones tienen acceso a esta paleta "raíz" llamando a la macro DefaultColormap (disp, screen). El display es el obtenido con XOpenDisplay() y screen suele ser 0 (una sola pantalla).

Cómo elegir el índice de color

Independientemente del sistema elegido, si queremos dibujar en un color determinado, rojo por ejemplo, tenemos funciones de X que nos permiten obtener el índice que luego usaremos con XSetForeground(). Una forma sencilla es la siguiente:

Rellenamos una estructura XColor con los valores RGB deseados.

XColor color;

/* Se indica que son válidos los tres valores red, green y blue */
color.flags = DoRed | DoGreen | DoBlue;       

/* Valor red, blue y green de 0 a 65535 */
color.red = 65535;                                       
color.blue = 0;                                           
color.green = 0;                                           

Luego, llamando a la función XAllocColor(), nos devuelve en color.pixel el índice del color deseado (rojo en nuestro caso)

XAllocColor (
    /* Una vez más, el display */
    display,         

    /* paleta de color por defecto para el display y screen. */
    DefaultColormap (disp, screen), 
              
    /* RGB que deseamos. En color.pixel nos devuelve el índice. */
    &color);                                                 

La función XAllocColor() en realidad le está pidiendo al servidor de X que reserve en la paleta una posición para el color deseado. El servidor buscará en la paleta si ya está ese color RGB y nos devolverá su posición. Si no lo hay, lo pondrá en un hueco libre (Sólo en PseudoColor) y nos devolverá su posición. Si no existe ese color y no hay hueco libre, la función devolverá un error.

XAllocColor() reserva un hueco en la paleta que deberíamos liberar cuando no nos haga falta. En nuestra aplicación, si decidimos que no vamos a usar más ese color, llamaríamos a la función

XFreeColor(). De todas formas, cuando nuestra aplicación termine, el servidor de X liberará, por defecto, todo lo que hayamos reservado.

Para los colores tipicos de blanco y negro, tenemos las macrsos BlackPixel(display, screen) y WhitePixel(display, screen), que nos devuelven el índice de la paleta correspondiente a esos colores.

Algunas funciones útiles

Las funciones que queremos usar (XCreateSimpleWindow(), XAllocColor(), XDrawLine(), ...) nos piden algunos parámetros un poco raros, aunque simples de obtener. Algunos, como el "screen" son un entero y normalmente con poner un 0 vale (sólo tenemos una pantalla y es la cero). Sin embargo existen unas funciones de utilidad que nos permiten obtener estos parámetros de una forma más portable, ya que nos darán un valor correcto aunque llevemos el ejecutable a otro ordenador con otra configuración. Veamos algunas de ellas:

DefaultScreen (display) : En cualquier sitio que se nos pida el screen, esta función nos devuelve el screen por defecto para la conexión display.

DefaultColormap (display, screen) : Nos devuelve el array de colores por defecto para una determinada conexión y una determinada pantalla. Podemos usar este array de colores o bien podríamos crearnos uno propio para cada ventana. La opción más simple es usar el de defecto.

XDefaultRootWindow (display) : Nos devuelve la ventana raíz de la conexión indicada. Podemos usar esta ventana como padre de todas las demás.

XDefaultGC (display, screen) : Nos devuelve el contexto gráfico por defecto para la conexión y pantalla indicadas. Suele usarse este GC para dibujar. En el programa del ejemplo, la función XSetForeground() que fija el color de dibujo lo mete en el XDefaultGC() y luego XDrawLine() utiliza este mismo XDefaultGC() para dibujar.

BlackPixel (display, screen) y WhitePixel (display, screen) : Nos devuelven los índices de los colores negro y blanco.

Estadísticas y comentarios

Numero de visitas desde el 4 Feb 2007: