Existen algunos detalles de los ejemplos anteriores que hay que aclarar. Los tipos gint, gchar, etc. que puede ver por ahí son typedefs a int y a char respectivamente. Sirven para que no haya que tener en cuenta el tamaño de cada uno de ellos a la hora de hacer cálculos.
Un buen ejemplo es "gint32" que es un entero de 32 bits independientemente de la plataforma, bien sea un Alpha de 64 bits o un i386 de 32. Todas las definiciones son muy intuitivas y se encuentran definidas en glib/glib.h (que se incluye desde gtk.h).
Probablemente el lector se haya dado cuenta de que se puede usar GtkWidget cuando la función llama a un GtkObject. Esto es debido a que GTK está orienta a objetos y un widget es un GtkObject.
Si estudiamos en mayor profundidad la declaración de gtk_signal_connect:
gint gtk_signal_connect( GtkObject *object,
gchar *name,
GtkSignalFunc func,
gpointer func_data );
Podemos darnos cuenta de que el valor devuelto es del tipo gint. Este valor es una etiqueta que identifica a la función de respuesta. Tal y como ya vimos podemos tener tantas funciones de respuesta por seÑal y objeto como sean necesarias, y cada una de ellas se ejecutará en el mismo orden en el que fueron enlazadas.
Esta etiqueta nos permite eliminar la función respuesta de la lista usando:
void gtk_signal_disconnect( GtkObject *object,
gint id );
Por lo tanto podemos desconectar un manejador de señal pasándole a la función anterior el widget del que queremos desconectar y la etiqueta o id devuelta por una de las funciones signal_connect.
Otra función que se usa para quitar desconectar todos los controladores de un objeto es:
void gtk_signal_handlers_destroy( GtkObject *object );
Esta llamada es bastante auto explicativa. Simplemente quitamos todos los controladores de señales del objeto que pasamos como primer argumento.
Vamos a mejorar el ejemplo para obtener una visión más amplia sobre el manejo de señales y respuestas. También introduciremos los widgets usados para empaquetar.
/* Aquí comienza el ejemplo helloworld2 */
#include <gtk/gtk.h>
/* Nuestra respuesta mejorada. Los argumentos de la función se imprimen en el stdout.*/
void callback (GtkWidget *widget, gpointer data)
{
g_print ("Hello again - %s was pressed\n", (char *) data);
}
/* otra respuesta*/
void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
{
gtk_main_quit ();
}
int main (int argc, char *argv[])
{
/* GtkWidget es el tipo de almacenamiento usado para los wigtes*/
GtkWidget *window;
GtkWidget *button;
GtkWidget *box1;
/* Esta llamada está presente en todas las aplicaciones basadas en GTK.
* Los argumentos introducidos
* a la aplicación*/
gtk_init (&argc, &argv);
/* creamos una nueva ventana*/
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* Esta llamada es nueva, establece el título de la ventana a "Hello Buttons!"*/
gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
/* Establecemos el controlador para la llamada delete_event que termina la aplicación
* inmediatamente. */
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC (delete_event), NULL);
/* Establecemos el ancho del borde de la ventana.*/
gtk_container_border_width (GTK_CONTAINER (window), 10);
/* Creamos una caja donde empaquetaremos los widgets. El procedimiento de empaquetamiento
* se describe en detalle en la sección correspondiente. La caja no se ve realmente,
* sólo sirve para introducir los widgets. */
box1 = gtk_hbox_new(FALSE, 0);
/* ponemos la caja en la ventana principal */
gtk_container_add (GTK_CONTAINER (window), box1);
/* Creamos un nuevo botón con la etiqueta "Button 1". */
button = gtk_button_new_with_label ("Button 1");
/* Cada vez que el botón sea pulsado llamamos a la función "callback" con un puntero a
* "button 1" como argumento.*/
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
/* En lugar de gtk_container_add empaquetamos el botón en la caja invisible, que a su vez
* ha sido empaquetado en la ventana.*/
gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
/* Siempre se debe realizar este paso. Sirve para decirle a GTK que los preparativos del
* botón ya se han finalizado y que por tanto puede ser mostrado. */
gtk_widget_show(button);
/* hacemos lo mismo para crear un segundo botón. */
button = gtk_button_new_with_label ("Button 2");
/* Llamamos a la misma función de respuesta pero con diferente argumento: un puntero
* a "button 2". */
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
/* El orden en que mostramos los botones no es realmente importante, pero se recomienda
* mostrar la ventana la última para que todo aparezca de golpe. */
gtk_widget_show(button);
gtk_widget_show(box1);
gtk_widget_show (window);
/* Esperamos en gtk_main a que comience el espectáculo.*/
gtk_main ();
return 0;
}
/* final del ejemplo*/
Compile el programa usando los mismos argumentos que en el ejemplo anterior. Probablemente ya se habrá dado cuenta de que no hay una forma sencilla para terminar el programa, se debe usar el gestor de ventanas o la línea de comandos para ello. Un buen ejercicio para el lector es introducir un tercer botón que termine el programa. También puede resultar interesante probar las diferentes opciones de gtk_box_pack_start() mientras lee la siguiente sección. Intente cambiar el tamaño de la ventana y observe el comportamiento.
Como última nota, existe otra definición bastante útil: gtk_widow_new() - GTK_WINDOW_DIALOG. Su comportamiento es un poco diferente y debe ser usado para ventanas intermedias (cuadros de diálogo).