ProgramacionGTKenC/CapituloVII

De Wiki GNOME Chile
(Diferencias entre revisiones)
Saltar a: navegación, buscar
(Comenzando)
 
(No se muestran 10 ediciones intermedias realizadas por un usuario)
Línea 1: Línea 1:
=Autotools y sus amigos=
+
{{Plantilla:Globo_alerta|Artículo incompleto.}}
  
En esta leccion, aprenderemos a crear y distribuir un proyecto usando las no bien ponderadas Autotools (Autoconf/Automake y amigos).
+
= Conceptos avanzados en GTK+ =
  
==Comenzando==
+
Hemos quedado con un monton de dudas hasta el momento acerca de algunos de los ejemplos presentados anteriormente.
  
Primero, debemos crear un directorio donde ira nuestro proyecto. En mi caso, /home/jci/code/proyecto1
+
Cubramos cada uno de ellos aqui, de menor a mayor complejidad.
  
<pre>$ mkdir ~/code/proyecto1
+
Habiamos visto que cada uno de los widgets recibe (y emite) señales. Estas son tomadas por el subsistema de GTK+ y ejecuta las funciones pertinentes, permitiendo que los programas dejen de ser aburridos y ejecuten mas acciones, con o sin la ayuda del usuario.
$ cd ~/code/proyecto1</pre>
+
  
Pueden elegir el directorio que deseen
+
Una señal que se ha visto seguido es la asociada al widget boton:
  
Dentro de ese directorio deben colocar los siguientes archivos:
+
<pre>
 +
g_signal_connect ((GObject *) boton_n,"clicked", (GCallback * ) funcion_n, NULL);
 +
</pre>
  
* AUTHORS, donde iran los autores del programa
+
esto es que la funcion "funcion_n" es ejecutada al momento de hacer clic en el boton "boton_n".
* LICENSE, donde describiran la licencia que adoptaran para el programa
+
* Changelog, un control de cambios del programa
+
* COPYING, donde ira una copia de la licencia (en el caso de GPL, GPLv2, etc)
+
* INSTALL, con instrucciones especiales para la instalacion del programa
+
* README, con instrucciones acerca del programa, o bien para indicar algo que debe leer el usuario antes de ejecutar el programa
+
  
Los archivos anteriores no tienen que ver directamente con el sistema de construccion. Estan como manera informativa, indicar la licencia en la cual se distribuyen, entre otros elementos (como dependencias, autores, entre otros topicos).
+
Antiguamente (y en varios ejemplos antiguos) se ve que la funcion se llamaba gtk_signal_connect(). Esta es una funcion que se depreco desde la version 2.x de GTK+.
  
Empecemos.
+
No crean que es la unica señal que es capaz de recibir el boton (ni otros widgets). Antes de continuar, hay que entender un poco la jerarquia de objetos de GTK+.
  
==configure.ac==
+
== Objetos ==
  
Esta es la plantilla para el script de configure. Indica, por ejemplo, las dependencias para compilar, tests para ver si existe o no alguna aplicacion o biblioteca del sistema, entre otras.
+
Habia dicho de un principio que todos los widgets son herencia de GObject, y a GtkWidget, y esta es una de las razones que la declaracion de los widgets en codigo pueda ser:
  
Su mision es solamente proveer un unico punto para la configuracion del programa, ademas de hacerlo un poco mas portable. Es la base de la mayoria de las GNU tools (o bien, de las que se distribuyen como tal).
+
<pre>
 +
GtkWidget * widget1;
 +
GtkWidget * widget2;
 +
...
 +
</pre>
  
El unico inconveniente de este archivo es que esta escrito en lenguaje de macros, que una vez usando autoconf, seran expandidas a un shell script. Algo complicado al principio de entender.
+
Ser "hijos" de GObject les permite, por ejemplo, la emision y recepcion de señales (de ahi la funcion g_object_signal).
  
Ahora, supongamos que mi proyecto se llama "diamante" y que el fuente del programa esta en la ruta src/diamante.c. Haremos un archivo configure.ac para mostrar la forma de crear uno correctamente.
+
Los GObjects es el tipo fundamental para los atributos y objetos en GTK+. Esto permite tener una serie de fundaciones (funciones base) para la construccion de objetos, acceso a metodos y soporte de señales.  
  
