0 Antes de empezar

0.1 ¿A quién va dirigido este tutorial?

Este pequeño tutorial va dirigido a los interesados en desarrollar aplicaciones utilizando la interface gráfica de usuario Motif. Está basado en la versión 1.2, pero es totalmente aplicable a la version 2.

0.2 ¿Qué conocimientos previos se requieren?

Básicamente, lenguaje C. Como es de esperarse, este tutorial no explica el uso del compilador, ni el uso del sistema operativo del usuario. En particular, el usuario debe poder ejecutar aplicaciones en el ambiente gráfico de los Unix (X Window).

0.3 ¿Qué ambiente de desarrollo necesito?

  • En cuanto al sistmea operativo, Motif ha sido llevado a la mayoría de sistemas Unix, o sus "clones", tales como: solaris, Tru-64/Digital, AIX, HP-UX, Linux, FreeBSD, etc. Los ejemplos de este tutorial han sido probados con Linux.

  • Se requiere de un compilador de lenguaje C (que se suele proporcionar con los Unix), e incluso se puede usar los compiladores "Open Source" como GCC, disponibles para la mayoría de Unix’es. Los ejemplos de este tutorial han sido probados con este último.

  • Es necesario disponer de las librerías y "headers" (archivos .h) de Motif, para poder enlazar nuestros programas. Esto muchas veces se proporciona como un producto separado, dependiendo del sistema operativo. Existe además una librería "clone" de Motif llamada "LESSTIF" (www.lesstif.org) utilizable en la mayoría de Unix’es importantes. Los ejemplos de este tutorial han sido probados con Lesstif en Linux y Solaris.

0.4 ¿Cómo nació este tutorial?

El mes de Mayo del año en curso, tuve el encargo de dictar un curso para una división de la Marina de Guerra del Perú, en el cual deberíamos tratar una serie de tópicos de la programación en ambiente Unix. Como es natural, el curso incluyó lenguaje C y C para Unix; adicionalmente dicté una introducción al C++ y finalmente debía terminar con el desarrollo de aplicaciones en ambiente gráfico usando Motif.

He de admitir que esto último no es muy usual en nuestro medio, y si bien yo tenía alguna experiencia en XView (que es una librería análoga), me resultó relativamente costoso conseguir material de Motif lo suficientemente didáctico como para el dictado. De tal suerte que decidí crear mis propios ejemplos, bastante triviales, pero por sobre todo, fácilmente entendibles y "explicables" a la clase.

Descubrí que estos ejemplos, junto con mis apuntes para la introducción teórica, podrían servir para cualquier interesado en aprender Motif (sobre todo de habla hispana), por lo que me decidí a adaptarlo para que adquiera un carácter de autoaprendizaje. Y así nace este pequeño tutorial.

1 Introducción

1.1 Noción de Motif

Empezaremos con una noción bastante breve. De seguro el lector que está leyendo este texto ya tiene una idea aproximada de lo que aquí se trata. Sin embargo, creo conveniente recapitular algunos conceptos a fin de proporcionar más rigurosidad al análisis.

Motif en términos generales, consiste en una cierta "apariencia" visual, una serie de elementos constituyentes de las "ventanas" (áreas de texto, botones, etc.) que son mejor conocidos como "widgets"; y todo lo necesario para que las aplicaciones puedan hacer uso de estos:

  • Estilo consistente (apariencia)

  • Widgets especializados

  • Librerías y herramientas de desarrollo

1.2 X Window

Antes de entrar en los detalles de la implementación de Motif, conviene recordar los aspectos principales del sistema de ventanas y de red "X Window". El lector puede saltar hasta la sección 1.3 si conoce los fundamentos del mismo.

Como es sabido, este sistema es el est ndar que utilizan todas las implementaciones importantes del sistema operativo Unix, pudiendo extenderse a otros ambientes computacionales. Al igual que en otros sistemas de ventanas, su función consiste en proporcionar una interface "adecuada", de cara al usuario final. Con "adecuada" se quiere decir:

  • Simple

  • Intuitiva

  • Eficiente

