1. ¿Qué es Motif?
Motif es, ante todo, un estándar (IEEE 1295) creado en los 80', el cual define una API en lenguaje C para el desarrollo de interfaces gráficas (GUIs) sobre X Window (para entornos Unix). También especifica una "Guía de estilo", detallando el aspecto que debería tener una aplicación Motif.
Por supuesto, esta denominación también se aplica a la biblioteca que implementa el estándar, y fue originalmente desarrollada por el Open Source Fundation, para competir con OpenLook. Actualmente es mantenida por el Open Group. Existen varias implementaciones de Motif además de la original, entre ellas OpenMotif (una versión libre para sistemas operativos de código abierto, como GNU/Linux o FreeBSD), Lesstif y SGI Motif.
2. ¿Porque Motif?
Habiendo tantas bibliotecas ("toolkits") disponibles (entre ellas GTK+, creada precisamente para reemplazar a Motif en el desarrollo de El Gimp), cabe preguntarse que utilidad tiene aprender a programar con esta biblioteca. Bien, en primer lugar, porque se encuentra estandarizada. Esto significa que existe estabilidad en la API, y si surgen nuevas adiciones a la biblioteca, probablemente no será necesario modificar el código fuente de nuestro programa. A pesar de sus años, sigue siendo la biblioteca de ventanas nativa de los sistemas Unix. Se ha utilizado en miles de programas, y hoy día se mantiene como el toolkit líder en estaciones de trabajo profesionales, para el desarrollo de aplicaciones críticas. También es relativamente pequeña, y muy eficiente (es probablemente la biblioteca de este tipo más rápida, en parte por su sencillez). Ese carácter minimalista hace que Motif no sea tan "bonita" en comparación con GTK+ o Qt, pero es sin duda eficaz. Incluso es posible compilarla estáticamente para obtener ejecutables de tamaño razonable, y prescindir de la instalación de bibliotecas dinámicas en el sistema destino. Motif también soporta Unicode, por lo que es apta para aplicaciones internacionalizadas.
3. Obteniendo la biblioteca.
La última especificación de Motif es la 2.1. Existen muchas implementaciones de este estándar, pero la mayoría de ellas son comerciales (debemos pagar por las licencias). La principal, por supuesto, es la del Open Group. Sin embargo, las versiones que se tendrán en cuenta en este artículo son las disponibles gratuitamente: OpenMotif y Lesstif.
OpenMotif es una versión libre, siempre que las aplicaciones se utilicen en sistemas operativos que también sean libres. La última versión estable es la 2.2, pero puede obtenerse la beta de la 2.3.
Lesstif es un proyecto de un grupo de programadores denominado "The Hungry Programmers". Si bien aún no implementa la totalidad del estándar, es una versión muy completa y evolucionada. Tiene licencia LGPL, por lo que resulta menos restrictiva que OpenMotif, y se puede usar en cualquier entorno Unix (o incluso bajo Windows, mediante Cygwin). La última versión es la 0.95.0.
Los que posean distribuciones de GNU/Linux basadas en Debian, pueden buscar en los repositorios de dichos sistemas ámbas bibliotecas.
4. Widgets, Gadgets y generalidades.
Motif es un toolkit construido sobre la biblioteca Xt Intrinsics (X Toolkit), que a su vez es soportada por Xlib (la API básica de X Window). Xt ofrece una serie de estructuras y funciones que pueden usarse como base para construir conjuntos de "widgets". También esconde la mayor parte de la complejidad de Xlib, facilitando la programación. Tanto Motif como Xt están dirigidas por eventos, lo que en pocas palabras significa que la aplicación entra, luego de su ejecución, en un bucle o "loop", manejando mensajes de X Window hasta que se ordena cerrar la aplicación (se sale del bucle). Este tutorial no discutirá las características distribuidas de X Window, y tampoco analizará en profundidad la biblioteca Xt.
Los "widgets" son los elementos que constituyen una interfaz gráfica (GUI), como por ejemplo ventanas, botones, etiquetas, etc. Los mismos operan de forma independiente de la aplicación, salvo por acciones predefinidas por el usuario. En Motif, los widgets se encuentran declarados en archivos de cabecera, como <MainW.h>, <PushB.h>, <Text.h>, entre muchos otros. Pueden encontrarse en la carpeta <Xm>, habitualmente ubicada en </usr/include>. Puede observarse que en dicha carpeta hay otros archivos con los mismos nombres que los citados anteriormente, con la salvedad de que terminan con una letra 'P' (por ejemplo, <PushBP.h>). Estos archivos son cabeceras privadas, y representan funciones y tipos de datos que se ocultan de la interfaz pública de Motif. Esto es así porque la biblioteca (al igual que Xt) está orientada a objetos, y por ende implementa conceptos como encapsulamiento y herencia (mediante la definición de clases de widgets), todo esto a pesar de estar escrita en C, un lenguaje que no brinda soporte explícito para dicho paradigma. Bizarro, sin lugar a dudas. Por cierto, también se pueden encontrar archivos cuyos nombres terminan con G. Estos son "gadgets", y son similares a los widgets en su aspecto. Sin embargo, el comportamiento de estos gadgets no está definido dentro de los mismos, sino que es responsabilidad del widget que los contiene. Por ejemplo, un gadget no se redibuja a si mismo en forma automática. Poseen la ventaja de ser más "ligeros" que los widgets (en lo que respecta a consumo de recursos), pero en las últimas versiones de Motif los widgets están más optimizados (al igual que lo está X Windows), por lo que no es común usar gadgets, y en el presente artículo no se los volverá a mencionar.
5. Funciones de la biblioteca.
Todo programa Motif necesita de dos elementos básicos: un "Application Context" (una estructura que utiliza Xt para manejar información interna relacionada con nuestra aplicación), y un "Top Level Widget", o widget principal (el cuál representa el control de más alta jerarquía, y será el "padre" de todos los demás widgets). Además, los widgets disponen de recursos ("resources"), los cuales son atributos configurables. Hay un gran número de recursos por cada widget, en parte debido a que son heredables. Los recursos tienen un nombre, que generalmente comienzan con "XmN"; por ejemplo, los botones (PushButtons) tienen recursos como XmNlabelString (el texto del botón) o XmNshadowThickness (el grosor de la sombra del botón). Un tipo de recurso especial es el denominado "callback resource". El mismo es un puntero a una función que debe ejecutarse cuando se efectúa cierta acción sobre el widget. Volviendo al caso del PushButton, el recurso XmNactivateCallback apunta a una función que será llamada al pulsar el botón (click con el botón izquierdo). Los recursos se pueden introducir al momento de crear el widget, o bien pueden ser modificados posteriormente con las siguientes funciones:
void XtSetValues(Widget hW, ArgList pArgs, Cardinal iNumArgs);
void XtVaSetValues(Widget hW, ...);En la primera, hW es el widget, pArgs es un array de elementos "Arg" (los cuales contienen cadenas de caracteres que representan a los recursos), y iNumArgs es simplemente un entero que indica el número de elementos del array pArgs. En el caso de XtVaSetValues, además del widget, se pasan los parámetros de a pares (el nombre del recurso primero, y luego el valor del mismo), terminando con un carácter nulo ("NULL"). Por ejemplo, para cambiar el texto y el grosor de la sombra de un botón previamente creado, se pueden usar las llamadas:
XmString sText = XmStringCreateLocalized ("Aceptar");
XtVaSetValues(hW, XmNlabelString, sText, XmNshadowThickness, 5, NULL );XmString es un tipo definido por Motif para manejar strings con soporte internacionalizado. Para crear los widgets, suelen llamarse a funciones del siguiente estilo:
Widget XmCreate<nombre del widget>(Widget hWparent, String szName, ArgList pArgs, Cardinal iNumArgs);
hWparent es el widget padre (normalmente, el que contiene al widget que estamos creando), szName es el nombre del widget, pArgs es el array de recursos, y por último iNumArgs es la cantidad de elementos de pArgs. Cada vez que se crea un widget, debe llamarse a la siguiente función:
void XtManageChild(Widget hWchild);donde hWchild es el widget que se acaba de crear. Esta llamada hará que Xt se encargue de administrar al widget. Existen otras funciones que habrá que utilizar, como XtVaOpenApplication, XtAddCallBack, XtRealizeWidget y XtAppMainLoop. Las mismas se explicarán brevemente con un ejemplo. Probablemente ya haya notado los prefijos "Xm" y "Xt" en todas las funciones expuestas hasta ahora. No es difícil adivinar su utilidad: "Xm" se refiere a las funciones que corresponden a la API de Motif, y "Xt" hace lo propio con X Toolkit. Se trata de una convención muy popular para evadir las colisiones de espacio de nombres.
6. Un ejemplo sencillo
El siguiente código representa uno de los programas Motif mas elementales, y está basado en un ejemplo del Manual del Programador Motif:
/* <hello.c> Ejemplo de programación Motif */
/*01*/ #include <Xm/PushB.h>
/*02*/ void button_pushed_cb (Widget hWidget, XtPointer pClientData, XtPointer pCallData)
/*03*/ {
/*04*/ printf ("¡Hola Mundo!"\n");
/*05*/ }
/*06*/
/*07*/ int main (int argc, char *argv[])
/*08*/ {
/*09*/ Widget hToplevel, hButton;
/*10*/ XtAppContext hApp;
/*11*/ Arg sArgs[2];
/*12*/
/*13*/ XtSetLanguageProc (NULL, NULL, NULL);
/*14*/ hToplevel = XtVaOpenApplication (&hApp, "Hello", NULL, 0, &argc, argv,
/*15*/ NULL,sessionShellWidgetClass, NULL);
/*16*/
/*17*/ hButton = XmCreatePushButton (hToplevel, "button", NULL, NULL);
/*18*/
/*19*/ XmString sText = XmStringCreateLocalized ("Presione, por favor ");
/*20*/ XtVaSetValues(hButton, XmNlabelString, sText, NULL);
/*21*/ XtAddCallback (hButton, XmNactivateCallback, button_pushed_cb, NULL);
/*22*/
/*23*/ XtManageChild (hButton);
/*24*/ XtRealizeWidget (hToplevel);
/*25*/ XtAppMainLoop (hApp);
/*26*/ }
Puede compilarse <hello.c> con el siguiente comando:
cc -o hello hello.c -lXm -lXt -lX11Observe el orden en el que se enlazan las bibliotecas (no debe alterarlo). El resultado de ejecutar el ejemplo es una pequeña ventana, cuyo único contenido es un botón, el cuál al pulsarlo imprimirá un saludo en la salida del terminal.
En la primer línea se incluye el archivo de cabecera que corresponde al widget PushButton. Luego se define una función, button_pushed_cb, que se llamará al presionar el botón. Observe los últimos tres caracteres del nombre de la función; es una convención que se recomienda usar para las funciones "callbacks" (de retrollamada). Esta función será el único "callback resource" que se utilizará en este programa. Ya dentro del main, en la línea 12 se declaran dos widgets (uno para el programa en sí, y otro para el PushButton). En la línea 13 se declara el "Application Context" de <hello.c>.
La función XtSetLanguageProc invocada en la línea 15 configura una función para el manejo del lenguaje local, asociada al "application context" del programa. En este caso, todos sus parámetros son NULL, por lo que se usa el procedimiento por defecto (es lo más común).
En la línea 16 se llama a XtVaOpenApplication. La misma realiza una variedad de acciones, de las cuales las más importantes son el crear el "application context" de nuestro programa, y llamar a XtOpenDisplay para abrir una ventana de X Window, sobre la cuál se mostrará la aplicación. Los parámetros usados en el ejemplo son los más comunes, como por ejemplo el tercero (el nombre de la aplicación), o el octavo (la "clase" del widget TopLevel). También se observa que se le pasan los parámetros obtenidos de la línea de comandos (argc y argv). De hecho, el título de la ventana de nuestro ejemplo será "hello", el cuál es por supuesto el valor de argv[0]. No es el objetivo de este tutorial describir a Xt, por lo que se omitirá el detalle de esta función. Pueden consultarse los enlaces recomendados para encontrar la documentación de Xt.
En la línea 19 se crea un PushButton (cuyo widget se guarda en la variable hButton), y en las líneas 21 y 22 se le asigna una etiqueta al mismo. En la siguiente línea se llama a XtAddCallback, la cuál tiene el siguiente prototipo:
void XtAddCallback(Widget hW, String szCallbackName,
XtCallbackProc pfCallback, XtPointer pClientData);En la llamada, hW es el widget a configurar; szCallbackName es el nombre del recurso; pfCallback es un puntero a función, y pClientData es un parámetro que se le pasará a la función button_pushed_cb cuando sea invocada. En forma genérica, el prototipo de las funciones de retrollamada debe ser:
void myfunc_cb(Widget hW, XtPointer pClientData, XtPointer pCallData);en donde hW es el widget al que se asoció la función. pClientData es un valor adicional, el cuál se registra al llamar a XtAddCallback; y por último, pCallData es un parámetro que el widget le pasa a myfunc_cb cuando la invoca. Este último parámetro depende del tipo de callback registrado, y suele ser un puntero a alguna estructura con información acerca del estado del widget.
En la línea 25 se asocia el botón a nuestra aplicación, y en la línea 26 se llama a XtRealizeWidget. Esta última función tiene una tarea un tanto compleja, la cual consiste (en síntesis), en recorrer la jerarquía de widgets (a partir del widget pasado como parámetro, o sea hTopLevel), inicializarlos y volverlos visibles. Por último, en la línea 27 se llama a XtAppMainLoop, que se encargará de entrar en un bucle infinito y procesar eventos de X Window, hasta que se ordene cerrar la ventana, en cuyo caso interrumpirá el bucle y dará por terminada la ejecución.
7. Enlaces recomendados
http://www.opengroup.org/motif/
El sitio oficial de Motif. Aquí pueden adquirirse licencias comerciales de la biblioteca.
http://www.motifzone.com
Documentación y foros sobre Motif. Además, pueden bajarse las últimas versiones de OpenMotif.
http://www.lesstif.org
Sitio oficial de Lesstif, la implementación LGPL de Motif.
http://www.ist.co.uk/motif/books/vol6A/BookTOC.fm.html
Manual del programador de Motif. Imprescindible para desarrollar aplicaciones serias.
http://docs.linux.cz/programming/gui/motif/motif.html
Muy buen tutorial de Motif (algo desactualizado, pero igual muy recomendable).
http://lesstif.sourceforge.net/doc/super-ux/g1ae03e/part1/contents.html#Part1
Manual de Xt, importante para entender con un poco más de profundidad la programación en X Windows.

3 comentarios:
Programador Bizarro!!!
Muy lindo el motif... pero no me podes hacer la consulta anidada en Access 2003. Me dejaste con el culo al aire.
Ehhh... ¿quién sois?
Soy sólo un humilde paladín de la verdad y la justicia, que sólo busca un software más bizarro.
Publicar un comentario en la entrada