<pre>AC_INIT([Diamante], [0.1], [[email protected]], [diamante])
+
Un GObject posee solo cuatro funciones basicas:
 +
* get_property()
 +
* set_property()
 +
* dispose()
 +
* finalize()
  
AC_CONFIG_SRCDIR(src/diamante.c)
+
Solo nos centraremos en las primeras dos.  
  
AC_CONFIG_HEADER(config.h)
+
Habiamos visto hace algunas entregas atras que podemos cambiar algunas propiedades de los widgets.
  
AM_INIT_AUTOMAKE
+
Un ejemplo simple:
AM_MAINTAINER_MODE
+
  
AC_PROG_CC
+
<pre>
AC_HEADER_STDC
+
gtk_window_set_title((GtkWindow *) ventana, "titulo de la ventana");
 +
</pre>
  
AC_SUBST(CFLAGS)
+
Esto solo cambia el titulo de la ventana a "titulo de la ventana".
AC_SUBST(CPPFLAGS)
+
AC_SUBST(LDFLAGS)
+
  
GTK_MODULES="gtk+-2.0"
+
Revisando un poco la documentacion de GTK+, se puede ver que el widget de ventana posee la propiedad "title" (titulo). Esta la podemos cambiar con la funcion anterior (gtk_window_set_title). Pero como un widget es un GObject, podemos cambiar la propiedad "title" usando una funcion de GObject:
PKG_CHECK_MODULES(GTK, $GTK_MODULES)
+
AC_SUBST(GTK_CFLAGS)
+
AC_SUBST(GTK_LIBS)
+
  
AC_OUTPUT([
+
<pre>
Makefile
+
g_object_set_property((Gobject *) ventana, "title", "titulo de la ventana");
src/Makefile
+
</pre>
])</pre>
+
  
Veamos que significa cada cosa
+
Ademas, las funciones de GObject nos permiten cambiar multiples propiedades de un widget!
  
AC_INIT indica que Autoconf debe iniciarse para crear el proyecto. Los argumentos son
+
<pre>
 +
g_object_set((GObject *) ventana,
 +
                        "title", "titulo de la ventana",
 +
                        "default-height", 100,
 +
                        "default-width", 200,
 +
                        "accept-focus", TRUE,
 +
                        "destroy-with-parent", TRUE,
 +
                        NULL);
 +
</pre>
  
(nombre_proyecto, version, email, nombrecorto)
+
La unica señal que puede recibir un GObject es "notify", que es usada para emitir advertencias acerca de propiedades no esperadas o no soportadas por el objeto. Por ejemplo, si queremos preguntar por "title" en un widget de boton.
  
AC_CONFIG_SRC indica cual es el directorio donde se encuentra el codigo fuente de nuestro programa (en este caso, src/diamante.c).
+
== GtkWidgets ==
  
AC_CONFIG_HEADERS le indica al preprocesador de C que deba leer un archivo antes de compilar. Por lo general, es config.h. Este config.h se crea de forma automatica usando autoheader.
+
Los GtkWidgets son capaces de recibir muchas señales. La lista completa es:
  
AM_INIT_AUTOMAKE hace que Automake inicie ;)
+
{| style="width: 80%; background=#cfd5dc; text-align:left"
 +
|+ style="background:#eae8e3" | Se&ntilde;ales
 +
|- style="background:#ffefdb; text-align:left"
 +
| &nbsp; || &nbsp;
 +
|-
 +
|
 +
* accel-closures-changed
 +
* button-press-event
 +
* button-release-event
 +
* can-activate-accel
 +
* child-notify
 +
* client-event
 +
* configure-event
 +
* delete-event
 +
* destroy-event
 +
* direction-changed
 +
* drag-begin
 +
* drag-data-delete
 +
* drag-data-get
 +
* drag-data-received
 +
* drag-drop
 +
* drag-end
 +
* drag-leave
 +
* drag-motion
 +
* enter-notify-event
 +
* event
 +
* event-after
 +
* expose-event
 +
* focus
 +
* focus-in-event
 +
* focus-out-event
 +
* grab-broken-event
 +
* grab-focus
 +
* grab-notify
 +
* hide
 +
* hierarchy-changed
 +
* key-press-event
 +
||
 +
* key-release-event
 +
* leave-notify-event
 +
* map
 +
* map-event
 +
* mnemonic-activate
 +
* motion-notify-event
 +
* no-expose-event
 +
* parent-set
 +
* popup-menu
 +
* property-notify-event
 +
* proximity-in-event
 +
* proximity-out-event
 +
* realize
 +
* screen-changed
 +
* scroll-event
 +
* selection-clear-event
 +
* selection-get
 +
* selection-notify-event
 +
* selection-received
 +
* selection-request-event
 +
* show
 +
* show-help
 +
* size-allocate
 +
* size-request
 +
* state-changed
 +
* style-set
 +
* unmap
 +
* unmap-event
 +
* unrealize
 +
* visibility-notify-event
 +
* window-state-event
 +
|}
  