Como se indicó, además de ser un sistema de ventanas, es un sistema que hace uso de la red (generalmente TCP/IP, aunque se han soportado otras implementaciones), pudiendo considerarse parte de un sistema distribuído.

No me propongo realizar una explicación extensiva de este sistema (para lo cual existe bastante bibliografía). Solo voy a indicar algunos puntos esenciales que nos serviran para comprender mejor la arquitectura en la que se ubica Motif:

1.2.1 El Modelo Cliente - Servidor

X Window (también denominado X11, o simplemente X), utiliza un consistente dise¤o de tipo cliente - servidor. Los clientes son los programas que requieren interactuar con el usuario (mostrar datos en una pantalla y recepcionar datos desde un teclado y/o mouse).

En el modelo cliente - servidor X Window, los clientes no se encargan directamente de esta operación, delegándola a un programa especializado (el servidor X Window, o "X Server"). Este X Server puede ejecutarse en un computador e inclusive en un sistema operativo distinto al del cliente, sin embargo, no habrá ninguna incompatibilidad.

Como se observa, sólo el X Server tiene que ver con el hardware involucrado en la visualización y captura de datos. Al respecto, un concepto muy importante es el de "display", que quiere decir aproximadamente "una pantalla, un teclado y un mouse", lo que a fin de cuentas representa a los medios de interacción de los usuarios con el sistema.

En realidad, un display potencialmente puede controlar varias pantallas (screen), pero solo un teclado y un mouse. Esta modalidad es rara vez utilizaada por lo que en nuestros ejemplos siempre se asumirá un único "screen" para el "display".

1.2.2 El X protocol

Para que los clientes (también llamados "aplicaciones") puedan comunicarse con el X server (a fin de interactuar con el usuario), se requiere de un mecanismo para codificar las acciones involucradas en el dibujo de los elementos de las ventanas y en las acciones llevadas a cabo por el usuario. Este mecanismo consiste en una serie de mensajes (enviados a través de la red) que de por sí constituyen un protocolo, es denominado el "X protocol". Este "X protocol" es quien permite establecer la relación entre cliente y servidor arriba mencionada.

En teoría, un programador de una aplicación X Window, podría "crear" estos mensajes (tramas) y enviarlas por la red (por ejemplo, a través de "Sockets"). Sin embargo, esta forma de programar es extremadamente laboriosa, poco portable, y difícil de mantener, motivo por el cual existe siempre una librería que "oculta" toda esta complejidad, permitiendo al programador operar con elementos de mayor nivel, es decir, con objetos graficos y no con tramas del X protocol y sockets. Esta librería se conoce como "X-LIB" o "libx11".

1.3 Arquitectura de las aplicaciones X Window

Esta sección tiene que ver con las librerías que son empleadas por los programadores de aplicaciones en X11, es decir, con el lado del cliente. No se presentará la arquitectura del X Server por no estar relacionada con nuestro tema, y porque cada vendedor es libre de implementar el X Server a su manera, siempre que respete el X protocol.

1.3.1 X-LIB

Como indicáramos, esta librería evita al programador la ardua tarea de controlar los aspectos del X protocol y su transmisión. X-LIB proporciona, entre otras cosas:

  • Rutinas para volcar texto y gr ficos en "objetos de dibujo" (ventanas)

  • Rutinas para crear y manipular recursos del servidor

  • Buffer de requerimientos al servidor y encolamiento de eventos desde el servidor

  • Estructuras de datos para todos los tipos de eventos

  • Rutinas para manejar mapas de colores (colomaps)

  • Administración de base de recursos del usuario (X resource manager)

Si bien es cierto que toda aplicación X11 se puede programar con X-LIB, en la mayoría de casos esto se convertir  en un reto casi imposible. El motivo estriba en que los elementos graficos de X-LIB son de un nivel muy bajo (pixels, lineas, eventos, etc), pero en mayoría de casos se requieren de objetos de mayor inteligencia (por ejemplo, campos de texto, botones, áreas editables, barras de scroll, menus, etc.). Estos objetos "inteligentes" que componen las ventanas se denominan widgets, y X-LIB no los proporciona.

