Ci sono alcune cose che avrete probabilmente notato nei precedenti esempi che hanno bisogno di una spiegazione. I gint, gchar ecc. che vedete sono tipi di dato (typedef) riferiti rispettivamente a int e char. Questo viene fatto per rimediare alle scomode dipendenze dalle dimensioni di semplici tipi di dato quando si fanno dei calcoli. Un buon esempio è ``gint32'' il quale sarà un tipo di dato riferito ad un intero a 32 bit per tutte le piattaforme, sia per gli x86 che per gli per gli alpha a 64 bit. I tipi di dato sono ben spiegati più avanti e molto intuitivi. Sono definiti in glib/glib.h (il quale viene incluso da gtk.h).
Noterete anche la possibilità di utilizzare un GtkWidget quando la funzione richiede un GtkObject. GTK è una libreria orienta agli oggetti ed un widget è un oggetto.
Diamo un'altra occhiata alla dichiarazione della funzione gtk_signal_connect.
gint gtk_signal_connect (GtkObject *object, gchar *name,
GtkSignalFunc func, gpointer func_data);
Notate il valore di ritorno definito come gint? Questo è un identificatore
per la vostra funzione di callback. Come detto sopra, si possono avere più
funzioni di ritorno per ogni segnale e per ogni ogetto a seconda delle
necessità, ed ognuna sarà eseguita in sequenza, nell'ordine in cui
è stata collegata.
Questo identificatore vi permette di rimuovere una funzione dalla lista delle funzioni di ritorno tramite la seguente chiamata
void gtk_signal_disconnect (GtkObject *object,
gint id);
Così, passando il widget da cui si vuole rimuovere il gestore di segnale e
l'identificativo restituito da una delle funzioni signal_connect, si può
rimuovere il gestore di segnale che si desidera dal widget.
Un'altra funzione, usata per rimuovere tutti i segnali di un widget in una volta sola è:
gtk_signal_handlers_destroy (GtkObject *object);
Questa chiamata è abbastanza auto esplicativa. Semplicemente rimuove tutti i segnali collegati al widget che si passa alla funzione come argomento.
Diamo un'occhiata ad una versione migliorata di Hello World con altri esempi sulle callback. Questo ci introdurrà anche al nostro prossimo argomento, l'impacchettamento dei widget.
/* helloworld2.c */
#include <gtk/gtk.h>
/* La nostra funzione di callback migliorata. I dati passati a questa
* vengono stampati su stdout. */
void callback (GtkWidget *widget, gpointer data)
{
g_print ("Hello again - %s was pressed\n", (char *) data);
}
/* Un'altra callback */
void delete_event (GtkWidget *widget, gpointer data)
{
gtk_main_quit ();
}
int main (int argc, char *argv[])
{
/* GtkWidget e' il tipo di dato per i widget */
GtkWidget *window;
GtkWidget *button;
GtkWidget *box1;
/* Questa funzione e' invocata in tutte le applicazioni GTK, gli
argomenti sono analizzati e restituiti all'applicazione. */
gtk_init (&argc, &argv);
/* Crea una nuova finestra */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* Questa e' una nuova chiamata. Assegna "Hello Buttons" come titolo
della nostra finestra */
gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
/* Qui settiamo il gestore per il segnale "delete_event" che
immediatamente esce dalla applicazione.
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC (delete_event), NULL);
/* predispone il bordo della finestra */
gtk_container_border_width (GTK_CONTAINER (window), 10);
/* creiamo una scatola dove mettere tutti i widget. Questa è descritta
dettagliatamente nella sezione "packing". La scatola non è realmente
visibile, è solamente usata per sistemare i widget. */
box1 = gtk_hbox_new(FALSE, 0);
/* Inseriamo la scatola nella finestra */
gtk_container_add (GTK_CONTAINER (window), box1);
/* Creiamo un nuovo bottone con etichetta "Button 1" */
button = gtk_button_new_with_label ("Button 1");
/* Quando il bottone e' premuto, noi invocheremo la funzione di callback,
con un puntatore alla stringa "button 1" come proprio argomento) */
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
/* invece di aggiungerlo alla finestra, lo inseriamo nella scatola invisibile,
la quale e' stata inserita nella finstra. */
gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
/* Ricordati sempre questo passo. Dice a GTK che la preparazione di questo
bottone e' finita e che quindi puo' essere mostrato. */
gtk_widget_show(button);
/* Facciamo la stessa cosa per il secondo bottone. */
button = gtk_button_new_with_label ("Button 2");
/* Chiamiamo la stessa funzione ma passandogli un argomento differente,
gli passiamo un puntatore alla stringa "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);
/* L'ordine nel quale i bottoni sono visualizzati non e' realmente importante,
ma io ti raccomando di mostrare per ultima la finestra cosi' che tutto
sia visualizzato in una volta sola */
gtk_widget_show(button);
gtk_widget_show(box1);
gtk_widget_show (window);
/* e ora ci mettiamo in gtk_main e aspettiamo che il diverimento inizi.
gtk_main ();
return 0;
}
Compilate questo programma usando gli stessi argomenti di link del nostro primo esempio. Noterete che questa volta non c'è un modo semplice per uscire dal programma, si deve usare il nostro window manager o la linea di comando per uccidere l'applicazione. Un buon esercizio per il lettore è quello di inserire un tezo bottone ``quit'' che faccia uscire dal programma. Potete anche divertirvi con le opzioni di gtk_box_pack_start() mentre leggete il prossimo capitolo. Provate a ridimensionare la finestra ed a osservare cosa succede.
Solo una piccola nota: c'è un'altra definizione di gtk_window_new() - GTK_WINDOW_DIALOG. Questa interagisce con il window manager in un modo un po' diverso, e dovrebbe essere usata per finestre temporanee.