AM_MAINTAINER_MODE hace que se habilite la opcion --enable-maintainer-mode en la configuracion del programa, para agregar opciones tales como bibliotecas con soporte de debugging, entre otras.
 
  
AC_PROG_CC y AC_HEADER_STDC le indica a Autoconf que debe aceptar un compilador de C y que debe poseer las cabeceras estandar. Por lo general, si no estan instaladas, el error sera el siguiente
 
  
<pre>C compiler error : cannot create executables</pre>
+
Cada una de estas señales posee una funcion tipo asociada. Por ejemplo, "selection-get":
  
Autoconf permite el uso de variables. En este caso, cree la variable GTK_MODULES, donde agregue los modulos necesarios para que el programa pudiera compilar. En este caso, gtk+-2.0.
+
<pre>
 +
void user_function (GtkWidget * widget,
 +
                    GtkSelectionData * data,
 +
                    guint info,
 +
                    guint time,
 +
                    gpointer user_data);
 +
</pre>
  
PKG_CHECK_MODULES permite que pkg-config (importante, lo vimos en la primera leccion) pueda verificar si los modulos existen. Y los comprueba desde la variable GTK_MODULES. Ademas, llena una variable llamada GTK.
+
mientras que "grab-broken-event"
  
La macro AC_SUBST pasa valores desde autoconf a automake (para la creacion del Makefile). Es decir, si existe una cadena para reemplazo (generalmente, $(CADENA) ) en un Makefile.in, configure reemplazara la cadena con el valor que exista en los parentesis de AC_SUBST.
+
<pre>
 +
gboolean user_function (GtkWidget * widget,
 +
                        GdkEvent * event,
 +
                        gpointer user_data);
 +
</pre>
  
Por ejemplo,  
+
Todas las funciones tienen como primer argumento "GtkWidget * widget", que es el widget que origina la señal, y como ultimo argumento "gpointer data" que es un tipo de dato cualquiera (un puntero).
  
<pre>AC_SUBST(CFLAGS)</pre>
+
== MVC ==
  
CFLAGS es una variable que contiene, por ejemplo, el siguiente valor:
+
Cuando salio la version 2.0 de GTK+, se penso introducir MVC (Model-View-Controller) al momento de crear algunos controles. Uno de esos es el combobox.
  
<pre>-l -g -d --march="i686" </pre>
+
Habia quedado debiendo el ejemplo, asi que aqui vamos.
  
Si existe algo asi en el Makefile.in
+
=== TreeModel ===
  
<pre>CFLAGS=$(CFLAGS)</pre>
+
El widget TreeModel define un arbol generico usado para el widget GtkTreeView. Es una interfaz bien abstracta, que es representada de forma de columnas.
  
sera reemplazado asi
+
Para hacer la vida mas facil para los programadores, hay dos modelos genericos para usarse : los GtkListStore y los GtkTreeStore. Para la mayoria de los casos, estos dos modelos bastan y sobran.
  
<pre>CFLAGS=-l -g -d --march="i686"</pre>
+
Ademas, cada nodo (de un ListStore o de TreeStore) esta representado por un GtkTreeIter. Estos iteradores son la forma basica de acceder a un modelo.
  