1.3.2 X Toolkit Intrinsics (Xt)

Xt es otra librería utilizada por las aplicaciones X Window. Su razón de ser es proporcionar una base de construcción de Widgets, cuyo diseño sigue una orientación a objetos. En resumen, el X Toolkit proporciona:

  • Objetos gráficos, conocidos como Widgets

  • Manipulación de la geometría de los Widgets

  • Despacho y manejo de eventos

El diseño orientado a objetos de Xt, se refleja en la "herencia" de widgets, que permite construir widgets más especializados a partir de los ya existentes. Sin embargo, la tarea de crear widgets suele ser bastante formidable, requiriendo un profundo conocimiento de Xt y X11.

Los creadores de X Window proporcionaron una serie de widgets de carácter "provisional" (conocidos como "Athena Widgets"). Sin embargo, la industria deberia desarrollar (y lo hizo) nuevos estándares de widgets que permitieran una interfaz más coherente entre sistemas operativos, y proporcionen mayores niveles de inteligencia a los objetos, a fin de facilitar la escritura de aplicaciones.

1.3.3 Motif

Motif es una librería que permite acceder a una serie de Widgets (Widgets Motif) con el fin de obtener una apariencia estandarizada entre diversos sistemas operativos (puesto que la mayoría de Unix’es importantes utilizan Motif):

  • Proporciona Widgets estandarizads (haciéndo uso automático del X Toolkit)

  • Permite obtener un estilo visual coherente

  • Facilidades "Drag and Drop"

  • Concepto de "ventana activa"

Además de la librería Motif, se distribuye una aplicación especial denominada "Motif Window Manager", la cual se encarga de la administración de la "ventana de fondo", permitiendo al usuario, entre otras cosas, lanzar nuevas aplicaciones.

1.3.4 Juntando todas las librerías

Como se pudo apreciar, la librería Motif hace uso de la librería Xt, la cual hace uso de la librería X-LIB. Desde este punto de vista, Motif es la librería de mayor nivel. Esto nos puede llevar a pensar que las aplicaciones sólo deben interactuar con Motif, y no con las demás, lo cual es completamente falso:

Hay muchas tareas del X Toolkit que no son "ocultadas" por Motif, por lo cual necesariamente tendremos que interactuar con Xt. Igualmente, hay muchas tareas de X-LIB que tampoco son ocultadas por el X Toolkit (por ejemplo, los dibujos de pixels arbitrarios), lo que obligará al programador a trabajar directamente con X-LIB.

De acuerdo a esto, si quisiéramos esquematizar la arquitectura de las aplicaciones, la figura sería como sigue:

xapparch

2 Estructura de las aplicaciones Motif

En este capítulo vamos a explicar las partes principales de una aplicación típica motif, la cual básicamente tiene como función mostrar una ventana conteniendo algún Widget con ciertas características.

2.1 Archivos cabecera de la aplicación

Una de las partes más sencillas y rutinarias consiste en indicar los archivos cabecera necesarios para la aplicación. En primer lugar, toda aplicación Motif deberá incluir el archivo Xm.h, el cual contiene una serie de definiciones y estructuras imprescindibles para toda aplicación Motif.

Como se mencionó, las aplicaciones Motif requieren hacer uso del X Toolkit y de X-LIB. Ambas librerías también tienen sus respectivos archivos cabecera, pero no es necesario especificarlos puesto que Xm.h los incluye como una forma de ahorrar tiempo.

Por otro lado, todos los archivos cabecera Motif están en un subdirectorio aparte “Xm”, el cual es a su vez un subdirectorio de los directorios estándar de archivos cabecera del compilador.

De acuerdo con esto, por lo común bastará con escribirse una línea similar a:

	#include <Xm/Xm.h>