al crear el archivo Makefile desde la plantilla. Esto se vera mas claro una vez que explique mas adelante el uso de AC_OUTPUT. Asi que sigan leyendo! :D
+
Podran imaginarse entonces para donde va toda esta conversacion : para poder crear un combo box mas nuevo es menos truculento de lo que parece.
  
Hasta el momento, tengo creado un directorio con los siguientes archivos:
+
=== ComboBoxes con y sin modelos ===
  
<pre>./configure.ac
+
Menti anteriormente cuando dije que solo era posible crear los combobox nuevo solo usando MVC. Hay interfaces para hacer combos de forma MUY facil.  
./src
+
./src/diamante.c</pre>
+
  
Por el momento no me voy a preocupar por los archivos faltantes, ya que no son necesarios para el proyecto (por ahora).
+
Veamos la razon con un programa:
  
Ahora, necesito que algunas plantillas (.m4) se copien al directorio de mi proyecto. Lo puedo hacer con aclocal:
+
<pre>
 +
#include <gtk/gtk.h>
  
<pre>$ aclocal</pre>
+
int main (int argc, char * argv[])
 
+
lo que copiara un archivo llamado aclocal.m4
+
 
+
Luego, ejecutar autoheader, para que cree automaticamente el archivo config.h.in
+
 
+
<pre>$ autoheader</pre>
+
 
+
Ahora, ejecutar
+
 
+
<pre>$ automake --add-missing --gnu</pre>
+
 
+
La salida sera la siguiente:
+
 
+
<pre>configure.ac: installing `./install-sh'
+
configure.ac: installing `./mkinstalldirs'
+
configure.ac: installing `./missing'</pre>
+
 
+
Ahora, ejecutemos autoconf
+
 
+
<pre>$ autoconf</pre>
+
 
+
Y listo. Tendremos un configure limpiecito.
+
 
+
ALTO! Veamos que pasa al ejecutar ./configure
+
 
+
<pre>$ ./configure
+
[...challa...]
+
configure: creating ./config.status
+
config.status: error: cannot find input file: Makefile.in</pre>
+
 
+
Hmmm...Makefile.in...de donde vendra eso?
+
 
+
Un Makefile en una distribucion con autotools esta creado con una serie de plantillas. Primero Makefile.am para automake que genera un Makefile.in, que es una plantilla para un archivo Makefile.
+
 
+
Como no existe el archivo Makefile.in, no puede generar el archivo Makefile.
+
 
+
Como se sabe esto?
+
 
+
Veamos las ultimas lineas del archivo configure.ac:
+
 
+
<pre>AC_OUTPUT([
+
Makefile
+
src/Makefile
+
])</pre>
+
 
+
AC_OUTPUT le indica a autoconf que genere esos archivos de forma automagica usando plantillas, o bien archivos .in. En este caso, Makefile.in y src/Makefile.in van a generar los archivos Makefile y src/Makefile, en ese orden. Ninguno de ellos esta. Tampoco podremos crear los archivos a mano, ya que esa es pega de Automake.
+
 
+
Creamos entonces un Makefile.am en el directorio raiz:
+
 
+
<pre>$ touch Makefile.am</pre>
+
 
+
y volvemos a ejecutar
+
 
+
<pre>$ automake --gnu --add-missing</pre>
+
 
+
La salida es un poco mas larga que la vez anterior:
+
 
+
<pre>Makefile.am: installing `./COPYING'
+
Makefile.am: installing `./INSTALL'
+
Makefile.am: required file `./NEWS' not found
+
Makefile.am: required file `./README' not found
+
Makefile.am: required file `./AUTHORS' not found
+
Makefile.am: required file `./ChangeLog' not found</pre>
+
 
+
Me indica que los archivos NEWS, README, AUTHORS y ChangeLog no existen. Creemos estos archivos en blanco:
+
 
+
<pre>$ touch NEWS README AUTHORS ChangeLog</pre>
+
 
+
No es necesario volver a ejecutar automake, ya que no hemos modificado Makefile.am
+
 
+
Ahora, un configure nuevamente:
+
 
+
<pre>$ ./configure</pre>
+
 
+
Esta vez, magicamente, funciono. Sin ningun error. Pero aun falta.
+
 
+
Por ahora, configure.ac y configure dejemoslo de lado. Concentremonos en el archivo Makefile.am
+
 
+
==Makefile.am==
+
 
+
Por el momento el archivo Makefile.am de la raiz del proyecto esta vacio. Pero agreguemos lo siguiente en el:
+
 
+
<pre>SUBDIRS=src</pre>
+
 
+
La directiva SUBDIRS indica a Automake cuales subdirectorios seguir una vez que termine con el make del directorio raiz. Por ejemplo, si hubiera puesto
+
 
+
<pre>SUBDIRS=src po intltool foo bar</pre>
+
 
+
Al ejecutar make, hubiera ejecutado  los makefiles de los directorios src, po, intltool, foo y bar, y luego el del raiz. Y en ese orden.
+
 
+
Volvamos a ejecutar automake
+
 
+
<pre>$ automake --gnu --add-missing</pre>
+
 
+
Y ahora
+
 
+
<pre>$ ./configure</pre>
+
 
+
Si todo va bien, ejecutemos
+
 
+
<pre>$ make</pre>
+
 
+
Deberia pasar el proyecto sin ningun problema. Mi salida fue la siguiente:
+
 
+
<pre>$ make
+
make  all-recursive
+
make[1]: Entering directory `/home/jci/code/diamante'
+
Making all in src
+
make[2]: Entering directory `/home/jci/code/diamante/src'
+
make[2]: Nothing to be done for `all'.
+
make[2]: Leaving directory `/home/jci/code/diamante/src'
+
make[2]: Entering directory `/home/jci/code/diamante'
+
make[2]: Leaving directory `/home/jci/code/diamante'
+
make[1]: Leaving directory `/home/jci/code/diamante'</pre>
+
 
+
Perfecto, nuestro sistema esta casi listo.
+
 
+
Pero solo falta ahora crear un programa, ya que diamante.c esta vacio! Y ademas, poder construirlo.
+
 
+
Asi que coloquemos un miserable hola mundo de la primera leccion. O bien, el programa que quieran.
+
 
+
Yo voy a ir con este :)
+
 
+
<pre>#include <gtk/gtk.h>
+
 
+
int main(int argc, char * argv[])
+
 
{
 
{
 
GtkWidget * ventana;
 
GtkWidget * ventana;
GtkWidget * boton;
+
GtkWidget * combo;
  
 
gtk_init(&argc, &argv);
 
gtk_init(&argc, &argv);
+
 
 
ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
boton = gtk_button_new_with_label("Hola Mundo");
+
combo = gtk_combo_box_new_text();
 +
 
 +
gtk_combo_box_append_text((GtkComboBox *) combo,
 +
  "Opcion 1");
 +
gtk_combo_box_append_text((GtkComboBox *) combo,
 +
  "Opcion 2");
 +
gtk_combo_box_append_text((GtkComboBox *) combo,
 +
  "Opcion 3");
 
 
gtk_container_add(GTK_CONTAINER(ventana), boton);
+
 
 +
gtk_container_add((GtkContainer *) ventana, combo);
 
gtk_widget_show_all(ventana);
 
gtk_widget_show_all(ventana);
  
gtk_main();
+
gtk_main();      
}</pre>
+
}
 
+
</pre>
Ahora, el siguiente actor : src/Makefile.am Ya que Autotools es un sistema de construccion automatica, y hemos dicho en el archivo Makefile.am, de la raiz del proyecto, que uno de los subdirectorios a ejecutar un Makefile es src/, entonces debemos tambien tener una plantilla (src/Makefile.am) para Automake.
+
 
+
Agreguemos lo siguiente en src/Makefile.am:
+
 
+
<pre>INCLUDES = -I$(top_srcdir) $(GTK_CFLAGS)
+
 
+
LIBS = $(GTK_LIBS)
+
 
+
bin_PROGRAMS = diamante</pre>
+
 
+
Recuerdan que AC_SUBST en Autoconf permitia reemplazar cadenas con los valores que tuvieran las variables? Las que se reemplazan son GTK_CFLAGS y GTK_LIBS.
+
 
+
La directiva INCLUDES indica que rutas de archivos de cabeceras agregar para compilar efectivamente un programa. Recuerdan que para compilar un programa en GTK+ era necesario usar el metodo de los backquotes para no colocar una tremenda linea?
+
 