Volveremos a esto al discutir el "Makefile" más adelante. Por ahora, debemos concentrarnos en los Widgets que utilizará nuestro programa, puesto que para cada Widget, existe un respectivo archivo cabecera que se deberá incluir en el programa. A modo de ejemplo, consideremos el Widget PUSH BUTTON, el cual implementa un clásico botón que muestra un texto con apariencia tridimensional y que puede ser "presionado" con el mouse. Pues bien, para este Widget existe su correspondiente archivo cabecera PushB.h, por lo que nuestro programa deberá empezar con:

	#include <Xm/Xm.h>
	#include <Xm/PushB.h>

Y de modo similar con cada tipo de Widget que utilicemos.

2.2 Inicializar X Toolkit

La librería X Toolkit (usada por Motif) requiere inicializarse explícitamente por el programador. La forma más simple consiste en utilizar la función XtAppInitialize, la cual se encargará de crear la estructura de datos de Xt que la relaciona a nuestra aplicación (application context), conectarnos al display (especificado tal vez en la línea de comandos), y definir los recursos iniciales (resources). Esta rutina retornará un Widget "de máximo nivel", a partir del cual podremos introducir nuevos widgets. En prácticamente todos los ejemplos que veremos, el programa empezará con:

	int main(int argc, char *argv[])
	{
	Widget app_shell;	/* top level widget */
	XtAppContext app;	/* para guardar el application context */

	app_shell = XtAppInitialize(
		&app,		/* la dirección del app. context */
		"Ejemplo",	/* el "nombre" de la aplicacion */
		NULL,0,
		&argc,argv,	/* procesar la línea de comandos */
		NULL,NULL,0);

2.2.1 Nota sobre la inicialización

La rutina XtAppInitialize automatiza una serie de etapas que se pueden llevar a cabo con más opciones mediante las rutinas:

  • XtToolkitInitialize.- Inicializar la librería

  • XtCreateApplicationContext.- Crear el application context

  • XtOpenDisplay.- Conectarse al display (XOpenDisplay) y construir la base de recursos (XtDisplayInitialize)

  • XtAppCreateShell.- Crear un Widget de máximo nivel

2.3 Crear Widgets

2.3.1 Rutinas de creación

Motif proporciona una serie de rutinas de la forma:

XmCreate Nombre_de_Widget

Por ejemplo, para un Widget Label, que permite mostrar un texto, la función correspondiente será XmCreateLabel. Para el Push Button, la función será XmCreatePushButton. Estas rutinas permiten especificar los recursos iniciales del Widget.

2.3.2 Especificación de recursos

Una forma sencilla de especificar los recursos es mediante el uso de un array de tipo Arg. Este array sirve de receptáculo temporal de los recursos que se desean asignar a un Widget. Los diferentes Widgets disponen de una serie de recursos bastante larga. Como es de esperarse, Motif proporciona recursos adicionales para sus propios Widgets.

Los recursos más simples son los que representan un valor numérico. Por ejemplo, supongamos que deseamos definir el ancho de un Widget (en pixels), existe un recurso llamado "XmNwidth". Este puede ser asignado a nuestro "array de recursos" (que llamaremos "r") en la primera posición:

Arg r[10];	/* Reservamos espacio para 10 recursos */

XtSetArg(r[0],XmNwidth,318);    /* Asignamos un recurso en la
                                   posición 0 */

Un tipo de recurso muy importante corresponde a los textos. En este caso, Motif proporciona un tipo de dato especial llamado "XmString" que permite contener cadenas de caracteres y un tipo de letra (font). Por ejemplo, para crear un XmString con el font estándar del sistema, usaremos:

XmString un_texto;	/* Declaro la variable */

un_texto = XmStringCreateSimple("Eso es todo, Amigos");

Este dato de tipo XmString, puede servir como un recurso para Motif. Por ejemplo, para asignar el texto a un Label (o a un PushButton), el recurso se denomina "XmNlabelString". Podríamos complementar el ejemplo de arriba del siguiente modo:

Arg r[10];
XmString un_texto;

un_texto = XmStringCreateSimple("Eso es todo, Amigos");

XtSetArg(r[0],XmNwidth,318);		/* Primer recurso */
XtSetArg(r[1],XmNlabelString,un_texto); /* Segundo recurso */

2.3.3 Usando las rutinas de creación

Teniendo definido nuestro array de recursos, podremos fácilmente crear el Widget con nuestras rutinas de creación de Widgets de la sección 2.3.1:

Widget pb;	/* Push Button */
Arg r[10];
XmString un_texto;

un_texto = XmStringCreateSimple("Texto de la etiqueta");

XtSetArg(r[0],XmNwidth,318);		/* Primer recurso */
XtSetArg(r[1],XmNlabelString,un_texto); /* Segundo recurso */

pb = (Widget)XmCreatePushButton(app_shell,"Botito",r,2);

Obsérvese que hemos declarado un nuevo Widget (llamado "pb") el cual es creado mediante XmCreatePushButton. Esta rutina ha tomado los siguientes argumentos, respectivamente:

  • El Widget de máximo nivel (retornado por XtAppInitialize), con lo que nuestro push button pasará a ser un "hijo" del primero, es decir, aparecerá en la misma ventana.

  • El nombre del Widget, que potencialmente puede ser utilizado para modificar sus recursos. Cualquier nombre hace el trabajo.

  • El array de recursos

  • La cantidad de recursos de ese array que se deben asignar. Nótese que si bien el array puede contener hasta 10 recursos, solo se han definido dos (con XtSetArg).

2.4 Especificar procedimientos Callback

2.4.1 Filosofía de diseño

En los sistemas de ventanas, el diseño del flujo de ejecución de los programas difiere sustancialmente del paradigma orientado al "proceso".

Tradicionalmente, la ejecución de un programa se ordenaba de acuerdo a las tareas que se debían realizar, y a las condiciones que satisfacían los datos de entrada.

Sin embargo, este no es el caso de los programas orientados a sistemas de ventanas. En éstos, el orden de ejecución está gobernado fundamentalmente por las acciones del usuario, y todo se orienta a "responder" a sus acciones. Por ejemplo, los programas típicamente "descansan" a la espera de que el usuario presione algún botón de la ventana, y sólo cuando esto ocurra, se ejecutará el código correspondiente. Esta forma de programación, orientada a "Eventos", es además la más eficiente desde el punto de vista de la compartición de recursos de procesamiento.

2.4.2 Funciones Callback

Como se explica líneas arriba, los programas normalmente "esperan" a que se produzca un evento que los "re-active", como puede ser la presión de un botón, o la introducción de un texto, o el desplazamiento de una barra de scroll, etc.

En otras palabras, el programador deberá programar "respuestas" a "eventos" generados en los Widgets de su aplicación; y siguiendo el paradigma del lenguaje C, estas "respuestas" deberán consistir de funciones a ser llamadas cuando se produce un determinado evento. A estas funciones que "retornan" el control a la aplicación se les denomina "funciones Callback".

2.4.3 Especificación de funciones Callback

Para especificar una función Callback, es necesario indica el Widget a partir del cual se genera el Callback, y el tipo de evento ocurrido en el Widget. Supongamos que nuestra función Callback (definida en otro lugar) se llama "hola_peru", ésta se podrá "instalar" para nuestro Push Button, en caso de ser presionado (evento XmNactivateCallback) mediante:

	XtAddCallback(pb,XmNactivateCallback,hola_peru,NULL);

Por otro lado, la función "hola_peru" debería tener la siguiente forma:

void hola_peru(Widget w, XtPointer client_data, XtPointer event_data)
{
printf("Hola desde el Peru!\n");
}

Para des-instalar una función Callback, usar la función XtRemoveCallback.

2.5 Hacer visible la ventana y sus widgets

Para que un widget pueda ser visualizado, hay que indicar a Xt que lo debe "administrar". Una forma de llevar esto a cabo es mediante la función XtManageChild. Para el caso anterior, bastará con:


	XtManageChild(pb);

La función XtCreateManagedWidget permite crear un widget y que éste sea automáticamente "administrado". Por motivos didácticos hemos prescindido de su utilización.

Por otro lado, para evitar que un widget sea visualizado de modo automático, podemos hacer el recurso XmNmappedWhenManaged a "false".

Una vez listos nuestros widgets, procedemos a "visualizar la ventana", para lo cual basta con invocar a la función XtRealizeWidget con el widget padre como argumento:


	XtRealizeWidget(app_shell);

2.6 Entrar al "loop" principal

Una vez que hemos terminado con la ventana, debemos hacer que nuestro programa "espere" a los eventos del usuario. Para esto podemos utilizar la función XtAppMainLoop, a la cual se le proporciona el "application context" visto en 2.2:

	XtAppMainLoop(app);

3 Programar y compilar ejemplos Motif

Aquí vamos a presentar de modo ordenado todo el código fragmentado del capítulo anterior. El primer ejemplo utiliza un widget tipo "Label", por lo que será creado con XmCreateLabel, y no utiliza ninguna función callback. Para ser coherentes con la siguiente sección, el lector debería denominar a su archivo de texto fuente etiqueta.c.

3.1 Crear un Label

	#include <Xm/Xm.h>
	#include <Xm/Label.h>

	int main(int argc, char *argv[])
	{
	Widget app_shell,lb;	/* top level widget y el label */
	XtAppContext app;	/* para guardar el application context */

	Arg r[1];		/* Recursos (solo requiero uno) */
	XmString un_texto;	/* Para almacenar un "XmString" */

	app_shell = XtAppInitialize(&app,"Ejemplo",NULL,0,&argc,argv,NULL,NULL,0);

	un_texto = XmStringCreateSimple("Una etiqueta de prueba");
	XtSetArg(r[0],XmNlabelString,un_texto);  /* Inscribir el recurso */

	lb = (Widget)XmCreateLabel(app_shell,"etq",r,1); /* Crear el widget */
	XtManageChild(lb);
	XtRealizeWidget(app_shell);

	XtAppMainLoop(app_shell); /* Loop Principal */

	return 0;  /* Para que el compilador no de mensajes de alerta */
	}

3.2 Compilar programas Motif

3.2.1 Sistema operativo

Ahora que tenemos un pequeño programa completo, probablemente sea un buen momento para ver cómo lo compilamos. Sólo me voy a referir al sistema Unix: Lo que sigue ha sido probado en Linux y Solaris, por lo que en otros Unix’es puede haber algunas diferencias.

3.2.2 El Makefile

En los sistemas Unix existe una herramienta de automatización de desarrollo de software denominada make. Este programa opera a partir de un archivo de configuración (o de reglas) conocido como el makefile. Recomiendo al lector nombrar a su archivo de reglas de make con la palabra Makefile.

Este archivo permite especificar diversos indicadores para la compilación del software. El siguiente ejemplo ha servido para compilar los ejemplos de este capítulo:


CFLAGS=-I/usr/X11R6/LessTif/Motif1.2/include
LDFLAGS=-L/usr/X11R6/LessTif/Motif1.2/lib -lXm -lXt -lX11 -lSM -lICE

all: etiqueta

En otro sistema tuve que utilizar en cambio:


CFLAGS=-I/usr/local/LessTif/Motif2.0/include
LDFLAGS=-L/usr/local/LessTif/Motif2.0/lib -lXm

all: etiqueta

Como se aprecia, en la primera línea he indicado al compilador dónde debe buscar los archivos cabecera (los .h) de Motif. En algunos sistemas (que traen la opción de desarrollo Motif incorporada) esto no será necesario, pues Motif estará instalado en los directorios "standard" del sistema (como /usr/include). La segunda línea, de igual modo, permite indicar al compilador (más precisamente al enlazador), dónde buscar las librerías para el programa, y qué librerías va a utilizar. Nuevamente, los usuarios con soporte Motif incorporado probablemente no requerirán la primera parte (la que corresponde al directorio de búsqueda de LessTif).

La tercera línea corresponde a los nombres de los programas ejecutables a ser "creados" partiendo de sus fuentes en lenguaje C. En nuestro caso, vamos a generar un programa llamado “etiqueta” y se entiende que nuestro archivo con el código fuente se llama etiqueta.c.

Si tuviéramos varios programas que compilar, sólo debemos añadir sus nombres a continuación de la palablabra "all:" como se muestra en el ejemplo:


CFLAGS=-I/usr/X11R6/LessTif/Motif1.2/include
LDFLAGS=-L/usr/X11R6/LessTif/Motif1.2/lib -lXm -lXt -lX11 -lSM -lICE

all: etiqueta botontest my_prog spreadsh

Lamentablemente otros detalles referidos a la configuración del "Makefile" podrían causar ciertos problemas por lo que el usuario deberá consultar con el administrador del sistema.

3.2.3 Compilar usando el Makefile

Una vez que el "makefile" está terminado, sólo se debe tipear make. Este comando buscará en el directorio actual un archivo de reglas llamado Makefile:

$ make
$ ./etiqueta

Si la compilación falla, y los errores no son de sintaxis o de escritura incorrecta del código fuente en C (lo cual es la causa más común), entonces el problema puede radicar en el "makefile". Por ejemplo, si no se pueden encontrar los archivos cabecera (como Xm.h), entonces el error está en el directorio especificado en CFLAGS. Por otro lado, si al final el enlazador no puede encontrar la librería Xm (suele aparecer como libXm), entonces se deberá corregir la definición de LDFLAGS.

Si no se disponde de los archivos cabecera o de la librería, entonces no se podrá desarrollar aplicaciones Motif.

3.3 Crear un PushButton

El segundo ejemplo muestra el uso de un widget tipo PushButton, así como una función callback:

	#include <Xm/Xm.h>
	#include <Xm/PushB.h>
	#include <stdio.h>

	/* Prototipo de la función callback */
	void hola_peru(Widget ,XtPointer ,XtPointer);

	int main(int argc, char *argv[])
	{
	Widget app_shell,pb;	/* top level widget y el push button */
	XtAppContext app;	/* para guardar el application context */

	Arg r[10];		/* Recursos */
	XmString un_texto;	/* Para almacenar un "XmString" */

	app_shell = XtAppInitialize(&app,"Ejemplo",NULL,0,&argc,argv,NULL,NULL,0);

	/* Inscribir dos recursos en "r" */
	XtSetArg(r[0],XmNwidth,318);
	un_texto = XmStringCreateSimple("Presionar");
	XtSetArg(r[1],XmNlabelString,un_texto);

	/* Crear el widget, función callback y "administrar" */
	pb = (Widget)XmCreatePushButton(app_shell,"Botito",r,2);
	XtAddCallback(pb,XmNactivateCallback,hola_peru,NULL);
	XtManageChild(pb);

	XtRealizeWidget(app_shell);

	/* Loop principal */
	XtAppMainLoop(app);

	return 0;
	}

	/* La definición de la función callback */
	void hola_peru(Widget w, XtPointer client_data, XtPointer event_data)
	{
	printf("Hola desde el Peru!\n");
	}

4 Más Widgets Motif

En este capítulo vamos a ver algunos ejemplos de otros widgets Motif. Como se apreciará, la estructura del programa es la misma que hemos venido desarrollando.

4.1 Arrow Button

	#include <Xm/Xm.h>
	#include <Xm/ArrowB.h>
	#include <stdio.h>

	void say_hello( Widget w, XtPointer client_data, XtPointer event_data)
	{
	    printf("Flechado!\n");
	}


	int main(int argc, char *argv[])
	{
	Widget toplevel, flecha;
	XtAppContext app;

	toplevel = XtAppInitialize(&app, "Flechita", NULL, 0,
        &argc, argv, NULL, NULL,0);

	flecha = (Widget) XmCreateArrowButton(toplevel, "boto", NULL, 0);
	XtManageChild(flecha);
	XtAddCallback(flecha,XmNactivateCallback, say_hello, NULL);

	XtRealizeWidget(toplevel);
	XtAppMainLoop(app);

	return 0;
	}

4.2 ScrollBar

El ScrollBar permite al usuario arrastrar un indicador linealmente para indicar en forma gráfica una magnitud. Es frecuentemente usado para desplazar los contenidos de las ventanas cuando éste es mayor que la última.

	#include <Xm/Xm.h>
	#include <Xm/ScrollBar.h>
	#include <stdio.h>

	Widget toplevel, scr;

	void say_scroll( Widget w, XtPointer client_data, XtPointer event_data)
	{
	int a;
	XmScrollBarGetValues(scr,&a,NULL,NULL,NULL);
	printf("Movido Scroll! Valor = %d\n",a);
	}

	int main(int argc, char *argv[])
	{
	XtAppContext  app;
	Arg rec[3];

	toplevel = XtAppInitialize(&app, "Scrolling", NULL, 0,
	&argc, argv, NULL, NULL,0);

	/* Vamos a dos recursos para el tamanho del widget: */
	XtSetArg(rec[0],XmNwidth,70);
	XtSetArg(rec[0],XmNheight,350);

	/* Se los aplicamos al widget toplevel */
	XtSetValues(toplevel,rec,2);

	/* El array rec se puede reutilizar ahora con el widget scr */

	/* Recursos para el widget ScrollBar  */
	XtSetArg(rec[0],XmNminimum,100);
	XtSetArg(rec[1],XmNmaximum,300);
	XtSetArg(rec[2],XmNsliderSize,35);
	scr = (Widget)XmCreateScrollBar(toplevel, "barrita", rec, 3);
	XtManageChild(scr);

	/* Introducir el callback */
	XtAddCallback(scr,XmNvalueChangedCallback, say_scroll, NULL);

	XtRealizeWidget(toplevel);
	XtAppMainLoop(app);

	return 0;
	}

Obsérvese el uso de los recursos XmNminimum, XmNmaximum y XmNsliderSize, los cuales representan los valores extremos de la escala del scroll (100-300). Sin embargo, la barra de desplazamiento tiene una longitud de 35 pixels, por lo que el rango que realmente retorna el widget será entre 100 y (300-35)=265. Esto se puede apreciar ejecutando el programa y desplazando la barra.

Comentarios finales

Resumen de lo aprendido

Al terminar este tutorial, el lector debe estar en la capacidad de comprender los aspectos principales involucrados en la ejecución y desarrollo de aplicaciones Motif bajo X11:

  • La arquitectura de X11

  • Los componentes de las aplicaciones Motif

  • El proceso de compilación de aplicaciones Motif

Así mismo deberá tener conocimiento de una serie de Widgets Motif relativamente básicos:

  • Label

  • PushButton

  • ArrowButton

  • ScrollBar

De aquí en adelante

Lo que hemos visto hasta aquí, debe permitir al lector desarrollar una serie de aplicaciones medianamente potentes de propósito general. Sin embargo, este tutorial es introductorio y todos los temas se han tocado superficialmente, mientras que hemos obviado otros más o menos relacionados. Por ejemplo, no hemos tratado los widgets más avanzados (en especial los soportados por la versión 2.0 de Motif), ni las facilidades de "drag and drop". De igual modo con los aspectos avenzados del X Toolkit (como la creación de nuevos Widgets). Como se dijo en la introducción, la programación de áreas de dibujo requiere utilizar algunas funciones de X-lib, cosa que tampoco se ha visto aquí. El interesado en realizar todas estas tareas deberá consultar una serie de libros para cada tema, por lo que se debe consultar la bibliografía.

Agradecimientos

Un agradecimiento especial a los estudiantes de la Marina de Guerra que tuvieron la paciencia y dedicación suficiente para desarrollar el "Workshop" con Motif incluido. Igualmente a Fernando Livia y César Castillo por permitirme participar del "Workshop".

Referencias/Bibliografía

Heller, Dan, Ferguson, Paula M. & Brennan, David, Motif Programming Manual, Volume 6A, O’Reilly & Associates, 2nd Edition February 1994, ISBN: 1-56592- 016-3.