+
<pre>$ gcc -o diamante.o diamante `pkg-config --cflags gtk+-2.0`</pre>
+
 
+
INCLUDES es equivalente.
+
 
+
Ahora, en INCLUDES hay ademas una variable $top_srcdir. Esa indica el directorio raiz de nuestro proyecto. Es solo en caso que usemos el archivo config.h para algo.
+
 
+
La directiva LIBS es la directiva para enlazar con las bibliotecas necesarias. En los ejemplos anteriores era algo asi
+
 
+
<pre>$ gcc -o diamante diamante.o `pkg_config --libs gtk+-2.0`</pre>
+
 
+
En este caso, es equivalente.
+
 
+
bin_PROGRAMS indica cual es el archivo binario a generar despues que se compilo el archivo. Recordar que se indica cuales archivos compilar en la directiva AC_CONFIG_SRCDIR de Autoconf :-D
+
 
+
De nuevo, ejecutamos automake en la raiz de nuestro proyecto.
+
 
+
<pre>$ automake --gnu --add-missing</pre>
+
 
+
Luego
+
 
+
<pre>$ ./configure</pre>
+
 
+
Y despues
+
 
+
<pre>$ make</pre>
+
 
+
Y veran que empezara a compilar el fuente que estaba en el directorio src. Excelente!
+
 
+
<pre>$ ls src/
+
diamante  diamante.c  diamante.o  Makefile  Makefile.am  Makefile.in</pre>
+
 
+
Perfecto! Es justo lo que necesito. Y hemos generado nuestro primer proyecto con Autotools!
+
 
+
==Creando la distribucion de nuestro proyecto==
+
 
+
Ahora veamos como podemos distribuirlo para colocarlo en nuestra pagina web y cachiporrearnos en el asado con los amigos que "publique mi primer programa en GTK+" :) . Para eso, primero debemos limpiar absolutamente todo.
+
 
+
No, no es borrar todo. Debemos sacar rastros de los Makefiles existentes. Para eso, una vez que ejecuten
+
 
+
<pre>$ ./configure</pre>
+
 
+
por enesima vez :) ejecuten
+
 
+
<pre>$ make
+
$ make distclean</pre>
+
 
+
Con make distclean, los archivos que se generan de forma automatica en el sistema de construccion son eliminados. Asi queda nuestro proyecto sin Makefiles ni archivos de dependencias, etc.
+
 
+
<pre>$ make distclean
+
make[1]: Entering directory `/home/jci/code/diamante/src'
+
test -z "diamante" || rm -f diamante
+
rm -f *.o core *.core
+
rm -f *.tab.c
+
rm -f
+
rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
rm -rf ./.deps
+
rm -f Makefile
+
make[1]: Leaving directory `/home/jci/code/diamante/src'
+
Making distclean in .
+
make[1]: Entering directory `/home/jci/code/diamante'
+
rm -f
+
rm -f config.h stamp-h1
+
rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
make[1]: Leaving directory `/home/jci/code/diamante'
+
rm -f config.status config.cache config.log configure.lineno
+
rm -f Makefile</pre>
+
 
+
Va a sonar a chiste, pero hay que ejecutar de nuevo
+
 
+
<pre>$ ./configure</pre>
+
 
+
Y una vez que termine, ejecutar
+
 
+
<pre>$ make distcheck</pre>
+
 
+
La opcion distcheck realiza una compilacion limpia, copia el arbol de compilacion completo en un directorio y ve si puede construir el proyecto. Si es asi, al final tendremos este lindo mensaje:
+
 
+
<pre>=============================================
+
diamante-0.1.tar.gz is ready for distribution
+
=============================================</pre>
+
 
+
Ese archivo .tar.gz podremos pasarselos a nuestros amigos, o bien respaldarlo donde queramos. :D
+
 
+
Veamos que tiene dentro...
+
 
+
<pre>$ tar tfz diamante-0.1.tar.gz
+
diamante-0.1/
+
diamante-0.1/aclocal.m4
+
diamante-0.1/AUTHORS
+
diamante-0.1/Makefile.am
+
diamante-0.1/README
+
diamante-0.1/install-sh
+
diamante-0.1/depcomp
+
diamante-0.1/config.h.in
+
diamante-0.1/INSTALL
+
diamante-0.1/ChangeLog
+
diamante-0.1/configure
+
diamante-0.1/src/
+
diamante-0.1/src/Makefile.am
+
diamante-0.1/src/diamante.c
+
diamante-0.1/src/Makefile.in
+
diamante-0.1/missing
+
diamante-0.1/Makefile.in
+
diamante-0.1/NEWS
+
diamante-0.1/mkinstalldirs
+
diamante-0.1/configure.ac
+
diamante-0.1/COPYING</pre>
+
 
+
La pregunta mas logica que se deben estar haciendo es "por que supo que era la version 0.1?"
+
 
+
Recuerdan la primera linea de AC_INIT del archivo configure.ac?
+
 
+
<pre>AC_INIT([Diamante], [0.1], [[email protected]], [diamante])</pre>
+
 
+
El segundo parametro es la version de nuestro programa.
+
 
+
No me creen? Cambien el valor de 0.1 a 0.2. Vuelvan a ejecutar todo en este orden:
+
 
+
<pre>$ autoheader
+
$ autoconf
+
$ automake --gnu --add-missing
+
$ make distclean
+
$ ./configure
+
$ make distcheck
+
...[challa]...
+
 
+
=============================================
+
diamante-0.2.tar.gz is ready for distribution
+
=============================================</pre>
+
 
+
Bonito, no?
+

Última revisión de 08:57 7 ago 2007

Error al crear miniatura: No se ha podido guardar la miniatura
Alerta
Artículo incompleto.

Contenido

[editar] Conceptos avanzados en GTK+

Hemos quedado con un monton de dudas hasta el momento acerca de algunos de los ejemplos presentados anteriormente.

Cubramos cada uno de ellos aqui, de menor a mayor complejidad.

Habiamos visto que cada uno de los widgets recibe (y emite) señales. Estas son tomadas por el subsistema de GTK+ y ejecuta las funciones pertinentes, permitiendo que los programas dejen de ser aburridos y ejecuten mas acciones, con o sin la ayuda del usuario.

Una señal que se ha visto seguido es la asociada al widget boton:

g_signal_connect ((GObject *) boton_n,"clicked", (GCallback * ) funcion_n, NULL);

esto es que la funcion "funcion_n" es ejecutada al momento de hacer clic en el boton "boton_n".

Antiguamente (y en varios ejemplos antiguos) se ve que la funcion se llamaba gtk_signal_connect(). Esta es una funcion que se depreco desde la version 2.x de GTK+.

No crean que es la unica señal que es capaz de recibir el boton (ni otros widgets). Antes de continuar, hay que entender un poco la jerarquia de objetos de GTK+.

[editar] Objetos

Habia dicho de un principio que todos los widgets son herencia de GObject, y a GtkWidget, y esta es una de las razones que la declaracion de los widgets en codigo pueda ser:

GtkWidget * widget1;
GtkWidget * widget2;
...

Ser "hijos" de GObject les permite, por ejemplo, la emision y recepcion de señales (de ahi la funcion g_object_signal).

Los GObjects es el tipo fundamental para los atributos y objetos en GTK+. Esto permite tener una serie de fundaciones (funciones base) para la construccion de objetos, acceso a metodos y soporte de señales.

Un GObject posee solo cuatro funciones basicas:

  • get_property()
  • set_property()
  • dispose()
  • finalize()

Solo nos centraremos en las primeras dos.

Habiamos visto hace algunas entregas atras que podemos cambiar algunas propiedades de los widgets.

Un ejemplo simple:

gtk_window_set_title((GtkWindow *) ventana, "titulo de la ventana");

Esto solo cambia el titulo de la ventana a "titulo de la ventana".

Revisando un poco la documentacion de GTK+, se puede ver que el widget de ventana posee la propiedad "title" (titulo). Esta la podemos cambiar con la funcion anterior (gtk_window_set_title). Pero como un widget es un GObject, podemos cambiar la propiedad "title" usando una funcion de GObject:

g_object_set_property((Gobject *) ventana, "title", "titulo de la ventana");

Ademas, las funciones de GObject nos permiten cambiar multiples propiedades de un widget!

g_object_set((GObject *) ventana, 
                         "title", "titulo de la ventana",
                         "default-height", 100,
                         "default-width", 200,
                         "accept-focus", TRUE,
                         "destroy-with-parent", TRUE,
                         NULL);

La unica señal que puede recibir un GObject es "notify", que es usada para emitir advertencias acerca de propiedades no esperadas o no soportadas por el objeto. Por ejemplo, si queremos preguntar por "title" en un widget de boton.

[editar] GtkWidgets

Los GtkWidgets son capaces de recibir muchas señales. La lista completa es:

Señales
   
  • accel-closures-changed
  • button-press-event
  • button-release-event
  • can-activate-accel
  • child-notify
  • client-event
  • configure-event
  • delete-event
  • destroy-event
  • direction-changed
  • drag-begin
  • drag-data-delete
  • drag-data-get
  • drag-data-received
  • drag-drop
  • drag-end
  • drag-leave
  • drag-motion
  • enter-notify-event
  • event
  • event-after
  • expose-event
  • focus
  • focus-in-event
  • focus-out-event
  • grab-broken-event
  • grab-focus
  • grab-notify
  • hide
  • hierarchy-changed
  • key-press-event
  • key-release-event
  • leave-notify-event
  • map
  • map-event
  • mnemonic-activate
  • motion-notify-event
  • no-expose-event
  • parent-set
  • popup-menu
  • property-notify-event
  • proximity-in-event
  • proximity-out-event
  • realize
  • screen-changed
  • scroll-event
  • selection-clear-event
  • selection-get
  • selection-notify-event
  • selection-received
  • selection-request-event
  • show
  • show-help
  • size-allocate
  • size-request
  • state-changed
  • style-set
  • unmap
  • unmap-event
  • unrealize
  • visibility-notify-event
  • window-state-event


Cada una de estas señales posee una funcion tipo asociada. Por ejemplo, "selection-get":

void user_function (GtkWidget * widget,
                    GtkSelectionData * data,
                    guint info,
                    guint time,
                    gpointer user_data);

mientras que "grab-broken-event"

gboolean user_function (GtkWidget * widget,
                        GdkEvent * event,
                        gpointer user_data);

Todas las funciones tienen como primer argumento "GtkWidget * widget", que es el widget que origina la señal, y como ultimo argumento "gpointer data" que es un tipo de dato cualquiera (un puntero).

[editar] MVC

Cuando salio la version 2.0 de GTK+, se penso introducir MVC (Model-View-Controller) al momento de crear algunos controles. Uno de esos es el combobox.

Habia quedado debiendo el ejemplo, asi que aqui vamos.

[editar] TreeModel

El widget TreeModel define un arbol generico usado para el widget GtkTreeView. Es una interfaz bien abstracta, que es representada de forma de columnas.

Para hacer la vida mas facil para los programadores, hay dos modelos genericos para usarse : los GtkListStore y los GtkTreeStore. Para la mayoria de los casos, estos dos modelos bastan y sobran.

Ademas, cada nodo (de un ListStore o de TreeStore) esta representado por un GtkTreeIter. Estos iteradores son la forma basica de acceder a un modelo.

Podran imaginarse entonces para donde va toda esta conversacion : para poder crear un combo box mas nuevo es menos truculento de lo que parece.

[editar] ComboBoxes con y sin modelos

Menti anteriormente cuando dije que solo era posible crear los combobox nuevo solo usando MVC. Hay interfaces para hacer combos de forma MUY facil.

Veamos la razon con un programa:

#include <gtk/gtk.h>

int main (int argc, char * argv[])
{
	GtkWidget * ventana;
	GtkWidget * combo;

	gtk_init(&argc, &argv);

	ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	combo = gtk_combo_box_new_text();

	gtk_combo_box_append_text((GtkComboBox *) combo, 
				  "Opcion 1");
	gtk_combo_box_append_text((GtkComboBox *) combo,
				  "Opcion 2");
	gtk_combo_box_append_text((GtkComboBox *) combo,
				  "Opcion 3");
	

	gtk_container_add((GtkContainer *) ventana, combo);
	gtk_widget_show_all(ventana);

	gtk_main();			       
}
Herramientas personales
Espacios de nombres

Variantes
Acciones
Navegación
Herramientas